-
Notifications
You must be signed in to change notification settings - Fork 86
Add monochrome mode #350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add monochrome mode #350
Conversation
Introduces a new monochrome setting that applies a high-quality grayscale filter before applying color temperature. This allows users with very low color temperatures (500K) to still distinguish blue objects as different shades of gray before the warm tint is applied. Implementation: - Requires root mode (uses SurfaceFlinger color matrix transformation) - Applies luminosity-based grayscale (0.299R + 0.587G + 0.114B) - Automatically hidden when root mode is disabled - Added UI checkbox with descriptive summary and root requirement notice - Backward compatible (defaults to false) Changes: - Added monochrome boolean field to Profile data class with JSON support - Implemented color matrix transformation in SurfaceFlinger - Added monochrome preference to Config with profile activation - Added FilterFragment logic to show/hide based on root mode availability - Added UI strings and preference resources The feature preserves contrast with extreme color temperatures while maintaining the benefits of blue light reduction.
The grgit 4.1.0 dependency was not available in Maven repositories, causing build failures. Updated to 4.1.1 which is available and compatible with the existing Gradle and Kotlin versions. Also added gradlePluginPortal() repository to buildscript to ensure proper dependency resolution.
smichel17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks really nice! Just a few small suggestions.
| } | ||
|
|
||
| var monochrome by BooleanPreference(R.string.pref_key_monochrome, false) { | ||
| activeProfile.run { if (it != monochrome) activateProfile(copy(monochrome = it)) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure this works, since it matches the other ones, but ugh, I was so hyperfixated on making code concise (specifically as measured by lines of code) when I wrote this.
Today I'd write it more like this (assuming I have correctly inferred it; I did this in GitHub webui):
| activeProfile.run { if (it != monochrome) activateProfile(copy(monochrome = it)) } | |
| if (it != monochrome) { | |
| activateProfile(activeProfile.copy(monochrome = it)) | |
| } |
No need to change this, unless you want to change the others too, which you are more than welcome to.
| val monochrome: Boolean = false) | ||
| : Event, Comparable<Profile> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Kotlin support trailing commas now?
| val monochrome: Boolean = false) | |
| : Event, Comparable<Profile> { | |
| val monochrome: Boolean = false, | |
| ) : Event, Comparable<Profile> { |
| Shell.su(call).exec() | ||
| val profile = activeProfile | ||
|
|
||
| if (profile.monochrome) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of duplication here, relative to the unique code. Here's how I'd suggest handling it:
- Move the
r,g, andbdeclarations before the if. Maybe they'll be calculated differently in the future, but for now they're the same, so no need to prematurely split code paths. - Extract a common
callfunction which takes the matrix part of the string, builds and logs the command, and does the SU call. Each of the branches would now end with this.
| pref.summary = if (Config.useRoot) { | ||
| getString(R.string.pref_summary_monochrome) | ||
| } else { | ||
| getString(R.string.pref_summary_monochrome_requires_root) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're hiding the pref when root is disabled, then no need for the "requires root" description, right?
This has been a wishlist feature for me for a while, so I decided to add it 😊
This preserves contrast when using a very low color temperature (close to 500K). It's rooted-only since it can't be replicated without SurfaceFlinger.
Tested on my Pixel 8 Pro running Android 16.
Simulated screenshots (you can see the largest difference in the download links, they're nearly invisible on low brightness without this):

