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 }