package io.mrarm.irc.util.theme.live; import android.content.Context; import android.content.ContextWrapper; import android.content.res.ColorStateList; import android.content.res.Resources; import android.util.TypedValue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import io.mrarm.irc.R; import io.mrarm.irc.util.StyledAttributesHelper; import io.mrarm.irc.util.theme.ThemeManager; public class LiveThemeComponent { private Context mContext; private LiveThemeManager mLiveThemeManager; private Map<Integer, List<LiveThemeManager.ColorPropertyApplier>> mColors = new HashMap<>(); private static final WeakHashMap<Context, WeakReference<Resources.Theme>> sThemeCache = new WeakHashMap<>(); public LiveThemeComponent(Context context) { mContext = context; } public Context getContext() { return mContext; } public void setLiveThemeManager(LiveThemeManager mgr) { mLiveThemeManager = mgr; if (mgr == null) return; for (Map.Entry<Integer, List<LiveThemeManager.ColorPropertyApplier>> e : mColors.entrySet()) { for (LiveThemeManager.ColorPropertyApplier v : e.getValue()) mgr.addColorProperty(e.getKey(), v); } } public LiveThemeManager getLiveThemeManager() { return mLiveThemeManager; } private static Resources.Theme getThemeForContext(Context context) { WeakReference<Resources.Theme> retWeak = sThemeCache.get(context); Resources.Theme ret = null; if (retWeak != null) ret = retWeak.get(); if (ret != null) return ret; if (context instanceof ContextWrapper) { Resources.Theme baseTheme = getThemeForContext(((ContextWrapper) context).getBaseContext()); ret = baseTheme; int childResId = 0; if (context instanceof androidx.appcompat.view.ContextThemeWrapper) { childResId = ((androidx.appcompat.view.ContextThemeWrapper) context) .getThemeResId(); } else if (context instanceof android.view.ContextThemeWrapper) { childResId = LiveThemeUtils.getContextThemeWrapperResId( (android.view.ContextThemeWrapper) context); } ThemeManager.ThemeResInfo t = ThemeManager.getInstance(context).getCurrentTheme(); if (childResId == t.getThemeResId() || childResId == t.getThemeNoActionBarResId()) childResId = R.style.LiveThemeHelperTheme; if (childResId != 0) { Resources.Theme newTheme = context.getResources().newTheme(); newTheme.setTo(baseTheme); newTheme.applyStyle(childResId, true); ret = newTheme; } } else { ret = context.getResources().newTheme(); } sThemeCache.put(context, new WeakReference<>(ret)); return ret; } public Resources.Theme getTheme() { return getThemeForContext(mContext); } public boolean addColorAttr(StyledAttributesHelper attrs, int attr, LiveThemeManager.ColorPropertyApplier applier, ColorStateListApplier colorStateListApplier) { TypedValue typedValue = new TypedValue(); if (!attrs.getValue(attr, typedValue)) return false; if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) { addColorProperty(typedValue.resourceId, applier); return true; } else if (typedValue.type != TypedValue.TYPE_NULL && colorStateListApplier != null) { try { ThemedColorStateList th = ThemedColorStateList.createFromXml( mContext.getResources(), mContext.getResources().getXml(typedValue.resourceId), getTheme()); th.attachToComponent(this, () -> colorStateListApplier.onColorStateListChanged(th.createColorStateList())); } catch (Exception e) { e.printStackTrace(); } return true; } return false; } public boolean addColorAttr(StyledAttributesHelper attrs, int attr, LiveThemeManager.ColorPropertyApplier applier) { return addColorAttr(attrs, attr, applier, null); } public void addColorProperty(int res, LiveThemeManager.ColorPropertyApplier applier) { List<LiveThemeManager.ColorPropertyApplier> appliers = mColors.get(res); if (appliers == null) { appliers = new ArrayList<>(); mColors.put(res, appliers); } appliers.add(applier); if (mLiveThemeManager != null) mLiveThemeManager.addColorProperty(res, applier); } public interface ColorStateListApplier { void onColorStateListChanged(ColorStateList newStateList); } }