Changed|Deprecated: Deprecate `use-black-ui` termux property and replace it with `night-mode`

This will not break existing `use-black-ui` settings for users and it will automatically be converted to `night-mode` when properties are loaded from disk but a deprecation message will be logged.

This `night-mode` key can be used to set the day/night theme variant for activities used by termux app and its plugin. The user can set a string value to `true` to force use dark variant of theme, `false` to force use light variant of theme or `system` to automatically set theme based on current system settings. The default value is still `system`. The app must be restarted for changes to take effect for existing activities, including main terminal `TermuxActivity`.

This is required since "theme != night mode". In future custom theme or color support may be provided that will have both dark and night modes for the same theme.
This commit is contained in:
agnostic-apollo 2021-10-22 00:58:16 +05:00
parent 28ecb64992
commit d96883c4d6
6 changed files with 174 additions and 34 deletions

View File

@ -49,6 +49,7 @@ import com.termux.app.settings.properties.TermuxAppSharedProperties;
import com.termux.shared.termux.interact.TextInputDialogUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxUtils;
import com.termux.shared.theme.ThemeUtils;
import com.termux.shared.view.ViewUtils;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSessionClient;
@ -406,7 +407,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
private void setActivityTheme() {
if (mProperties.isUsingBlackUI()) {
if (ThemeUtils.shouldEnableDarkTheme(this, mProperties.getNightMode())) {
this.setTheme(R.style.Theme_Termux_Black);
} else {
this.setTheme(R.style.Theme_Termux);
@ -414,7 +415,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
}
private void setDrawerTheme() {
if (mProperties.isUsingBlackUI()) {
if (ThemeUtils.shouldEnableDarkTheme(this, mProperties.getNightMode())) {
findViewById(R.id.left_drawer).setBackgroundColor(ContextCompat.getColor(this,
android.R.color.background_dark));
((ImageButton) findViewById(R.id.settings_button)).setColorFilter(Color.WHITE);

View File

@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat;
import com.termux.R;
import com.termux.app.TermuxActivity;
import com.termux.shared.termux.shell.TermuxSession;
import com.termux.shared.theme.ThemeUtils;
import com.termux.terminal.TerminalSession;
import java.util.List;
@ -55,9 +56,9 @@ public class TermuxSessionsListViewController extends ArrayAdapter<TermuxSession
return sessionRowView;
}
boolean isUsingBlackUI = mActivity.getProperties().isUsingBlackUI();
boolean shouldEnableDarkTheme = ThemeUtils.shouldEnableDarkTheme(mActivity, mActivity.getProperties().getNightMode());
if (isUsingBlackUI) {
if (shouldEnableDarkTheme) {
sessionTitleView.setBackground(
ContextCompat.getDrawable(mActivity, R.drawable.session_background_black_selected)
);
@ -84,7 +85,7 @@ public class TermuxSessionsListViewController extends ArrayAdapter<TermuxSession
} else {
sessionTitleView.setPaintFlags(sessionTitleView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
int defaultColor = isUsingBlackUI ? Color.WHITE : Color.BLACK;
int defaultColor = shouldEnableDarkTheme ? Color.WHITE : Color.BLACK;
int color = sessionRunning || sessionAtRow.getExitStatus() == 0 ? defaultColor : Color.RED;
sessionTitleView.setTextColor(color);
return sessionRowView;

View File

@ -0,0 +1,48 @@
package com.termux.shared.models.theme;
import androidx.appcompat.app.AppCompatDelegate;
/** The modes used by to decide night mode for themes. */
public enum NightMode {
/** Night theme should be enabled. */
TRUE("true", AppCompatDelegate.MODE_NIGHT_YES),
/** Dark theme should be enabled. */
FALSE("false", AppCompatDelegate.MODE_NIGHT_NO),
/**
* Use night or dark theme depending on system night mode.
* https://developer.android.com/guide/topics/resources/providing-resources#NightQualifier
*/
SYSTEM("system", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
private final String name;
private final int mode;
NightMode(final String name, int mode) {
this.name = name;
this.mode = mode;
}
public String getName() {
return name;
}
public int getMode() {
return mode;
}
public static Integer modeOf(String name) {
if (TRUE.name.equals(name))
return TRUE.mode;
else if (FALSE.name.equals(name))
return FALSE.mode;
else if (SYSTEM.name.equals(name)) {
return SYSTEM.mode;
} else {
return null;
}
}
}

View File

@ -1,6 +1,7 @@
package com.termux.shared.termux.settings.properties;
import com.google.common.collect.ImmutableBiMap;
import com.termux.shared.models.theme.NightMode;
import com.termux.shared.file.FileUtils;
import com.termux.shared.file.filesystem.FileType;
import com.termux.shared.settings.properties.SharedProperties;
@ -16,7 +17,7 @@ import java.util.List;
import java.util.Set;
/*
* Version: v0.15.0
* Version: v0.16.0
* SPDX-License-Identifier: MIT
*
* Changelog
@ -69,6 +70,9 @@ import java.util.Set;
*
* - 0.15.0 (2021-09-05)
* - Add `KEY_EXTRA_KEYS_TEXT_ALL_CAPS`.
*
* - 0.16.0 (2021-10-21)
* - Add `KEY_NIGHT_MODE`.
*/
/**
@ -118,6 +122,7 @@ public final class TermuxPropertyConstants {
/** Defines the key for whether to use black UI */
@Deprecated
public static final String KEY_USE_BLACK_UI = "use-black-ui"; // Default: "use-black-ui"
@ -295,6 +300,24 @@ public final class TermuxPropertyConstants {
/** Defines the key for {@link NightMode}. */
public static final String KEY_NIGHT_MODE = "night-mode"; // Default: "night-mode"
public static final String IVALUE_NIGHT_MODE_TRUE = NightMode.TRUE.getName();
public static final String IVALUE_NIGHT_MODE_FALSE = NightMode.FALSE.getName();
public static final String IVALUE_NIGHT_MODE_SYSTEM = NightMode.SYSTEM.getName();
public static final String DEFAULT_IVALUE_NIGHT_MODE = IVALUE_NIGHT_MODE_SYSTEM;
/** Defines the bidirectional map for {@link NightMode} values and their internal values */
public static final ImmutableBiMap<String, String> MAP_NIGHT_MODE =
new ImmutableBiMap.Builder<String, String>()
.put(IVALUE_NIGHT_MODE_TRUE, IVALUE_NIGHT_MODE_TRUE)
.put(IVALUE_NIGHT_MODE_FALSE, IVALUE_NIGHT_MODE_FALSE)
.put(IVALUE_NIGHT_MODE_SYSTEM, IVALUE_NIGHT_MODE_SYSTEM)
.build();
/** Defines the key for whether toggle soft keyboard request will show/hide or enable/disable keyboard */
public static final String KEY_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR = "soft-keyboard-toggle-behaviour"; // Default: "soft-keyboard-toggle-behaviour"
@ -340,7 +363,6 @@ public final class TermuxPropertyConstants {
KEY_EXTRA_KEYS_TEXT_ALL_CAPS,
KEY_HIDE_SOFT_KEYBOARD_ON_STARTUP,
KEY_TERMINAL_ONCLICK_URL_OPEN,
KEY_USE_BLACK_UI,
KEY_USE_CTRL_SPACE_WORKAROUND,
KEY_USE_FULLSCREEN,
KEY_USE_FULLSCREEN_WORKAROUND,
@ -368,9 +390,10 @@ public final class TermuxPropertyConstants {
KEY_DEFAULT_WORKING_DIRECTORY,
KEY_EXTRA_KEYS,
KEY_EXTRA_KEYS_STYLE,
KEY_NIGHT_MODE,
KEY_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR,
KEY_VOLUME_KEYS_BEHAVIOUR
));
));
/** Defines the set for keys loaded by termux that have default boolean behaviour with false as default.
* "true" -> true

View File

@ -183,17 +183,47 @@ public abstract class TermuxSharedProperties {
* The class that implements the {@link SharedPropertiesParser} interface.
*/
public static class SharedPropertiesParserClient implements SharedPropertiesParser {
@NonNull
@Override
public Properties preProcessPropertiesOnReadFromDisk(@NonNull Context context, @NonNull Properties properties) {
return replaceUseBlackUIProperty(properties);
}
/**
* Override the
* {@link SharedPropertiesParser#getInternalPropertyValueFromValue(Context,String,String)}
* interface function.
*/
@Override
public Object getInternalPropertyValueFromValue(Context context, String key, String value) {
public Object getInternalPropertyValueFromValue(@NonNull Context context, String key, String value) {
return getInternalTermuxPropertyValueFromValue(context, key, value);
}
}
@NonNull
public static Properties replaceUseBlackUIProperty(@NonNull Properties properties) {
String useBlackUIStringValue = properties.getProperty(TermuxPropertyConstants.KEY_USE_BLACK_UI);
if (useBlackUIStringValue == null) return properties;
Logger.logWarn(LOG_TAG, "Removing deprecated property " + TermuxPropertyConstants.KEY_USE_BLACK_UI + "=" + useBlackUIStringValue);
properties.remove(TermuxPropertyConstants.KEY_USE_BLACK_UI);
// If KEY_NIGHT_MODE is not set
if (properties.getProperty(TermuxPropertyConstants.KEY_NIGHT_MODE) == null) {
Boolean useBlackUI = SharedProperties.getBooleanValueForStringValue(useBlackUIStringValue);
if (useBlackUI != null) {
String termuxAppTheme = useBlackUI ? TermuxPropertyConstants.IVALUE_NIGHT_MODE_TRUE :
TermuxPropertyConstants.IVALUE_NIGHT_MODE_FALSE;
Logger.logWarn(LOG_TAG, "Replacing deprecated property " + TermuxPropertyConstants.KEY_USE_BLACK_UI + "=" + useBlackUI + " with " + TermuxPropertyConstants.KEY_NIGHT_MODE + "=" + termuxAppTheme);
properties.put(TermuxPropertyConstants.KEY_NIGHT_MODE, termuxAppTheme);
}
}
return properties;
}
/**
* A static function that should return the internal termux {@link Object} for a key/value pair
* read from properties file.
@ -213,10 +243,6 @@ public abstract class TermuxSharedProperties {
- If the value is not null and does exist in MAP_*, then internal value returned by map will be used.
*/
switch (key) {
/* boolean */
case TermuxPropertyConstants.KEY_USE_BLACK_UI:
return (boolean) getUseBlackUIInternalPropertyValueFromValue(context, value);
/* int */
case TermuxPropertyConstants.KEY_BELL_BEHAVIOUR:
return (int) getBellBehaviourInternalPropertyValueFromValue(value);
@ -251,6 +277,8 @@ public abstract class TermuxSharedProperties {
return (String) getExtraKeysInternalPropertyValueFromValue(value);
case TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE:
return (String) getExtraKeysStyleInternalPropertyValueFromValue(value);
case TermuxPropertyConstants.KEY_NIGHT_MODE:
return (String) getNightModeInternalPropertyValueFromValue(value);
case TermuxPropertyConstants.KEY_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR:
return (String) getSoftKeyboardToggleBehaviourInternalPropertyValueFromValue(value);
case TermuxPropertyConstants.KEY_VOLUME_KEYS_BEHAVIOUR:
@ -279,18 +307,6 @@ public abstract class TermuxSharedProperties {
/**
* Returns {@code true} or {@code false} if value is the literal string "true" or "false" respectively regardless of case.
* Otherwise returns {@code true} if the night mode is currently enabled in the system.
*
* @param value The {@link String} value to convert.
* @return Returns the internal value for value.
*/
public static boolean getUseBlackUIInternalPropertyValueFromValue(Context context, String value) {
int nightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
return SharedProperties.getBooleanValueForStringValue(TermuxPropertyConstants.KEY_USE_BLACK_UI, value, nightMode == Configuration.UI_MODE_NIGHT_YES, true, LOG_TAG);
}
/**
* Returns the internal value after mapping it based on
* {@code TermuxPropertyConstants#MAP_BELL_BEHAVIOUR} if the value is not {@code null}
@ -314,11 +330,11 @@ public abstract class TermuxSharedProperties {
*/
public static int getTerminalCursorBlinkRateInternalPropertyValueFromValue(String value) {
return SharedProperties.getDefaultIfNotInRange(TermuxPropertyConstants.KEY_TERMINAL_CURSOR_BLINK_RATE,
DataUtils.getIntFromString(value, TermuxPropertyConstants.DEFAULT_IVALUE_TERMINAL_CURSOR_BLINK_RATE),
TermuxPropertyConstants.DEFAULT_IVALUE_TERMINAL_CURSOR_BLINK_RATE,
TermuxPropertyConstants.IVALUE_TERMINAL_CURSOR_BLINK_RATE_MIN,
TermuxPropertyConstants.IVALUE_TERMINAL_CURSOR_BLINK_RATE_MAX,
true, true, LOG_TAG);
DataUtils.getIntFromString(value, TermuxPropertyConstants.DEFAULT_IVALUE_TERMINAL_CURSOR_BLINK_RATE),
TermuxPropertyConstants.DEFAULT_IVALUE_TERMINAL_CURSOR_BLINK_RATE,
TermuxPropertyConstants.IVALUE_TERMINAL_CURSOR_BLINK_RATE_MIN,
TermuxPropertyConstants.IVALUE_TERMINAL_CURSOR_BLINK_RATE_MAX,
true, true, LOG_TAG);
}
/**
@ -487,6 +503,18 @@ public abstract class TermuxSharedProperties {
return SharedProperties.getDefaultIfNullOrEmpty(value, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE);
}
/**
* Returns the value itself if it is not {@code null}, otherwise returns {@link TermuxPropertyConstants#DEFAULT_IVALUE_NIGHT_MODE}.
*
* @param value {@link String} value to convert.
* @return Returns the internal value for value.
*/
public static String getNightModeInternalPropertyValueFromValue(String value) {
return (String) SharedProperties.getDefaultIfNotInMap(TermuxPropertyConstants.KEY_NIGHT_MODE,
TermuxPropertyConstants.MAP_NIGHT_MODE, SharedProperties.toLowerCase(value),
TermuxPropertyConstants.DEFAULT_IVALUE_NIGHT_MODE, true, LOG_TAG);
}
/**
* Returns the value itself if it is not {@code null}, otherwise returns {@link TermuxPropertyConstants#DEFAULT_IVALUE_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR}.
*
@ -535,10 +563,6 @@ public abstract class TermuxSharedProperties {
return (boolean) getInternalPropertyValue(TermuxPropertyConstants.KEY_TERMINAL_ONCLICK_URL_OPEN, true);
}
public boolean isUsingBlackUI() {
return (boolean) getInternalPropertyValue(TermuxPropertyConstants.KEY_USE_BLACK_UI, true);
}
public boolean isUsingCtrlSpaceWorkaround() {
return (boolean) getInternalPropertyValue(TermuxPropertyConstants.KEY_USE_CTRL_SPACE_WORKAROUND, true);
}
@ -587,6 +611,16 @@ public abstract class TermuxSharedProperties {
return (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_DEFAULT_WORKING_DIRECTORY, true);
}
public String getNightMode() {
return (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_NIGHT_MODE, true);
}
/** Get the {@link TermuxPropertyConstants#KEY_NIGHT_MODE} value from the properties file on disk. */
public static String getNightMode(Context context) {
return (String) TermuxSharedProperties.getTermuxInternalPropertyValue(context,
TermuxPropertyConstants.KEY_NIGHT_MODE);
}
public boolean shouldEnableDisableSoftKeyboardOnToggle() {
return (boolean) TermuxPropertyConstants.IVALUE_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR_ENABLE_DISABLE.equals(getInternalPropertyValue(TermuxPropertyConstants.KEY_SOFT_KEYBOARD_TOGGLE_BEHAVIOUR, true));
}

View File

@ -0,0 +1,33 @@
package com.termux.shared.theme;
import android.content.Context;
import android.content.res.Configuration;
import com.termux.shared.models.theme.NightMode;
public class ThemeUtils {
/**
* Will return true if system has enabled night mode.
* https://developer.android.com/guide/topics/resources/providing-resources#NightQualifier
*/
public static boolean isNightModeEnabled(Context context) {
if (context == null) return false;
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
}
/** Will return true if mode is set to {@link NightMode#TRUE}, otherwise will return true if
* mode is set to {@link NightMode#SYSTEM} and night mode is enabled by system. */
public static boolean shouldEnableDarkTheme(Context context, String name) {
if (NightMode.TRUE.getName().equals(name))
return true;
else if (NightMode.FALSE.getName().equals(name))
return false;
else if (NightMode.SYSTEM.getName().equals(name)) {
return isNightModeEnabled(context);
} else {
return false;
}
}
}