mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-22 18:55:12 +00:00
Add foundation for using Android's DayNight theming system.
This commit is contained in:
@@ -70,6 +70,7 @@ import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -146,6 +147,9 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
||||
}
|
||||
|
||||
ApplicationDependencies.getJobManager().beginJobLoop();
|
||||
|
||||
DynamicTheme.setDefaultDayNightMode(this);
|
||||
|
||||
Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.PorterDuff;
|
||||
@@ -29,7 +28,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.thoughtcrime.securesms.help.HelpFragment;
|
||||
@@ -139,6 +137,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(TextSecurePreferences.THEME_PREF)) {
|
||||
DynamicTheme.setDefaultDayNightMode(this);
|
||||
recreate();
|
||||
} else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) {
|
||||
recreate();
|
||||
|
||||
@@ -11,7 +11,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -51,7 +50,7 @@ public class CachedInflater {
|
||||
@MainThread
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends View> V inflate(@LayoutRes int layoutRes, @Nullable ViewGroup parent, boolean attachToRoot) {
|
||||
View cached = ViewCache.getInstance().pull(layoutRes);
|
||||
View cached = ViewCache.getInstance().pull(layoutRes, ContextUtil.getNightModeConfiguration(context));
|
||||
if (cached != null) {
|
||||
if (parent != null && attachToRoot) {
|
||||
parent.addView(cached);
|
||||
@@ -87,12 +86,20 @@ public class CachedInflater {
|
||||
|
||||
private long lastClearTime;
|
||||
|
||||
private int nightModeConfiguration;
|
||||
|
||||
static ViewCache getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
void cacheUntilLimit(Context context, @LayoutRes int layoutRes, @Nullable ViewGroup parent, int limit) {
|
||||
void cacheUntilLimit(@NonNull Context context, @LayoutRes int layoutRes, @Nullable ViewGroup parent, int limit) {
|
||||
int currentNightModeConfiguration = ContextUtil.getNightModeConfiguration(context);
|
||||
if (nightModeConfiguration != currentNightModeConfiguration) {
|
||||
clear();
|
||||
nightModeConfiguration = currentNightModeConfiguration;
|
||||
}
|
||||
|
||||
AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
|
||||
|
||||
int existingCount = Util.getOrDefault(cache, layoutRes, Collections.emptyList()).size();
|
||||
@@ -118,7 +125,12 @@ public class CachedInflater {
|
||||
}
|
||||
|
||||
@MainThread
|
||||
@Nullable View pull(@LayoutRes int layoutRes) {
|
||||
@Nullable View pull(@LayoutRes int layoutRes, int nightModeConfiguration) {
|
||||
if (this.nightModeConfiguration != nightModeConfiguration) {
|
||||
clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
List<View> views = cache.get(layoutRes);
|
||||
return views != null && !views.isEmpty() ? views.remove(0)
|
||||
: null;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
@@ -15,4 +16,8 @@ public final class ContextUtil {
|
||||
public static @NonNull Drawable requireDrawable(@NonNull Context context, @DrawableRes int drawable) {
|
||||
return Objects.requireNonNull(ContextCompat.getDrawable(context, drawable));
|
||||
}
|
||||
|
||||
public static int getNightModeConfiguration(@NonNull Context context) {
|
||||
return context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicDarkActionBarTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightTheme_Conversation;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkTheme_Conversation;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_DarkActionBar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicDarkToolbarTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightNoActionBar_DarkToolbar;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkNoActionBar_DarkToolbar;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_DarkNoActionBar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicIntroTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightIntroTheme;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkIntroTheme;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_IntroTheme;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicNoActionBarInviteTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.Signal_Light_NoActionBar_Invite;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.Signal_NoActionBar_Invite;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_Invite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicNoActionBarTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightNoActionBar;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkNoActionBar;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_NoActionBar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DynamicRegistrationTheme extends DynamicTheme {
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightRegistrationTheme;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkRegistrationTheme;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight_Registration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
@@ -17,54 +17,51 @@ public class DynamicTheme {
|
||||
public static final String LIGHT = "light";
|
||||
public static final String SYSTEM = "system";
|
||||
|
||||
private static boolean isDarkTheme;
|
||||
private static int globalNightModeConfiguration;
|
||||
|
||||
private int currentTheme;
|
||||
private int onCreateNightModeConfiguration;
|
||||
|
||||
public void onCreate(Activity activity) {
|
||||
boolean wasDarkTheme = isDarkTheme;
|
||||
public void onCreate(@NonNull Activity activity) {
|
||||
int previousGlobalConfiguration = globalNightModeConfiguration;
|
||||
|
||||
currentTheme = getSelectedTheme(activity);
|
||||
isDarkTheme = isDarkTheme(activity);
|
||||
onCreateNightModeConfiguration = ContextUtil.getNightModeConfiguration(activity);
|
||||
globalNightModeConfiguration = onCreateNightModeConfiguration;
|
||||
|
||||
activity.setTheme(currentTheme);
|
||||
activity.setTheme(getTheme());
|
||||
|
||||
if (isDarkTheme != wasDarkTheme) {
|
||||
if (previousGlobalConfiguration != globalNightModeConfiguration) {
|
||||
CachedInflater.from(activity).clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void onResume(Activity activity) {
|
||||
if (currentTheme != getSelectedTheme(activity)) {
|
||||
Intent intent = activity.getIntent();
|
||||
activity.finish();
|
||||
OverridePendingTransition.invoke(activity);
|
||||
activity.startActivity(intent);
|
||||
OverridePendingTransition.invoke(activity);
|
||||
public void onResume(@NonNull Activity activity) {
|
||||
if (onCreateNightModeConfiguration != ContextUtil.getNightModeConfiguration(activity)) {
|
||||
CachedInflater.from(activity).clear();
|
||||
}
|
||||
}
|
||||
|
||||
private @StyleRes int getSelectedTheme(Activity activity) {
|
||||
if (isDarkTheme(activity)) {
|
||||
return getDarkThemeStyle();
|
||||
} else {
|
||||
return getLightThemeStyle();
|
||||
}
|
||||
}
|
||||
|
||||
protected @StyleRes int getLightThemeStyle() {
|
||||
return R.style.TextSecure_LightTheme;
|
||||
}
|
||||
|
||||
protected @StyleRes int getDarkThemeStyle() {
|
||||
return R.style.TextSecure_DarkTheme;
|
||||
protected @StyleRes int getTheme() {
|
||||
return R.style.Signal_DayNight;
|
||||
}
|
||||
|
||||
public static boolean systemThemeAvailable() {
|
||||
return Build.VERSION.SDK_INT >= 29;
|
||||
}
|
||||
|
||||
public static void setDefaultDayNightMode(@NonNull Context context) {
|
||||
String theme = TextSecurePreferences.getTheme(context);
|
||||
|
||||
if (theme.equals(SYSTEM)) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
} else if (DynamicTheme.isDarkTheme(context)) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
|
||||
CachedInflater.from(context).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the system theme into account.
|
||||
*/
|
||||
@@ -81,10 +78,4 @@ public class DynamicTheme {
|
||||
private static boolean isSystemInDarkTheme(@NonNull Context context) {
|
||||
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
private static final class OverridePendingTransition {
|
||||
static void invoke(Activity activity) {
|
||||
activity.overridePendingTransition(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user