File indexing completed on 2024-12-22 04:41:42

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Erik Duisters <e.duisters1@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 package org.kde.kdeconnect.UserInterface;
0008 
0009 import android.os.Bundle;
0010 import android.os.Parcelable;
0011 
0012 import androidx.annotation.NonNull;
0013 import androidx.fragment.app.FragmentActivity;
0014 import androidx.preference.PreferenceFragmentCompat;
0015 import androidx.preference.PreferenceScreen;
0016 import androidx.recyclerview.widget.RecyclerView;
0017 
0018 import org.kde.kdeconnect.Device;
0019 import org.kde.kdeconnect.KdeConnect;
0020 import org.kde.kdeconnect.Plugins.PluginFactory;
0021 import org.kde.kdeconnect_tp.R;
0022 
0023 import java.util.List;
0024 
0025 public class PluginSettingsListFragment extends PreferenceFragmentCompat {
0026     private static final String ARG_DEVICE_ID = "deviceId";
0027     private static final String KEY_RECYCLERVIEW_LAYOUTMANAGER_STATE = "RecyclerViewLayoutmanagerState";
0028 
0029     private PluginPreference.PluginPreferenceCallback callback;
0030     private Parcelable recyclerViewLayoutManagerState;
0031 
0032     /*
0033         https://bricolsoftconsulting.com/state-preservation-in-backstack-fragments/
0034         When adding a fragment to the backstack the fragments onDestroyView is called (which releases
0035         the RecyclerView) but the fragments onSaveInstanceState is not called. When the fragment is destroyed later
0036         on, its onSaveInstanceState() is called but I don't have access to the RecyclerView or it's LayoutManager any more
0037      */
0038     private boolean stateSaved;
0039 
0040     public static PluginSettingsListFragment newInstance(@NonNull String deviceId) {
0041         PluginSettingsListFragment fragment = new PluginSettingsListFragment();
0042 
0043         Bundle args = new Bundle();
0044         args.putString(ARG_DEVICE_ID, deviceId);
0045         fragment.setArguments(args);
0046 
0047         return fragment;
0048     }
0049 
0050     @Override
0051     public void onCreate(Bundle savedInstanceState) {
0052         if (requireActivity() instanceof PluginPreference.PluginPreferenceCallback) {
0053             callback = (PluginPreference.PluginPreferenceCallback) getActivity();
0054         } else {
0055             throw new RuntimeException(requireActivity().getClass().getSimpleName()
0056                     + " must implement PluginPreference.PluginPreferenceCallback");
0057         }
0058 
0059         super.onCreate(savedInstanceState);
0060 
0061         if (savedInstanceState != null && savedInstanceState.containsKey(KEY_RECYCLERVIEW_LAYOUTMANAGER_STATE)) {
0062             recyclerViewLayoutManagerState = savedInstanceState.getParcelable(KEY_RECYCLERVIEW_LAYOUTMANAGER_STATE);
0063         }
0064     }
0065 
0066     @Override
0067     public void onDestroy() {
0068         super.onDestroy();
0069 
0070         callback = null;
0071     }
0072 
0073     @Override
0074     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
0075         PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(requireContext());
0076         setPreferenceScreen(preferenceScreen);
0077 
0078         final String deviceId = getArguments().getString(ARG_DEVICE_ID);
0079 
0080         Device device = KdeConnect.getInstance().getDevice(deviceId);
0081         if (device == null) {
0082             final FragmentActivity activity = requireActivity();
0083             activity.runOnUiThread(activity::finish);
0084             return;
0085         }
0086         List<String> plugins = device.getSupportedPlugins();
0087         PluginFactory.sortPluginList(plugins);
0088 
0089         for (final String pluginKey : plugins) {
0090             //TODO: Use PreferenceManagers context
0091             PluginPreference pref = new PluginPreference(requireContext(), pluginKey, device, callback);
0092             preferenceScreen.addPreference(pref);
0093         }
0094     }
0095 
0096     @NonNull
0097     @Override
0098     protected RecyclerView.Adapter onCreateAdapter(@NonNull PreferenceScreen preferenceScreen) {
0099         RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen);
0100 
0101         /*
0102             The layoutmanager's state (e.g. scroll position) can only be restored when the recyclerView's
0103             adapter has been re-populated with data.
0104          */
0105         if (recyclerViewLayoutManagerState != null) {
0106             adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
0107                 @Override
0108                 public void onChanged() {
0109                     RecyclerView.LayoutManager layoutManager = getListView().getLayoutManager();
0110 
0111                     if (layoutManager != null) {
0112                         layoutManager.onRestoreInstanceState(recyclerViewLayoutManagerState);
0113                     }
0114 
0115                     recyclerViewLayoutManagerState = null;
0116                     adapter.unregisterAdapterDataObserver(this);
0117                 }
0118             });
0119         }
0120 
0121         return adapter;
0122     }
0123 
0124     @Override
0125     public void onPause() {
0126         super.onPause();
0127 
0128         stateSaved = false;
0129     }
0130 
0131     @Override
0132     public void onResume() {
0133         super.onResume();
0134 
0135         requireActivity().setTitle(getString(R.string.device_menu_plugins));
0136     }
0137 
0138     @Override
0139     public void onDestroyView() {
0140         if (!stateSaved && getListView() != null && getListView().getLayoutManager() != null) {
0141             recyclerViewLayoutManagerState = getListView().getLayoutManager().onSaveInstanceState();
0142         }
0143 
0144         super.onDestroyView();
0145     }
0146 
0147     @Override
0148     public void onSaveInstanceState(@NonNull Bundle outState) {
0149         super.onSaveInstanceState(outState);
0150 
0151         Parcelable layoutManagerState = recyclerViewLayoutManagerState;
0152 
0153         if (getListView() != null && getListView().getLayoutManager() != null) {
0154             layoutManagerState = getListView().getLayoutManager().onSaveInstanceState();
0155         }
0156 
0157         if (layoutManagerState != null) {
0158             outState.putParcelable(KEY_RECYCLERVIEW_LAYOUTMANAGER_STATE, layoutManagerState);
0159         }
0160 
0161         stateSaved = true;
0162     }
0163 }