package com.moez.QKSMS.common; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import com.moez.QKSMS.enums.QKPreference; import com.moez.QKSMS.interfaces.LiveView; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.WeakHashMap; /** * Allows views to register for updates on preferences * <p> * Example: A button may need to know when the theme changes, so it that * it can change colors accordingly * <p> * In order to do this, you can use this class as following: * LiveViewManager.registerView(QKPreference.THEME, key -> { * // Change button color * } * <p> * You won't need to initialize the button color in addition to registering it * in the LiveViewManager, because registering it will trigger a refresh automatically, * which will initialize it */ public abstract class LiveViewManager { private static final String TAG = "LiveViewManager"; /** * Maps all of the LiveViews to their associated preference */ private static final HashMap<String, WeakHashMap<Object, Set<LiveView>>> sViews = new HashMap<>(); /** * A list of preferences to be excluded from LiveView refreshing when the preference changes */ private static final HashSet<String> sExcludedPrefs = new HashSet<>(Arrays.asList( QKPreference.THEME.getKey(), QKPreference.BACKGROUND.getKey() )); /** * Initialize preferences and register a listener for changes * * @param context Context */ public static void init(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> { if (!sExcludedPrefs.contains(key)) { refreshViews(key); } }); } /** * Register a view to be updated when a QKPreference is changed * We don't need to manually unregister the views because we're using weak sets * * @param preference The preference to listen for * @param parent The object to tie the lifecycle of the LiveView to. If we only reference * a LiveView anonymous inner class, then it'll be quickly garbage collected * and removed from the WeakHashMap. Instead, we should reference the parent * object (ie. The Activity, Fragment, View, etc...) that this LiveView is * concerned with. In most cases, it's acceptable to just pass in `this` * @param view The LiveView */ public static void registerView(QKPreference preference, Object parent, LiveView view) { synchronized (sViews) { if (sViews.containsKey(preference.getKey())) { WeakHashMap<Object, Set<LiveView>> parents = sViews.get(preference.getKey()); if (!parents.containsKey(parent)) { parents.put(parent, new HashSet<>()); } if (!parents.get(parent).contains(view)) { parents.get(parent).add(view); } } else { WeakHashMap<Object, Set<LiveView>> set = new WeakHashMap<>(); set.put(parent, new HashSet<>()); set.get(parent).add(view); sViews.put(preference.getKey(), set); } } // Fire it off once registered view.refresh(preference.getKey()); } /** * Refresh all views that are registered to listen for updates to the given preference * Convenience method for #refreshViews(String key) * * @param preference The preference */ public static void refreshViews(QKPreference preference) { refreshViews(preference.getKey()); } /** * Refresh all views that are registered to listen for updates to the given preference * Convenience method for #refreshViews(String key) * * @param key The preference key */ private static void refreshViews(String key) { synchronized (sViews) { if (sViews.get(key) != null) { for (Set<LiveView> views : sViews.get(key).values()) { for (LiveView view : views) { view.refresh(key); } } } } } }