Skip to content

Commit

Permalink
feat(android): fetchSemanticColor() support dynamic light/dark change
Browse files Browse the repository at this point in the history
  • Loading branch information
jquick-axway authored and sgtcoolguy committed Mar 5, 2021
1 parent a664bc8 commit 0b07d89
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.TiApplication;

import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import androidx.annotation.ColorInt;
Expand Down Expand Up @@ -91,6 +92,25 @@ public static int parseColor(String value)
Math.round(Float.valueOf(m.group(2)) * 255f), Math.round(Float.valueOf(m.group(3)) * 255f));
}

// Check if this a "semantic.colors.json" generated string from our common "ti.ui.js" script.
// Example: "ti.semantic.color:dark=<ColorString>;light=<ColorString>"
final String TI_SEMANTIC_COLOR_PREFIX = "ti.semantic.color:";
if (value.startsWith(TI_SEMANTIC_COLOR_PREFIX)) {
String themePrefix = "light=";
Configuration config = TiApplication.getInstance().getResources().getConfiguration();
if ((config.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0) {
themePrefix = "dark=";
}
String[] stringArray = value.substring(TI_SEMANTIC_COLOR_PREFIX.length()).split(";");
for (String nextString : stringArray) {
if (nextString.startsWith(themePrefix)) {
return TiColorHelper.parseColor(nextString.substring(themePrefix.length()));
}
}
Log.e(TAG, "Cannot find named color: " + value);
return Color.TRANSPARENT;
}

// Ti.Android.R.color or Ti.App.Android.R.color resource (by name)
if (TiColorHelper.hasColorResource(value)) {
try {
Expand Down Expand Up @@ -125,14 +145,19 @@ public static int parseColor(String value)

public static boolean hasColorResource(String colorName)
{
return TiRHelper.hasResource("color." + colorName);
return getColorResourceId(colorName) != 0;
}

public static int getColorResourceId(String colorName)
{
TiApplication app = TiApplication.getInstance();
return app.getResources().getIdentifier(colorName, "color", app.getPackageName());
}

public static @ColorInt int getColorResource(String colorName)
throws TiRHelper.ResourceNotFoundException, Resources.NotFoundException
{
int colorResId = TiRHelper.getResource("color." + colorName);
// Now we need to convert it!
int colorResId = getColorResourceId(colorName);
return ContextCompat.getColor(TiApplication.getInstance(), colorResId);
}

Expand Down
47 changes: 26 additions & 21 deletions common/Resources/ti.internal/extensions/ti/ui/semanticColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,40 +63,45 @@ if (!isIOS13Plus && !isMACOSXCatalinaPlus) {

let colorset;
UI.fetchSemanticColor = function fetchSemanticColor (colorName) {
// Load all semantic colors from JSON if not done already.
// Do so via require() in case this file was changed while running LiveView.
if (!colorset) {
const colorsetFileName = 'semantic.colors.json';
try {
const colorsetFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'semantic.colors.json');
const colorsetFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, colorsetFileName);
if (colorsetFile.exists()) {
colorset = JSON.parse(colorsetFile.read().text);
// eslint-disable-next-line security/detect-non-literal-require
colorset = require(`/${colorsetFileName}`);
}
} catch (error) {
// We should probably throw an Error here (or return a fallback color!)
console.error('Failed to load colors file \'semantic.colors.json\'');
console.error(`Failed to load colors file '${colorsetFileName}'`);
return Color.fallback().toHex();
}
}

try {
if (!colorset[colorName]) {
if (OS_ANDROID) {
// if it's not in the semantic colors and we're on Android, it may be a Ti.Android.R.color value
const systemColorId = Ti.Android.R.color[colorName];
if (systemColorId) {
const resourceColor = Ti.UI.Android.getColorResource(systemColorId);
if (resourceColor) {
return resourceColor.toHex();
}
if (OS_ANDROID) {
// On Android, use custom string references to be handled by "TiColorHelper.java".
if (colorset[colorName]) {
// Add all theme colors to a single string.
// Example: "ti.semantic.color:dark=<ColorString>;light=<ColorString>"
let stringResult = 'ti.semantic.color:';
for (const colorType in colorset[colorName]) {
const colorObj = Color.fromSemanticColorsEntry(colorset[colorName][colorType]);
stringResult += `${colorType}=${colorObj.toRGBAString()};`;
}
return stringResult;
} else if (Ti.Android.R.color[colorName]) {
// We're referencing a native "res" color entry.
return `@color/${colorName}`;
}
return Color.fallback().toHex();
} else if (colorset[colorName]) {
// Return the raw color string value from the "semantic.colors.json".
// Use the more exact rgba function over 8-char ARGB hex. Hard to convert things like 75% alpha properly.
const entry = colorset[colorName][UI.semanticColorType];
const colorObj = Color.fromSemanticColorsEntry(entry);
return colorObj.toRGBAString();
}

const entry = colorset[colorName][UI.semanticColorType];
const colorObj = Color.fromSemanticColorsEntry(entry);
// For now, return a string on iOS < 13, Android so we can pass the result directly to the UI property we want to set
// Otherwise we need to modify the Android APIs to accept fake/real Ti.UI.Color instances and convert it to it's own internal
// Color representation
return colorObj.toRGBAString(); // If there's an entry, use the more exact rgba function over 8-char ARGB hex. Hard to convert things like 75% alpha properly.
} catch (error) {
console.error(`Failed to lookup color for ${colorName}`);
}
Expand Down
2 changes: 1 addition & 1 deletion common/lib/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class Color {

/**
* Converts this color to an rgba expression. This expression is more consistent across platforms.
* (whereas iOS/Android differ in expecttaiosn for hex strings.)
* (whereas iOS/Android differ in expectations for hex strings.)
* @returns {string}
*/
toRGBAString() {
Expand Down

0 comments on commit 0b07d89

Please sign in to comment.