mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Move extension preferences to separate controller
(cherry picked from commit 9cb45b92e1)
			
			
This commit is contained in:
		| @@ -1,51 +1,23 @@ | ||||
| package eu.kanade.tachiyomi.ui.browse.extension | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Context | ||||
| import android.os.Bundle | ||||
| import android.util.TypedValue | ||||
| import android.view.ContextThemeWrapper | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.preference.DialogPreference | ||||
| import androidx.preference.EditTextPreference | ||||
| import androidx.preference.EditTextPreferenceDialogController | ||||
| import androidx.preference.ListPreference | ||||
| import androidx.preference.ListPreferenceDialogController | ||||
| import androidx.preference.MultiSelectListPreference | ||||
| import androidx.preference.MultiSelectListPreferenceDialogController | ||||
| import androidx.preference.Preference | ||||
| import androidx.preference.PreferenceGroupAdapter | ||||
| import androidx.preference.PreferenceManager | ||||
| import androidx.preference.PreferenceScreen | ||||
| import androidx.recyclerview.widget.DividerItemDecoration | ||||
| import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore | ||||
| import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore | ||||
| import eu.kanade.tachiyomi.databinding.ExtensionDetailControllerBinding | ||||
| import eu.kanade.tachiyomi.source.ConfigurableSource | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.ui.base.controller.NucleusController | ||||
| import eu.kanade.tachiyomi.util.preference.preferenceCategory | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.util.system.LocaleHelper | ||||
| import eu.kanade.tachiyomi.util.view.visible | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import reactivecircus.flowbinding.android.view.clicks | ||||
| import timber.log.Timber | ||||
|  | ||||
| @SuppressLint("RestrictedApi") | ||||
| class ExtensionDetailsController(bundle: Bundle? = null) : | ||||
|     NucleusController<ExtensionDetailControllerBinding, ExtensionDetailsPresenter>(bundle), | ||||
|     PreferenceManager.OnDisplayPreferenceDialogListener, | ||||
|     DialogPreference.TargetFragment { | ||||
|  | ||||
|     private var lastOpenPreferencePosition: Int? = null | ||||
|  | ||||
|     private var preferenceScreen: PreferenceScreen? = null | ||||
|     NucleusController<ExtensionDetailControllerBinding, ExtensionDetailsPresenter>(bundle) { | ||||
|  | ||||
|     constructor(pkgName: String) : this( | ||||
|         Bundle().apply { | ||||
| @@ -54,8 +26,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) : | ||||
|     ) | ||||
|  | ||||
|     override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { | ||||
|         val themedInflater = inflater.cloneInContext(getPreferenceThemeContext()) | ||||
|         binding = ExtensionDetailControllerBinding.inflate(themedInflater) | ||||
|         binding = ExtensionDetailControllerBinding.inflate(inflater) | ||||
|         return binding.root | ||||
|     } | ||||
|  | ||||
| @@ -93,132 +64,25 @@ class ExtensionDetailsController(bundle: Bundle? = null) : | ||||
|             binding.extensionWarningBanner.setText(R.string.unofficial_extension_message) | ||||
|         } | ||||
|  | ||||
|         val themedContext by lazy { getPreferenceThemeContext() } | ||||
|         val manager = PreferenceManager(themedContext) | ||||
|         manager.preferenceDataStore = EmptyPreferenceDataStore() | ||||
|         manager.onDisplayPreferenceDialogListener = this | ||||
|         val screen = manager.createPreferenceScreen(themedContext) | ||||
|         preferenceScreen = screen | ||||
|  | ||||
|         val multiSource = extension.sources.size > 1 | ||||
|  | ||||
|         for (source in extension.sources) { | ||||
|             if (source is ConfigurableSource) { | ||||
|                 try { | ||||
|                     addPreferencesForSource(screen, source, multiSource) | ||||
|                 } catch (e: AbstractMethodError) { | ||||
|                     Timber.e("Source did not implement [addPreferencesForSource]: ${source.name}") | ||||
|                 } | ||||
|             } | ||||
|         if (presenter.extension?.sources?.find { it is ConfigurableSource } != null) { | ||||
|             binding.extensionPrefs.visible() | ||||
|             binding.extensionPrefs.clicks() | ||||
|                 .onEach { openPreferences() } | ||||
|                 .launchIn(scope) | ||||
|         } | ||||
|  | ||||
|         manager.setPreferences(screen) | ||||
|  | ||||
|         binding.extensionPrefsRecycler.layoutManager = LinearLayoutManager(context) | ||||
|         binding.extensionPrefsRecycler.adapter = PreferenceGroupAdapter(screen) | ||||
|         binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL)) | ||||
|  | ||||
|         if (screen.preferenceCount == 0) { | ||||
|             binding.extensionPrefsEmptyView.show(R.string.ext_empty_preferences) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onDestroyView(view: View) { | ||||
|         preferenceScreen = null | ||||
|         super.onDestroyView(view) | ||||
|     } | ||||
|  | ||||
|     fun onExtensionUninstalled() { | ||||
|         router.popCurrentController() | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
|         lastOpenPreferencePosition?.let { outState.putInt(LASTOPENPREFERENCE_KEY, it) } | ||||
|         super.onSaveInstanceState(outState) | ||||
|     } | ||||
|  | ||||
|     override fun onRestoreInstanceState(savedInstanceState: Bundle) { | ||||
|         super.onRestoreInstanceState(savedInstanceState) | ||||
|         lastOpenPreferencePosition = savedInstanceState.get(LASTOPENPREFERENCE_KEY) as? Int | ||||
|     } | ||||
|  | ||||
|     private fun addPreferencesForSource(screen: PreferenceScreen, source: Source, multiSource: Boolean) { | ||||
|         val context = screen.context | ||||
|  | ||||
|         // TODO | ||||
|         val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) { | ||||
|             source.preferences | ||||
|         } else {*/ | ||||
|             context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE) | ||||
|             /*}*/ | ||||
|     private fun openPreferences() { | ||||
|         router.pushController( | ||||
|             ExtensionPreferencesController(presenter.extension!!.pkgName).withFadeTransaction() | ||||
|         ) | ||||
|  | ||||
|         if (source is ConfigurableSource) { | ||||
|             if (multiSource) { | ||||
|                 screen.preferenceCategory { | ||||
|                     title = source.toString() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             val newScreen = screen.preferenceManager.createPreferenceScreen(context) | ||||
|             source.setupPreferenceScreen(newScreen) | ||||
|  | ||||
|             // Reparent the preferences | ||||
|             while (newScreen.preferenceCount != 0) { | ||||
|                 val pref = newScreen.getPreference(0) | ||||
|                 pref.isIconSpaceReserved = false | ||||
|                 pref.preferenceDataStore = dataStore | ||||
|                 pref.order = Int.MAX_VALUE // reset to default order | ||||
|  | ||||
|                 newScreen.removePreference(pref) | ||||
|                 screen.addPreference(pref) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun getPreferenceThemeContext(): Context { | ||||
|         val tv = TypedValue() | ||||
|         activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true) | ||||
|         return ContextThemeWrapper(activity, tv.resourceId) | ||||
|     } | ||||
|  | ||||
|     override fun onDisplayPreferenceDialog(preference: Preference) { | ||||
|         if (!isAttached) return | ||||
|  | ||||
|         val screen = preference.parent!! | ||||
|  | ||||
|         lastOpenPreferencePosition = (0 until screen.preferenceCount).indexOfFirst { | ||||
|             screen.getPreference(it) === preference | ||||
|         } | ||||
|  | ||||
|         val f = when (preference) { | ||||
|             is EditTextPreference -> | ||||
|                 EditTextPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             is ListPreference -> | ||||
|                 ListPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             is MultiSelectListPreference -> | ||||
|                 MultiSelectListPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             else -> throw IllegalArgumentException( | ||||
|                 "Tried to display dialog for unknown " + | ||||
|                     "preference type. Did you forget to override onDisplayPreferenceDialog()?" | ||||
|             ) | ||||
|         } | ||||
|         f.targetController = this | ||||
|         f.showDialog(router) | ||||
|     } | ||||
|  | ||||
|     @Suppress("UNCHECKED_CAST") | ||||
|     override fun <T : Preference> findPreference(key: CharSequence): T? { | ||||
|         // We track [lastOpenPreferencePosition] when displaying the dialog | ||||
|         // [key] isn't useful since there may be duplicates | ||||
|         return preferenceScreen!!.getPreference(lastOpenPreferencePosition!!) as T | ||||
|     } | ||||
|  | ||||
|     private companion object { | ||||
|         const val PKGNAME_KEY = "pkg_name" | ||||
|         const val LASTOPENPREFERENCE_KEY = "last_open_preference" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,196 @@ | ||||
| package eu.kanade.tachiyomi.ui.browse.extension | ||||
|  | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Context | ||||
| import android.os.Bundle | ||||
| import android.util.TypedValue | ||||
| import android.view.ContextThemeWrapper | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.preference.DialogPreference | ||||
| import androidx.preference.EditTextPreference | ||||
| import androidx.preference.EditTextPreferenceDialogController | ||||
| import androidx.preference.ListPreference | ||||
| import androidx.preference.ListPreferenceDialogController | ||||
| import androidx.preference.MultiSelectListPreference | ||||
| import androidx.preference.MultiSelectListPreferenceDialogController | ||||
| import androidx.preference.Preference | ||||
| import androidx.preference.PreferenceGroupAdapter | ||||
| import androidx.preference.PreferenceManager | ||||
| import androidx.preference.PreferenceScreen | ||||
| import androidx.recyclerview.widget.DividerItemDecoration | ||||
| import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore | ||||
| import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore | ||||
| import eu.kanade.tachiyomi.databinding.ExtensionPreferencesControllerBinding | ||||
| import eu.kanade.tachiyomi.source.ConfigurableSource | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.ui.base.controller.NucleusController | ||||
| import eu.kanade.tachiyomi.util.preference.preferenceCategory | ||||
| import timber.log.Timber | ||||
|  | ||||
| @SuppressLint("RestrictedApi") | ||||
| class ExtensionPreferencesController(bundle: Bundle? = null) : | ||||
|     NucleusController<ExtensionPreferencesControllerBinding, ExtensionPreferencesPresenter>(bundle), | ||||
|     PreferenceManager.OnDisplayPreferenceDialogListener, | ||||
|     DialogPreference.TargetFragment { | ||||
|  | ||||
|     private var lastOpenPreferencePosition: Int? = null | ||||
|  | ||||
|     private var preferenceScreen: PreferenceScreen? = null | ||||
|  | ||||
|     constructor(pkgName: String) : this( | ||||
|         Bundle().apply { | ||||
|             putString(PKGNAME_KEY, pkgName) | ||||
|         } | ||||
|     ) | ||||
|  | ||||
|     override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { | ||||
|         val themedInflater = inflater.cloneInContext(getPreferenceThemeContext()) | ||||
|         binding = ExtensionPreferencesControllerBinding.inflate(themedInflater) | ||||
|         return binding.root | ||||
|     } | ||||
|  | ||||
|     override fun createPresenter(): ExtensionPreferencesPresenter { | ||||
|         return ExtensionPreferencesPresenter(args.getString(PKGNAME_KEY)!!) | ||||
|     } | ||||
|  | ||||
|     override fun getTitle(): String? { | ||||
|         return resources?.getString(R.string.label_extension_info) | ||||
|     } | ||||
|  | ||||
|     @SuppressLint("PrivateResource") | ||||
|     override fun onViewCreated(view: View) { | ||||
|         super.onViewCreated(view) | ||||
|  | ||||
|         val extension = presenter.extension ?: return | ||||
|         val context = view.context | ||||
|  | ||||
|         val themedContext by lazy { getPreferenceThemeContext() } | ||||
|         val manager = PreferenceManager(themedContext) | ||||
|         manager.preferenceDataStore = EmptyPreferenceDataStore() | ||||
|         manager.onDisplayPreferenceDialogListener = this | ||||
|         val screen = manager.createPreferenceScreen(themedContext) | ||||
|         preferenceScreen = screen | ||||
|  | ||||
|         val multiSource = extension.sources.size > 1 | ||||
|  | ||||
|         for (source in extension.sources) { | ||||
|             if (source is ConfigurableSource) { | ||||
|                 try { | ||||
|                     addPreferencesForSource(screen, source, multiSource) | ||||
|                 } catch (e: AbstractMethodError) { | ||||
|                     Timber.e("Source did not implement [addPreferencesForSource]: ${source.name}") | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         manager.setPreferences(screen) | ||||
|  | ||||
|         binding.extensionPrefsRecycler.layoutManager = LinearLayoutManager(context) | ||||
|         binding.extensionPrefsRecycler.adapter = PreferenceGroupAdapter(screen) | ||||
|         binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL)) | ||||
|  | ||||
|         if (screen.preferenceCount == 0) { | ||||
|             binding.extensionPrefsEmptyView.show(R.string.ext_empty_preferences) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onDestroyView(view: View) { | ||||
|         preferenceScreen = null | ||||
|         super.onDestroyView(view) | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
|         lastOpenPreferencePosition?.let { outState.putInt(LASTOPENPREFERENCE_KEY, it) } | ||||
|         super.onSaveInstanceState(outState) | ||||
|     } | ||||
|  | ||||
|     override fun onRestoreInstanceState(savedInstanceState: Bundle) { | ||||
|         super.onRestoreInstanceState(savedInstanceState) | ||||
|         lastOpenPreferencePosition = savedInstanceState.get(LASTOPENPREFERENCE_KEY) as? Int | ||||
|     } | ||||
|  | ||||
|     private fun addPreferencesForSource(screen: PreferenceScreen, source: Source, multiSource: Boolean) { | ||||
|         val context = screen.context | ||||
|  | ||||
|         // TODO | ||||
|         val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) { | ||||
|             source.preferences | ||||
|         } else {*/ | ||||
|             context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE) | ||||
|             /*}*/ | ||||
|         ) | ||||
|  | ||||
|         if (source is ConfigurableSource) { | ||||
|             if (multiSource) { | ||||
|                 screen.preferenceCategory { | ||||
|                     title = source.toString() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             val newScreen = screen.preferenceManager.createPreferenceScreen(context) | ||||
|             source.setupPreferenceScreen(newScreen) | ||||
|  | ||||
|             // Reparent the preferences | ||||
|             while (newScreen.preferenceCount != 0) { | ||||
|                 val pref = newScreen.getPreference(0) | ||||
|                 pref.isIconSpaceReserved = false | ||||
|                 pref.preferenceDataStore = dataStore | ||||
|                 pref.order = Int.MAX_VALUE // reset to default order | ||||
|  | ||||
|                 newScreen.removePreference(pref) | ||||
|                 screen.addPreference(pref) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun getPreferenceThemeContext(): Context { | ||||
|         val tv = TypedValue() | ||||
|         activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true) | ||||
|         return ContextThemeWrapper(activity, tv.resourceId) | ||||
|     } | ||||
|  | ||||
|     override fun onDisplayPreferenceDialog(preference: Preference) { | ||||
|         if (!isAttached) return | ||||
|  | ||||
|         val screen = preference.parent!! | ||||
|  | ||||
|         lastOpenPreferencePosition = (0 until screen.preferenceCount).indexOfFirst { | ||||
|             screen.getPreference(it) === preference | ||||
|         } | ||||
|  | ||||
|         val f = when (preference) { | ||||
|             is EditTextPreference -> | ||||
|                 EditTextPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             is ListPreference -> | ||||
|                 ListPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             is MultiSelectListPreference -> | ||||
|                 MultiSelectListPreferenceDialogController | ||||
|                     .newInstance(preference.getKey()) | ||||
|             else -> throw IllegalArgumentException( | ||||
|                 "Tried to display dialog for unknown " + | ||||
|                     "preference type. Did you forget to override onDisplayPreferenceDialog()?" | ||||
|             ) | ||||
|         } | ||||
|         f.targetController = this | ||||
|         f.showDialog(router) | ||||
|     } | ||||
|  | ||||
|     @Suppress("UNCHECKED_CAST") | ||||
|     override fun <T : Preference> findPreference(key: CharSequence): T? { | ||||
|         // We track [lastOpenPreferencePosition] when displaying the dialog | ||||
|         // [key] isn't useful since there may be duplicates | ||||
|         return preferenceScreen!!.getPreference(lastOpenPreferencePosition!!) as T | ||||
|     } | ||||
|  | ||||
|     private companion object { | ||||
|         const val PKGNAME_KEY = "pkg_name" | ||||
|         const val LASTOPENPREFERENCE_KEY = "last_open_preference" | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| package eu.kanade.tachiyomi.ui.browse.extension | ||||
|  | ||||
| import eu.kanade.tachiyomi.extension.ExtensionManager | ||||
| import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
|  | ||||
| class ExtensionPreferencesPresenter( | ||||
|     val pkgName: String, | ||||
|     extensionManager: ExtensionManager = Injekt.get() | ||||
| ) : BasePresenter<ExtensionPreferencesController>() { | ||||
|  | ||||
|     val extension = extensionManager.installedExtensions.find { it.pkgName == pkgName } | ||||
| } | ||||
| @@ -5,6 +5,21 @@ | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/extension_warning_banner" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginBottom="16dp" | ||||
|         android:background="@color/red_error" | ||||
|         android:gravity="center" | ||||
|         android:padding="16dp" | ||||
|         android:textColor="@android:color/white" | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <ImageView | ||||
|         android:id="@+id/extension_icon" | ||||
|         android:layout_width="56dp" | ||||
| @@ -13,7 +28,7 @@ | ||||
|         android:src="@mipmap/ic_launcher" | ||||
|         app:layout_constraintBottom_toBottomOf="@id/extension_pkg" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="@id/extension_title" /> | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_warning_banner" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/extension_title" | ||||
| @@ -23,7 +38,7 @@ | ||||
|         android:layout_marginStart="16dp" | ||||
|         android:layout_marginTop="16dp" | ||||
|         app:layout_constraintStart_toEndOf="@id/extension_icon" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_warning_banner" | ||||
|         tools:text="Tachiyomi: Extension" /> | ||||
|  | ||||
|     <TextView | ||||
| @@ -60,60 +75,32 @@ | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_lang" | ||||
|         tools:text="eu.kanade.tachiyomi.extension.en.myext" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/extension_warning_banner" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:layout_marginBottom="16dp" | ||||
|         android:background="@color/red_error" | ||||
|         android:gravity="center" | ||||
|         android:padding="16dp" | ||||
|         android:textColor="@android:color/white" | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_pkg" /> | ||||
|  | ||||
|     <Button | ||||
|         android:id="@+id/extension_uninstall_button" | ||||
|         style="@style/Theme.Widget.Button.FilledAccent" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="16dp" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:layout_marginTop="32dp" | ||||
|         android:layout_marginEnd="16dp" | ||||
|         android:paddingStart="32dp" | ||||
|         android:paddingEnd="32dp" | ||||
|         android:text="@string/ext_uninstall" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="@id/guideline" | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_warning_banner" /> | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_lang" /> | ||||
|  | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/extension_prefs_recycler" | ||||
|     <TextView | ||||
|         android:id="@+id/extension_prefs" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_height="@dimen/material_component_lists_two_line_height" | ||||
|         android:layout_marginTop="16dp" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button" /> | ||||
|  | ||||
|     <eu.kanade.tachiyomi.widget.EmptyView | ||||
|         android:id="@+id/extension_prefs_empty_view" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:gravity="center" | ||||
|         android:background="@drawable/list_item_selector" | ||||
|         android:gravity="center_vertical" | ||||
|         android:padding="16dp" | ||||
|         android:text="@string/ext_preferences" | ||||
|         android:visibility="gone" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button" /> | ||||
|  | ||||
|     <androidx.constraintlayout.widget.Guideline | ||||
|         android:id="@+id/guideline" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:orientation="vertical" | ||||
|         app:layout_constraintGuide_percent="0.5" /> | ||||
|         app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
							
								
								
									
										20
									
								
								app/src/main/res/layout/extension_preferences_controller.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/src/main/res/layout/extension_preferences_controller.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
|  | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/extension_prefs_recycler" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" /> | ||||
|  | ||||
|     <eu.kanade.tachiyomi.widget.EmptyView | ||||
|         android:id="@+id/extension_prefs_empty_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
| </FrameLayout> | ||||
		Reference in New Issue
	
	Block a user