Skip to content

Commit 1943c5e

Browse files
committed
feat(message-reader): add css style providers
1 parent 43a85eb commit 1943c5e

File tree

7 files changed

+197
-0
lines changed

7 files changed

+197
-0
lines changed

app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import app.k9mail.feature.launcher.FeatureLauncherExternalContract
44
import app.k9mail.feature.launcher.di.featureLauncherModule
55
import net.thunderbird.app.common.feature.mail.appCommonFeatureMailModule
66
import net.thunderbird.feature.mail.message.composer.inject.featureMessageComposerModule
7+
import net.thunderbird.feature.mail.message.reader.impl.inject.featureMessageReaderModule
78
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract
89
import net.thunderbird.feature.notification.impl.inject.featureNotificationModule
910
import org.koin.android.ext.koin.androidContext
@@ -14,6 +15,7 @@ internal val appCommonFeatureModule = module {
1415
includes(featureNotificationModule)
1516
includes(featureMessageComposerModule)
1617
includes(appCommonFeatureMailModule)
18+
includes(featureMessageReaderModule)
1719

1820
factory<FeatureLauncherExternalContract.AccountSetupFinishedLauncher> {
1921
AccountSetupFinishedLauncher(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package net.thunderbird.feature.mail.message.reader.api.css
2+
3+
/**
4+
* Provides CSS styles to be injected into the message viewer's web view.
5+
*
6+
* This sealed interface serves as a common type for different CSS style providers.
7+
* Each implementation is responsible for a specific part of the message styling,
8+
* such as global styles, signature styles, or plain text formatting.
9+
*/
10+
sealed interface CssStyleProvider {
11+
/**
12+
* The CSS style tag with its content as a string.
13+
*
14+
* This string should contain valid CSS rules that can be injected into an HTML document (e.g., a message view).
15+
*
16+
* Example:
17+
* ```
18+
* "body { color: red; } a { text-decoration: none; }"
19+
* ```
20+
*/
21+
val style: String
22+
}
23+
24+
/**
25+
* Provides CSS styles that are applied to the entire message view.
26+
*
27+
* This is used for global styles that affect the overall appearance of the email content,
28+
* such as font size, colors, and layout adjustments for the entire message body.
29+
*/
30+
interface GlobalCssStyleProvider : CssStyleProvider
31+
32+
/**
33+
* Provides CSS styles specifically for the `<pre>` element used to wrap plain text messages.
34+
*
35+
* This allows for custom styling of plain text content, such as setting the font family,
36+
* size, and controlling word wrapping behavior to ensure readability.
37+
*/
38+
interface PlainTextMessagePreElementCssStyleProvider : CssStyleProvider {
39+
interface Factory {
40+
fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider
41+
}
42+
}
43+
44+
/**
45+
* Provides CSS styles specifically for email signatures.
46+
*
47+
* This is used to apply custom styling to the signature block within an email message,
48+
* allowing it to be visually distinct from the main message body.
49+
*/
50+
interface SignatureCssStyleProvider : CssStyleProvider

feature/mail/message/reader/impl/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ plugins {
55
kotlin {
66
sourceSets {
77
commonMain.dependencies {
8+
implementation(projects.core.common)
9+
implementation(projects.core.featureflag)
10+
implementation(projects.core.preference.api)
11+
implementation(projects.core.ui.theme.api)
812
implementation(projects.feature.mail.message.reader.api)
913
}
1014
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package net.thunderbird.feature.mail.message.reader.impl.css
2+
3+
import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
4+
import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
5+
import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
6+
import org.intellij.lang.annotations.Language
7+
8+
internal class DefaultGlobalCssStyleProvider(
9+
cssClassNameProvider: CssClassNameProvider,
10+
cssVariableNameProvider: CssVariableNameProvider,
11+
) : GlobalCssStyleProvider {
12+
@Language("HTML")
13+
override val style: String = """
14+
|<style>
15+
| body { font-size: 0.9rem; }
16+
| .clear:after {
17+
| content: "";
18+
| clear: both;
19+
| display: block;
20+
| }
21+
| .${cssClassNameProvider.rootClassName} {
22+
| display: block;
23+
| user-select: auto;
24+
| -webkit-user-select: auto;
25+
| }
26+
| .${cssClassNameProvider.rootClassName}.${cssClassNameProvider.mainContentClassName} {
27+
| width: 100%;
28+
| overflow-wrap: break-word;
29+
| }
30+
| .${cssClassNameProvider.rootClassName}.${cssClassNameProvider.mainContentClassName} pre {
31+
| white-space: pre-wrap;
32+
| }
33+
| .${cssClassNameProvider.rootClassName}.${cssClassNameProvider.mainContentClassName} blockquote {
34+
| margin: auto 0 auto 0.8ex !important;
35+
| padding-left: 1ex !important;
36+
| border-left-width: 1px !important;
37+
| border-left-style: solid !important;
38+
| border-left-color: var(${cssVariableNameProvider.blockquoteDefaultBorderLeftColor}, #ccc);
39+
| }
40+
|</style>
41+
""".trimMargin()
42+
}
43+
44+
internal class LegacyGlobalCssStyleProvider : GlobalCssStyleProvider {
45+
@Language("HTML")
46+
override val style: String = """
47+
|<style type="text/css">
48+
| * {
49+
| background: #121212 !important;
50+
| color: #F3F3F3 !important
51+
| }
52+
| :link, :link * { color: #CCFF33 !important }
53+
| :visited, :visited * { color: #551A8B !important }
54+
|</style>
55+
""".trimMargin()
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package net.thunderbird.feature.mail.message.reader.impl.css
2+
3+
import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
4+
import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
5+
import org.intellij.lang.annotations.Language
6+
7+
class DefaultPlainTextMessagePreElementCssStyleProvider(
8+
cssClassNameProvider: CssClassNameProvider,
9+
useFixedWidthFont: Boolean,
10+
) : PlainTextMessagePreElementCssStyleProvider {
11+
12+
@Language("HTML")
13+
override val style: String = """
14+
|<style>
15+
| pre.${cssClassNameProvider.plainTextMessagePreClassName} {
16+
| white-space: pre-wrap;
17+
| word-wrap: break-word;
18+
| font-family: ${if (useFixedWidthFont) "monospace" else "sans-serif"};
19+
| margin-top: 0px;
20+
| }
21+
|</style>
22+
""".trimMargin()
23+
24+
class Factory(
25+
private val cssClassNameProvider: CssClassNameProvider,
26+
) : PlainTextMessagePreElementCssStyleProvider.Factory {
27+
override fun create(useFixedWidthFont: Boolean): PlainTextMessagePreElementCssStyleProvider {
28+
return DefaultPlainTextMessagePreElementCssStyleProvider(
29+
cssClassNameProvider = cssClassNameProvider,
30+
useFixedWidthFont = useFixedWidthFont,
31+
)
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package net.thunderbird.feature.mail.message.reader.impl.css
2+
3+
import net.thunderbird.feature.mail.message.reader.api.css.CssClassNameProvider
4+
import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
5+
import org.intellij.lang.annotations.Language
6+
7+
class DefaultSignatureCssStyleProvider(
8+
cssClassNameProvider: CssClassNameProvider,
9+
) : SignatureCssStyleProvider {
10+
@Language("HTML")
11+
override val style: String = """
12+
|<style>
13+
| .${cssClassNameProvider.signatureClassName} {
14+
| opacity: 0.5;
15+
| }
16+
|</style>
17+
""".trimMargin()
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package net.thunderbird.feature.mail.message.reader.impl.inject
2+
3+
import net.thunderbird.core.featureflag.FeatureFlagProvider
4+
import net.thunderbird.feature.mail.message.reader.api.MessageReaderFeatureFlags
5+
import net.thunderbird.feature.mail.message.reader.api.css.CssVariableNameProvider
6+
import net.thunderbird.feature.mail.message.reader.api.css.GlobalCssStyleProvider
7+
import net.thunderbird.feature.mail.message.reader.api.css.PlainTextMessagePreElementCssStyleProvider
8+
import net.thunderbird.feature.mail.message.reader.api.css.SignatureCssStyleProvider
9+
import net.thunderbird.feature.mail.message.reader.impl.css.DefaultCssVariableNameProvider
10+
import net.thunderbird.feature.mail.message.reader.impl.css.DefaultGlobalCssStyleProvider
11+
import net.thunderbird.feature.mail.message.reader.impl.css.DefaultPlainTextMessagePreElementCssStyleProvider
12+
import net.thunderbird.feature.mail.message.reader.impl.css.DefaultSignatureCssStyleProvider
13+
import net.thunderbird.feature.mail.message.reader.impl.css.LegacyGlobalCssStyleProvider
14+
import org.koin.dsl.module
15+
16+
val featureMessageReaderModule = module {
17+
single<CssVariableNameProvider> { DefaultCssVariableNameProvider(get()) }
18+
single<GlobalCssStyleProvider> {
19+
val featureFlagProvider = get<FeatureFlagProvider>()
20+
if (featureFlagProvider.provide(MessageReaderFeatureFlags.UseNewMessageReaderCssStyles).isEnabled()) {
21+
DefaultGlobalCssStyleProvider(
22+
cssClassNameProvider = get(),
23+
cssVariableNameProvider = get(),
24+
)
25+
} else {
26+
LegacyGlobalCssStyleProvider()
27+
}
28+
}
29+
single<SignatureCssStyleProvider> { DefaultSignatureCssStyleProvider(get()) }
30+
factory<PlainTextMessagePreElementCssStyleProvider.Factory> {
31+
DefaultPlainTextMessagePreElementCssStyleProvider.Factory(cssClassNameProvider = get())
32+
}
33+
}

0 commit comments

Comments
 (0)