Use activity contracts for callbacks

This commit is contained in:
Willi Ye 2021-02-26 12:41:57 +01:00 committed by ◱ Mark
parent 8dd4858612
commit 8f3390f073
20 changed files with 156 additions and 336 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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()

View File

@ -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) }
@ -40,52 +36,16 @@ class SettingsActivity : AppCompatActivity() {
.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)
}
/**
* 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)
}
}
}
}

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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?)
}

View File

@ -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))
}

View File

@ -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()
}
}

View File

@ -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 = "*/*"
}
}

View File

@ -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()
}
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()
}
}

View File

@ -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)
}

View File

@ -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"))

View File

@ -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" />

View File

@ -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()
}
}