Refreshing Settings Fragment to Incorporate Dark Mode

1.5k views Asked by At

I have an app in which I use AppCompatDelegate and values-night.xml to switch to a Dark theme in-app programatically. I have a SettingsActivity.java with a SettingsFragment, where I have set an OnSharedPreferenceChangeListener to listen to the respective SharedPreferences values. In the Settings page, I have included a Dark mode setting. On toggling the setting, however, the dark mode does not automatically turn on; instead, I have to exit the SettingsActivity for the app to change mode. Here is my code:

SettingsActivity.java

    public class SettingsActivity extends AppCompatActivity {

    private Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);

        toolbar = findViewById(R.id.toolbar_settings);
        setSupportActionBar(toolbar);

        if (findViewById(R.id.fragment_container)!=null) {
            if (savedInstanceState!=null) {
                return;
            }
            getFragmentManager().beginTransaction().add(R.id.fragment_container, new SettingsFragment()).commit();
        }

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(SettingsActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.settings_menu, menu);
        return true;
    }

    public void savePrefs () {
        SharedPreferences sharedPreferences = getSharedPreferences("Shared_Preferences", MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();

    }
}

SettingsFragment.java

public class SettingsFragment extends PreferenceFragment {

    public int currTheme;
    public static final String theme = "theme";
    private SharedPreferences.OnSharedPreferenceChangeListener listener;
    private ViewGroup parent;
    private View currView;
    @Override
    public void onCreate(@Nullable Bundle SavedInstanceState) {
        super.onCreate(SavedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
                Preference preference = findPreference(s);
                if (s.equals(theme)) {
                    currTheme = Integer.valueOf(sharedPreferences.getString(s, "0"));
                    switch (currTheme) {
                        case 2 :
                            preference.setSummary("Dark");
                            break;
                        case 1 :
                            preference.setSummary("Light");
                            break;
                        default:
                            preference.setSummary("System Settings");
                    }
                    preference.setTitle("Theme");
                } ... 
            }
        };
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = super.onCreateView(inflater, container, savedInstanceState);
        parent = container;
        currView = view;        
        view.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.colorPrimary));
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        setPreferenceScreen(null);
        addPreferencesFromResource(R.xml.preferences);
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
        ...
        preferenceTheme.setTitle("Theme");
        int themeSet = Integer.valueOf(getPreferenceScreen().getSharedPreferences().getString(theme, "System Settings"));
        switch (themeSet) {
            case 2 :
                preferenceTheme.setSummary("Dark");
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                break;
            case 1 :
                preferenceTheme.setSummary("Light");
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                break;
            default :
                preferenceTheme.setSummary("System Default");
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
        }
        currView.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.cpWhite));
        parent.getContext().setTheme(R.style.PreferenceTheme);
    }

    @Override
    public void onStart() {
        super.onStart();
        setPreferenceScreen(null);
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    public void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
    }
}

When run, the fragment does register the change in theme, but it does not change the theme. Here's how it goes:

Dark Theme Set:

Dark Theme Set

Changing to Light Theme:

Changing to Light Theme

The Preference is set to Light theme but the Theme is not set to Light:

The Preference is set to Light theme but the Theme is not set to Light

Is there any fix for this problem?

1

There are 1 answers

0
Thomas Lee On BEST ANSWER

It doesn't look like you included any theme-setting logic in your preference change listeners (only in onResume).

Try including AppCompatDelegate.setDefaultNightMode(...) in your listeners.