mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 02:51:52 +01:00
Use activity contracts for callbacks
This commit is contained in:
parent
8dd4858612
commit
8f3390f073
@ -28,11 +28,6 @@ android {
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion.toString()
|
||||
}
|
||||
|
||||
/* Build Options */
|
||||
buildTypes {
|
||||
release {
|
||||
debuggable true
|
||||
@ -53,9 +48,6 @@ android {
|
||||
shrinkResources false
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
/* Linting */
|
||||
lintOptions {
|
||||
@ -75,9 +67,18 @@ android {
|
||||
aaptOptions {
|
||||
ignoreAssetsPattern "*.md"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion.toString()
|
||||
useIR = true
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
prefab true
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion compose_version
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,9 +98,13 @@ dependencies {
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.0'
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
implementation "androidx.compose.ui:ui:$compose_version"
|
||||
implementation "androidx.compose.material:material:$compose_version"
|
||||
implementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
implementation 'androidx.activity:activity-compose:1.3.0-alpha03'
|
||||
implementation 'com.google.android:flexbox:2.0.1'
|
||||
|
||||
/* Kotlin */
|
||||
|
@ -68,11 +68,8 @@ class AppDialog : BottomSheetDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This fills all the dialog with the information from [item] if it is valid and setup all user interaction
|
||||
*/
|
||||
override fun onActivityCreated(savedInstanceState : Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val missingIcon = ContextCompat.getDrawable(requireActivity(), R.drawable.default_icon)!!.toBitmap(256, 256)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
@ -20,7 +21,6 @@ import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.size
|
||||
import androidx.lifecycle.observe
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -75,6 +75,19 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val documentPicker = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
|
||||
it?.let { uri ->
|
||||
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
settings.searchLocation = uri.toString()
|
||||
|
||||
loadRoms(false)
|
||||
}
|
||||
}
|
||||
|
||||
private val settingsCallback = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (settings.refreshRequired) loadRoms(false)
|
||||
}
|
||||
|
||||
private fun AppItem.toViewItem() = AppViewItem(layoutType, this, missingIcon, ::selectStartGame, ::selectShowGameDialog)
|
||||
|
||||
override fun onCreate(savedInstanceState : Bundle?) {
|
||||
@ -117,12 +130,12 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
binding.chipGroup.check(binding.chipGroup.getChildAt(settings.filter).id)
|
||||
|
||||
viewModel.stateData.observe(owner = this, onChanged = ::handleState)
|
||||
viewModel.stateData.observe(this, ::handleState)
|
||||
loadRoms(!settings.refreshRequired)
|
||||
|
||||
binding.searchBar.apply {
|
||||
binding.logIcon.setOnClickListener { startActivity(Intent(context, LogActivity::class.java)) }
|
||||
binding.settingsIcon.setOnClickListener { startActivityForResult(Intent(context, SettingsActivity::class.java), 3) }
|
||||
binding.settingsIcon.setOnClickListener { settingsCallback.launch(Intent(context, SettingsActivity::class.java)) }
|
||||
binding.refreshIcon.setOnClickListener { loadRoms(false) }
|
||||
addTextChangedListener(afterTextChanged = { editable ->
|
||||
editable?.let { text -> adapter.filter.filter(text.toString()) }
|
||||
@ -222,11 +235,7 @@ class MainActivity : AppCompatActivity() {
|
||||
binding.appList.layoutManager = CustomLayoutManager(gridSpan)
|
||||
setAppListDecoration()
|
||||
|
||||
if (settings.searchLocation.isEmpty()) startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
|
||||
flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}, 1)
|
||||
if (settings.searchLocation.isEmpty()) documentPicker.launch(null)
|
||||
}
|
||||
|
||||
private fun getDataItems() = mutableListOf<DataItem>().apply {
|
||||
@ -288,41 +297,6 @@ class MainActivity : AppCompatActivity() {
|
||||
if (items.isEmpty()) adapter.setItems(listOf(HeaderViewItem(getString(R.string.no_rom))))
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles receiving activity result from [Intent.ACTION_OPEN_DOCUMENT_TREE], [Intent.ACTION_OPEN_DOCUMENT] and [SettingsActivity]
|
||||
*/
|
||||
override fun onActivityResult(requestCode : Int, resultCode : Int, intent : Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, intent)
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
when (requestCode) {
|
||||
1 -> {
|
||||
val uri = intent!!.data!!
|
||||
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
settings.searchLocation = uri.toString()
|
||||
|
||||
loadRoms(!settings.refreshRequired)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
try {
|
||||
val intentGame = Intent(this, EmulationActivity::class.java)
|
||||
intentGame.data = intent!!.data!!
|
||||
|
||||
if (resultCode != 0)
|
||||
startActivityForResult(intentGame, resultCode)
|
||||
else
|
||||
startActivity(intentGame)
|
||||
} catch (e : Exception) {
|
||||
Snackbar.make(findViewById(android.R.id.content), getString(R.string.error) + ": ${e.localizedMessage}", Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
3 -> if (settings.refreshRequired) loadRoms(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
|
@ -5,15 +5,11 @@
|
||||
|
||||
package emu.skyline
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceGroup
|
||||
import emu.skyline.databinding.SettingsActivityBinding
|
||||
import emu.skyline.preference.ActivityResultPreference
|
||||
import emu.skyline.preference.DocumentActivity
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
val binding by lazy { SettingsActivityBinding.inflate(layoutInflater) }
|
||||
@ -35,57 +31,21 @@ class SettingsActivity : AppCompatActivity() {
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, preferenceFragment)
|
||||
.commit()
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to refresh the preferences after [DocumentActivity] or [emu.skyline.input.ControllerActivity] has returned
|
||||
*/
|
||||
public override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
preferenceFragment.delegateActivityResult(requestCode, resultCode, data)
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, preferenceFragment)
|
||||
.commit()
|
||||
}
|
||||
|
||||
/**
|
||||
* This fragment is used to display all of the preferences
|
||||
*/
|
||||
class PreferenceFragment : PreferenceFragmentCompat() {
|
||||
private var requestCodeCounter = 0
|
||||
|
||||
/**
|
||||
* Delegates activity result to all preferences which implement [ActivityResultPreference]
|
||||
*/
|
||||
fun delegateActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
preferenceScreen.delegateActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructs the preferences from [R.xml.preferences]
|
||||
*/
|
||||
override fun onCreatePreferences(savedInstanceState : Bundle?, rootKey : String?) {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
preferenceScreen.assignActivityRequestCode()
|
||||
}
|
||||
|
||||
private fun PreferenceGroup.assignActivityRequestCode() {
|
||||
for (i in 0 until preferenceCount) {
|
||||
when (val pref = getPreference(i)) {
|
||||
is PreferenceGroup -> pref.assignActivityRequestCode()
|
||||
is ActivityResultPreference -> pref.requestCode = requestCodeCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PreferenceGroup.delegateActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
for (i in 0 until preferenceCount) {
|
||||
when (val pref = getPreference(i)) {
|
||||
is PreferenceGroup -> pref.delegateActivityResult(requestCode, resultCode, data)
|
||||
is ActivityResultPreference -> pref.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import emu.skyline.input.InputManager
|
||||
import emu.skyline.utils.Settings
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@ -14,3 +15,11 @@ interface InputManagerProviderEntryPoint {
|
||||
}
|
||||
|
||||
fun Context.getInputManager() = EntryPointAccessors.fromApplication(this, InputManagerProviderEntryPoint::class.java).inputManager()
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface SettingsProviderEntryPoint {
|
||||
fun settings() : Settings
|
||||
}
|
||||
|
||||
fun Context.getSettings() = EntryPointAccessors.fromApplication(this, SettingsProviderEntryPoint::class.java).settings()
|
@ -45,19 +45,16 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets up all user interaction with this dialog
|
||||
*/
|
||||
override fun onActivityCreated(savedInstanceState : Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (item != null && context is ControllerActivity) {
|
||||
val context = requireContext() as ControllerActivity
|
||||
val controller = inputManager.controllers[context.id]!!
|
||||
|
||||
// View focus handling so all input is always directed to this view
|
||||
view?.requestFocus()
|
||||
view?.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() }
|
||||
view.requestFocus()
|
||||
view.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() }
|
||||
|
||||
// Write the text for the button's icon
|
||||
binding.buttonText.text = item.button.short ?: item.button.toString()
|
||||
@ -145,7 +142,7 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton
|
||||
|
||||
val axesHistory = arrayOfNulls<Float>(axes.size) // The last recorded value of an axis, this is used to eliminate any stagnant axes
|
||||
|
||||
view?.setOnGenericMotionListener { _, event ->
|
||||
view.setOnGenericMotionListener { _, event ->
|
||||
// We retrieve the value of the HAT axes so that we can check for change and ignore any input from them so it'll be passed onto the [KeyEvent] handler
|
||||
val dpadX = event.getAxisValue(MotionEvent.AXIS_HAT_X)
|
||||
val dpadY = event.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
||||
|
@ -45,11 +45,8 @@ class RumbleDialog @JvmOverloads constructor(val item : ControllerGeneralViewIte
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets up all user interaction with this dialog
|
||||
*/
|
||||
override fun onActivityCreated(savedInstanceState : Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (item != null && context is ControllerActivity) {
|
||||
val context = requireContext() as ControllerActivity
|
||||
|
@ -14,7 +14,6 @@ import android.view.*
|
||||
import android.view.animation.LinearInterpolator
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import emu.skyline.R
|
||||
import emu.skyline.adapter.controller.ControllerStickViewItem
|
||||
import emu.skyline.databinding.StickDialogBinding
|
||||
@ -22,7 +21,6 @@ import emu.skyline.di.getInputManager
|
||||
import emu.skyline.input.*
|
||||
import emu.skyline.input.MotionHostEvent.Companion.axes
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
@ -224,19 +222,16 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets up all user interaction with this dialog
|
||||
*/
|
||||
override fun onActivityCreated(savedInstanceState : Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (item != null && context is ControllerActivity) {
|
||||
val context = requireContext() as ControllerActivity
|
||||
val controller = inputManager.controllers[context.id]!!
|
||||
|
||||
// View focus handling so all input is always directed to this view
|
||||
view?.requestFocus()
|
||||
view?.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() }
|
||||
view.requestFocus()
|
||||
view.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() }
|
||||
|
||||
// Write the text for the stick's icon
|
||||
binding.stickName.text = item.stick.button.short ?: item.stick.button.toString()
|
||||
@ -286,7 +281,7 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem?
|
||||
axisRunnable?.let { handler.removeCallbacks(it) }
|
||||
}
|
||||
|
||||
view?.setOnKeyListener { _, _, event ->
|
||||
view.setOnKeyListener { _, _, event ->
|
||||
when {
|
||||
// We want all input events from Joysticks and Buttons except for [KeyEvent.KEYCODE_BACK] as that will should be processed elsewhere
|
||||
((event.isFromSource(InputDevice.SOURCE_CLASS_BUTTON) && event.keyCode != KeyEvent.KEYCODE_BACK) || event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) && event.repeatCount == 0 -> {
|
||||
@ -415,7 +410,7 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem?
|
||||
|
||||
var oldHat = Pair(0.0f, 0.0f) // The last values of the HAT axes so that they can be ignored in [View.OnGenericMotionListener] so they are passed onto [DialogInterface.OnKeyListener] as [KeyEvent]s
|
||||
|
||||
view?.setOnGenericMotionListener { _, event ->
|
||||
view.setOnGenericMotionListener { _, event ->
|
||||
// We retrieve the value of the HAT axes so that we can check for change and ignore any input from them so it'll be passed onto the [KeyEvent] handler
|
||||
val hat = Pair(event.getAxisValue(MotionEvent.AXIS_HAT_X), event.getAxisValue(MotionEvent.AXIS_HAT_Y))
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.Preference
|
||||
|
||||
/**
|
||||
* Some preferences need results from activities, this delegates the results to them
|
||||
*/
|
||||
abstract class ActivityResultPreference @JvmOverloads constructor(context : Context?, attrs : AttributeSet? = null, defStyleAttr : Int = 0) : Preference(context, attrs, defStyleAttr) {
|
||||
var requestCode = 0
|
||||
|
||||
abstract fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?)
|
||||
}
|
@ -5,10 +5,12 @@
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.AttributeSet
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.Preference.SummaryProvider
|
||||
import emu.skyline.R
|
||||
import emu.skyline.di.getInputManager
|
||||
@ -17,7 +19,12 @@ import emu.skyline.input.ControllerActivity
|
||||
/**
|
||||
* This preference is used to launch [ControllerActivity] using a preference
|
||||
*/
|
||||
class ControllerPreference @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = R.attr.preferenceStyle) : ActivityResultPreference(context, attrs, defStyleAttr) {
|
||||
class ControllerPreference @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = R.attr.preferenceStyle) : Preference(context, attrs, defStyleAttr) {
|
||||
private val controllerCallback = (context as ComponentActivity).registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
inputManager.syncObjects()
|
||||
notifyChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of the controller this preference manages
|
||||
*/
|
||||
@ -48,14 +55,5 @@ class ControllerPreference @JvmOverloads constructor(context : Context, attrs :
|
||||
/**
|
||||
* This launches [ControllerActivity] on click to configure the controller
|
||||
*/
|
||||
override fun onClick() {
|
||||
(context as Activity).startActivityForResult(Intent(context, ControllerActivity::class.java).apply { putExtra("index", index) }, requestCode)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
if (this.requestCode == requestCode) {
|
||||
inputManager.syncObjects()
|
||||
notifyChanged()
|
||||
}
|
||||
}
|
||||
override fun onClick() = controllerCallback.launch(Intent(context, ControllerActivity::class.java))
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import emu.skyline.utils.Settings
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This activity is used to launch a document picker and saves the result to preferences
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
abstract class DocumentActivity : AppCompatActivity() {
|
||||
companion object {
|
||||
const val KEY_NAME = "key_name"
|
||||
}
|
||||
|
||||
private lateinit var keyName : String
|
||||
|
||||
protected abstract val actionIntent : Intent
|
||||
|
||||
@Inject
|
||||
lateinit var settings : Settings
|
||||
|
||||
/**
|
||||
* This launches the [Intent.ACTION_OPEN_DOCUMENT_TREE] intent on creation
|
||||
*/
|
||||
override fun onCreate(state : Bundle?) {
|
||||
super.onCreate(state)
|
||||
|
||||
keyName = intent.getStringExtra(KEY_NAME)!!
|
||||
|
||||
this.startActivityForResult(actionIntent, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* This changes the search location preference if the [Intent.ACTION_OPEN_DOCUMENT_TREE] has returned and [finish]es the activity
|
||||
*/
|
||||
public override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
|
||||
val uri = data!!.data!!
|
||||
|
||||
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
settings.refreshRequired = true
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit()
|
||||
.putString(keyName, uri.toString())
|
||||
.apply()
|
||||
}
|
||||
setResult(resultCode)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* Launches document picker to select one file
|
||||
*/
|
||||
class FileActivity : DocumentActivity() {
|
||||
override val actionIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "*/*"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import emu.skyline.KeyReader
|
||||
import emu.skyline.R
|
||||
import emu.skyline.SettingsActivity
|
||||
|
||||
/**
|
||||
* Launches [FileActivity] and process the selected file for key import
|
||||
*/
|
||||
class FilePreference @JvmOverloads constructor(context : Context?, attrs : AttributeSet? = null, defStyleAttr : Int = androidx.preference.R.attr.preferenceStyle) : ActivityResultPreference(context, attrs, defStyleAttr) {
|
||||
override fun onClick() = (context as Activity).startActivityForResult(Intent(context, FileActivity::class.java).apply { putExtra(DocumentActivity.KEY_NAME, key) }, requestCode)
|
||||
|
||||
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
if (this.requestCode == requestCode && resultCode == Activity.RESULT_OK && (key == KeyReader.KeyType.Prod.keyName || key == KeyReader.KeyType.Title.keyName)) {
|
||||
val success = KeyReader.import(
|
||||
context,
|
||||
Uri.parse(PreferenceManager.getDefaultSharedPreferences(context).getString(key, "")),
|
||||
KeyReader.KeyType.parse(key)
|
||||
)
|
||||
Snackbar.make((context as SettingsActivity).binding.root, if (success) R.string.import_keys_success else R.string.import_keys_failed, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* Launches document picker to select a folder
|
||||
*/
|
||||
class FolderActivity : DocumentActivity() {
|
||||
override val actionIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.Preference.SummaryProvider
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.preference.R
|
||||
import emu.skyline.di.getSettings
|
||||
|
||||
class FolderPickerPreference @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = R.attr.preferenceStyle) : Preference(context, attrs, defStyleAttr) {
|
||||
private val documentPicker = (context as ComponentActivity).registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
|
||||
it?.let { uri ->
|
||||
context.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
context.getSettings().refreshRequired = true
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, uri.toString()).apply()
|
||||
notifyChanged()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
summaryProvider = SummaryProvider<FolderPickerPreference> { preference ->
|
||||
Uri.decode(preference.getPersistedString(""))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick() = documentPicker.launch(null)
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.Preference.SummaryProvider
|
||||
import androidx.preference.R
|
||||
|
||||
/**
|
||||
* This preference shows the decoded URI of it's preference and launches [DocumentActivity]
|
||||
*/
|
||||
class FolderPreference @JvmOverloads constructor(context : Context?, attrs : AttributeSet? = null, defStyleAttr : Int = R.attr.preferenceStyle) : ActivityResultPreference(context, attrs, defStyleAttr) {
|
||||
init {
|
||||
summaryProvider = SummaryProvider<FolderPreference> { preference ->
|
||||
Uri.decode(preference.getPersistedString(""))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This launches [DocumentActivity] on click to change the directory
|
||||
*/
|
||||
override fun onClick() {
|
||||
(context as Activity).startActivityForResult(Intent(context, FolderActivity::class.java).apply { putExtra(DocumentActivity.KEY_NAME, key) }, requestCode)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
if (requestCode == requestCode) notifyChanged()
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.AttributeSet
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import emu.skyline.KeyReader
|
||||
import emu.skyline.R
|
||||
import emu.skyline.SettingsActivity
|
||||
import emu.skyline.di.getSettings
|
||||
|
||||
class KeyPickerPreference @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = androidx.preference.R.attr.preferenceStyle) : Preference(context, attrs, defStyleAttr) {
|
||||
private val documentPicker = (context as ComponentActivity).registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||
it?.let { uri ->
|
||||
context.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
context.getSettings().refreshRequired = true
|
||||
|
||||
val success = KeyReader.import(context, uri, KeyReader.KeyType.parse(key))
|
||||
Snackbar.make((context as SettingsActivity).binding.root, if (success) R.string.import_keys_success else R.string.import_keys_failed, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick() = documentPicker.launch(null)
|
||||
}
|
@ -32,8 +32,8 @@ class LicenseDialog : DialogFragment() {
|
||||
}.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState : Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.licenseUrl.text = requireArguments().getString("libraryUrl")
|
||||
binding.licenseContent.text = getString(requireArguments().getInt("libraryLicense"))
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PreferenceCategory
|
||||
android:key="category_emulator"
|
||||
android:title="@string/emulator">
|
||||
<emu.skyline.preference.FolderPreference
|
||||
<emu.skyline.preference.FolderPickerPreference
|
||||
app:key="search_location"
|
||||
app:title="@string/search_location" />
|
||||
<emu.skyline.preference.ThemePreference
|
||||
@ -54,11 +54,11 @@
|
||||
<PreferenceCategory
|
||||
android:key="category_keys"
|
||||
android:title="@string/keys">
|
||||
<emu.skyline.preference.FilePreference
|
||||
<emu.skyline.preference.KeyPickerPreference
|
||||
app:key="prod_keys"
|
||||
app:title="@string/prod_keys"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<emu.skyline.preference.FilePreference
|
||||
<emu.skyline.preference.KeyPickerPreference
|
||||
app:key="title_keys"
|
||||
app:title="@string/title_keys"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
14
build.gradle
14
build.gradle
@ -1,17 +1,19 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.4.30'
|
||||
ext.lifecycle_version = '2.2.0'
|
||||
ext.hilt_version = '2.31.2-alpha'
|
||||
ext {
|
||||
kotlin_version = '1.4.31'
|
||||
lifecycle_version = '2.3.0'
|
||||
hilt_version = '2.32-alpha'
|
||||
compose_version = '1.0.0-beta01'
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.2'
|
||||
classpath 'com.android.tools.build:gradle:7.0.0-alpha08'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
||||
|
||||
@ -23,6 +25,8 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url "https://google.bintray.com/flexbox-layout" }
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user