diff --git a/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java b/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java
index 895cb0023..9a3ff44dd 100644
--- a/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java
+++ b/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java
@@ -1,7 +1,12 @@
package protect.card_locker;
import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class CatimaAppCompatActivity extends AppCompatActivity {
@@ -10,4 +15,33 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
// Apply chosen language
super.attachBaseContext(Utils.updateBaseContextLocale(base));
}
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // XXX on the splash screen activity, aka the main activity, this has to be executed after applying dynamic colors, not before
+ // so running this only on non main for now
+ if (!this.getClass().getSimpleName().equals(MainActivity.class.getSimpleName())) {
+ Utils.patchOledDarkTheme(this);
+ }
+ }
+
+ @Override
+ protected void onPostCreate(@Nullable Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ // material 3 designer does not consider status bar colors
+ // XXX changing this in onCreate causes issues with the splash screen activity, so doing this here
+ if (Build.VERSION.SDK_INT >= 23) {
+ getWindow().setStatusBarColor(Color.TRANSPARENT);
+ getWindow().getDecorView().setSystemUiVisibility(Utils.isDarkModeEnabled(this) ? 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));
+ }
+ // 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);
+ }
+ }
}
diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
index 79d11e440..e2654a158 100644
--- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
+++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
@@ -50,6 +50,7 @@ import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.NestedScrollView;
@@ -575,7 +576,16 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
maximizeButton.setColorFilter(textColor);
minimizeButton.setColorFilter(textColor);
bottomSheetButton.setColorFilter(textColor);
- editButton.setBackgroundTintList(ColorStateList.valueOf(Utils.getComplementaryColor(darkenedColor)));
+ int complementaryColor = Utils.getComplementaryColor(darkenedColor);
+ editButton.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
+ Drawable editButtonIcon = editButton.getDrawable();
+ editButtonIcon.mutate();
+ if (Utils.needsDarkForeground(complementaryColor)) {
+ editButtonIcon.setTint(ContextCompat.getColor(this, R.color.md_theme_light_onBackground));
+ } else {
+ editButtonIcon.setTint(ContextCompat.getColor(this, R.color.md_theme_dark_onBackground));
+ }
+ editButton.setImageDrawable(editButtonIcon);
Bitmap icon = Utils.retrieveCardImage(this, loyaltyCard.id, ImageLocationType.icon);
if (icon != null) {
diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java
index e5721a3c5..0f4906d0b 100644
--- a/app/src/main/java/protect/card_locker/MainActivity.java
+++ b/app/src/main/java/protect/card_locker/MainActivity.java
@@ -11,6 +11,7 @@ import android.database.CursorIndexOutOfBoundsException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
+import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
@@ -28,6 +29,7 @@ import androidx.appcompat.widget.Toolbar;
import androidx.core.splashscreen.SplashScreen;
import androidx.recyclerview.widget.RecyclerView;
+import com.google.android.material.color.DynamicColors;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
@@ -178,8 +180,20 @@ 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);
+
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/Utils.java b/app/src/main/java/protect/card_locker/Utils.java
index 89a757865..f5e4fd328 100644
--- a/app/src/main/java/protect/card_locker/Utils.java
+++ b/app/src/main/java/protect/card_locker/Utils.java
@@ -14,6 +14,7 @@ import android.os.Build;
import android.os.LocaleList;
import android.provider.MediaStore;
import android.util.Log;
+import android.util.TypedValue;
import android.widget.Toast;
import com.google.zxing.BinaryBitmap;
@@ -39,9 +40,11 @@ import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
+import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.ColorUtils;
import androidx.exifinterface.media.ExifInterface;
+
import protect.card_locker.preferences.Settings;
public class Utils {
@@ -457,6 +460,25 @@ public class Utils {
R = 255 - R;
G = 255 - G;
B = 255 - B;
- return R + (G << 8) + ( B << 16) + ( A << 24);
+ return R + (G << 8) + (B << 16) + (A << 24);
+ }
+
+ // 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);
+ }
+ }
+
+ // 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);
+ }
}
}
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 1583382be..bd77dc135 100644
--- a/app/src/main/java/protect/card_locker/preferences/Settings.java
+++ b/app/src/main/java/protect/card_locker/preferences/Settings.java
@@ -9,6 +9,7 @@ import androidx.annotation.IntegerRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
+
import protect.card_locker.R;
import protect.card_locker.Utils;
@@ -102,4 +103,8 @@ public class Settings {
public boolean getDisableLockscreenWhileViewingCard() {
return getBoolean(R.string.settings_key_disable_lockscreen_while_viewing_card, true);
}
+
+ public boolean getOledDark() {
+ return getBoolean(R.string.settings_key_oled_dark, false);
+ }
}
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 afb47e31c..bb710b1f7 100644
--- a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java
+++ b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java
@@ -18,6 +18,7 @@ import androidx.fragment.app.DialogFragment;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
+
import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
import protect.card_locker.CatimaAppCompatActivity;
@@ -132,6 +133,13 @@ public class SettingsActivity extends CatimaAppCompatActivity {
refreshActivity(true);
return true;
});
+
+ Preference oledDarkPreference = findPreference(getResources().getString(R.string.settings_key_oled_dark));
+ assert oledDarkPreference != null;
+ oledDarkPreference.setOnPreferenceChangeListener((preference, newValue) -> {
+ refreshActivity(true);
+ return true;
+ });
}
private void refreshActivity(boolean reloadMain) {
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index f58017c6e..939599068 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -30,4 +30,12 @@
- true
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 784b20df1..bf381222d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -109,6 +109,7 @@
pref_keep_screen_on
Prevent screen lock
pref_disable_lockscreen_while_viewing_card
+ pref_oled_dark
sharedpreference_active_tab
sharedpreference_privacy_policy_shown
sharedpreference_sort
@@ -212,6 +213,7 @@
Turn flashlight on
Turn flashlight off
Language
+ Pure black background for dark theme
pref_locale
System
Select color
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index b5d76e47c..9b0486158 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,4 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index cbd9051cd..14e295d34 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,6 +1,5 @@
-
+
+
@@ -29,11 +35,11 @@
android:key="@string/settings_key_max_font_size_scale"
android:title="@string/settings_max_font_size_scale"
app:defaultValue="@integer/settings_max_font_size_scale_pct"
+ app:iconSpaceReserved="false"
app:numberPickerPreference_maxValue="@integer/settings_max_font_size_scale_pct_max"
app:numberPickerPreference_minValue="@integer/settings_max_font_size_scale_pct_min"
app:numberPickerPreference_stepValue="10"
app:numberPickerPreference_unitText="%"
- app:iconSpaceReserved="false"
app:singleLineTitle="false" />