From 2ebce5610a61e109217ad6629b08e52b5a3105c4 Mon Sep 17 00:00:00 2001 From: Rafael Tonholo Date: Tue, 28 Oct 2025 09:17:28 -0300 Subject: [PATCH 1/8] chore(message-reader): add :feature:mail:message:reader module --- feature/mail/message/reader/api/build.gradle.kts | 14 ++++++++++++++ .../feature/mail/message/reader/api/.gitkeep | 0 feature/mail/message/reader/impl/build.gradle.kts | 15 +++++++++++++++ .../feature/mail/message/reader/impl/.gitkeep | 0 settings.gradle.kts | 2 ++ 5 files changed, 31 insertions(+) create mode 100644 feature/mail/message/reader/api/build.gradle.kts create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep create mode 100644 feature/mail/message/reader/impl/build.gradle.kts create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep diff --git a/feature/mail/message/reader/api/build.gradle.kts b/feature/mail/message/reader/api/build.gradle.kts new file mode 100644 index 00000000000..36dd498f42b --- /dev/null +++ b/feature/mail/message/reader/api/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id(ThunderbirdPlugins.Library.kmp) +} + +kotlin { + sourceSets { + commonMain.dependencies { + } + } +} + +android { + namespace = "net.thunderbird.feature.mail.message.reader.api" +} diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/feature/mail/message/reader/impl/build.gradle.kts b/feature/mail/message/reader/impl/build.gradle.kts new file mode 100644 index 00000000000..6d94c5abee4 --- /dev/null +++ b/feature/mail/message/reader/impl/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id(ThunderbirdPlugins.Library.kmp) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.feature.mail.message.reader.api) + } + } +} + +android { + namespace = "net.thunderbird.feature.mail.message.reader.impl" +} diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/settings.gradle.kts b/settings.gradle.kts index e39595534d8..16f8cb1c8da 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -101,6 +101,8 @@ include( ":feature:mail:message:list", ":feature:mail:message:export:api", ":feature:mail:message:export:impl-eml", + ":feature:mail:message:reader:api", + ":feature:mail:message:reader:impl", ) include( From 77af91ce7dd2a51bdbe0c932c5c0c66aab05d75b Mon Sep 17 00:00:00 2001 From: Rafael Tonholo Date: Tue, 28 Oct 2025 09:37:25 -0300 Subject: [PATCH 2/8] chore(message-reader): enable webview debugging on development builds --- .../ui/legacy/src/main/java/com/fsck/k9/view/MessageWebView.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/view/MessageWebView.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/view/MessageWebView.kt index 6555c4a966e..ff121d80162 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/view/MessageWebView.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/view/MessageWebView.kt @@ -6,6 +6,7 @@ import android.util.AttributeSet import android.webkit.WebSettings.LayoutAlgorithm import android.webkit.WebSettings.RenderPriority import android.webkit.WebView +import com.fsck.k9.core.BuildConfig import com.fsck.k9.mailstore.AttachmentResolver import net.thunderbird.core.android.common.view.showInDarkMode import net.thunderbird.core.android.common.view.showInLightMode @@ -62,6 +63,7 @@ class MessageWebView : WebView, KoinComponent { // Disable network images by default. This is overridden by preferences. blockNetworkData(true) + setWebContentsDebuggingEnabled(BuildConfig.DEBUG) } private fun configureDarkLightMode( From e32bc2e3e266316491cd4f15985588dd13b08a92 Mon Sep 17 00:00:00 2001 From: Rafael Tonholo Date: Thu, 6 Nov 2025 12:54:11 -0400 Subject: [PATCH 3/8] chore(message-reader): add use_new_message_reader_css_styles feature flag --- app-k9mail/build.gradle.kts | 1 + .../kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt | 2 ++ .../kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt | 2 ++ app-thunderbird/build.gradle.kts | 1 + .../android/featureflag/TbFeatureFlagFactory.kt | 2 ++ .../android/featureflag/TbFeatureFlagFactory.kt | 2 ++ .../android/featureflag/TbFeatureFlagFactory.kt | 2 ++ .../android/featureflag/TbFeatureFlagFactory.kt | 2 ++ feature/mail/message/reader/api/build.gradle.kts | 2 ++ .../thunderbird/feature/mail/message/reader/api/.gitkeep | 0 .../mail/message/reader/api/MessageReaderFeatureFlags.kt | 7 +++++++ 11 files changed, 23 insertions(+) delete mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/MessageReaderFeatureFlags.kt diff --git a/app-k9mail/build.gradle.kts b/app-k9mail/build.gradle.kts index ecad942e649..1e1ae615999 100644 --- a/app-k9mail/build.gradle.kts +++ b/app-k9mail/build.gradle.kts @@ -142,6 +142,7 @@ dependencies { implementation(projects.core.ui.legacy.theme2.k9mail) implementation(projects.feature.launcher) implementation(projects.feature.mail.message.list) + implementation(projects.feature.mail.message.reader.api) implementation(projects.legacy.core) implementation(projects.legacy.ui.legacy) diff --git a/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt b/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt index 71b0651713f..64b58c3eda6 100644 --- a/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt +++ b/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags class K9FeatureFlagFactory : FeatureFlagFactory { override fun createFeatureCatalog(): List { @@ -20,6 +21,7 @@ class K9FeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = true), ) } } diff --git a/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt b/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt index 9a39c1364ba..194e533466e 100644 --- a/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt +++ b/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags /** * Feature flags for K-9 Mail (release) @@ -23,6 +24,7 @@ class K9FeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = false), ) } } diff --git a/app-thunderbird/build.gradle.kts b/app-thunderbird/build.gradle.kts index 6e36feb3d75..9e7b514092e 100644 --- a/app-thunderbird/build.gradle.kts +++ b/app-thunderbird/build.gradle.kts @@ -222,6 +222,7 @@ dependencies { implementation(projects.feature.account.settings.impl) implementation(projects.feature.mail.message.list) + implementation(projects.feature.mail.message.reader.api) implementation(projects.feature.widget.messageList) implementation(projects.feature.widget.messageListGlance) diff --git a/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 3b5526ed6ee..1d2ad5f28b0 100644 --- a/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags /** * Feature flags for Thunderbird Beta @@ -23,6 +24,7 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = false), ) } } diff --git a/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index f0f957042e3..1b09198e0ef 100644 --- a/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags /** * Feature flags for Thunderbird Daily @@ -23,6 +24,7 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = true), ) } } diff --git a/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 498e87865db..0daf653fe54 100644 --- a/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags /** * Feature flags for Thunderbird Debug @@ -23,6 +24,7 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = true), ) } } diff --git a/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 470e84e59c0..c6f0c59c2fb 100644 --- a/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -7,6 +7,7 @@ import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags /** * Feature flags for Thunderbird (release) @@ -23,6 +24,7 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), + FeatureFlag(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles, enabled = false), ) } } diff --git a/feature/mail/message/reader/api/build.gradle.kts b/feature/mail/message/reader/api/build.gradle.kts index 36dd498f42b..76d4b7b5e65 100644 --- a/feature/mail/message/reader/api/build.gradle.kts +++ b/feature/mail/message/reader/api/build.gradle.kts @@ -5,6 +5,8 @@ plugins { kotlin { sourceSets { commonMain.dependencies { + implementation(projects.core.common) + implementation(projects.core.featureflag) } } } diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/MessageReaderFeatureFlags.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/MessageReaderFeatureFlags.kt new file mode 100644 index 00000000000..e093461c43d --- /dev/null +++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/MessageReaderFeatureFlags.kt @@ -0,0 +1,7 @@ +package net.thunderbird.feature.mail.message.reader.api + +import net.thunderbird.core.featureflag.FeatureFlagKey + +object MessageReaderFeatureFlags { + val UseNewMessageReaderCssStyles = FeatureFlagKey("use_new_message_reader_css_styles") +} From 0fefd2d9074f0c15ac1a31cef51e3fa0330fed14 Mon Sep 17 00:00:00 2001 From: Rafael Tonholo Date: Thu, 6 Nov 2025 12:57:58 -0400 Subject: [PATCH 4/8] feat(message-reader): add css classname provider --- app-common/build.gradle.kts | 2 + .../api/css/DefaultCssClassNameProvider.kt | 26 +++++++++++++ .../app/k9mail/feature/FeatureModule.kt | 10 +++++ .../android/feature/FeatureModule.kt | 10 +++++ .../reader/api/css/CssClassNameProvider.kt | 37 +++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssClassNameProvider.kt diff --git a/app-common/build.gradle.kts b/app-common/build.gradle.kts index 373e8e396a0..4e6e3f97476 100644 --- a/app-common/build.gradle.kts +++ b/app-common/build.gradle.kts @@ -49,6 +49,8 @@ dependencies { implementation(projects.feature.mail.message.export.api) implementation(projects.feature.mail.message.export.implEml) + implementation(projects.feature.mail.message.reader.api) + implementation(projects.feature.mail.message.reader.impl) implementation(projects.mail.protocols.imap) implementation(projects.backend.imap) diff --git a/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt b/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt new file mode 100644 index 00000000000..59d9bdf013b --- /dev/null +++ b/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt @@ -0,0 +1,26 @@ +package net.thunderbird.android.feature.mail.message.reader.api.css + +import com.fsck.k9.message.html.EmailTextToHtml +import net.thunderbird.core.featureflag.FeatureFlagProvider +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider + +class DefaultCssClassNameProvider( + featureFlagProvider: FeatureFlagProvider, + override val defaultNamespaceClassName: String, +) : CssClassNameProvider { + override val rootClassName: String = "${defaultNamespaceClassName}__message-viewer" + override val mainContentClassName: String = "${defaultNamespaceClassName}__main-content" + override val plainTextMessagePreClassName: String = + if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) { + EmailTextToHtml.K9MAIL_CSS_CLASS + } else { + "${defaultNamespaceClassName}__plain-text-message-pre" + } + override val signatureClassName: String = + if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) { + "${defaultNamespaceClassName}__signature" + } else { + "k9mail-signature" + } +} diff --git a/app-k9mail/src/main/kotlin/app/k9mail/feature/FeatureModule.kt b/app-k9mail/src/main/kotlin/app/k9mail/feature/FeatureModule.kt index 5fd16ed15e1..93ddebcabd8 100644 --- a/app-k9mail/src/main/kotlin/app/k9mail/feature/FeatureModule.kt +++ b/app-k9mail/src/main/kotlin/app/k9mail/feature/FeatureModule.kt @@ -5,8 +5,11 @@ import app.k9mail.feature.funding.featureFundingModule import app.k9mail.feature.migration.launcher.featureMigrationModule import app.k9mail.feature.onboarding.migration.onboardingMigrationModule import app.k9mail.feature.telemetry.telemetryModule +import com.fsck.k9.BuildConfig +import net.thunderbird.android.feature.mail.message.reader.api.css.DefaultCssClassNameProvider import net.thunderbird.feature.account.settings.featureAccountSettingsModule import net.thunderbird.feature.mail.message.list.featureMessageListModule +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider import org.koin.dsl.module val featureModule = module { @@ -18,4 +21,11 @@ val featureModule = module { includes(featureMessageListModule) single { K9FundingSettings() } + + single { + DefaultCssClassNameProvider( + featureFlagProvider = get(), + defaultNamespaceClassName = BuildConfig.APPLICATION_ID.replace(".", "-"), + ) + } } diff --git a/app-thunderbird/src/main/kotlin/net/thunderbird/android/feature/FeatureModule.kt b/app-thunderbird/src/main/kotlin/net/thunderbird/android/feature/FeatureModule.kt index 82a9250486c..bd5df1fe0b4 100644 --- a/app-thunderbird/src/main/kotlin/net/thunderbird/android/feature/FeatureModule.kt +++ b/app-thunderbird/src/main/kotlin/net/thunderbird/android/feature/FeatureModule.kt @@ -5,8 +5,11 @@ import app.k9mail.feature.funding.featureFundingModule import app.k9mail.feature.migration.launcher.featureMigrationModule import app.k9mail.feature.onboarding.migration.onboardingMigrationModule import app.k9mail.feature.telemetry.telemetryModule +import net.thunderbird.android.BuildConfig +import net.thunderbird.android.feature.mail.message.reader.api.css.DefaultCssClassNameProvider import net.thunderbird.feature.account.settings.featureAccountSettingsModule import net.thunderbird.feature.mail.message.list.featureMessageListModule +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider import org.koin.dsl.module internal val featureModule = module { @@ -18,4 +21,11 @@ internal val featureModule = module { includes(featureMessageListModule) single { TbFundingSettings() } + + single { + DefaultCssClassNameProvider( + featureFlagProvider = get(), + defaultNamespaceClassName = BuildConfig.APPLICATION_ID.replace(".", "-"), + ) + } } diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssClassNameProvider.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssClassNameProvider.kt new file mode 100644 index 00000000000..76be3c1d750 --- /dev/null +++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssClassNameProvider.kt @@ -0,0 +1,37 @@ +package net.thunderbird.feature.mail.message.reader.api.css + +/** + * Provides CSS class names used for styling the message viewer. + * + * This allows for a consistent and centralized way to manage the class names + * used in the HTML of the message display, making it easier to style and + * maintain. + */ +interface CssClassNameProvider { + /** + * The class name used to namespace all CSS rules to avoid conflicts with message content. + * + * This class should be applied to a high-level container element wrapping the entire message view. + */ + val defaultNamespaceClassName: String + + /** + * The class name for the root element of the message content. This is typically the `` tag. + */ + val rootClassName: String + + /** + * The class name for the main content block of the message viewer. + */ + val mainContentClassName: String + + /** + * The class name for the `
` tag that wraps plain text messages to preserve formatting.
+     */
+    val plainTextMessagePreClassName: String
+
+    /**
+     * The class name used to style email signatures.
+     */
+    val signatureClassName: String
+}

From 43a85eb7f4bc34856f401f27277203492eaf5339 Mon Sep 17 00:00:00 2001
From: Rafael Tonholo 
Date: Fri, 7 Nov 2025 10:45:08 -0400
Subject: [PATCH 5/8] feat(message-reader): add css variable name provider

---
 .../reader/api/css/CssVariableNameProvider.kt      | 14 ++++++++++++++
 .../feature/mail/message/reader/impl/.gitkeep      |  0
 .../impl/css/DefaultCssVariableNameProvider.kt     | 11 +++++++++++
 3 files changed, 25 insertions(+)
 create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssVariableNameProvider.kt
 delete mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultCssVariableNameProvider.kt

diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssVariableNameProvider.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssVariableNameProvider.kt
new file mode 100644
index 00000000000..8fb9acef9fc
--- /dev/null
+++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssVariableNameProvider.kt
@@ -0,0 +1,14 @@
+package net.thunderbird.feature.mail.message.reader.api.css
+
+/**
+ * Provides CSS variable values for theming the message viewer.
+ *
+ * Implementations of this interface supply the name of the variables (e.g., "--my-variable")
+ * that will be used in the message display's stylesheet.
+ */
+interface CssVariableNameProvider {
+    /**
+     * The name of the CSS variable used to specify the 'border-left-color' for blockquote elements.
+     */
+    val blockquoteDefaultBorderLeftColor: String
+}
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/.gitkeep
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultCssVariableNameProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultCssVariableNameProvider.kt
new file mode 100644
index 00000000000..418e87399ac
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultCssVariableNameProvider.kt
@@ -0,0 +1,11 @@
+package net.thunderbird.feature.mail.message.reader.impl.css
+
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
+
+internal class DefaultCssVariableNameProvider(
+    cssClassNameProvider: CssClassNameProvider,
+) : CssVariableNameProvider {
+    override val blockquoteDefaultBorderLeftColor: String =
+        "--${cssClassNameProvider.defaultNamespaceClassName}__blockquote-default-border-color"
+}

From 1943c5e645da2d9017f13c577cbdddf9f9003a6f Mon Sep 17 00:00:00 2001
From: Rafael Tonholo 
Date: Fri, 7 Nov 2025 10:50:36 -0400
Subject: [PATCH 6/8] feat(message-reader): add css style providers

---
 .../common/feature/AppCommonFeatureModule.kt  |  2 +
 .../reader/api/css/CssStyleProvider.kt        | 50 +++++++++++++++++
 .../mail/message/reader/impl/build.gradle.kts |  4 ++
 .../impl/css/DefaultGlobalCssStyleProvider.kt | 56 +++++++++++++++++++
 ...inTextMessagePreElementCssStyleProvider.kt | 34 +++++++++++
 .../css/DefaultSignatureCssStyleProvider.kt   | 18 ++++++
 .../impl/inject/FeatureMessageReaderModule.kt | 33 +++++++++++
 7 files changed, 197 insertions(+)
 create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt

diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt
index 3d8411b57ff..5220223895c 100644
--- a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt
+++ b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt
@@ -4,6 +4,7 @@ import app.k9mail.feature.launcher.FeatureLauncherExternalContract
 import app.k9mail.feature.launcher.di.featureLauncherModule
 import net.thunderbird.app.common.feature.mail.appCommonFeatureMailModule
 import net.thunderbird.feature.mail.message.composer.inject.featureMessageComposerModule
+import net.thunderbird.feature.mail.message.reader.impl.inject.featureMessageReaderModule
 import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract
 import net.thunderbird.feature.notification.impl.inject.featureNotificationModule
 import org.koin.android.ext.koin.androidContext
@@ -14,6 +15,7 @@ internal val appCommonFeatureModule = module {
     includes(featureNotificationModule)
     includes(featureMessageComposerModule)
     includes(appCommonFeatureMailModule)
+    includes(featureMessageReaderModule)
 
     factory {
         AccountSetupFinishedLauncher(
diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
new file mode 100644
index 00000000000..8ec618aa1cf
--- /dev/null
+++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
@@ -0,0 +1,50 @@
+package net.thunderbird.feature.mail.message.reader.api.css
+
+/**
+ * Provides CSS styles to be injected into the message viewer's web view.
+ *
+ * This sealed interface serves as a common type for different CSS style providers.
+ * Each implementation is responsible for a specific part of the message styling,
+ * such as global styles, signature styles, or plain text formatting.
+ */
+sealed interface CssStyleProvider {
+    /**
+     * The CSS style tag with its content as a string.
+     *
+     * This string should contain valid CSS rules that can be injected into an HTML document (e.g., a message view).
+     *
+     * Example:
+     * ```
+     * "body { color: red; } a { text-decoration: none; }"
+     * ```
+     */
+    val style: String
+}
+
+/**
+ * Provides CSS styles that are applied to the entire message view.
+ *
+ * This is used for global styles that affect the overall appearance of the email content,
+ * such as font size, colors, and layout adjustments for the entire message body.
+ */
+interface GlobalCssStyleProvider : CssStyleProvider
+
+/**
+ * Provides CSS styles specifically for the `
` element used to wrap plain text messages.
+ *
+ * This allows for custom styling of plain text content, such as setting the font family,
+ * size, and controlling word wrapping behavior to ensure readability.
+ */
+interface PlainTextMessagePreElementCssStyleProvider : CssStyleProvider {
+    interface Factory {
+        fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider
+    }
+}
+
+/**
+ * Provides CSS styles specifically for email signatures.
+ *
+ * This is used to apply custom styling to the signature block within an email message,
+ * allowing it to be visually distinct from the main message body.
+ */
+interface SignatureCssStyleProvider : CssStyleProvider
diff --git a/feature/mail/message/reader/impl/build.gradle.kts b/feature/mail/message/reader/impl/build.gradle.kts
index 6d94c5abee4..72874141d3e 100644
--- a/feature/mail/message/reader/impl/build.gradle.kts
+++ b/feature/mail/message/reader/impl/build.gradle.kts
@@ -5,6 +5,10 @@ plugins {
 kotlin {
     sourceSets {
         commonMain.dependencies {
+            implementation(projects.core.common)
+            implementation(projects.core.featureflag)
+            implementation(projects.core.preference.api)
+            implementation(projects.core.ui.theme.api)
             implementation(projects.feature.mail.message.reader.api)
         }
     }
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
new file mode 100644
index 00000000000..1768e910d24
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
@@ -0,0 +1,56 @@
+package net.thunderbird.feature.mail.message.reader.impl.css
+
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
+import org.intellij.lang.annotations.Language
+
+internal class DefaultGlobalCssStyleProvider(
+    cssClassNameProvider: CssClassNameProvider,
+    cssVariableNameProvider: CssVariableNameProvider,
+) : GlobalCssStyleProvider {
+    @Language("HTML")
+    override val style: String = """
+        |
+    """.trimMargin()
+}
+
+internal class LegacyGlobalCssStyleProvider : GlobalCssStyleProvider {
+    @Language("HTML")
+    override val style: String = """
+        |
+    """.trimMargin()
+}
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
new file mode 100644
index 00000000000..2f15a167016
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
@@ -0,0 +1,34 @@
+package net.thunderbird.feature.mail.message.reader.impl.css
+
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
+import org.intellij.lang.annotations.Language
+
+class DefaultPlainTextMessagePreElementCssStyleProvider(
+    cssClassNameProvider: CssClassNameProvider,
+    useFixedWidthFont: Boolean,
+) : PlainTextMessagePreElementCssStyleProvider {
+
+    @Language("HTML")
+    override val style: String = """
+        |
+    """.trimMargin()
+
+    class Factory(
+        private val cssClassNameProvider: CssClassNameProvider,
+    ) : PlainTextMessagePreElementCssStyleProvider.Factory {
+        override fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider {
+            return DefaultPlainTextMessagePreElementCssStyleProvider(
+                cssClassNameProvider = cssClassNameProvider,
+                useFixedWidthFont = useFixedWidthFont,
+            )
+        }
+    }
+}
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
new file mode 100644
index 00000000000..1b959894da3
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
@@ -0,0 +1,18 @@
+package net.thunderbird.feature.mail.message.reader.impl.css
+
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
+import org.intellij.lang.annotations.Language
+
+class DefaultSignatureCssStyleProvider(
+    cssClassNameProvider: CssClassNameProvider,
+) : SignatureCssStyleProvider {
+    @Language("HTML")
+    override val style: String = """
+        |
+    """.trimMargin()
+}
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt
new file mode 100644
index 00000000000..7b9d5dbf7d3
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt
@@ -0,0 +1,33 @@
+package net.thunderbird.feature.mail.message.reader.impl.inject
+
+import net.thunderbird.core.featureflag.FeatureFlagProvider
+import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags
+import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.impl.css.DefaultCssVariableNameProvider
+import net.thunderbird.feature.mail.message.reader.impl.css.DefaultGlobalCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.impl.css.DefaultPlainTextMessagePreElementCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.impl.css.DefaultSignatureCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.impl.css.LegacyGlobalCssStyleProvider
+import org.koin.dsl.module
+
+val featureMessageReaderModule = module {
+    single { DefaultCssVariableNameProvider(get()) }
+    single {
+        val featureFlagProvider = get()
+        if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) {
+            DefaultGlobalCssStyleProvider(
+                cssClassNameProvider = get(),
+                cssVariableNameProvider = get(),
+            )
+        } else {
+            LegacyGlobalCssStyleProvider()
+        }
+    }
+    single { DefaultSignatureCssStyleProvider(get()) }
+    factory {
+        DefaultPlainTextMessagePreElementCssStyleProvider.Factory(cssClassNameProvider = get())
+    }
+}

From dfdbeed8b495fe934805104f8920e1d1f055d5fa Mon Sep 17 00:00:00 2001
From: Rafael Tonholo 
Date: Fri, 7 Nov 2025 11:07:59 -0400
Subject: [PATCH 7/8] refactor(message-reader): use CSS providers instead of
 building css directly on DisplayHtml

The key changes include:
- Moving `HtmlSettings.kt` and `HtmlSettingsProvider.kt` to :core:common.
- Introducing `CssClassNameProvider`, `GlobalCssStyleProvider`, `PlainTextMessagePreElementCssStyleProvider`, and `SignatureCssStyleProvider` to dynamically generate CSS for message display.
- Updating `DisplayHtml`, `HtmlProcessor`, and their factories to use these new providers.
- Refactoring dependency injection to provide the new CSS services.
- Using CSS variables for blockquote border colors in `EmailTextToHtml`.
---
 .../api/css/DefaultCssClassNameProvider.kt    |   4 +-
 .../app/k9mail/DependencyInjectionTest.kt     |  13 +-
 .../android/DependencyInjectionTest.kt        |  13 +-
 cli/html-cleaner-cli/build.gradle.kts         |   2 +
 .../app/k9mail/cli/html/cleaner/Main.kt       |  26 +-
 .../inject/KoinMultibindingCollection.kt      |  19 ++
 .../core/common/mail}/html/HtmlSettings.kt    |   2 +-
 .../common/mail/html/HtmlSettingsProvider.kt  |   5 +
 .../mail/message/composer/build.gradle.kts    |   1 +
 .../MessageComposerHtmlSettingsProvider.kt    |  16 ++
 .../inject/FeatureMessageComposerModule.kt    |   2 +
 .../reader/api/css/CssStyleProvider.kt        |  18 +-
 .../html/MessageReaderHtmlSettingsProvider.kt |   5 +
 .../impl/css/DefaultGlobalCssStyleProvider.kt |  31 ++-
 ...inTextMessagePreElementCssStyleProvider.kt |   5 +-
 .../css/DefaultSignatureCssStyleProvider.kt   |   7 +
 ...efaultMessageReaderHtmlSettingsProvider.kt |  17 ++
 .../impl/inject/FeatureMessageReaderModule.kt |  17 +-
 legacy/core/build.gradle.kts                  |   1 +
 .../MessageViewInfoExtractorFactory.kt        |   2 +-
 .../com/fsck/k9/message/html/DisplayHtml.kt   |  76 +++---
 .../k9/message/html/DisplayHtmlFactory.kt     |  17 +-
 .../fsck/k9/message/html/EmailTextToHtml.kt   |  31 ++-
 .../k9/message/html/HtmlProcessorFactory.kt   |   7 +-
 .../com/fsck/k9/message/html/KoinModule.kt    |  16 +-
 .../core/src/test/java/com/fsck/k9/TestApp.kt |  14 ++
 .../fsck/k9/message/html/DisplayHtmlTest.kt   |  67 ++++-
 .../fsck/k9/message/html/HtmlConverterTest.kt | 228 +++++++++++-------
 .../java/com/fsck/k9/ui/base/KoinModule.kt    |   4 +-
 legacy/ui/legacy/build.gradle.kts             |   1 +
 .../java/com/fsck/k9/activity/KoinModule.kt   |   8 +-
 .../k9/activity/MessageLoaderHelperFactory.kt |  10 +-
 .../main/java/com/fsck/k9/ui/KoinModule.kt    |  12 +-
 .../fsck/k9/ui/helper/DisplayHtmlUiFactory.kt |  27 ++-
 .../fsck/k9/ui/helper/HtmlSettingsProvider.kt |  21 --
 .../src/test/java/com/fsck/k9/TestApp.kt      |   7 +
 library/html-cleaner/build.gradle.kts         |   2 +
 .../app/k9mail/html/cleaner/HtmlProcessor.kt  |  18 +-
 38 files changed, 549 insertions(+), 223 deletions(-)
 rename {legacy/core/src/main/java/com/fsck/k9/message => core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail}/html/HtmlSettings.kt (67%)
 create mode 100644 core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettingsProvider.kt
 create mode 100644 feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/html/MessageComposerHtmlSettingsProvider.kt
 create mode 100644 feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/html/MessageReaderHtmlSettingsProvider.kt
 create mode 100644 feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/html/DefaultMessageReaderHtmlSettingsProvider.kt
 delete mode 100644 legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/HtmlSettingsProvider.kt

diff --git a/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt b/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt
index 59d9bdf013b..45c41efe0cc 100644
--- a/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt
+++ b/app-common/src/main/kotlin/net/thunderbird/android/feature/mail/message/reader/api/css/DefaultCssClassNameProvider.kt
@@ -13,9 +13,9 @@ class DefaultCssClassNameProvider(
     override val mainContentClassName: String = "${defaultNamespaceClassName}__main-content"
     override val plainTextMessagePreClassName: String =
         if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) {
-            EmailTextToHtml.K9MAIL_CSS_CLASS
-        } else {
             "${defaultNamespaceClassName}__plain-text-message-pre"
+        } else {
+            EmailTextToHtml.K9MAIL_CSS_CLASS
         }
     override val signatureClassName: String =
         if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) {
diff --git a/app-k9mail/src/test/kotlin/app/k9mail/DependencyInjectionTest.kt b/app-k9mail/src/test/kotlin/app/k9mail/DependencyInjectionTest.kt
index e813a0b02a1..9da93210e2b 100644
--- a/app-k9mail/src/test/kotlin/app/k9mail/DependencyInjectionTest.kt
+++ b/app-k9mail/src/test/kotlin/app/k9mail/DependencyInjectionTest.kt
@@ -15,15 +15,18 @@ import com.fsck.k9.job.MailSyncWorker
 import com.fsck.k9.job.SyncDebugWorker
 import com.fsck.k9.mailstore.AttachmentResolver
 import com.fsck.k9.message.html.DisplayHtml
-import com.fsck.k9.message.html.HtmlSettings
+import com.fsck.k9.message.html.DisplayHtmlFactory
 import com.fsck.k9.ui.changelog.ChangeLogMode
 import com.fsck.k9.ui.changelog.ChangelogViewModel
+import com.fsck.k9.ui.helper.DisplayHtmlUiFactory
 import com.fsck.k9.view.K9WebViewClient
 import com.fsck.k9.view.MessageWebView
 import net.openid.appauth.AppAuthConfiguration
+import net.thunderbird.core.common.mail.html.HtmlSettings
 import net.thunderbird.core.preference.storage.Storage
 import net.thunderbird.feature.account.AccountId
 import net.thunderbird.feature.mail.message.list.ui.dialog.SetupArchiveFolderDialogContract
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
 import org.junit.Test
 import org.koin.core.annotation.KoinExperimentalAPI
 import org.koin.test.verify.definition
@@ -53,7 +56,13 @@ class DependencyInjectionTest {
             injections = injectedParameters(
                 definition(WorkerParameters::class),
                 definition(ChangeLogMode::class),
-                definition(HtmlSettings::class),
+                definition(
+                    HtmlSettings::class,
+                    CssClassNameProvider::class,
+                    List::class,
+                ),
+                definition(List::class),
+                definition(List::class),
                 definition(AttachmentResolver::class, MessageWebView.OnPageFinishedListener::class),
                 definition(WorkerParameters::class),
                 definition(WorkerParameters::class),
diff --git a/app-thunderbird/src/test/kotlin/net/thunderbird/android/DependencyInjectionTest.kt b/app-thunderbird/src/test/kotlin/net/thunderbird/android/DependencyInjectionTest.kt
index ba388640f0b..1213d55afb2 100644
--- a/app-thunderbird/src/test/kotlin/net/thunderbird/android/DependencyInjectionTest.kt
+++ b/app-thunderbird/src/test/kotlin/net/thunderbird/android/DependencyInjectionTest.kt
@@ -15,15 +15,18 @@ import com.fsck.k9.job.MailSyncWorker
 import com.fsck.k9.job.SyncDebugWorker
 import com.fsck.k9.mailstore.AttachmentResolver
 import com.fsck.k9.message.html.DisplayHtml
-import com.fsck.k9.message.html.HtmlSettings
+import com.fsck.k9.message.html.DisplayHtmlFactory
 import com.fsck.k9.ui.changelog.ChangeLogMode
 import com.fsck.k9.ui.changelog.ChangelogViewModel
+import com.fsck.k9.ui.helper.DisplayHtmlUiFactory
 import com.fsck.k9.view.K9WebViewClient
 import com.fsck.k9.view.MessageWebView
 import net.openid.appauth.AppAuthConfiguration
+import net.thunderbird.core.common.mail.html.HtmlSettings
 import net.thunderbird.core.preference.storage.Storage
 import net.thunderbird.feature.account.AccountId
 import net.thunderbird.feature.mail.message.list.ui.dialog.SetupArchiveFolderDialogContract
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
 import org.junit.Test
 import org.koin.core.annotation.KoinExperimentalAPI
 import org.koin.test.verify.definition
@@ -53,7 +56,13 @@ class DependencyInjectionTest {
             injections = injectedParameters(
                 definition(WorkerParameters::class),
                 definition(ChangeLogMode::class),
-                definition(HtmlSettings::class),
+                definition(
+                    HtmlSettings::class,
+                    CssClassNameProvider::class,
+                    List::class,
+                ),
+                definition(List::class),
+                definition(List::class),
                 definition(AttachmentResolver::class, MessageWebView.OnPageFinishedListener::class),
                 definition(WorkerParameters::class),
                 definition(WorkerParameters::class),
diff --git a/cli/html-cleaner-cli/build.gradle.kts b/cli/html-cleaner-cli/build.gradle.kts
index 9f8b4e20d93..6f682f5adff 100644
--- a/cli/html-cleaner-cli/build.gradle.kts
+++ b/cli/html-cleaner-cli/build.gradle.kts
@@ -9,6 +9,8 @@ application {
 }
 
 dependencies {
+    implementation(projects.core.featureflag)
+    implementation(projects.feature.mail.message.reader.api)
     implementation(projects.library.htmlCleaner)
 
     implementation(libs.clikt)
diff --git a/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt b/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt
index 79cf382d7fe..608ccbe3469 100644
--- a/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt
+++ b/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt
@@ -6,10 +6,14 @@ import com.github.ajalt.clikt.core.CliktCommand
 import com.github.ajalt.clikt.core.Context
 import com.github.ajalt.clikt.core.main
 import com.github.ajalt.clikt.parameters.arguments.argument
+import com.github.ajalt.clikt.parameters.arguments.default
 import com.github.ajalt.clikt.parameters.arguments.optional
+import com.github.ajalt.clikt.parameters.types.enum
 import com.github.ajalt.clikt.parameters.types.file
 import com.github.ajalt.clikt.parameters.types.inputStream
 import java.io.File
+import net.thunderbird.core.featureflag.FeatureFlagResult
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
 import okio.buffer
 import okio.sink
 import okio.source
@@ -19,6 +23,10 @@ class HtmlCleaner : CliktCommand() {
     val input by argument(help = "HTML input file (needs to be UTF-8 encoded)")
         .inputStream()
 
+    val app by argument(help = "The app the email will be target to")
+        .enum(ignoreCase = true)
+        .default(App.THUNDERBIRD)
+
     val output by argument(help = "Output file")
         .file(mustExist = false, canBeDir = false)
         .optional()
@@ -38,7 +46,21 @@ class HtmlCleaner : CliktCommand() {
 
     private fun cleanHtml(html: String): String {
         val htmlProcessor = HtmlProcessor(
-            object : HtmlHeadProvider {
+            featureFlagProvider = { FeatureFlagResult.Enabled },
+            cssClassNameProvider = object : CssClassNameProvider {
+                override val defaultNamespaceClassName: String
+                    get() = if (app == App.THUNDERBIRD) {
+                        "net_thunderbird_android"
+                    } else {
+                        "com_fsck_k9"
+                    }
+                override val rootClassName: String = "${defaultNamespaceClassName}__message-viewer"
+                override val mainContentClassName: String = "${defaultNamespaceClassName}__main-content"
+                override val plainTextMessagePreClassName: String =
+                    "${defaultNamespaceClassName}__plain-text-message-pre"
+                override val signatureClassName: String = "${defaultNamespaceClassName}__signature"
+            },
+            htmlHeadProvider = object : HtmlHeadProvider {
                 override val headHtml = """"""
             },
         )
@@ -57,4 +79,6 @@ class HtmlCleaner : CliktCommand() {
     }
 }
 
+enum class App { THUNDERBIRD, K9MAIL }
+
 fun main(args: Array) = HtmlCleaner().main(args)
diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/inject/KoinMultibindingCollection.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/inject/KoinMultibindingCollection.kt
index 4263f311885..f75207b992c 100644
--- a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/inject/KoinMultibindingCollection.kt
+++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/inject/KoinMultibindingCollection.kt
@@ -29,6 +29,25 @@ inline fun  Module.singleListOf(vararg items: Definition, qualifie
     }
 }
 
+/**
+ * Defines a factory for a list of elements of type [T].
+ *
+ * This function creates a factory definition for a list of elements. Each time this list is
+ * requested, a new list is created, and each element in the list is resolved anew from the
+ * provided [items] definitions.
+ *
+ * @param T The type of elements in the list.
+ * @param items Vararg of [Definition]s that will be resolved and added to the list.
+ * @param qualifier Optional [Qualifier] to distinguish this list from others of the same type.
+ *                  If null, a default qualifier based on the type [T] will be used.
+ */
+@KoinDslMarker
+inline fun  Module.factoryListOf(vararg items: Definition, qualifier: Qualifier? = null) {
+    factory(qualifier ?: defaultListQualifier()) {
+        items.map { definition -> definition(this, parametersOf()) }
+    }
+}
+
 /**
  * Resolves a [List] of instances of type [T].
  * This is a helper function for Koin's multibinding feature.
diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlSettings.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettings.kt
similarity index 67%
rename from legacy/core/src/main/java/com/fsck/k9/message/html/HtmlSettings.kt
rename to core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettings.kt
index 0eb934e4bb9..3fd71b5021b 100644
--- a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlSettings.kt
+++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettings.kt
@@ -1,4 +1,4 @@
-package com.fsck.k9.message.html
+package net.thunderbird.core.common.mail.html
 
 data class HtmlSettings(
     val useDarkMode: Boolean,
diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettingsProvider.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettingsProvider.kt
new file mode 100644
index 00000000000..0f9ee2b5dd4
--- /dev/null
+++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/mail/html/HtmlSettingsProvider.kt
@@ -0,0 +1,5 @@
+package net.thunderbird.core.common.mail.html
+
+fun interface HtmlSettingsProvider {
+    fun create(): HtmlSettings
+}
diff --git a/feature/mail/message/composer/build.gradle.kts b/feature/mail/message/composer/build.gradle.kts
index c80bbe6a3e1..90067d40f7b 100644
--- a/feature/mail/message/composer/build.gradle.kts
+++ b/feature/mail/message/composer/build.gradle.kts
@@ -8,6 +8,7 @@ android {
 }
 
 dependencies {
+    implementation(projects.core.common)
     implementation(projects.core.ui.compose.designsystem)
     implementation(projects.core.ui.theme.api)
     implementation(projects.feature.notification.api)
diff --git a/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/html/MessageComposerHtmlSettingsProvider.kt b/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/html/MessageComposerHtmlSettingsProvider.kt
new file mode 100644
index 00000000000..71199e9b5c1
--- /dev/null
+++ b/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/html/MessageComposerHtmlSettingsProvider.kt
@@ -0,0 +1,16 @@
+package net.thunderbird.feature.mail.message.composer.html
+
+import net.thunderbird.core.common.mail.html.HtmlSettings
+import net.thunderbird.core.common.mail.html.HtmlSettingsProvider
+import net.thunderbird.core.ui.theme.api.Theme
+import net.thunderbird.core.ui.theme.api.ThemeManager
+
+interface MessageComposerHtmlSettingsProvider : HtmlSettingsProvider
+
+internal fun MessageComposerHtmlSettingsProvider(themeManager: ThemeManager): MessageComposerHtmlSettingsProvider =
+    object : MessageComposerHtmlSettingsProvider {
+        override fun create(): HtmlSettings = HtmlSettings(
+            useDarkMode = themeManager.messageComposeTheme == Theme.DARK,
+            useFixedWidthFont = false,
+        )
+    }
diff --git a/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/inject/FeatureMessageComposerModule.kt b/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/inject/FeatureMessageComposerModule.kt
index 38ed1056004..ec944789b36 100644
--- a/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/inject/FeatureMessageComposerModule.kt
+++ b/feature/mail/message/composer/src/main/kotlin/net/thunderbird/feature/mail/message/composer/inject/FeatureMessageComposerModule.kt
@@ -2,10 +2,12 @@ package net.thunderbird.feature.mail.message.composer.inject
 
 import net.thunderbird.feature.mail.message.composer.dialog.SentFolderNotFoundConfirmationDialogFragment
 import net.thunderbird.feature.mail.message.composer.dialog.SentFolderNotFoundConfirmationDialogFragmentFactory
+import net.thunderbird.feature.mail.message.composer.html.MessageComposerHtmlSettingsProvider
 import org.koin.dsl.module
 
 val featureMessageComposerModule = module {
     factory {
         SentFolderNotFoundConfirmationDialogFragment.Factory
     }
+    factory { MessageComposerHtmlSettingsProvider(themeManager = get()) }
 }
diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
index 8ec618aa1cf..098e65bf883 100644
--- a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
+++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/css/CssStyleProvider.kt
@@ -1,5 +1,7 @@
 package net.thunderbird.feature.mail.message.reader.api.css
 
+import net.thunderbird.core.common.mail.html.HtmlSettings
+
 /**
  * Provides CSS styles to be injected into the message viewer's web view.
  *
@@ -19,6 +21,10 @@ sealed interface CssStyleProvider {
      * ```
      */
     val style: String
+
+    fun interface Factory {
+        fun create(htmlSettings: HtmlSettings): CssStyleProvider
+    }
 }
 
 /**
@@ -27,7 +33,9 @@ sealed interface CssStyleProvider {
  * This is used for global styles that affect the overall appearance of the email content,
  * such as font size, colors, and layout adjustments for the entire message body.
  */
-interface GlobalCssStyleProvider : CssStyleProvider
+interface GlobalCssStyleProvider : CssStyleProvider {
+    fun interface Factory : CssStyleProvider.Factory
+}
 
 /**
  * Provides CSS styles specifically for the `
` element used to wrap plain text messages.
@@ -36,9 +44,7 @@ interface GlobalCssStyleProvider : CssStyleProvider
  * size, and controlling word wrapping behavior to ensure readability.
  */
 interface PlainTextMessagePreElementCssStyleProvider : CssStyleProvider {
-    interface Factory {
-        fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider
-    }
+    fun interface Factory : CssStyleProvider.Factory
 }
 
 /**
@@ -47,4 +53,6 @@ interface PlainTextMessagePreElementCssStyleProvider : CssStyleProvider {
  * This is used to apply custom styling to the signature block within an email message,
  * allowing it to be visually distinct from the main message body.
  */
-interface SignatureCssStyleProvider : CssStyleProvider
+interface SignatureCssStyleProvider : CssStyleProvider {
+    fun interface Factory : CssStyleProvider.Factory
+}
diff --git a/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/html/MessageReaderHtmlSettingsProvider.kt b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/html/MessageReaderHtmlSettingsProvider.kt
new file mode 100644
index 00000000000..eb4e247b740
--- /dev/null
+++ b/feature/mail/message/reader/api/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/api/html/MessageReaderHtmlSettingsProvider.kt
@@ -0,0 +1,5 @@
+package net.thunderbird.feature.mail.message.reader.api.html
+
+import net.thunderbird.core.common.mail.html.HtmlSettingsProvider
+
+interface MessageReaderHtmlSettingsProvider : HtmlSettingsProvider
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
index 1768e910d24..49de988d992 100644
--- a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultGlobalCssStyleProvider.kt
@@ -1,11 +1,13 @@
 package net.thunderbird.feature.mail.message.reader.impl.css
 
+import net.thunderbird.core.common.mail.html.HtmlSettings
 import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider
 import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
 import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
 import org.intellij.lang.annotations.Language
 
-internal class DefaultGlobalCssStyleProvider(
+internal class DefaultGlobalCssStyleProvider private constructor(
     cssClassNameProvider: CssClassNameProvider,
     cssVariableNameProvider: CssVariableNameProvider,
 ) : GlobalCssStyleProvider {
@@ -26,6 +28,7 @@ internal class DefaultGlobalCssStyleProvider(
         |  .${cssClassNameProvider.rootClassName}.${cssClassNameProvider.mainContentClassName} {
         |    width: 100%;
         |    overflow-wrap: break-word;
+        |    padding: 0 8px;
         |  }
         |  .${cssClassNameProvider.rootClassName}.${cssClassNameProvider.mainContentClassName} pre {
         |    white-space: pre-wrap;
@@ -39,11 +42,22 @@ internal class DefaultGlobalCssStyleProvider(
         |  }
         |
     """.trimMargin()
+
+    internal class Factory(
+        private val cssClassNameProvider: CssClassNameProvider,
+        private val cssVariableNameProvider: CssVariableNameProvider,
+    ) : GlobalCssStyleProvider.Factory {
+        override fun create(htmlSettings: HtmlSettings): CssStyleProvider = DefaultGlobalCssStyleProvider(
+            cssClassNameProvider = cssClassNameProvider,
+            cssVariableNameProvider = cssVariableNameProvider,
+        )
+    }
 }
 
-internal class LegacyGlobalCssStyleProvider : GlobalCssStyleProvider {
+internal class LegacyGlobalCssStyleProvider(useDarkMode: Boolean) : GlobalCssStyleProvider {
     @Language("HTML")
-    override val style: String = """
+    override val style: String = if (useDarkMode) {
+        """
         |
-    """.trimMargin()
+        """.trimMargin()
+    } else {
+        ""
+    }
+
+    internal class Factory : GlobalCssStyleProvider.Factory {
+        override fun create(htmlSettings: HtmlSettings): CssStyleProvider = LegacyGlobalCssStyleProvider(
+            useDarkMode = htmlSettings.useDarkMode,
+        )
+    }
 }
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
index 2f15a167016..69e6f852621 100644
--- a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultPlainTextMessagePreElementCssStyleProvider.kt
@@ -1,5 +1,6 @@
 package net.thunderbird.feature.mail.message.reader.impl.css
 
+import net.thunderbird.core.common.mail.html.HtmlSettings
 import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
 import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
 import org.intellij.lang.annotations.Language
@@ -24,10 +25,10 @@ class DefaultPlainTextMessagePreElementCssStyleProvider(
     class Factory(
         private val cssClassNameProvider: CssClassNameProvider,
     ) : PlainTextMessagePreElementCssStyleProvider.Factory {
-        override fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider {
+        override fun create(htmlSettings: HtmlSettings): PlainTextMessagePreElementCssStyleProvider {
             return DefaultPlainTextMessagePreElementCssStyleProvider(
                 cssClassNameProvider = cssClassNameProvider,
-                useFixedWidthFont = useFixedWidthFont,
+                useFixedWidthFont = htmlSettings.useFixedWidthFont,
             )
         }
     }
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
index 1b959894da3..a2dadab5ccb 100644
--- a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/css/DefaultSignatureCssStyleProvider.kt
@@ -1,6 +1,8 @@
 package net.thunderbird.feature.mail.message.reader.impl.css
 
+import net.thunderbird.core.common.mail.html.HtmlSettings
 import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider
 import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
 import org.intellij.lang.annotations.Language
 
@@ -15,4 +17,9 @@ class DefaultSignatureCssStyleProvider(
         |  }
         |
     """.trimMargin()
+
+    class Factory(private val cssClassNameProvider: CssClassNameProvider) : SignatureCssStyleProvider.Factory {
+        override fun create(htmlSettings: HtmlSettings): CssStyleProvider =
+            DefaultSignatureCssStyleProvider(cssClassNameProvider)
+    }
 }
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/html/DefaultMessageReaderHtmlSettingsProvider.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/html/DefaultMessageReaderHtmlSettingsProvider.kt
new file mode 100644
index 00000000000..1d2518b100b
--- /dev/null
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/html/DefaultMessageReaderHtmlSettingsProvider.kt
@@ -0,0 +1,17 @@
+package net.thunderbird.feature.mail.message.reader.impl.html
+
+import net.thunderbird.core.common.mail.html.HtmlSettings
+import net.thunderbird.core.preference.display.visualSettings.DisplayVisualSettingsPreferenceManager
+import net.thunderbird.core.ui.theme.api.Theme
+import net.thunderbird.core.ui.theme.api.ThemeManager
+import net.thunderbird.feature.mail.message.reader.api.html.MessageReaderHtmlSettingsProvider
+
+internal class DefaultMessageReaderHtmlSettingsProvider(
+    private val themeManager: ThemeManager,
+    private val visualSettingsPreferenceManager: DisplayVisualSettingsPreferenceManager,
+) : MessageReaderHtmlSettingsProvider {
+    override fun create(): HtmlSettings = HtmlSettings(
+        useDarkMode = themeManager.messageViewTheme == Theme.DARK,
+        useFixedWidthFont = visualSettingsPreferenceManager.getConfig().isUseMessageViewFixedWidthFont,
+    )
+}
diff --git a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt
index 7b9d5dbf7d3..10d7044e788 100644
--- a/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt
+++ b/feature/mail/message/reader/impl/src/commonMain/kotlin/net/thunderbird/feature/mail/message/reader/impl/inject/FeatureMessageReaderModule.kt
@@ -1,33 +1,42 @@
 package net.thunderbird.feature.mail.message.reader.impl.inject
 
+import net.thunderbird.core.common.inject.factoryListOf
 import net.thunderbird.core.featureflag.FeatureFlagProvider
 import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags
 import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
 import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
 import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
 import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.api.html.MessageReaderHtmlSettingsProvider
 import net.thunderbird.feature.mail.message.reader.impl.css.DefaultCssVariableNameProvider
 import net.thunderbird.feature.mail.message.reader.impl.css.DefaultGlobalCssStyleProvider
 import net.thunderbird.feature.mail.message.reader.impl.css.DefaultPlainTextMessagePreElementCssStyleProvider
 import net.thunderbird.feature.mail.message.reader.impl.css.DefaultSignatureCssStyleProvider
 import net.thunderbird.feature.mail.message.reader.impl.css.LegacyGlobalCssStyleProvider
+import net.thunderbird.feature.mail.message.reader.impl.html.DefaultMessageReaderHtmlSettingsProvider
 import org.koin.dsl.module
 
 val featureMessageReaderModule = module {
+    factory { DefaultMessageReaderHtmlSettingsProvider(get(), get()) }
     single { DefaultCssVariableNameProvider(get()) }
-    single {
+    factory {
         val featureFlagProvider = get()
         if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) {
-            DefaultGlobalCssStyleProvider(
+            DefaultGlobalCssStyleProvider.Factory(
                 cssClassNameProvider = get(),
                 cssVariableNameProvider = get(),
             )
         } else {
-            LegacyGlobalCssStyleProvider()
+            LegacyGlobalCssStyleProvider.Factory()
         }
     }
-    single { DefaultSignatureCssStyleProvider(get()) }
+    factory { DefaultSignatureCssStyleProvider.Factory(get()) }
     factory {
         DefaultPlainTextMessagePreElementCssStyleProvider.Factory(cssClassNameProvider = get())
     }
+    factoryListOf(
+        { get() },
+        { get() },
+        { get() },
+    )
 }
diff --git a/legacy/core/build.gradle.kts b/legacy/core/build.gradle.kts
index 92c06fc4b7e..b4a275d0f33 100644
--- a/legacy/core/build.gradle.kts
+++ b/legacy/core/build.gradle.kts
@@ -47,6 +47,7 @@ dependencies {
     implementation(libs.mime4j.dom)
     implementation(libs.uri)
     implementation(projects.feature.navigation.drawer.api)
+    implementation(projects.feature.mail.message.reader.api)
 
     testApi(projects.core.testing)
     testApi(projects.core.android.testing)
diff --git a/legacy/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractorFactory.kt b/legacy/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractorFactory.kt
index 98194d8cf75..e40a5f069fa 100644
--- a/legacy/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractorFactory.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractorFactory.kt
@@ -3,7 +3,7 @@ package com.fsck.k9.mailstore
 import com.fsck.k9.CoreResourceProvider
 import com.fsck.k9.message.extractors.AttachmentInfoExtractor
 import com.fsck.k9.message.html.HtmlProcessorFactory
-import com.fsck.k9.message.html.HtmlSettings
+import net.thunderbird.core.common.mail.html.HtmlSettings
 
 class MessageViewInfoExtractorFactory(
     private val attachmentInfoExtractor: AttachmentInfoExtractor,
diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtml.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtml.kt
index f1551b3aa2d..07583970857 100644
--- a/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtml.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtml.kt
@@ -1,59 +1,43 @@
 package com.fsck.k9.message.html
 
 import app.k9mail.html.cleaner.HtmlHeadProvider
-
-class DisplayHtml(private val settings: HtmlSettings) : HtmlHeadProvider {
+import net.thunderbird.core.common.mail.html.HtmlSettings
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider
+import org.intellij.lang.annotations.Language
+
+class DisplayHtml(
+    private val htmlSettings: HtmlSettings,
+    private val cssClassNameProvider: CssClassNameProvider,
+    private val cssStyleProviders: List,
+) : HtmlHeadProvider {
     override val headHtml: String
-        get() {
-            return """""" +
-                cssStyleTheme() +
-                cssStylePre() +
-                cssStyleSignature()
-        }
+        @Language("HTML")
+        get() = """
+            |
+            |${cssStyleProviders.joinToString("\n") { it.create(htmlSettings).style }}
+        """.trimMargin()
 
     fun wrapStatusMessage(status: CharSequence): String {
         return wrapMessageContent("
$status
") } + @Language("HTML") fun wrapMessageContent(messageContent: CharSequence): String { + // TODO(#10074): This should be consolidated in a single place. There are many places that + // build an HTML document to almost the same purpose (Viewer, Composer, etc). + // Current files that build the HTML document: this, HtmlProcessor.kt, and + // HtmlQuoteCreator.java (maybe). // Include a meta tag so the WebView will not use a fixed viewport width of 980 px - return "" + - cssStyleTheme() + - cssStylePre() + - "" + - messageContent + - "" - } - - private fun cssStyleTheme(): String { - return if (settings.useDarkMode) { - // TODO: Don't hardcode these values. Inject them via HtmlSettings. - " " - } else { - "" - } - } - - /** - * Dynamically generate a CSS style for `
` elements.
-     *
-     * The style incorporates the user's current preference setting for the font family used for plain text messages.
-     *
-     * @return A `"
-    }
-
-    private fun cssStyleSignature(): String {
-        return """"""
+        return """
+            |
+            |  
+            |    $headHtml
+            |  
+            |  
+            |    $messageContent
+            |  
+            |
+        """.trimMargin()
     }
 }
diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtmlFactory.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtmlFactory.kt
index 8e717af9d74..880505d2eef 100644
--- a/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtmlFactory.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/message/html/DisplayHtmlFactory.kt
@@ -1,7 +1,16 @@
 package com.fsck.k9.message.html
 
-class DisplayHtmlFactory {
-    fun create(settings: HtmlSettings): DisplayHtml {
-        return DisplayHtml(settings)
-    }
+import net.thunderbird.core.common.mail.html.HtmlSettings
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider
+
+class DisplayHtmlFactory(
+    private val cssClassNameProvider: CssClassNameProvider,
+    private val cssStyleProviders: List,
+) {
+    fun create(settings: HtmlSettings): DisplayHtml = DisplayHtml(
+        htmlSettings = settings,
+        cssClassNameProvider = cssClassNameProvider,
+        cssStyleProviders = cssStyleProviders,
+    )
 }
diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt
index 81c4e2db35d..3c6bc86064c 100644
--- a/legacy/core/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt
@@ -1,6 +1,15 @@
 package com.fsck.k9.message.html
 
-class EmailTextToHtml private constructor(private val text: String) {
+import app.k9mail.legacy.di.DI
+import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
+import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
+import org.intellij.lang.annotations.Language
+
+class EmailTextToHtml private constructor(
+    private val cssClassNameProvider: CssClassNameProvider,
+    private val cssVariableNameProvider: CssVariableNameProvider,
+    private val text: String,
+) {
     private val html = StringBuilder(text.length + EXTRA_BUFFER_LENGTH)
     private var previousQuoteDepth = 0
 
@@ -22,7 +31,7 @@ class EmailTextToHtml private constructor(private val text: String) {
     }
 
     private fun appendHtmlPrefix() {
-        html.append("
")
+        html.append("
")
     }
 
     private fun appendHtmlSuffix() {
@@ -36,13 +45,13 @@ class EmailTextToHtml private constructor(private val text: String) {
             }
         } else if (quoteDepth > previousQuoteDepth) {
             for (depth in (previousQuoteDepth + 1)..quoteDepth) {
-                html.append(
-                    "
") + val borderColorStyle = + "${cssVariableNameProvider.blockquoteDefaultBorderLeftColor}: ${quoteColor(depth)};" + + @Language("HTML") + val blockQuoteStartTag = + "
" + html.append(blockQuoteStartTag) } } previousQuoteDepth = quoteDepth @@ -63,7 +72,9 @@ class EmailTextToHtml private constructor(private val text: String) { @JvmStatic fun convert(text: String): String { - return EmailTextToHtml(text).convert() + val cssClassNameProvider = DI.get() + val cssVariableNameProvider = DI.get() + return EmailTextToHtml(cssClassNameProvider, cssVariableNameProvider, text).convert() } } } diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt index 6ea3392421d..06eaadfebd0 100644 --- a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt +++ b/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt @@ -1,12 +1,17 @@ package com.fsck.k9.message.html import app.k9mail.html.cleaner.HtmlProcessor +import net.thunderbird.core.common.mail.html.HtmlSettings +import net.thunderbird.core.featureflag.FeatureFlagProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider class HtmlProcessorFactory( + private val featureFlagProvider: FeatureFlagProvider, + private val cssClassNameProvider: CssClassNameProvider, private val displayHtmlFactory: DisplayHtmlFactory, ) { fun create(settings: HtmlSettings): HtmlProcessor { val displayHtml = displayHtmlFactory.create(settings) - return HtmlProcessor(displayHtml) + return HtmlProcessor(featureFlagProvider, cssClassNameProvider, displayHtml) } } diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/KoinModule.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/KoinModule.kt index 7c6151ad0c8..74ca64e30ba 100644 --- a/legacy/core/src/main/java/com/fsck/k9/message/html/KoinModule.kt +++ b/legacy/core/src/main/java/com/fsck/k9/message/html/KoinModule.kt @@ -1,8 +1,20 @@ package com.fsck.k9.message.html +import net.thunderbird.core.common.inject.getList import org.koin.dsl.module val htmlModule = module { - single { HtmlProcessorFactory(displayHtmlFactory = get()) } - single { DisplayHtmlFactory() } + factory { + HtmlProcessorFactory( + featureFlagProvider = get(), + cssClassNameProvider = get(), + displayHtmlFactory = get(), + ) + } + factory { + DisplayHtmlFactory( + cssClassNameProvider = get(), + cssStyleProviders = getList(), + ) + } } diff --git a/legacy/core/src/test/java/com/fsck/k9/TestApp.kt b/legacy/core/src/test/java/com/fsck/k9/TestApp.kt index 555d2c8f836..b19df888228 100644 --- a/legacy/core/src/test/java/com/fsck/k9/TestApp.kt +++ b/legacy/core/src/test/java/com/fsck/k9/TestApp.kt @@ -17,6 +17,7 @@ import net.thunderbird.core.android.account.AccountDefaultsProvider import net.thunderbird.core.android.account.LegacyAccountManager import net.thunderbird.core.android.preferences.TestStoragePersister import net.thunderbird.core.common.appConfig.PlatformConfigProvider +import net.thunderbird.core.common.inject.factoryListOf import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagProvider import net.thunderbird.core.featureflag.InMemoryFeatureFlagProvider @@ -32,12 +33,17 @@ import net.thunderbird.core.logging.testing.TestLogLevelManager import net.thunderbird.core.logging.testing.TestLogger import net.thunderbird.core.preference.storage.StoragePersister import net.thunderbird.feature.mail.folder.api.OutboxFolderManager +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider import net.thunderbird.legacy.core.FakeAccountDefaultsProvider import net.thunderbird.legacy.core.mailstore.folder.FakeOutboxFolderManager import org.koin.core.qualifier.named import org.koin.dsl.bind import org.koin.dsl.module +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever class TestApp : Application() { override fun onCreate() { @@ -98,6 +104,14 @@ val testModule = module { single { mock() } single { TestNotificationIconResourceProvider() } single { FakePlatformConfigProvider() } + single { mock() } + single { + mock { + whenever(it.plainTextMessagePreClassName).doReturn("k9mail") + } + } + factoryListOf() + single { mock() } } class FakePlatformConfigProvider : PlatformConfigProvider { diff --git a/legacy/core/src/test/java/com/fsck/k9/message/html/DisplayHtmlTest.kt b/legacy/core/src/test/java/com/fsck/k9/message/html/DisplayHtmlTest.kt index 41132e96c85..fd16c62ed1f 100644 --- a/legacy/core/src/test/java/com/fsck/k9/message/html/DisplayHtmlTest.kt +++ b/legacy/core/src/test/java/com/fsck/k9/message/html/DisplayHtmlTest.kt @@ -2,13 +2,25 @@ package com.fsck.k9.message.html import assertk.Assert import assertk.assertThat +import assertk.assertions.atLeast import assertk.assertions.hasSize import assertk.assertions.isEqualTo +import assertk.assertions.prop +import net.thunderbird.core.common.mail.html.HtmlSettings +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider +import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider +import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider +import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider import org.jsoup.Jsoup +import org.jsoup.nodes.Element import org.junit.Test class DisplayHtmlTest { - val displayHtml = DisplayHtml(HtmlSettings(useDarkMode = false, useFixedWidthFont = false)) + val displayHtml = DisplayHtml( + htmlSettings = HtmlSettings(useDarkMode = false, useFixedWidthFont = false), + cssClassNameProvider = FakeCssClassNameProvider(), + cssStyleProviders = listOf(), + ) @Test fun wrapMessageContent_addsViewportMetaElement() { @@ -26,18 +38,31 @@ class DisplayHtmlTest { @Test fun wrapMessageContent_addsPreCSS() { + val expectedStyleCssRule = ".my-custom-pre-class { mock-property: mock-value }" + val displayHtml = DisplayHtml( + htmlSettings = HtmlSettings(useDarkMode = false, useFixedWidthFont = false), + cssClassNameProvider = FakeCssClassNameProvider(), + cssStyleProviders = listOf( + GlobalCssStyleProvider.Factory { FakeGlobalCssStyleProvider() }, + PlainTextMessagePreElementCssStyleProvider.Factory { + FakePlainTextMessagePreElementCssStyleProvider( + style = "", + ) + }, + SignatureCssStyleProvider.Factory { FakeSignatureCssStyleProvider() }, + ), + ) val html = displayHtml.wrapMessageContent("Some text") - assertThat(html).containsHtmlElement("head > style") - } - - @Test - fun wrapMessageContent_whenDarkMessageViewTheme_addsDarkThemeCSS() { - val darkModeDisplayHtml = DisplayHtml(HtmlSettings(useDarkMode = true, useFixedWidthFont = false)) - - val html = darkModeDisplayHtml.wrapMessageContent("Some text") - - assertThat(html).htmlElements("head > style").hasSize(2) + assertThat(html).given { raw -> + val html = Jsoup.parse(raw) + assertThat(html.select("head > style")) + .atLeast(1) { element -> + element + .prop(Element::data) + .isEqualTo(expectedStyleCssRule) + } + } } @Test @@ -60,4 +85,24 @@ class DisplayHtmlTest { private fun Assert.bodyText() = transform { html -> Jsoup.parse(html).body().text() } + + private class FakeCssClassNameProvider( + override val defaultNamespaceClassName: String = "mock defaultNamespaceClassName", + override val rootClassName: String = "mock rootClassName", + override val mainContentClassName: String = "mock mainContentClassName", + override val plainTextMessagePreClassName: String = "mock plainTextMessagePreClassName", + override val signatureClassName: String = "mock signatureClassName", + ) : CssClassNameProvider + + private class FakeGlobalCssStyleProvider( + override val style: String = "", + ) : GlobalCssStyleProvider + + private class FakePlainTextMessagePreElementCssStyleProvider( + override val style: String = "", + ) : PlainTextMessagePreElementCssStyleProvider + + private class FakeSignatureCssStyleProvider( + override val style: String = "", + ) : SignatureCssStyleProvider } diff --git a/legacy/core/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.kt b/legacy/core/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.kt index 50251127e83..78a60ebb199 100644 --- a/legacy/core/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.kt +++ b/legacy/core/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.kt @@ -2,45 +2,81 @@ package com.fsck.k9.message.html import assertk.assertThat import assertk.assertions.isEqualTo +import com.fsck.k9.K9RobolectricTest import com.fsck.k9.mail.testing.crlf import com.fsck.k9.mail.testing.removeLineBreaks +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider +import org.intellij.lang.annotations.Language +import org.junit.Before +import org.junit.Rule import org.junit.Test +import org.koin.test.mock.MockProviderRule +import org.koin.test.mock.declareMock +import org.mockito.Mockito +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +class HtmlConverterTest : K9RobolectricTest() { + private val mockedBlockquoteVarName = "--mocked-blockquote-var" + private val mockedPreClassName = "mocked-classname" + + @get:Rule + val mockProvider = MockProviderRule.create { clazz -> + Mockito.mock(clazz.java) + } + + @Before + fun setup() { + declareMock { + mock { + whenever(blockquoteDefaultBorderLeftColor) doReturn mockedBlockquoteVarName + } + } + + declareMock { + mock { + whenever(plainTextMessagePreClassName) doReturn mockedPreClassName + } + } + } -class HtmlConverterTest { @Test fun `textToHtml() should convert quoted text using blockquote tags`() { + @Language("Markdown") val message = """ Panama! - + Bob Barker wrote: > a canal > > Dorothy Jo Gideon espoused: > >A man, a plan... > Too easy! - + Nice job :) >> Guess! """.trimIndent().crlf() val result = HtmlConverter.textToHtml(message) - assertThat(result).isEqualTo( - """ - |
+        @Language("HTML")
+        val expected = """
+            |
             |
|Panama!
|
|Bob Barker <bob@aol.com> wrote:
|
- |
+ |
|
| a canal
|
| Dorothy Jo Gideon <dorothy@aol.com> espoused:
|
- |
+ |
|
|A man, a plan...
|
@@ -53,24 +89,25 @@ class HtmlConverterTest { |
|Nice job :)
| - |
- |
+ |
+ |
|
|Guess! |
|
|
|
- """.trimMargin().removeLineBreaks(), - ) + """.trimMargin().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should retain indentation inside quoted text`() { + @Language("Markdown") val message = """ *facepalm* - + Bob Barker wrote: > A wise man once said... > @@ -81,15 +118,15 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(message) - assertThat(result).isEqualTo( - """ - |
+        @Language("HTML")
+        val expected = """
+            |
             |
|*facepalm*
|
|Bob Barker <bob@aol.com> wrote:
|
- |
+ |
|
| A wise man once said...
|
@@ -99,12 +136,13 @@ class HtmlConverterTest { |
|
|
- """.trimMargin().removeLineBreaks(), - ) + """.trimMargin().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() with various quotation depths`() { + @Language("Markdown") val message = """ zero @@ -118,33 +156,33 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(message) - assertThat(result).isEqualTo( - """ - |
+        @Language("HTML")
+        val expected = """
+            |
             |
|zero
|
- |
+ |
|
|one
|
- |
+ |
|
|two
|
- |
+ |
|
|three
|
- |
+ |
|
|four
|
- |
+ |
|
|five
|
- |
+ |
|
|six |
@@ -155,12 +193,13 @@ class HtmlConverterTest { |
|
|
- """.trimMargin().removeLineBreaks(), - ) + """.trimMargin().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should preserve spaces at the start of a line`() { + @Language("Markdown") val message = """ |foo @@ -171,24 +210,25 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(message) - assertThat(result).isEqualTo( - """ - |
+        @Language("HTML")
+        val expected = """
+            |
             |
|foo
| bar
| baz
|
|
- """.trimMargin().removeLineBreaks(), - ) + """.trimMargin().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should preserve spaces at the start of a line followed by special characters`() { + @Language("Markdown") val message = """ - | + |${" "} | & | ${" "} | < @@ -198,27 +238,27 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(message) - assertThat(result).isEqualTo( - """ - |
+        val expected = """
+            |
             |
|
| &
|
| <
|
- |
+ |
|
|
|
|
|
- """.trimMargin().removeLineBreaks(), - ) + """.trimMargin().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should replace common horizontal divider ASCII patterns with HR tags`() { + @Language("Markdown") val text = """ text @@ -236,9 +276,9 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
text
@@ -253,12 +293,13 @@ class HtmlConverterTest { end
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should not convert dashes mixed with spaces to an HR tag`() { + @Language("Markdown") val text = """ hello @@ -268,21 +309,22 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
hello
--- --- --- --- ---
foo bar
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should merge consecutive horizontal dividers into a single HR tag`() { + @Language("Markdown") val text = """ hello @@ -293,35 +335,37 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
hello
foo bar
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should not replace dashed horizontal divider prefixed with text`() { + @Language("Markdown") val text = "hello----\n\n" val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        val expected = """
+            
             
hello----

- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + @Language("HTML") + assertThat(result).isEqualTo(expected) } @Test @@ -330,7 +374,9 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo("""
--
""") + @Language("HTML") + val expected = """
--
""" + assertThat(result).isEqualTo(expected) } @Test @@ -339,7 +385,7 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo("""
==
""") + assertThat(result).isEqualTo("""
==
""") } @Test @@ -348,11 +394,14 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo("""
__
""") + @Language("HTML") + val expected = """
__
""" + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should replace any combination of three consecutive divider characters with an HR tag`() { + @Language("Markdown") val text = """ --= @@ -364,47 +413,51 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo("""

""") + @Language("HTML") + val expected = """

""" + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should replace dashes at the start of the input`() { + @Language("Markdown") val text = "---------------------------\nfoo bar" val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        val expected = """
+            
             

foo bar
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should replace dashes at the end of the input`() { + @Language("Markdown") val text = "hello\n__________________________________" val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
hello
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should replace horizontal divider using ASCII scissors with an HR tag`() { + @Language("Markdown") val text = """ hello @@ -414,21 +467,22 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
hello
world
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test fun `textToHtml() should wrap email signature in a DIV`() { + @Language("Markdown") val text = """ text @@ -438,9 +492,9 @@ class HtmlConverterTest { val result = HtmlConverter.textToHtml(text) - assertThat(result).isEqualTo( - """ -
+        @Language("HTML")
+        val expected = """
+            
             
text
@@ -449,8 +503,8 @@ class HtmlConverterTest {
- """.trimIndent().removeLineBreaks(), - ) + """.trimIndent().removeLineBreaks() + assertThat(result).isEqualTo(expected) } @Test @@ -549,7 +603,7 @@ class HtmlConverterTest { Two Three - + Four """.trimIndent(), ) diff --git a/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt b/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt index 2878bb87847..bf5f3fff9cb 100644 --- a/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt +++ b/legacy/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt @@ -3,7 +3,9 @@ package com.fsck.k9.ui.base import com.fsck.k9.ui.base.locale.SystemLocaleManager import net.thunderbird.core.ui.theme.manager.ThemeManager import org.koin.core.qualifier.named +import org.koin.dsl.bind import org.koin.dsl.module +import net.thunderbird.core.ui.theme.api.ThemeManager as ThemeManagerApi val uiBaseModule = module { single { @@ -13,7 +15,7 @@ val uiBaseModule = module { generalSettingsManager = get(), appCoroutineScope = get(named("AppCoroutineScope")), ) - } + } bind ThemeManagerApi::class single { AppLanguageManager(systemLocaleManager = get(), displayCoreSettingsPreferenceManager = get()) } single { SystemLocaleManager(context = get()) } } diff --git a/legacy/ui/legacy/build.gradle.kts b/legacy/ui/legacy/build.gradle.kts index 52eccefa9ba..c76219c1aca 100644 --- a/legacy/ui/legacy/build.gradle.kts +++ b/legacy/ui/legacy/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation(projects.feature.mail.message.list) implementation(projects.feature.mail.message.composer) implementation(projects.feature.mail.message.export.api) + implementation(projects.feature.mail.message.reader.api) compileOnly(projects.mail.protocols.imap) diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/KoinModule.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/KoinModule.kt index 3b533bbeae6..20ba8845d1c 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/KoinModule.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/KoinModule.kt @@ -3,5 +3,11 @@ package com.fsck.k9.activity import org.koin.dsl.module val activityModule = module { - single { MessageLoaderHelperFactory(messageViewInfoExtractorFactory = get(), htmlSettingsProvider = get()) } + single { + MessageLoaderHelperFactory( + messageViewInfoExtractorFactory = get(), + messageReaderHtmlSettingsProvider = get(), + messageComposerHtmlSettingsProvider = get(), + ) + } } diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelperFactory.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelperFactory.kt index 5e0caab781b..2e19b07ccb4 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelperFactory.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MessageLoaderHelperFactory.kt @@ -5,11 +5,13 @@ import androidx.fragment.app.FragmentManager import androidx.loader.app.LoaderManager import com.fsck.k9.activity.MessageLoaderHelper.MessageLoaderCallbacks import com.fsck.k9.mailstore.MessageViewInfoExtractorFactory -import com.fsck.k9.ui.helper.HtmlSettingsProvider +import net.thunderbird.feature.mail.message.composer.html.MessageComposerHtmlSettingsProvider +import net.thunderbird.feature.mail.message.reader.api.html.MessageReaderHtmlSettingsProvider class MessageLoaderHelperFactory( private val messageViewInfoExtractorFactory: MessageViewInfoExtractorFactory, - private val htmlSettingsProvider: HtmlSettingsProvider, + private val messageReaderHtmlSettingsProvider: MessageReaderHtmlSettingsProvider, + private val messageComposerHtmlSettingsProvider: MessageComposerHtmlSettingsProvider, ) { fun createForMessageView( context: Context, @@ -17,7 +19,7 @@ class MessageLoaderHelperFactory( fragmentManager: FragmentManager, callback: MessageLoaderCallbacks, ): MessageLoaderHelper { - val htmlSettings = htmlSettingsProvider.createForMessageView() + val htmlSettings = messageReaderHtmlSettingsProvider.create() val messageViewInfoExtractor = messageViewInfoExtractorFactory.create(htmlSettings) return MessageLoaderHelper(context, loaderManager, fragmentManager, callback, messageViewInfoExtractor) } @@ -28,7 +30,7 @@ class MessageLoaderHelperFactory( fragmentManager: FragmentManager, callback: MessageLoaderCallbacks, ): MessageLoaderHelper { - val htmlSettings = htmlSettingsProvider.createForMessageCompose() + val htmlSettings = messageComposerHtmlSettingsProvider.create() val messageViewInfoExtractor = messageViewInfoExtractorFactory.create(htmlSettings) return MessageLoaderHelper(context, loaderManager, fragmentManager, callback, messageViewInfoExtractor) } diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/KoinModule.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/KoinModule.kt index 84ce80f0133..113258af5ba 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/KoinModule.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/KoinModule.kt @@ -4,16 +4,22 @@ import android.content.Context import app.k9mail.legacy.message.controller.MessagingControllerMailChecker import com.fsck.k9.controller.MessagingController import com.fsck.k9.ui.helper.DisplayHtmlUiFactory -import com.fsck.k9.ui.helper.HtmlSettingsProvider import com.fsck.k9.ui.helper.SizeFormatter import com.fsck.k9.ui.messageview.LinkTextHandler import com.fsck.k9.ui.share.ShareIntentBuilder +import net.thunderbird.core.common.inject.getList import org.koin.core.qualifier.named import org.koin.dsl.module val uiModule = module { - single { HtmlSettingsProvider(themeManager = get(), generalSettingsManager = get()) } - single { DisplayHtmlUiFactory(get()) } + factory { + DisplayHtmlUiFactory( + cssClassNameProvider = get(), + cssStyleProviders = getList(), + messageReaderHtmlSettingsProvider = get(), + messageComposerHtmlSettingsProvider = get(), + ) + } single { get() } factory(named("MessageView")) { get().createForMessageView() } factory { (context: Context) -> SizeFormatter(context.resources) } diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/DisplayHtmlUiFactory.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/DisplayHtmlUiFactory.kt index 671981ee62f..91c0c60d917 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/DisplayHtmlUiFactory.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/DisplayHtmlUiFactory.kt @@ -1,13 +1,26 @@ package com.fsck.k9.ui.helper import com.fsck.k9.message.html.DisplayHtml +import net.thunderbird.feature.mail.message.composer.html.MessageComposerHtmlSettingsProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider +import net.thunderbird.feature.mail.message.reader.api.html.MessageReaderHtmlSettingsProvider -class DisplayHtmlUiFactory(private val htmlSettingsProvider: HtmlSettingsProvider) { - fun createForMessageView(): DisplayHtml { - return DisplayHtml(htmlSettingsProvider.createForMessageView()) - } +class DisplayHtmlUiFactory( + private val cssClassNameProvider: CssClassNameProvider, + private val cssStyleProviders: List, + private val messageReaderHtmlSettingsProvider: MessageReaderHtmlSettingsProvider, + private val messageComposerHtmlSettingsProvider: MessageComposerHtmlSettingsProvider, +) { + fun createForMessageView(): DisplayHtml = DisplayHtml( + htmlSettings = messageReaderHtmlSettingsProvider.create(), + cssClassNameProvider = cssClassNameProvider, + cssStyleProviders = cssStyleProviders, + ) - fun createForMessageCompose(): DisplayHtml { - return DisplayHtml(htmlSettingsProvider.createForMessageCompose()) - } + fun createForMessageCompose(): DisplayHtml = DisplayHtml( + htmlSettings = messageComposerHtmlSettingsProvider.create(), + cssClassNameProvider = cssClassNameProvider, + cssStyleProviders = cssStyleProviders, + ) } diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/HtmlSettingsProvider.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/HtmlSettingsProvider.kt deleted file mode 100644 index 8596167c198..00000000000 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/HtmlSettingsProvider.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.fsck.k9.ui.helper - -import com.fsck.k9.message.html.HtmlSettings -import net.thunderbird.core.preference.GeneralSettingsManager -import net.thunderbird.core.ui.theme.api.Theme -import net.thunderbird.core.ui.theme.manager.ThemeManager - -class HtmlSettingsProvider( - private val themeManager: ThemeManager, - private val generalSettingsManager: GeneralSettingsManager, -) { - fun createForMessageView() = HtmlSettings( - useDarkMode = themeManager.messageViewTheme == Theme.DARK, - useFixedWidthFont = generalSettingsManager.getConfig().display.visualSettings.isUseMessageViewFixedWidthFont, - ) - - fun createForMessageCompose() = HtmlSettings( - useDarkMode = themeManager.messageComposeTheme == Theme.DARK, - useFixedWidthFont = false, - ) -} diff --git a/legacy/ui/legacy/src/test/java/com/fsck/k9/TestApp.kt b/legacy/ui/legacy/src/test/java/com/fsck/k9/TestApp.kt index e15fe16e6d6..bd0d76012bc 100644 --- a/legacy/ui/legacy/src/test/java/com/fsck/k9/TestApp.kt +++ b/legacy/ui/legacy/src/test/java/com/fsck/k9/TestApp.kt @@ -8,6 +8,7 @@ import net.thunderbird.core.android.account.AccountDefaultsProvider import net.thunderbird.core.android.account.LegacyAccountManager import net.thunderbird.core.android.preferences.TestStoragePersister import net.thunderbird.core.common.appConfig.PlatformConfigProvider +import net.thunderbird.core.common.inject.factoryListOf import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagProvider import net.thunderbird.core.featureflag.InMemoryFeatureFlagProvider @@ -22,6 +23,9 @@ import net.thunderbird.core.logging.legacy.Log import net.thunderbird.core.logging.testing.TestLogLevelManager import net.thunderbird.core.logging.testing.TestLogger import net.thunderbird.core.preference.storage.StoragePersister +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssStyleProvider +import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider import org.koin.core.qualifier.named import org.koin.dsl.bind import org.koin.dsl.module @@ -83,6 +87,9 @@ val testModule = module { single { mock() } single { mock() } single { FakePlatformConfigProvider() } + single { mock() } + single { mock() } + factoryListOf() } class FakePlatformConfigProvider : PlatformConfigProvider { diff --git a/library/html-cleaner/build.gradle.kts b/library/html-cleaner/build.gradle.kts index 976791cc02b..519d2d79578 100644 --- a/library/html-cleaner/build.gradle.kts +++ b/library/html-cleaner/build.gradle.kts @@ -5,4 +5,6 @@ plugins { dependencies { implementation(libs.jsoup) + implementation(projects.core.featureflag) + implementation(projects.feature.mail.message.reader.api) } diff --git a/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt b/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt index 2da379b4eca..665b12e52b0 100644 --- a/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt +++ b/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt @@ -1,13 +1,21 @@ package app.k9mail.html.cleaner +import net.thunderbird.core.featureflag.FeatureFlagProvider +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags +import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider import org.jsoup.nodes.Document -class HtmlProcessor(private val htmlHeadProvider: HtmlHeadProvider) { +class HtmlProcessor( + private val featureFlagProvider: FeatureFlagProvider, + private val cssClassNameProvider: CssClassNameProvider, + private val htmlHeadProvider: HtmlHeadProvider, +) { private val htmlSanitizer = HtmlSanitizer() fun processForDisplay(html: String): String { return htmlSanitizer.sanitize(html) .addCustomHeadContents() + .addCustomClasses() .toCompactString() } @@ -22,4 +30,12 @@ class HtmlProcessor(private val htmlHeadProvider: HtmlHeadProvider) { return html() } + + private fun Document.addCustomClasses() = apply { + if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageViewerCssStyles).isEnabled()) { + body() + .addClass(cssClassNameProvider.rootClassName) + .addClass(cssClassNameProvider.mainContentClassName) + } + } } From d3e565fcac53c9b2cd673de2c69439ba35825085 Mon Sep 17 00:00:00 2001 From: Rafael Tonholo Date: Mon, 10 Nov 2025 08:47:02 -0400 Subject: [PATCH 8/8] chore(message-reader): remove html-cleaner feature project dependency --- cli/html-cleaner-cli/build.gradle.kts | 2 -- .../app/k9mail/cli/html/cleaner/Main.kt | 25 +++++++------------ .../k9/message/html/HtmlProcessorFactory.kt | 9 ++++++- library/html-cleaner/build.gradle.kts | 2 -- .../app/k9mail/html/cleaner/HtmlProcessor.kt | 14 ++++------- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/cli/html-cleaner-cli/build.gradle.kts b/cli/html-cleaner-cli/build.gradle.kts index 6f682f5adff..9f8b4e20d93 100644 --- a/cli/html-cleaner-cli/build.gradle.kts +++ b/cli/html-cleaner-cli/build.gradle.kts @@ -9,8 +9,6 @@ application { } dependencies { - implementation(projects.core.featureflag) - implementation(projects.feature.mail.message.reader.api) implementation(projects.library.htmlCleaner) implementation(libs.clikt) diff --git a/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt b/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt index 608ccbe3469..608ebb293a4 100644 --- a/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt +++ b/cli/html-cleaner-cli/src/main/kotlin/app/k9mail/cli/html/cleaner/Main.kt @@ -12,8 +12,6 @@ import com.github.ajalt.clikt.parameters.types.enum import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.inputStream import java.io.File -import net.thunderbird.core.featureflag.FeatureFlagResult -import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider import okio.buffer import okio.sink import okio.source @@ -45,21 +43,16 @@ class HtmlCleaner : CliktCommand() { } private fun cleanHtml(html: String): String { + val defaultNamespaceClassName = if (app == App.THUNDERBIRD) { + "net_thunderbird_android" + } else { + "com_fsck_k9" + } val htmlProcessor = HtmlProcessor( - featureFlagProvider = { FeatureFlagResult.Enabled }, - cssClassNameProvider = object : CssClassNameProvider { - override val defaultNamespaceClassName: String - get() = if (app == App.THUNDERBIRD) { - "net_thunderbird_android" - } else { - "com_fsck_k9" - } - override val rootClassName: String = "${defaultNamespaceClassName}__message-viewer" - override val mainContentClassName: String = "${defaultNamespaceClassName}__main-content" - override val plainTextMessagePreClassName: String = - "${defaultNamespaceClassName}__plain-text-message-pre" - override val signatureClassName: String = "${defaultNamespaceClassName}__signature" - }, + customClasses = setOf( + "${defaultNamespaceClassName}__message-viewer", + "${defaultNamespaceClassName}__main-content", + ), htmlHeadProvider = object : HtmlHeadProvider { override val headHtml = """""" }, diff --git a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt b/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt index 06eaadfebd0..fdd03b2ab8e 100644 --- a/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt +++ b/legacy/core/src/main/java/com/fsck/k9/message/html/HtmlProcessorFactory.kt @@ -3,6 +3,7 @@ package com.fsck.k9.message.html import app.k9mail.html.cleaner.HtmlProcessor import net.thunderbird.core.common.mail.html.HtmlSettings import net.thunderbird.core.featureflag.FeatureFlagProvider +import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider class HtmlProcessorFactory( @@ -12,6 +13,12 @@ class HtmlProcessorFactory( ) { fun create(settings: HtmlSettings): HtmlProcessor { val displayHtml = displayHtmlFactory.create(settings) - return HtmlProcessor(featureFlagProvider, cssClassNameProvider, displayHtml) + val customClasses = + if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) { + setOf(cssClassNameProvider.rootClassName, cssClassNameProvider.mainContentClassName) + } else { + emptySet() + } + return HtmlProcessor(customClasses, displayHtml) } } diff --git a/library/html-cleaner/build.gradle.kts b/library/html-cleaner/build.gradle.kts index 519d2d79578..976791cc02b 100644 --- a/library/html-cleaner/build.gradle.kts +++ b/library/html-cleaner/build.gradle.kts @@ -5,6 +5,4 @@ plugins { dependencies { implementation(libs.jsoup) - implementation(projects.core.featureflag) - implementation(projects.feature.mail.message.reader.api) } diff --git a/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt b/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt index 665b12e52b0..daaf1d292bb 100644 --- a/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt +++ b/library/html-cleaner/src/main/kotlin/app/k9mail/html/cleaner/HtmlProcessor.kt @@ -1,13 +1,9 @@ package app.k9mail.html.cleaner -import net.thunderbird.core.featureflag.FeatureFlagProvider -import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags -import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider import org.jsoup.nodes.Document class HtmlProcessor( - private val featureFlagProvider: FeatureFlagProvider, - private val cssClassNameProvider: CssClassNameProvider, + private val customClasses: Set, private val htmlHeadProvider: HtmlHeadProvider, ) { private val htmlSanitizer = HtmlSanitizer() @@ -32,10 +28,10 @@ class HtmlProcessor( } private fun Document.addCustomClasses() = apply { - if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageViewerCssStyles).isEnabled()) { - body() - .addClass(cssClassNameProvider.rootClassName) - .addClass(cssClassNameProvider.mainContentClassName) + if (customClasses.isNotEmpty()) { + body().apply { + customClasses.forEach(::addClass) + } } } }