mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-24 00:51:48 +01:00
Use property delegate to handle preferences
* Add option to disable joystick recentering
This commit is contained in:
parent
5c4aa95da6
commit
7526a985fb
@ -15,9 +15,9 @@ import android.util.Log
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import emu.skyline.input.*
|
import emu.skyline.input.*
|
||||||
import emu.skyline.loader.getRomFormat
|
import emu.skyline.loader.getRomFormat
|
||||||
|
import emu.skyline.utils.Settings
|
||||||
import kotlinx.android.synthetic.main.emu_activity.*
|
import kotlinx.android.synthetic.main.emu_activity.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@ -36,11 +36,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
*/
|
*/
|
||||||
private var vibrators = HashMap<Int, Vibrator>()
|
private var vibrators = HashMap<Int, Vibrator>()
|
||||||
|
|
||||||
/**
|
|
||||||
* A boolean flag denoting the current operation mode of the emulator (Docked = true/Handheld = false)
|
|
||||||
*/
|
|
||||||
private var operationMode = true
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The surface object used for displaying frames
|
* The surface object used for displaying frames
|
||||||
*/
|
*/
|
||||||
@ -63,6 +58,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
*/
|
*/
|
||||||
private lateinit var emulationThread : Thread
|
private lateinit var emulationThread : Thread
|
||||||
|
|
||||||
|
private val settings by lazy { Settings(this) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the entry point into the emulation code for libskyline
|
* This is the entry point into the emulation code for libskyline
|
||||||
*
|
*
|
||||||
@ -149,7 +146,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
if (controller.type != ControllerType.None) {
|
if (controller.type != ControllerType.None) {
|
||||||
val type = when (controller.type) {
|
val type = when (controller.type) {
|
||||||
ControllerType.None -> throw IllegalArgumentException()
|
ControllerType.None -> throw IllegalArgumentException()
|
||||||
ControllerType.HandheldProController -> if (operationMode) ControllerType.ProController.id else ControllerType.HandheldProController.id
|
ControllerType.HandheldProController -> if (settings.operationMode) ControllerType.ProController.id else ControllerType.HandheldProController.id
|
||||||
ControllerType.ProController, ControllerType.JoyConLeft, ControllerType.JoyConRight -> controller.type.id
|
ControllerType.ProController, ControllerType.JoyConLeft, ControllerType.JoyConRight -> controller.type.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +209,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
|
|
||||||
game_view.holder.addCallback(this)
|
game_view.holder.addCallback(this)
|
||||||
|
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
if (settings.perfStats) {
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("perf_stats", false)) {
|
|
||||||
perf_stats.postDelayed(object : Runnable {
|
perf_stats.postDelayed(object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
perf_stats.text = "${getFps()} FPS\n${getFrametime()}ms"
|
perf_stats.text = "${getFps()} FPS\n${getFrametime()}ms"
|
||||||
@ -223,15 +218,13 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
}, 250)
|
}, 250)
|
||||||
}
|
}
|
||||||
|
|
||||||
operationMode = sharedPreferences.getBoolean("operation_mode", operationMode)
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION") val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display!! else windowManager.defaultDisplay
|
@Suppress("DEPRECATION") val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display!! else windowManager.defaultDisplay
|
||||||
display?.supportedModes?.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
display?.supportedModes?.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||||
|
|
||||||
game_view.setOnTouchListener(this)
|
game_view.setOnTouchListener(this)
|
||||||
|
|
||||||
// Hide on screen controls when first controller is not set
|
// Hide on screen controls when first controller is not set
|
||||||
on_screen_controller_view.isInvisible = !InputManager.controllers[0]!!.type.firstController || !sharedPreferences.getBoolean("on_screen_control", false)
|
on_screen_controller_view.isInvisible = !InputManager.controllers[0]!!.type.firstController || !settings.onScreenControl
|
||||||
on_screen_controller_view.setOnButtonStateChangedListener(::onButtonStateChanged)
|
on_screen_controller_view.setOnButtonStateChangedListener(::onButtonStateChanged)
|
||||||
on_screen_controller_view.setOnStickStateChangedListener(::onStickStateChanged)
|
on_screen_controller_view.setOnStickStateChangedListener(::onStickStateChanged)
|
||||||
|
|
||||||
|
@ -14,13 +14,13 @@ import android.view.MenuItem
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import emu.skyline.adapter.GenericAdapter
|
import emu.skyline.adapter.GenericAdapter
|
||||||
import emu.skyline.adapter.HeaderViewItem
|
import emu.skyline.adapter.HeaderViewItem
|
||||||
import emu.skyline.adapter.LogViewItem
|
import emu.skyline.adapter.LogViewItem
|
||||||
|
import emu.skyline.utils.Settings
|
||||||
import kotlinx.android.synthetic.main.log_activity.*
|
import kotlinx.android.synthetic.main.log_activity.*
|
||||||
import kotlinx.android.synthetic.main.titlebar.*
|
import kotlinx.android.synthetic.main.titlebar.*
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
@ -52,9 +52,10 @@ class LogActivity : AppCompatActivity() {
|
|||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val settings = Settings(this)
|
||||||
val compact = prefs.getBoolean("log_compact", false)
|
|
||||||
val logLevel = prefs.getString("log_level", "3")!!.toInt()
|
val compact = settings.logCompact
|
||||||
|
val logLevel = settings.logLevel.toInt()
|
||||||
val logLevels = resources.getStringArray(R.array.log_level)
|
val logLevels = resources.getStringArray(R.array.log_level)
|
||||||
|
|
||||||
log_list.adapter = adapter
|
log_list.adapter = adapter
|
||||||
|
@ -37,6 +37,9 @@ import emu.skyline.data.ElementType
|
|||||||
import emu.skyline.loader.LoaderResult
|
import emu.skyline.loader.LoaderResult
|
||||||
import emu.skyline.loader.RomFile
|
import emu.skyline.loader.RomFile
|
||||||
import emu.skyline.loader.RomFormat
|
import emu.skyline.loader.RomFormat
|
||||||
|
import emu.skyline.utils.Settings
|
||||||
|
import emu.skyline.utils.loadSerializedList
|
||||||
|
import emu.skyline.utils.serialize
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import kotlinx.android.synthetic.main.titlebar.*
|
import kotlinx.android.synthetic.main.titlebar.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -50,10 +53,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private val TAG = MainActivity::class.java.simpleName
|
private val TAG = MainActivity::class.java.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private val settings by lazy { Settings(this) }
|
||||||
* This is used to get/set shared preferences
|
|
||||||
*/
|
|
||||||
private val sharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The adapter used for adding elements to [app_list]
|
* The adapter used for adding elements to [app_list]
|
||||||
@ -62,7 +62,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private var reloading = AtomicBoolean()
|
private var reloading = AtomicBoolean()
|
||||||
|
|
||||||
private val layoutType get() = LayoutType.values()[sharedPreferences.getString("layout_type", "1")!!.toInt()]
|
private val layoutType get() = LayoutType.values()[settings.layoutType.toInt()]
|
||||||
|
|
||||||
private val missingIcon by lazy { ContextCompat.getDrawable(this, R.drawable.default_icon)!!.toBitmap(256, 256) }
|
private val missingIcon by lazy { ContextCompat.getDrawable(this, R.drawable.default_icon)!!.toBitmap(256, 256) }
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
try {
|
try {
|
||||||
runOnUiThread { adapter.removeAllItems() }
|
runOnUiThread { adapter.removeAllItems() }
|
||||||
|
|
||||||
val searchLocation = DocumentFile.fromTreeUri(this, Uri.parse(sharedPreferences.getString("search_location", "")))!!
|
val searchLocation = DocumentFile.fromTreeUri(this, Uri.parse(settings.searchLocation))!!
|
||||||
|
|
||||||
val romElements = ArrayList<BaseElement>()
|
val romElements = ArrayList<BaseElement>()
|
||||||
addEntries("nro", RomFormat.NRO, searchLocation, romElements)
|
addEntries("nro", RomFormat.NRO, searchLocation, romElements)
|
||||||
@ -155,10 +155,10 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences.edit().putBoolean("refresh_required", false).apply()
|
settings.refreshRequired = false
|
||||||
} catch (e : IllegalArgumentException) {
|
} catch (e : IllegalArgumentException) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
sharedPreferences.edit().remove("search_location").apply()
|
settings.searchLocation = ""
|
||||||
|
|
||||||
val intent = intent
|
val intent = intent
|
||||||
finish()
|
finish()
|
||||||
@ -191,7 +191,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
|
PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
|
||||||
|
|
||||||
AppCompatDelegate.setDefaultNightMode(when ((sharedPreferences.getString("app_theme", "2")?.toInt())) {
|
AppCompatDelegate.setDefaultNightMode(when ((settings.appTheme.toInt())) {
|
||||||
0 -> AppCompatDelegate.MODE_NIGHT_NO
|
0 -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
1 -> AppCompatDelegate.MODE_NIGHT_YES
|
1 -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
2 -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
@ -267,13 +267,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
setAppListDecoration()
|
setAppListDecoration()
|
||||||
|
|
||||||
if (sharedPreferences.getString("search_location", "") == "") {
|
if (settings.searchLocation.isEmpty()) {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
intent.flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
intent.flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
|
||||||
startActivityForResult(intent, 1)
|
startActivityForResult(intent, 1)
|
||||||
} else {
|
} else {
|
||||||
refreshAdapter(!sharedPreferences.getBoolean("refresh_required", false))
|
refreshAdapter(!settings.refreshRequired)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun selectStartGame(appItem : AppItem) {
|
private fun selectStartGame(appItem : AppItem) {
|
||||||
if (sharedPreferences.getBoolean("select_action", false))
|
if (settings.selectAction)
|
||||||
AppDialog.newInstance(appItem).show(supportFragmentManager, "game")
|
AppDialog.newInstance(appItem).show(supportFragmentManager, "game")
|
||||||
else if (appItem.loaderResult == LoaderResult.Success)
|
else if (appItem.loaderResult == LoaderResult.Success)
|
||||||
startActivity(Intent(this, EmulationActivity::class.java).apply { data = appItem.uri })
|
startActivity(Intent(this, EmulationActivity::class.java).apply { data = appItem.uri })
|
||||||
@ -341,9 +341,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
1 -> {
|
1 -> {
|
||||||
val uri = intent!!.data!!
|
val uri = intent!!.data!!
|
||||||
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
sharedPreferences.edit().putString("search_location", uri.toString()).apply()
|
settings.searchLocation = uri.toString()
|
||||||
|
|
||||||
refreshAdapter(!sharedPreferences.getBoolean("refresh_required", false))
|
refreshAdapter(!settings.refreshRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> {
|
||||||
@ -361,8 +361,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
3 -> {
|
3 -> {
|
||||||
if (sharedPreferences.getBoolean("refresh_required", false))
|
if (settings.refreshRequired) refreshAdapter(false)
|
||||||
refreshAdapter(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package emu.skyline.adapter.controller
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isGone
|
||||||
import emu.skyline.R
|
import emu.skyline.R
|
||||||
import emu.skyline.adapter.GenericLayoutFactory
|
import emu.skyline.adapter.GenericLayoutFactory
|
||||||
import emu.skyline.adapter.GenericViewHolder
|
import emu.skyline.adapter.GenericViewHolder
|
||||||
@ -22,7 +23,9 @@ class ControllerCheckBoxViewItem(var title : String, var summary : String, var c
|
|||||||
override fun getLayoutFactory() : GenericLayoutFactory = ControllerCheckBoxLayoutFactory
|
override fun getLayoutFactory() : GenericLayoutFactory = ControllerCheckBoxLayoutFactory
|
||||||
|
|
||||||
override fun bind(holder : GenericViewHolder, position : Int) {
|
override fun bind(holder : GenericViewHolder, position : Int) {
|
||||||
|
holder.text_title.isGone = title.isEmpty()
|
||||||
holder.text_title.text = title
|
holder.text_title.text = title
|
||||||
|
holder.text_subtitle.isGone = summary.isEmpty()
|
||||||
holder.text_subtitle.text = summary
|
holder.text_subtitle.text = summary
|
||||||
holder.checkbox.isChecked = checked
|
holder.checkbox.isChecked = checked
|
||||||
holder.itemView.setOnClickListener {
|
holder.itemView.setOnClickListener {
|
||||||
|
@ -9,7 +9,6 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import emu.skyline.R
|
import emu.skyline.R
|
||||||
@ -20,6 +19,7 @@ import emu.skyline.input.dialog.ButtonDialog
|
|||||||
import emu.skyline.input.dialog.RumbleDialog
|
import emu.skyline.input.dialog.RumbleDialog
|
||||||
import emu.skyline.input.dialog.StickDialog
|
import emu.skyline.input.dialog.StickDialog
|
||||||
import emu.skyline.input.onscreen.OnScreenEditActivity
|
import emu.skyline.input.onscreen.OnScreenEditActivity
|
||||||
|
import emu.skyline.utils.Settings
|
||||||
import kotlinx.android.synthetic.main.controller_activity.*
|
import kotlinx.android.synthetic.main.controller_activity.*
|
||||||
import kotlinx.android.synthetic.main.titlebar.*
|
import kotlinx.android.synthetic.main.titlebar.*
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class ControllerActivity : AppCompatActivity() {
|
|||||||
*/
|
*/
|
||||||
val axisMap = mutableMapOf<AxisId, ControllerStickViewItem>()
|
val axisMap = mutableMapOf<AxisId, ControllerStickViewItem>()
|
||||||
|
|
||||||
private val sharedPrefs by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
private val settings by lazy { Settings(this) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function updates the [adapter] based on information from [InputManager]
|
* This function updates the [adapter] based on information from [InputManager]
|
||||||
@ -65,9 +65,15 @@ class ControllerActivity : AppCompatActivity() {
|
|||||||
if (id == 0 && controller.type.firstController) {
|
if (id == 0 && controller.type.firstController) {
|
||||||
adapter.addItem(HeaderViewItem(getString(R.string.osc)))
|
adapter.addItem(HeaderViewItem(getString(R.string.osc)))
|
||||||
|
|
||||||
adapter.addItem(ControllerCheckBoxViewItem(getString(R.string.osc_enable), getString(R.string.osc_not_shown), sharedPrefs.getBoolean("on_screen_control", false)) { item, position ->
|
val oscSummary = { checked : Boolean -> getString(if (checked) R.string.osc_shown else R.string.osc_not_shown) }
|
||||||
item.summary = getString(if (item.checked) R.string.osc_shown else R.string.osc_not_shown)
|
adapter.addItem(ControllerCheckBoxViewItem(getString(R.string.osc_enable), oscSummary.invoke(settings.onScreenControl), settings.onScreenControl) { item, position ->
|
||||||
sharedPrefs.edit().putBoolean("on_screen_control", item.checked).apply()
|
item.summary = oscSummary.invoke(item.checked)
|
||||||
|
settings.onScreenControl = item.checked
|
||||||
|
adapter.notifyItemChanged(position)
|
||||||
|
})
|
||||||
|
|
||||||
|
adapter.addItem(ControllerCheckBoxViewItem(getString(R.string.osc_recenter_sticks), "", settings.onScreenControlRecenterSticks) { item, position ->
|
||||||
|
settings.onScreenControlRecenterSticks = item.checked
|
||||||
adapter.notifyItemChanged(position)
|
adapter.notifyItemChanged(position)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import kotlin.math.abs
|
|||||||
*
|
*
|
||||||
* @param item This is used to hold the [ControllerButtonViewItem] between instances
|
* @param item This is used to hold the [ControllerButtonViewItem] between instances
|
||||||
*/
|
*/
|
||||||
class ButtonDialog @JvmOverloads constructor(private val item : ControllerButtonViewItem? = null, private val position : Int? = null) : BottomSheetDialogFragment() {
|
class ButtonDialog @JvmOverloads constructor(private val item : ControllerButtonViewItem? = null) : BottomSheetDialogFragment() {
|
||||||
/**
|
/**
|
||||||
* This inflates the layout of the dialog after initial view creation
|
* This inflates the layout of the dialog after initial view creation
|
||||||
*/
|
*/
|
||||||
|
@ -7,8 +7,7 @@ package emu.skyline.input.onscreen
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import emu.skyline.input.ButtonId
|
import emu.skyline.input.ButtonId
|
||||||
import kotlin.properties.ReadWriteProperty
|
import emu.skyline.utils.sharedPreferences
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
interface ControllerConfiguration {
|
interface ControllerConfiguration {
|
||||||
var enabled : Boolean
|
var enabled : Boolean
|
||||||
@ -17,55 +16,18 @@ interface ControllerConfiguration {
|
|||||||
var relativeY : Float
|
var relativeY : Float
|
||||||
}
|
}
|
||||||
|
|
||||||
class ControllerConfigurationDummy(
|
class ControllerConfigurationDummy(defaultRelativeX : Float, defaultRelativeY : Float) : ControllerConfiguration {
|
||||||
defaultRelativeX : Float,
|
|
||||||
defaultRelativeY : Float
|
|
||||||
) : ControllerConfiguration {
|
|
||||||
override var enabled = true
|
override var enabled = true
|
||||||
override var globalScale = 1f
|
override var globalScale = 1f
|
||||||
override var relativeX = defaultRelativeX
|
override var relativeX = defaultRelativeX
|
||||||
override var relativeY = defaultRelativeY
|
override var relativeY = defaultRelativeY
|
||||||
}
|
}
|
||||||
|
|
||||||
class ControllerConfigurationImpl(
|
class ControllerConfigurationImpl(private val context : Context, private val buttonId : ButtonId, defaultRelativeX : Float, defaultRelativeY : Float) : ControllerConfiguration {
|
||||||
private val context : Context,
|
private inline fun <reified T> config(default : T, prefix : String = "${buttonId.name}_") = sharedPreferences(context, default, prefix, "controller_config")
|
||||||
private val buttonId : ButtonId,
|
|
||||||
defaultRelativeX : Float,
|
|
||||||
defaultRelativeY : Float
|
|
||||||
) : ControllerConfiguration {
|
|
||||||
private inline fun <reified T> config(default : T) = ControllerPrefs(context, "${buttonId.name}_", T::class.java, default)
|
|
||||||
|
|
||||||
override var enabled by config(true)
|
override var enabled by config(true)
|
||||||
override var globalScale by ControllerPrefs(context, "on_screen_controller_", Float::class.java, 1f)
|
override var globalScale by config(1f, "")
|
||||||
override var relativeX by config(defaultRelativeX)
|
override var relativeX by config(defaultRelativeX)
|
||||||
override var relativeY by config(defaultRelativeY)
|
override var relativeY by config(defaultRelativeY)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private class ControllerPrefs<T>(context : Context, private val prefix : String, private val clazz : Class<T>, private val default : T) : ReadWriteProperty<Any, T> {
|
|
||||||
companion object {
|
|
||||||
const val CONTROLLER_CONFIG = "controller_config"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val prefs = context.getSharedPreferences(CONTROLLER_CONFIG, Context.MODE_PRIVATE)
|
|
||||||
|
|
||||||
override fun setValue(thisRef : Any, property : KProperty<*>, value : T) {
|
|
||||||
prefs.edit().apply {
|
|
||||||
when (clazz) {
|
|
||||||
Float::class.java, java.lang.Float::class.java -> putFloat(prefix + property.name, value as Float)
|
|
||||||
Boolean::class.java, java.lang.Boolean::class.java -> putBoolean(prefix + property.name, value as Boolean)
|
|
||||||
else -> error("Unsupported type $clazz ${Float::class.java}")
|
|
||||||
}
|
|
||||||
}.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValue(thisRef : Any, property : KProperty<*>) : T =
|
|
||||||
prefs.let {
|
|
||||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
|
||||||
when (clazz) {
|
|
||||||
Float::class.java, java.lang.Float::class.java -> it.getFloat(prefix + property.name, default as Float)
|
|
||||||
Boolean::class.java, java.lang.Boolean::class.java -> it.getBoolean(prefix + property.name, default as Boolean)
|
|
||||||
else -> error("Unsupported type $clazz")
|
|
||||||
}
|
|
||||||
} as T
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,9 @@ import android.view.View
|
|||||||
import android.view.View.OnTouchListener
|
import android.view.View.OnTouchListener
|
||||||
import emu.skyline.input.ButtonId
|
import emu.skyline.input.ButtonId
|
||||||
import emu.skyline.input.ButtonState
|
import emu.skyline.input.ButtonState
|
||||||
|
import emu.skyline.utils.add
|
||||||
|
import emu.skyline.utils.multiply
|
||||||
|
import emu.skyline.utils.normalize
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
typealias OnButtonStateChangedListener = (buttonId : ButtonId, state : ButtonState) -> Unit
|
typealias OnButtonStateChangedListener = (buttonId : ButtonId, state : ButtonState) -> Unit
|
||||||
@ -32,6 +35,11 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
private var onButtonStateChangedListener : OnButtonStateChangedListener? = null
|
private var onButtonStateChangedListener : OnButtonStateChangedListener? = null
|
||||||
private var onStickStateChangedListener : OnStickStateChangedListener? = null
|
private var onStickStateChangedListener : OnStickStateChangedListener? = null
|
||||||
private val joystickAnimators = mutableMapOf<JoystickButton, Animator?>()
|
private val joystickAnimators = mutableMapOf<JoystickButton, Animator?>()
|
||||||
|
var recenterSticks = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
controls.joysticks.forEach { it.recenterSticks = recenterSticks }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDraw(canvas : Canvas) {
|
override fun onDraw(canvas : Canvas) {
|
||||||
super.onDraw(canvas)
|
super.onDraw(canvas)
|
||||||
@ -95,7 +103,7 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
val value = animation.animatedValue as Float
|
val value = animation.animatedValue as Float
|
||||||
val vector = direction.multiply(value)
|
val vector = direction.multiply(value)
|
||||||
val newPosition = position.add(vector)
|
val newPosition = position.add(vector)
|
||||||
joystick.onFingerMoved(newPosition.x, newPosition.y)
|
joystick.onFingerMoved(newPosition.x, newPosition.y, false)
|
||||||
onStickStateChangedListener?.invoke(joystick.buttonId, vector.multiply(1f / radius))
|
onStickStateChangedListener?.invoke(joystick.buttonId, vector.multiply(1f / radius))
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
@ -129,6 +137,8 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
joystick.onFingerDown(x, y)
|
joystick.onFingerDown(x, y)
|
||||||
if (joystick.shortDoubleTapped)
|
if (joystick.shortDoubleTapped)
|
||||||
onButtonStateChangedListener?.invoke(joystick.buttonId, ButtonState.Pressed)
|
onButtonStateChangedListener?.invoke(joystick.buttonId, ButtonState.Pressed)
|
||||||
|
if (recenterSticks)
|
||||||
|
onStickStateChangedListener?.invoke(joystick.buttonId, joystick.outerToInnerRelative())
|
||||||
performClick()
|
performClick()
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
@ -144,8 +154,7 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handled.also { if (it) invalidate() }
|
||||||
handled.also { if (it) invalidate() else super.onTouchEvent(event) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val editingTouchHandler = OnTouchListener { _, event ->
|
private val editingTouchHandler = OnTouchListener { _, event ->
|
||||||
@ -175,7 +184,7 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}.also { handled -> if (handled) invalidate() else super.onTouchEvent(event) }
|
}.also { handled -> if (handled) invalidate() }
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -194,12 +203,12 @@ class OnScreenControllerView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun increaseScale() {
|
fun increaseScale() {
|
||||||
controls.globalScale *= 1.1f
|
controls.globalScale += 0.05f
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decreaseScale() {
|
fun decreaseScale() {
|
||||||
controls.globalScale *= 0.9f
|
controls.globalScale -= 0.05f
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import androidx.core.content.ContextCompat
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import emu.skyline.R
|
import emu.skyline.R
|
||||||
|
import emu.skyline.utils.Settings
|
||||||
import kotlinx.android.synthetic.main.main_activity.fab_parent
|
import kotlinx.android.synthetic.main.main_activity.fab_parent
|
||||||
import kotlinx.android.synthetic.main.on_screen_edit_activity.*
|
import kotlinx.android.synthetic.main.on_screen_edit_activity.*
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ class OnScreenEditActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
fullEditVisible = !fullEditVisible
|
fullEditVisible = !fullEditVisible
|
||||||
toggleFabVisibility(fullEditVisible)
|
toggleFabVisibility(fullEditVisible)
|
||||||
fabMapping[R.drawable.ic_close]!!.animate().rotationBy(if (fullEditVisible) -45f else 45f)
|
fabMapping[R.drawable.ic_close]!!.animate().rotation(if (fullEditVisible) 0f else 45f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ class OnScreenEditActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val actions : List<Pair<Int, () -> Unit>> = listOf(
|
private val actions : List<Pair<Int, () -> Unit>> = listOf(
|
||||||
Pair(R.drawable.ic_refresh, { on_screen_controller_view.resetControls() }),
|
Pair(R.drawable.ic_restore, { on_screen_controller_view.resetControls() }),
|
||||||
Pair(R.drawable.ic_toggle, toggleAction),
|
Pair(R.drawable.ic_toggle, toggleAction),
|
||||||
Pair(R.drawable.ic_edit, editAction),
|
Pair(R.drawable.ic_edit, editAction),
|
||||||
Pair(R.drawable.ic_zoom_out, { on_screen_controller_view.decreaseScale() }),
|
Pair(R.drawable.ic_zoom_out, { on_screen_controller_view.decreaseScale() }),
|
||||||
@ -83,6 +84,7 @@ class OnScreenEditActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState : Bundle?) {
|
override fun onCreate(savedInstanceState : Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.on_screen_edit_activity)
|
setContentView(R.layout.on_screen_edit_activity)
|
||||||
|
on_screen_controller_view.recenterSticks = Settings(this).onScreenControlRecenterSticks
|
||||||
|
|
||||||
actions.forEach { pair ->
|
actions.forEach { pair ->
|
||||||
fab_parent.addView(FloatingActionButton(this).apply {
|
fab_parent.addView(FloatingActionButton(this).apply {
|
||||||
|
@ -12,6 +12,8 @@ import androidx.core.graphics.minus
|
|||||||
import emu.skyline.R
|
import emu.skyline.R
|
||||||
import emu.skyline.input.ButtonId
|
import emu.skyline.input.ButtonId
|
||||||
import emu.skyline.input.ButtonId.*
|
import emu.skyline.input.ButtonId.*
|
||||||
|
import emu.skyline.utils.add
|
||||||
|
import emu.skyline.utils.multiply
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
open class CircularButton(
|
open class CircularButton(
|
||||||
@ -55,11 +57,12 @@ class JoystickButton(
|
|||||||
defaultRelativeX,
|
defaultRelativeX,
|
||||||
defaultRelativeY,
|
defaultRelativeY,
|
||||||
defaultRelativeRadiusToX,
|
defaultRelativeRadiusToX,
|
||||||
R.drawable.ic_stick_circle
|
R.drawable.ic_button
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick)
|
private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick)
|
||||||
|
|
||||||
|
var recenterSticks = false
|
||||||
|
private lateinit var initialTapPosition : PointF
|
||||||
private var fingerDownTime = 0L
|
private var fingerDownTime = 0L
|
||||||
private var fingerUpTime = 0L
|
private var fingerUpTime = 0L
|
||||||
var shortDoubleTapped = false
|
var shortDoubleTapped = false
|
||||||
@ -76,12 +79,17 @@ class JoystickButton(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFingerDown(x : Float, y : Float) {
|
override fun onFingerDown(x : Float, y : Float) {
|
||||||
relativeX = x / width
|
val relativeX = x / width
|
||||||
relativeY = (y - heightDiff) / adjustedHeight
|
val relativeY = (y - heightDiff) / adjustedHeight
|
||||||
|
if (!recenterSticks) {
|
||||||
|
this.relativeX = relativeX
|
||||||
|
this.relativeY = relativeY
|
||||||
|
}
|
||||||
innerButton.relativeX = relativeX
|
innerButton.relativeX = relativeX
|
||||||
innerButton.relativeY = relativeY
|
innerButton.relativeY = relativeY
|
||||||
|
|
||||||
val currentTime = SystemClock.elapsedRealtime()
|
val currentTime = SystemClock.elapsedRealtime()
|
||||||
|
initialTapPosition = PointF(x, y)
|
||||||
val firstTapDiff = fingerUpTime - fingerDownTime
|
val firstTapDiff = fingerUpTime - fingerDownTime
|
||||||
val secondTapDiff = currentTime - fingerUpTime
|
val secondTapDiff = currentTime - fingerUpTime
|
||||||
if (firstTapDiff in 0..500 && secondTapDiff in 0..500) {
|
if (firstTapDiff in 0..500 && secondTapDiff in 0..500) {
|
||||||
@ -101,16 +109,17 @@ class JoystickButton(
|
|||||||
drawable.alpha = 255
|
drawable.alpha = 255
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFingerMoved(x : Float, y : Float) : PointF {
|
fun onFingerMoved(x : Float, y : Float, manualMove : Boolean = true) : PointF {
|
||||||
val position = PointF(currentX, currentY)
|
val position = PointF(currentX, currentY)
|
||||||
var finger = PointF(x, y)
|
var finger = PointF(x, y)
|
||||||
val outerToInner = finger.minus(position)
|
val outerToInner = finger.minus(position)
|
||||||
val distance = outerToInner.length()
|
val distance = outerToInner.length()
|
||||||
if (distance >= radius) {
|
if (distance > radius) {
|
||||||
finger = position.add(outerToInner.multiply(1f / distance * radius))
|
finger = position.add(outerToInner.multiply(1f / distance * radius))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance > radius * 0.075f) {
|
// If finger get moved to much, then don't trigger as joystick being pressed
|
||||||
|
if (manualMove && initialTapPosition.minus(finger).length() > radius * 0.075f) {
|
||||||
fingerDownTime = 0
|
fingerDownTime = 0
|
||||||
fingerUpTime = 0
|
fingerUpTime = 0
|
||||||
}
|
}
|
||||||
@ -122,6 +131,8 @@ class JoystickButton(
|
|||||||
|
|
||||||
fun outerToInner() = PointF(innerButton.currentX, innerButton.currentY).minus(PointF(currentX, currentY))
|
fun outerToInner() = PointF(innerButton.currentX, innerButton.currentY).minus(PointF(currentX, currentY))
|
||||||
|
|
||||||
|
fun outerToInnerRelative() = outerToInner().multiply(1f / radius)
|
||||||
|
|
||||||
override fun edit(x : Float, y : Float) {
|
override fun edit(x : Float, y : Float) {
|
||||||
super.edit(x, y)
|
super.edit(x, y)
|
||||||
|
|
||||||
@ -209,13 +220,13 @@ class Controls(onScreenControllerView : OnScreenControllerView) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val rectangularButtons = listOf(
|
val rectangularButtons = listOf(
|
||||||
RectangularButton(onScreenControllerView, L, 0.1f, 0.25f, 0.075f, 0.08f),
|
RectangularButton(onScreenControllerView, L, 0.1f, 0.25f, 0.09f, 0.1f),
|
||||||
RectangularButton(onScreenControllerView, R, 0.9f, 0.25f, 0.075f, 0.08f)
|
RectangularButton(onScreenControllerView, R, 0.9f, 0.25f, 0.09f, 0.1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
val triggerButtons = listOf(
|
val triggerButtons = listOf(
|
||||||
TriggerButton(onScreenControllerView, ZL, 0.1f, 0.1f, 0.075f, 0.08f),
|
TriggerButton(onScreenControllerView, ZL, 0.1f, 0.1f, 0.09f, 0.1f),
|
||||||
TriggerButton(onScreenControllerView, ZR, 0.9f, 0.1f, 0.075f, 0.08f)
|
TriggerButton(onScreenControllerView, ZR, 0.9f, 0.1f, 0.09f, 0.1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
val allButtons = circularButtons + joysticks + rectangularButtons + triggerButtons
|
val allButtons = circularButtons + joysticks + rectangularButtons + triggerButtons
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package emu.skyline.input.onscreen
|
package emu.skyline.utils
|
||||||
|
|
||||||
import android.graphics.PointF
|
import android.graphics.PointF
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package emu.skyline
|
package emu.skyline.utils
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.ObjectInputStream
|
import java.io.ObjectInputStream
|
32
app/src/main/java/emu/skyline/utils/Settings.kt
Normal file
32
app/src/main/java/emu/skyline/utils/Settings.kt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package emu.skyline.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
class Settings(context : Context) {
|
||||||
|
var layoutType by sharedPreferences(context, "1")
|
||||||
|
|
||||||
|
var searchLocation by sharedPreferences(context, "")
|
||||||
|
|
||||||
|
var refreshRequired by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var appTheme by sharedPreferences(context, "2")
|
||||||
|
|
||||||
|
var selectAction by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var perfStats by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var operationMode by sharedPreferences(context, true)
|
||||||
|
|
||||||
|
var onScreenControl by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var onScreenControlRecenterSticks by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var logCompact by sharedPreferences(context, false)
|
||||||
|
|
||||||
|
var logLevel by sharedPreferences(context, "3")
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package emu.skyline.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
inline fun <reified T> sharedPreferences(context : Context, default : T, prefix : String = "", prefName : String? = null) = SharedPreferencesDelegate(context, T::class.java, default, prefix, prefName)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
class SharedPreferencesDelegate<T>(context : Context, private val clazz : Class<T>, private val default : T, private val prefix : String, prefName : String?) : ReadWriteProperty<Any, T> {
|
||||||
|
private val prefs = prefName?.let { context.getSharedPreferences(prefName, Context.MODE_PRIVATE) } ?: PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
override fun setValue(thisRef : Any, property : KProperty<*>, value : T) = (prefix + pascalToSnakeCase(property.name)).let { keyName ->
|
||||||
|
prefs.edit().apply {
|
||||||
|
when (clazz) {
|
||||||
|
Float::class.java, java.lang.Float::class.java -> putFloat(keyName, value as Float)
|
||||||
|
Boolean::class.java, java.lang.Boolean::class.java -> putBoolean(keyName, value as Boolean)
|
||||||
|
String::class.java, java.lang.String::class.java -> putString(keyName, value as String)
|
||||||
|
else -> error("Unsupported type $clazz ${Float::class.java}")
|
||||||
|
}
|
||||||
|
}.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(thisRef : Any, property : KProperty<*>) : T = (prefix + pascalToSnakeCase(property.name)).let { keyName ->
|
||||||
|
prefs.let {
|
||||||
|
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||||
|
when (clazz) {
|
||||||
|
Float::class.java, java.lang.Float::class.java -> it.getFloat(keyName, default as Float)
|
||||||
|
Boolean::class.java, java.lang.Boolean::class.java -> it.getBoolean(keyName, default as Boolean)
|
||||||
|
String::class.java, java.lang.String::class.java -> it.getString(keyName, default as String)
|
||||||
|
else -> error("Unsupported type $clazz")
|
||||||
|
}
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pascalToSnakeCase(text : String) = StringBuilder().apply {
|
||||||
|
text.forEachIndexed { index, c ->
|
||||||
|
if (index != 0 && c.isUpperCase()) append('_')
|
||||||
|
append(c.toLowerCase())
|
||||||
|
}.toString()
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="oval">
|
android:shape="oval">
|
||||||
<solid android:color="#50FFFFFF" />
|
<solid android:color="#20FFFFFF" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="2.5dp"
|
android:width="2.5dp"
|
||||||
android:color="#A0FFFFFF" />
|
android:color="#25FFFFFF" />
|
||||||
</shape>
|
</shape>
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="#50FFFFFF" />
|
<solid android:color="#20FFFFFF" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="2dp"
|
android:width="2dp"
|
||||||
android:color="#A0FFFFFF" />
|
android:color="#25FFFFFF" />
|
||||||
<size
|
<size
|
||||||
android:width="25dp"
|
android:width="25dp"
|
||||||
android:height="25dp" />
|
android:height="25dp" />
|
||||||
|
10
app/src/main/res/drawable/ic_restore.xml
Normal file
10
app/src/main/res/drawable/ic_restore.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000"
|
||||||
|
android:pathData="M12,3A9,9 0 0,0 3,12H0L4,16L8,12H5A7,7 0 0,1 12,5A7,7 0 0,1 19,12A7,7 0 0,1 12,19C10.5,19 9.09,18.5 7.94,17.7L6.5,19.14C8.04,20.3 9.94,21 12,21A9,9 0 0,0 21,12A9,9 0 0,0 12,3M14,12A2,2 0 0,0 12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12Z" />
|
||||||
|
</vector>
|
@ -2,10 +2,10 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="oval">
|
<shape android:shape="oval">
|
||||||
<solid android:color="#50FFFFFF" />
|
<solid android:color="#10FFFFFF" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="2dp"
|
android:width="2dp"
|
||||||
android:color="#A0FFFFFF" />
|
android:color="#25FFFFFF" />
|
||||||
<size
|
<size
|
||||||
android:width="25dp"
|
android:width="25dp"
|
||||||
android:height="25dp" />
|
android:height="25dp" />
|
||||||
@ -18,7 +18,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="oval">
|
<shape android:shape="oval">
|
||||||
<solid android:color="#50000000" />
|
<solid android:color="#30000000" />
|
||||||
<size
|
<size
|
||||||
android:width="30dp"
|
android:width="30dp"
|
||||||
android:height="30dp" />
|
android:height="30dp" />
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="oval">
|
|
||||||
<solid android:color="#50FFFFFF" />
|
|
||||||
<stroke
|
|
||||||
android:width="2.5dp"
|
|
||||||
android:color="#A0FFFFFF" />
|
|
||||||
</shape>
|
|
@ -2,10 +2,10 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="#50FFFFFF" />
|
<solid android:color="#20FFFFFF" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="2dp"
|
android:width="2dp"
|
||||||
android:color="#A0FFFFFF" />
|
android:color="#25FFFFFF" />
|
||||||
<size
|
<size
|
||||||
android:width="25dp"
|
android:width="25dp"
|
||||||
android:height="25dp" />
|
android:height="25dp" />
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="#50FFFFFF" />
|
<solid android:color="#20FFFFFF" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="2dp"
|
android:width="2dp"
|
||||||
android:color="#A0FFFFFF" />
|
android:color="#25FFFFFF" />
|
||||||
<size
|
<size
|
||||||
android:width="25dp"
|
android:width="25dp"
|
||||||
android:height="25dp" />
|
android:height="25dp" />
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
android:id="@+id/button_icon"
|
android:id="@+id/button_icon"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:alpha="0.15"
|
|
||||||
android:contentDescription="@string/buttons"
|
android:contentDescription="@string/buttons"
|
||||||
android:outlineProvider="bounds"
|
android:outlineProvider="bounds"
|
||||||
android:src="@drawable/ic_button" />
|
android:src="@drawable/ic_button"
|
||||||
|
android:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/button_text"
|
android:id="@+id/button_text"
|
||||||
|
@ -1,52 +1,42 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/controller_item"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true">
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_title"
|
android:id="@+id/text_title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/text_subtitle"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/checkbox"
|
|
||||||
app:layout_constraintHorizontal_bias="0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="Title" />
|
tools:text="Title" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_subtitle"
|
android:id="@+id/text_subtitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||||
android:textColor="@android:color/tertiary_text_light"
|
android:textColor="@android:color/tertiary_text_light"
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/checkbox"
|
|
||||||
app:layout_constraintHorizontal_bias="0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_title"
|
|
||||||
tools:text="Summary" />
|
tools:text="Summary" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/checkbox"
|
android:id="@+id/checkbox"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="false"
|
android:layout_gravity="center_vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:clickable="false" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
</LinearLayout>
|
||||||
app:layout_constraintHorizontal_bias="1"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
@ -50,7 +50,8 @@
|
|||||||
android:alpha="0.4"
|
android:alpha="0.4"
|
||||||
android:contentDescription="@string/buttons"
|
android:contentDescription="@string/buttons"
|
||||||
android:outlineProvider="bounds"
|
android:outlineProvider="bounds"
|
||||||
android:src="@drawable/ic_stick_circle" />
|
android:src="@drawable/ic_button"
|
||||||
|
android:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
@ -70,7 +71,8 @@
|
|||||||
android:alpha="0.4"
|
android:alpha="0.4"
|
||||||
android:contentDescription="@string/buttons"
|
android:contentDescription="@string/buttons"
|
||||||
android:outlineProvider="bounds"
|
android:outlineProvider="bounds"
|
||||||
android:src="@drawable/ic_stick" />
|
android:src="@drawable/ic_stick"
|
||||||
|
android:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stick_name"
|
android:id="@+id/stick_name"
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
<string name="joystick">Joystick</string>
|
<string name="joystick">Joystick</string>
|
||||||
<string name="confirm">Confirm</string>
|
<string name="confirm">Confirm</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="osc_recenter_sticks">Recenter sticks on touch</string>
|
||||||
<string name="controller">Controller</string>
|
<string name="controller">Controller</string>
|
||||||
<string name="config_controller">Configure Controller</string>
|
<string name="config_controller">Configure Controller</string>
|
||||||
<string name="controller_type">Controller Type</string>
|
<string name="controller_type">Controller Type</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user