diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 848cc08bc..4af7841e0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -116,7 +116,7 @@ = 23) { getWindow().setStatusBarColor(Color.TRANSPARENT); - getWindow().getDecorView().setSystemUiVisibility(Utils.isDarkModeEnabled(this) ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } else { // icons are always white back then - getWindow().setStatusBarColor(Utils.isDarkModeEnabled(this) ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0)); + getWindow().setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0)); } // XXX android 9 and below has a nasty rendering bug if the theme was patched earlier - // the splash screen activity needs the fix regardless to solve a dynamic color api issue - if (!this.getClass().getSimpleName().equals(MainActivity.class.getSimpleName())) { - Utils.postPatchOledDarkTheme(this); - } + Utils.postPatchColors(this); } } diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java index 14c6aaf1c..2366eebb0 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java @@ -69,6 +69,7 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; @@ -135,6 +136,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { Button enterButton; + Toolbar toolbar; + int loyaltyCardId; boolean updateLoyaltyCard; String cardId; @@ -291,7 +294,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.loyalty_card_edit_activity); - Toolbar toolbar = findViewById(R.id.toolbar); + toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { @@ -690,9 +693,22 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { ); // Fix theming + int colorPrimary = MaterialColors.getColor(this, R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary)); - mCropperOptions.setToolbarColor(colorPrimary); - mCropperOptions.setStatusBarColor(colorPrimary); + int colorOnPrimary = MaterialColors.getColor(this, R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary)); + int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface)); + int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); + int colorBackground = MaterialColors.getColor(this, android.R.attr.colorBackground, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); + mCropperOptions.setToolbarColor(colorSurface); + mCropperOptions.setStatusBarColor(colorSurface); + mCropperOptions.setToolbarWidgetColor(colorOnSurface); + mCropperOptions.setRootViewBackgroundColor(colorBackground); + // set tool tip to be the darker of primary color + if (Utils.isDarkModeEnabled(this)) { + mCropperOptions.setActiveControlsWidgetColor(colorOnPrimary); + } else { + mCropperOptions.setActiveControlsWidgetColor(colorPrimary); + } } @Override @@ -906,7 +922,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { protected void setColorFromIcon() { Object icon = thumbnail.getTag(); if (icon != null && (icon instanceof Bitmap)) { - updateTempState(LoyaltyCardField.headerColor, new Palette.Builder((Bitmap) icon).generate().getDominantColor(tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : R.attr.colorPrimary)); + updateTempState(LoyaltyCardField.headerColor, new Palette.Builder((Bitmap) icon).generate().getDominantColor(tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : R.attr.colorPrimary)); } else { Log.d("setColorFromIcon", "attempting header color change from icon but icon does not exist"); } @@ -1391,13 +1407,22 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { } } } - mCropperLauncher.launch( - UCrop.of( - sourceUri, - destUri - ).withOptions(mCropperOptions) - .getIntent(this) - ); + Intent ucropIntent = UCrop.of( + sourceUri, + destUri + ).withOptions(mCropperOptions) + .getIntent(this); + ucropIntent.setClass(this, UCropWrapper.class); + for (int i = 0; i < toolbar.getChildCount(); i++) { + // send toolbar font details to ucrop wrapper + View child = toolbar.getChildAt(i); + if (child instanceof AppCompatTextView) { + AppCompatTextView childTextView = (AppCompatTextView) child; + ucropIntent.putExtra(UCropWrapper.UCROP_TOOLBAR_TYPEFACE_STYLE, childTextView.getTypeface().getStyle()); + break; + } + } + mCropperLauncher.launch(ucropIntent); } private void generateBarcode() { diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java index 3b817c540..4ed97eb92 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java @@ -16,6 +16,5 @@ public class LoyaltyCardLockerApplication extends Application { Settings settings = new Settings(this); AppCompatDelegate.setDefaultNightMode(settings.getTheme()); - DynamicColors.applyToActivitiesIfAvailable(this); } } diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index e2654a158..24ab41787 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -33,6 +33,7 @@ import android.widget.Toast; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.color.MaterialColors; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.io.UnsupportedEncodingException; @@ -580,10 +581,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements editButton.setBackgroundTintList(ColorStateList.valueOf(complementaryColor)); Drawable editButtonIcon = editButton.getDrawable(); editButtonIcon.mutate(); + int colorPrimary = MaterialColors.getColor(this, R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary)); + int colorOnPrimary = MaterialColors.getColor(this, R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary)); + boolean darkMode = Utils.isDarkModeEnabled(this); if (Utils.needsDarkForeground(complementaryColor)) { - editButtonIcon.setTint(ContextCompat.getColor(this, R.color.md_theme_light_onBackground)); + editButtonIcon.setTint(darkMode ? colorOnPrimary : colorPrimary); } else { - editButtonIcon.setTint(ContextCompat.getColor(this, R.color.md_theme_dark_onBackground)); + editButtonIcon.setTint(darkMode ? colorPrimary : colorOnPrimary); } editButton.setImageDrawable(editButtonIcon); @@ -647,7 +651,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements dotIndicator.removeAllViews(); if (imageTypes.size() >= 2) { dots = new ImageView[imageTypes.size()]; - boolean darkMode = Utils.isDarkModeEnabled(getApplicationContext()); for (int i = 0; i < imageTypes.size(); i++) { dots[i] = new ImageView(this); diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java index 0f4906d0b..81c5d6536 100644 --- a/app/src/main/java/protect/card_locker/MainActivity.java +++ b/app/src/main/java/protect/card_locker/MainActivity.java @@ -180,20 +180,10 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard protected void onCreate(Bundle inputSavedInstanceState) { super.onCreate(inputSavedInstanceState); SplashScreen.installSplashScreen(this); - - // onPreCreate can't tell this activity uses a material theme due to splash screen, force color application here - DynamicColors.applyIfAvailable(this); - Utils.patchOledDarkTheme(this); setTitle(R.string.app_name); - + // XXX color patching has to be done again after setting splash screen + Utils.patchColors(this); setContentView(R.layout.main_activity); - - // XXX more dynamic color fixing due to splash screen - // without this the background color will get stuck with the old color before dynamic color - TypedValue typedValue = new TypedValue(); - getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true); - findViewById(android.R.id.content).setBackgroundColor(typedValue.data); - Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); diff --git a/app/src/main/java/protect/card_locker/UCropWrapper.java b/app/src/main/java/protect/card_locker/UCropWrapper.java new file mode 100644 index 000000000..2f32d5001 --- /dev/null +++ b/app/src/main/java/protect/card_locker/UCropWrapper.java @@ -0,0 +1,79 @@ +package protect.card_locker; + +import android.content.Intent; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; + +import com.google.android.material.color.MaterialColors; +import com.google.android.material.textview.MaterialTextView; +import com.yalantis.ucrop.UCropActivity; + +public class UCropWrapper extends UCropActivity { + public static final String UCROP_TOOLBAR_TYPEFACE_STYLE = "ucop_toolbar_typeface_style"; + + @Override + protected void onPostCreate(@Nullable Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + boolean darkMode = Utils.isDarkModeEnabled(this); + // setup status bar to look like the rest of the app + if (Build.VERSION.SDK_INT >= 23) { + getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } else { + // icons are always white back then + if (!darkMode) { + getWindow().setStatusBarColor(ColorUtils.compositeColors(Color.argb(127, 0, 0, 0), getWindow().getStatusBarColor())); + } + } + + // find and check views that we wish to color modify + // for when we update ucrop or switch to another cropper + View check = findViewById(com.yalantis.ucrop.R.id.wrapper_controls); + if (check instanceof FrameLayout) { + FrameLayout controls = (FrameLayout) check; + check = findViewById(com.yalantis.ucrop.R.id.wrapper_states); + if (check instanceof LinearLayout) { + LinearLayout states = (LinearLayout) check; + for (int i = 0; i < controls.getChildCount(); i++) { + check = controls.getChildAt(i); + if (check instanceof AppCompatImageView) { + AppCompatImageView controlsBackgroundImage = (AppCompatImageView) check; + // everything gathered and are as expected, now perform color patching + Utils.patchColors(this); + int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface)); + int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); + + Drawable controlsBackgroundImageDrawable = controlsBackgroundImage.getBackground(); + controlsBackgroundImageDrawable.mutate(); + controlsBackgroundImageDrawable.setTint(darkMode ? colorOnSurface : colorSurface); + controlsBackgroundImage.setBackgroundDrawable(controlsBackgroundImageDrawable); + + states.setBackgroundColor(darkMode ? colorSurface : colorOnSurface); + break; + } + } + } + } + + // change toolbar font + check = findViewById(com.yalantis.ucrop.R.id.toolbar_title); + if (check instanceof MaterialTextView) { + MaterialTextView toolbarTextview = (MaterialTextView) check; + Intent intent = getIntent(); + int style = intent.getIntExtra(UCROP_TOOLBAR_TYPEFACE_STYLE, -1); + if (style != -1) { + toolbarTextview.setTypeface(Typeface.defaultFromStyle(style)); + } + } + } +} diff --git a/app/src/main/java/protect/card_locker/Utils.java b/app/src/main/java/protect/card_locker/Utils.java index f5e4fd328..23f7cb84e 100644 --- a/app/src/main/java/protect/card_locker/Utils.java +++ b/app/src/main/java/protect/card_locker/Utils.java @@ -17,6 +17,7 @@ import android.util.Log; import android.util.TypedValue; import android.widget.Toast; +import com.google.android.material.color.DynamicColors; import com.google.zxing.BinaryBitmap; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; @@ -464,21 +465,45 @@ public class Utils { } // replace colors in the current theme - // use before views are inflated, after dynamic color - public static void patchOledDarkTheme(AppCompatActivity activity) { - if (isDarkModeEnabled(activity) && new Settings(activity).getOledDark()) { - activity.getTheme().applyStyle(R.style.DarkBackground, true); + public static void patchColors(AppCompatActivity activity) { + Settings settings = new Settings(activity); + String color = settings.getColor(); + + Resources.Theme theme = activity.getTheme(); + Resources resources = activity.getResources(); + if (color.equals(resources.getString(R.string.settings_key_pink_theme))) { + theme.applyStyle(R.style.pink, true); + } else if (color.equals(resources.getString(R.string.settings_key_magenta_theme))) { + theme.applyStyle(R.style.magenta, true); + } else if (color.equals(resources.getString(R.string.settings_key_violet_theme))) { + theme.applyStyle(R.style.violet, true); + } else if (color.equals(resources.getString(R.string.settings_key_blue_theme))) { + theme.applyStyle(R.style.blue, true); + } else if (color.equals(resources.getString(R.string.settings_key_sky_blue_theme))) { + theme.applyStyle(R.style.skyblue, true); + } else if (color.equals(resources.getString(R.string.settings_key_green_theme))) { + theme.applyStyle(R.style.green, true); + } else if (color.equals(resources.getString(R.string.settings_key_brown_theme))) { + theme.applyStyle(R.style.brown, true); + } else if (color.equals(resources.getString(R.string.settings_key_catima_theme))) { + // catima theme is AppTheme itself, no dynamic colors nor applyStyle + } else { + // final catch all in case of invalid theme value from older versions + // also handles R.string.settings_key_system_theme + DynamicColors.applyIfAvailable(activity); + } + + if (isDarkModeEnabled(activity) && settings.getOledDark()) { + theme.applyStyle(R.style.DarkBackground, true); } } // XXX android 9 and below has issues with patched theme where the background becomes a // rendering mess // use after views are inflated - public static void postPatchOledDarkTheme(AppCompatActivity activity) { - if (isDarkModeEnabled(activity) && new Settings(activity).getOledDark()) { - TypedValue typedValue = new TypedValue(); - activity.getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true); - activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data); - } + public static void postPatchColors(AppCompatActivity activity) { + TypedValue typedValue = new TypedValue(); + activity.getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true); + activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data); } } diff --git a/app/src/main/java/protect/card_locker/preferences/Settings.java b/app/src/main/java/protect/card_locker/preferences/Settings.java index bd77dc135..345107429 100644 --- a/app/src/main/java/protect/card_locker/preferences/Settings.java +++ b/app/src/main/java/protect/card_locker/preferences/Settings.java @@ -107,4 +107,8 @@ public class Settings { public boolean getOledDark() { return getBoolean(R.string.settings_key_oled_dark, false); } + + public String getColor() { + return getString(R.string.setting_key_theme_color, mContext.getResources().getString(R.string.settings_key_system_theme)); + } } diff --git a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java index bb710b1f7..d2fc17448 100644 --- a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java +++ b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java @@ -19,6 +19,8 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import com.google.android.material.color.DynamicColors; + import nl.invissvenska.numberpickerpreference.NumberDialogPreference; import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment; import protect.card_locker.CatimaAppCompatActivity; @@ -140,6 +142,17 @@ public class SettingsActivity extends CatimaAppCompatActivity { refreshActivity(true); return true; }); + + ListPreference colorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color)); + assert colorPreference != null; + colorPreference.setOnPreferenceChangeListener((preference, o) -> { + refreshActivity(true); + return true; + }); + if (!DynamicColors.isDynamicColorAvailable()) { + colorPreference.setEntryValues(R.array.color_values_no_dynamic); + colorPreference.setEntries(R.array.color_value_strings_no_dynamic); + } } private void refreshActivity(boolean reloadMain) { diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml index 8630f2c4a..e7351758a 100644 --- a/app/src/main/res/layout/settings_activity.xml +++ b/app/src/main/res/layout/settings_activity.xml @@ -1,9 +1,11 @@ - + android:fitsSystemWindows="true" + tools:context="protect.card_locker.preferences.SettingsActivity"> + android:layout_height="?attr/actionBarSize" /> + android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize" /> - + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 939599068..a36d1b0b9 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -38,4 +38,208 @@ #000000 #000000 + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index 4c472fc4c..96db0eecb 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -12,6 +12,52 @@ @string/settings_dark_theme + + @string/settings_key_system_theme + @string/settings_key_catima_theme + @string/settings_key_pink_theme + @string/settings_key_magenta_theme + @string/settings_key_violet_theme + @string/settings_key_blue_theme + @string/settings_key_sky_blue_theme + @string/settings_key_green_theme + @string/settings_key_brown_theme + + + + @string/settings_system_theme + @string/settings_catima_theme + @string/settings_pink_theme + @string/settings_magenta_theme + @string/settings_violet_theme + @string/settings_blue_theme + @string/settings_sky_blue_theme + @string/settings_green_theme + @string/settings_brown_theme + + + + @string/settings_key_system_theme + @string/settings_key_pink_theme + @string/settings_key_magenta_theme + @string/settings_key_violet_theme + @string/settings_key_blue_theme + @string/settings_key_sky_blue_theme + @string/settings_key_green_theme + @string/settings_key_brown_theme + + + + @string/settings_catima_theme + @string/settings_pink_theme + @string/settings_magenta_theme + @string/settings_violet_theme + @string/settings_blue_theme + @string/settings_sky_blue_theme + @string/settings_green_theme + @string/settings_brown_theme + + bg diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 9b0486158..6932df1b3 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -52,4 +52,208 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 14e295d34..16624a099 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -15,6 +15,15 @@ app:iconSpaceReserved="false" app:singleLineTitle="false" /> + +