2020-03-27 20:36:02 +01:00
/ *
2020-04-19 23:04:05 +02:00
* SPDX - License - Identifier : MPL - 2.0
2020-03-27 20:36:02 +01:00
* Copyright © 2020 Skyline Team and Contributors ( https : //github.com/skyline-emu/)
* /
2023-02-14 14:17:17 +01:00
package emu.skyline.settings
2019-12-02 14:39:08 +01:00
2023-02-22 17:47:33 +01:00
import android.annotation.SuppressLint
2019-12-02 14:39:08 +01:00
import android.os.Bundle
2023-02-22 17:47:33 +01:00
import android.text.TextUtils
import android.view.KeyEvent
2023-03-10 17:56:31 +01:00
import android.view.Menu
2023-02-22 17:47:33 +01:00
import android.view.ViewTreeObserver
import android.widget.TextView
2019-12-02 14:39:08 +01:00
import androidx.appcompat.app.AppCompatActivity
2023-03-10 17:56:31 +01:00
import androidx.appcompat.widget.SearchView
2022-03-11 12:05:41 +01:00
import androidx.coordinatorlayout.widget.CoordinatorLayout
2023-02-22 17:47:33 +01:00
import androidx.core.view.WindowCompat
2023-03-07 23:35:35 +01:00
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.Preference
2023-03-10 17:56:31 +01:00
import androidx.preference.PreferenceCategory
2023-02-22 17:47:33 +01:00
import androidx.preference.PreferenceFragmentCompat
2023-03-10 17:56:31 +01:00
import androidx.preference.forEach
import com.google.android.material.appbar.AppBarLayout
2023-02-22 17:47:33 +01:00
import com.google.android.material.internal.ToolbarUtils
2023-03-24 15:08:54 +01:00
import emu.skyline.BuildConfig
2023-02-14 14:17:17 +01:00
import emu.skyline.R
2023-02-23 01:14:05 +01:00
import emu.skyline.data.AppItemTag
2021-01-31 22:11:26 +01:00
import emu.skyline.databinding.SettingsActivityBinding
2023-03-07 23:35:35 +01:00
import emu.skyline.preference.IntegerListPreference
import emu.skyline.preference.dialog.EditTextPreferenceMaterialDialogFragmentCompat
import emu.skyline.preference.dialog.IntegerListPreferenceMaterialDialogFragmentCompat
import emu.skyline.preference.dialog.ListPreferenceMaterialDialogFragmentCompat
2022-11-10 16:48:25 +01:00
import emu.skyline.utils.WindowInsetsHelper
2019-12-02 14:39:08 +01:00
2023-03-07 23:35:35 +01:00
private const val PREFERENCE _DIALOG _FRAGMENT _TAG = " androidx.preference.PreferenceFragment.DIALOG "
class SettingsActivity : AppCompatActivity ( ) , PreferenceFragmentCompat . OnPreferenceDisplayDialogCallback {
2021-01-31 22:11:26 +01:00
val binding by lazy { SettingsActivityBinding . inflate ( layoutInflater ) }
2023-03-24 15:08:54 +01:00
val hiddenCategoriesFromSearch = if ( BuildConfig . BUILD _TYPE == " release " ) {
arrayOf ( " category_debug " , " category_credits " , " category_licenses " )
} else {
arrayOf ( " category_credits " , " category_licenses " )
}
2021-01-31 22:11:26 +01:00
2020-04-12 22:29:19 +02:00
/ * *
2023-02-22 17:47:33 +01:00
* The instance of [ PreferenceFragmentCompat ] that is shown inside [ R . id . settings ]
2023-02-23 00:48:28 +01:00
* Retrieves extras from the intent if any and instantiates the appropriate fragment
2020-04-12 22:29:19 +02:00
* /
2023-02-22 17:47:33 +01:00
private val preferenceFragment by lazy {
2023-02-23 01:14:05 +01:00
if ( intent . hasExtra ( AppItemTag ) )
2023-02-23 00:48:28 +01:00
GameSettingsFragment ( ) . apply { arguments = intent . extras }
else
2023-02-22 17:47:33 +01:00
GlobalSettingsFragment ( )
}
2019-12-02 14:39:08 +01:00
2020-05-28 21:27:25 +02:00
/ * *
* This initializes all of the elements in the activity and displays the settings fragment
2020-04-12 22:29:19 +02:00
* /
2020-04-24 13:39:13 +02:00
override fun onCreate ( savedInstanceState : Bundle ? ) {
2019-12-02 14:39:08 +01:00
super . onCreate ( savedInstanceState )
2020-04-12 22:29:19 +02:00
2021-01-31 22:11:26 +01:00
setContentView ( binding . root )
2022-11-04 01:21:14 +01:00
WindowCompat . setDecorFitsSystemWindows ( window , false )
2022-11-10 16:48:25 +01:00
WindowInsetsHelper . applyToActivity ( binding . root )
2020-04-12 22:29:19 +02:00
2021-01-31 22:11:26 +01:00
setSupportActionBar ( binding . titlebar . toolbar )
2020-04-12 22:29:19 +02:00
supportActionBar ?. setDisplayHomeAsUpEnabled ( true )
2022-03-11 12:05:41 +01:00
var layoutDone = false // Tracks if the layout is complete to avoid retrieving invalid attributes
binding . coordinatorLayout . viewTreeObserver . addOnTouchModeChangeListener { isTouchMode ->
2022-10-18 19:26:18 +02:00
val layoutUpdate = {
2022-03-11 12:05:41 +01:00
val params = binding . settings . layoutParams as CoordinatorLayout . LayoutParams
if ( !is TouchMode ) {
binding . titlebar . appBarLayout . setExpanded ( true )
params . height = binding . coordinatorLayout . height - binding . titlebar . toolbar . height
} else {
params . height = CoordinatorLayout . LayoutParams . MATCH _PARENT
}
binding . settings . layoutParams = params
binding . settings . requestLayout ( )
}
if ( ! layoutDone ) {
binding . coordinatorLayout . viewTreeObserver . addOnGlobalLayoutListener ( object : ViewTreeObserver . OnGlobalLayoutListener {
override fun onGlobalLayout ( ) {
// We need to wait till the layout is done to get the correct height of the toolbar
binding . coordinatorLayout . viewTreeObserver . removeOnGlobalLayoutListener ( this )
layoutUpdate ( )
layoutDone = true
}
} )
} else {
layoutUpdate ( )
}
2021-04-17 12:41:38 +02:00
}
2023-02-22 17:47:33 +01:00
fun enableMarquee ( textView : TextView ) {
textView . ellipsize = TextUtils . TruncateAt . MARQUEE
textView . isSelected = true
textView . marqueeRepeatLimit = - 1
2022-11-04 01:21:14 +01:00
}
2023-02-22 17:47:33 +01:00
// Set a temporary subtitle because the retrieval of the subtitle TextView fails if subtitle is null
supportActionBar ?. subtitle = " sub "
2022-10-23 22:04:10 +02:00
2023-02-22 17:47:33 +01:00
@SuppressLint ( " RestrictedApi " )
val toolbarTitleTextView = ToolbarUtils . getTitleTextView ( binding . titlebar . toolbar )
2023-03-10 17:56:31 +01:00
2023-02-22 17:47:33 +01:00
@SuppressLint ( " RestrictedApi " )
val toolbarSubtitleTextView = ToolbarUtils . getSubtitleTextView ( binding . titlebar . toolbar )
toolbarTitleTextView ?. let { enableMarquee ( it ) }
toolbarSubtitleTextView ?. let { enableMarquee ( it ) }
2022-10-23 22:04:10 +02:00
2023-02-22 17:47:33 +01:00
// Reset the subtitle to null
supportActionBar ?. subtitle = null
2022-12-24 21:38:51 +01:00
2023-02-22 17:47:33 +01:00
supportFragmentManager
. beginTransaction ( )
. replace ( R . id . settings , preferenceFragment )
. commit ( )
2019-12-02 14:39:08 +01:00
}
2020-05-28 07:39:36 +02:00
2023-03-10 17:56:31 +01:00
override fun onCreateOptionsMenu ( menu : Menu ? ) : Boolean {
menuInflater . inflate ( R . menu . settings _menu , menu )
val menuItem = menu !! . findItem ( R . id . app _bar _search )
val searchView = menuItem . actionView as SearchView
searchView . queryHint = getString ( R . string . search )
searchView . setOnQueryTextFocusChangeListener { _ , focus ->
( binding . titlebar . toolbar . layoutParams as AppBarLayout . LayoutParams ) . scrollFlags =
if ( focus )
AppBarLayout . LayoutParams . SCROLL _FLAG _NO _SCROLL
else
AppBarLayout . LayoutParams . SCROLL _FLAG _SCROLL
}
searchView . setOnQueryTextListener ( object : SearchView . OnQueryTextListener {
override fun onQueryTextSubmit ( query : String ) : Boolean {
return false
}
override fun onQueryTextChange ( newText : String ) : Boolean {
val queries = newText . split ( " , " )
if ( newText . isNotEmpty ( ) ) {
preferenceFragment . preferenceScreen . forEach { preferenceCategory ->
2023-03-24 15:08:54 +01:00
if ( hiddenCategoriesFromSearch . contains ( preferenceCategory . key ) ) {
2023-03-10 17:56:31 +01:00
preferenceCategory . isVisible = false
return @forEach
}
val queryMatchesCategory = queries . any { preferenceCategory . title ?. contains ( it , true ) ?: false }
// Tracks whether all preferences under this category are hidden
var areAllPrefsHidden = true
( preferenceCategory as PreferenceCategory ) . forEach { preference ->
preference . isVisible = queryMatchesCategory || queries . any { preference . title ?. contains ( it , true ) ?: false }
if ( preference . isVisible && areAllPrefsHidden )
areAllPrefsHidden = false
}
// Hide PreferenceCategory if none of its preferences match the search and neither the category title
preferenceCategory . isVisible = ! areAllPrefsHidden || queryMatchesCategory
}
} else { // If user input is empty, show all preferences
preferenceFragment . preferenceScreen . forEach { preferenceCategory ->
preferenceCategory . isVisible = true
( preferenceCategory as PreferenceCategory ) . forEach { preference ->
preference . isVisible = true
}
}
}
return true
}
} )
return super . onCreateOptionsMenu ( menu )
}
2020-05-28 07:39:36 +02:00
/ * *
* This handles on calling [ onBackPressed ] when [ KeyEvent . KEYCODE _BUTTON _B ] is lifted
* /
override fun onKeyUp ( keyCode : Int , event : KeyEvent ? ) : Boolean {
if ( keyCode == KeyEvent . KEYCODE _BUTTON _B ) {
2023-01-22 15:42:08 +01:00
onBackPressedDispatcher . onBackPressed ( )
2020-05-28 07:39:36 +02:00
return true
}
return super . onKeyUp ( keyCode , event )
}
2021-01-30 14:59:11 +01:00
override fun finish ( ) {
setResult ( RESULT _OK )
super . finish ( )
}
2023-03-07 23:35:35 +01:00
override fun onPreferenceDisplayDialog ( caller : PreferenceFragmentCompat , pref : Preference ) : Boolean {
when ( pref ) {
is IntegerListPreference -> {
// Check if dialog is already showing
if ( supportFragmentManager . findFragmentByTag ( PREFERENCE _DIALOG _FRAGMENT _TAG ) != null )
return true
val dialogFragment = IntegerListPreferenceMaterialDialogFragmentCompat . newInstance ( pref . getKey ( ) )
@Suppress ( " DEPRECATION " )
dialogFragment . setTargetFragment ( caller , 0 ) // androidx.preference.PreferenceDialogFragmentCompat depends on the target fragment being set correctly even though it's deprecated
dialogFragment . show ( supportFragmentManager , PREFERENCE _DIALOG _FRAGMENT _TAG )
return true
}
2023-03-10 17:56:31 +01:00
2023-03-07 23:35:35 +01:00
is EditTextPreference -> {
if ( supportFragmentManager . findFragmentByTag ( PREFERENCE _DIALOG _FRAGMENT _TAG ) != null )
return true
val dialogFragment = EditTextPreferenceMaterialDialogFragmentCompat . newInstance ( pref . getKey ( ) )
@Suppress ( " DEPRECATION " )
dialogFragment . setTargetFragment ( caller , 0 )
dialogFragment . show ( supportFragmentManager , PREFERENCE _DIALOG _FRAGMENT _TAG )
return true
}
2023-03-10 17:56:31 +01:00
2023-03-07 23:35:35 +01:00
is ListPreference -> {
if ( supportFragmentManager . findFragmentByTag ( PREFERENCE _DIALOG _FRAGMENT _TAG ) != null )
return true
val dialogFragment = ListPreferenceMaterialDialogFragmentCompat . newInstance ( pref . getKey ( ) )
@Suppress ( " DEPRECATION " )
dialogFragment . setTargetFragment ( caller , 0 )
dialogFragment . show ( supportFragmentManager , PREFERENCE _DIALOG _FRAGMENT _TAG )
return true
}
2023-03-10 17:56:31 +01:00
2023-03-07 23:35:35 +01:00
else -> return false
}
}
2019-12-02 14:39:08 +01:00
}