Add comments

This commit is contained in:
Willi Ye 2020-10-05 12:04:57 +02:00 committed by ◱ PixelyIon
parent 7526a985fb
commit f479aeb4ac
21 changed files with 72 additions and 81 deletions

View File

@ -96,7 +96,7 @@ class AppDialog : BottomSheetDialogFragment() {
game_pin.setOnClickListener { game_pin.setOnClickListener {
val info = ShortcutInfo.Builder(context, item.title) val info = ShortcutInfo.Builder(context, item.title)
info.setShortLabel(item.meta.name) info.setShortLabel(item.title)
info.setActivity(ComponentName(requireContext(), EmulationActivity::class.java)) info.setActivity(ComponentName(requireContext(), EmulationActivity::class.java))
info.setIcon(Icon.createWithAdaptiveBitmap(item.icon ?: missingIcon)) info.setIcon(Icon.createWithAdaptiveBitmap(item.icon ?: missingIcon))

View File

@ -164,7 +164,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
} }
/** /**
* This executes the specified ROM, [preferenceFd] is assumed to be valid beforehand * This executes the specified ROM
* *
* @param rom The URI of the ROM to execute * @param rom The URI of the ROM to execute
*/ */
@ -186,7 +186,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
} }
/** /**
* This makes the window fullscreen then sets up [preferenceFd], sets up the performance statistics and finally calls [executeApplication] for executing the application * This makes the window fullscreen, sets up the performance statistics and finally calls [executeApplication] for executing the application
*/ */
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState : Bundle?) { override fun onCreate(savedInstanceState : Bundle?) {
@ -415,7 +415,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
else -> error("Invalid button id") else -> error("Invalid button id")
} }
setAxisValue(0, stickId.xAxis.ordinal, (position.x * Short.MAX_VALUE).toInt()) setAxisValue(0, stickId.xAxis.ordinal, (position.x * Short.MAX_VALUE).toInt())
setAxisValue(0, stickId.yAxis.ordinal, (-position.y * Short.MAX_VALUE).toInt()) // Y is inverted setAxisValue(0, stickId.yAxis.ordinal, (-position.y * Short.MAX_VALUE).toInt()) // Y is inverted, since drawing starts from top left
} }
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")

View File

@ -31,9 +31,8 @@ import emu.skyline.adapter.GenericAdapter
import emu.skyline.adapter.HeaderViewItem import emu.skyline.adapter.HeaderViewItem
import emu.skyline.adapter.LayoutType import emu.skyline.adapter.LayoutType
import emu.skyline.data.AppItem import emu.skyline.data.AppItem
import emu.skyline.data.BaseElement import emu.skyline.data.DataItem
import emu.skyline.data.BaseHeader import emu.skyline.data.HeaderItem
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
@ -71,7 +70,7 @@ class MainActivity : AppCompatActivity() {
/** /**
* This adds all files in [directory] with [extension] as an entry in [adapter] using [RomFile] to load metadata * This adds all files in [directory] with [extension] as an entry in [adapter] using [RomFile] to load metadata
*/ */
private fun addEntries(extension : String, romFormat : RomFormat, directory : DocumentFile, romElements : ArrayList<BaseElement>, found : Boolean = false) : Boolean { private fun addEntries(extension : String, romFormat : RomFormat, directory : DocumentFile, romElements : ArrayList<DataItem>, found : Boolean = false) : Boolean {
var foundCurrent = found var foundCurrent = found
directory.listFiles().forEach { file -> directory.listFiles().forEach { file ->
@ -83,7 +82,7 @@ class MainActivity : AppCompatActivity() {
val finalFoundCurrent = foundCurrent val finalFoundCurrent = foundCurrent
runOnUiThread { runOnUiThread {
if (!finalFoundCurrent) { if (!finalFoundCurrent) {
romElements.add(BaseHeader(romFormat.name)) romElements.add(HeaderItem(romFormat.name))
adapter.addItem(HeaderViewItem(romFormat.name)) adapter.addItem(HeaderViewItem(romFormat.name))
} }
@ -111,8 +110,8 @@ class MainActivity : AppCompatActivity() {
if (loadFromFile) { if (loadFromFile) {
try { try {
loadSerializedList<BaseElement>(romsFile).forEach { loadSerializedList<DataItem>(romsFile).forEach {
if (it.elementType == ElementType.Header && it is BaseHeader) if (it is HeaderItem)
adapter.addItem(HeaderViewItem(it.title)) adapter.addItem(HeaderViewItem(it.title))
else if (it is AppItem) else if (it is AppItem)
adapter.addItem(it.toViewItem()) adapter.addItem(it.toViewItem())
@ -136,7 +135,7 @@ class MainActivity : AppCompatActivity() {
val searchLocation = DocumentFile.fromTreeUri(this, Uri.parse(settings.searchLocation))!! val searchLocation = DocumentFile.fromTreeUri(this, Uri.parse(settings.searchLocation))!!
val romElements = ArrayList<BaseElement>() val romElements = ArrayList<DataItem>()
addEntries("nro", RomFormat.NRO, searchLocation, romElements) addEntries("nro", RomFormat.NRO, searchLocation, romElements)
addEntries("nso", RomFormat.NSO, searchLocation, romElements) addEntries("nso", RomFormat.NSO, searchLocation, romElements)
addEntries("nca", RomFormat.NCA, searchLocation, romElements) addEntries("nca", RomFormat.NCA, searchLocation, romElements)
@ -144,7 +143,7 @@ class MainActivity : AppCompatActivity() {
runOnUiThread { runOnUiThread {
if (romElements.isEmpty()) { if (romElements.isEmpty()) {
romElements.add(BaseHeader(getString(R.string.no_rom))) romElements.add(HeaderItem(getString(R.string.no_rom)))
adapter.addItem(HeaderViewItem(getString(R.string.no_rom))) adapter.addItem(HeaderViewItem(getString(R.string.no_rom)))
} }

View File

@ -8,6 +8,9 @@ package emu.skyline
import android.app.Application import android.app.Application
import emu.skyline.input.InputManager import emu.skyline.input.InputManager
/**
* Custom application class to initialize [InputManager]
*/
class SkylineApplication : Application() { class SkylineApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()

View File

@ -69,5 +69,5 @@ class AppViewItem(var layoutType : LayoutType, private val item : AppItem, priva
builder.show() builder.show()
} }
override fun toString() = item.key() override fun key() = item.key()
} }

View File

@ -13,6 +13,9 @@ import info.debatty.java.stringsimilarity.Cosine
import info.debatty.java.stringsimilarity.JaroWinkler import info.debatty.java.stringsimilarity.JaroWinkler
import java.util.* import java.util.*
/**
* Can handle any view types with [GenericViewHolderBinder] implemented, [GenericViewHolderBinder] are differentiated by the return value of [GenericViewHolderBinder.getLayoutFactory]
*/
class GenericAdapter : RecyclerView.Adapter<GenericViewHolder>(), Filterable { class GenericAdapter : RecyclerView.Adapter<GenericViewHolder>(), Filterable {
var currentSearchTerm = "" var currentSearchTerm = ""
@ -70,7 +73,7 @@ class GenericAdapter : RecyclerView.Adapter<GenericViewHolder>(), Filterable {
* This sorts the items in [allItems] in relation to how similar they are to [currentSearchTerm] * This sorts the items in [allItems] in relation to how similar they are to [currentSearchTerm]
*/ */
fun extractSorted() = allItems.mapNotNull { item -> fun extractSorted() = allItems.mapNotNull { item ->
item.toString().toLowerCase(Locale.getDefault()).let { item.key().toLowerCase(Locale.getDefault()).let {
val similarity = (jw.similarity(currentSearchTerm, it)) + cos.similarity(currentSearchTerm, it) / 2 val similarity = (jw.similarity(currentSearchTerm, it)) + cos.similarity(currentSearchTerm, it) / 2
if (similarity != 0.0) ScoredItem(similarity, item) else null if (similarity != 0.0) ScoredItem(similarity, item) else null
} }

View File

@ -22,4 +22,9 @@ abstract class GenericViewHolderBinder {
abstract fun getLayoutFactory() : GenericLayoutFactory abstract fun getLayoutFactory() : GenericLayoutFactory
abstract fun bind(holder : GenericViewHolder, position : Int) abstract fun bind(holder : GenericViewHolder, position : Int)
/**
* Used for filtering
*/
open fun key() : String = ""
} }

View File

@ -13,7 +13,7 @@ import emu.skyline.loader.LoaderResult
/** /**
* This class is a wrapper around [AppEntry], it is used for passing around game metadata * This class is a wrapper around [AppEntry], it is used for passing around game metadata
*/ */
class AppItem(val meta : AppEntry) : BaseItem() { class AppItem(private val meta : AppEntry) : DataItem {
/** /**
* The icon of the application * The icon of the application
*/ */
@ -56,5 +56,5 @@ class AppItem(val meta : AppEntry) : BaseItem() {
/** /**
* The name and author is used as the key * The name and author is used as the key
*/ */
override fun key() = meta.name + if (meta.author != null) " ${meta.author}" else "" fun key() = meta.name + if (meta.author != null) " ${meta.author}" else ""
} }

View File

@ -1,16 +0,0 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
package emu.skyline.data
/**
* This is an abstract class that all adapter item classes inherit from
*/
abstract class BaseItem : BaseElement(ElementType.Item) {
/**
* This function returns a string used for searching
*/
open fun key() : String = ""
}

View File

@ -5,4 +5,6 @@
package emu.skyline.data package emu.skyline.data
class BaseHeader(val title : String) : BaseElement(ElementType.Header) import java.io.Serializable
interface DataItem : Serializable

View File

@ -5,11 +5,4 @@
package emu.skyline.data package emu.skyline.data
import java.io.Serializable class HeaderItem(val title : String) : DataItem
enum class ElementType {
Header,
Item
}
abstract class BaseElement(val elementType : ElementType) : Serializable

View File

@ -38,7 +38,7 @@ class ControllerActivity : AppCompatActivity() {
private val adapter = GenericAdapter() private val adapter = GenericAdapter()
/** /**
* This is a map between a button and it's corresponding [ControllerItem] in [adapter] * This is a map between a button and it's corresponding [ControllerViewItem] in [adapter]
*/ */
val buttonMap = mutableMapOf<ButtonId, ControllerViewItem>() val buttonMap = mutableMapOf<ButtonId, ControllerViewItem>()

View File

@ -10,7 +10,7 @@ import android.view.MotionEvent
import java.io.Serializable import java.io.Serializable
/** /**
* This an abstract class for all host events that is inherited by all other event classes * This a sealed class for all host events that is inherited by all other event classes
* *
* @param descriptor The device descriptor of the device this event originates from * @param descriptor The device descriptor of the device this event originates from
*/ */

View File

@ -11,9 +11,11 @@ import android.graphics.Paint
import android.graphics.Rect import android.graphics.Rect
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import emu.skyline.input.ButtonId import emu.skyline.input.ButtonId
import kotlin.math.absoluteValue
import kotlin.math.roundToInt import kotlin.math.roundToInt
/**
* Converts relative values, such as coordinates and boundaries, to their absolute counterparts, also handles layout modifications like scaling and custom positioning
*/
abstract class OnScreenButton( abstract class OnScreenButton(
onScreenControllerView : OnScreenControllerView, onScreenControllerView : OnScreenControllerView,
val buttonId : ButtonId, val buttonId : ButtonId,
@ -47,7 +49,11 @@ abstract class OnScreenButton(
var height = 0 var height = 0
protected val adjustedHeight get() = width / CONFIGURED_ASPECT_RATIO protected val adjustedHeight get() = width / CONFIGURED_ASPECT_RATIO
protected val heightDiff get() = (height - adjustedHeight).absoluteValue
/**
* Buttons should be at bottom when device have large height than [adjustedHeight]
*/
protected val heightDiff get() = (height - adjustedHeight).coerceAtLeast(0f)
protected val itemWidth get() = width * relativeWidth protected val itemWidth get() = width * relativeWidth
private val itemHeight get() = adjustedHeight * relativeHeight private val itemHeight get() = adjustedHeight * relativeHeight
@ -58,37 +64,23 @@ abstract class OnScreenButton(
private val left get() = currentX - itemWidth / 2f private val left get() = currentX - itemWidth / 2f
private val top get() = currentY - itemHeight / 2f private val top get() = currentY - itemHeight / 2f
protected val currentBounds protected val currentBounds get() = Rect(left.roundToInt(), top.roundToInt(), (left + itemWidth).roundToInt(), (top + itemHeight).roundToInt())
get() = Rect(
left.roundToInt(),
top.roundToInt(),
(left + itemWidth).roundToInt(),
(top + itemHeight).roundToInt()
)
/**
* Keeps track of finger when there are multiple touches
*/
var touchPointerId = -1 var touchPointerId = -1
var isEditing = false var isEditing = false
private set private set
protected open fun renderCenteredText( protected open fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float) {
canvas : Canvas,
text : String,
size : Float,
x : Float,
y : Float
) {
buttonSymbolPaint.apply { buttonSymbolPaint.apply {
textSize = size textSize = size
textAlign = Paint.Align.LEFT textAlign = Paint.Align.LEFT
getTextBounds(text, 0, text.length, textBoundsRect) getTextBounds(text, 0, text.length, textBoundsRect)
} }
canvas.drawText( canvas.drawText(text, x - textBoundsRect.width() / 2f - textBoundsRect.left, y + textBoundsRect.height() / 2f - textBoundsRect.bottom, buttonSymbolPaint)
text,
x - textBoundsRect.width() / 2f - textBoundsRect.left,
y + textBoundsRect.height() / 2f - textBoundsRect.bottom,
buttonSymbolPaint
)
} }
open fun render(canvas : Canvas) { open fun render(canvas : Canvas) {

View File

@ -16,6 +16,9 @@ interface ControllerConfiguration {
var relativeY : Float var relativeY : Float
} }
/**
* Dummy implementation so layout editor is able to render [OnScreenControllerView] when [android.view.View.isInEditMode] is true
*/
class ControllerConfigurationDummy(defaultRelativeX : Float, defaultRelativeY : Float) : ControllerConfiguration { class ControllerConfigurationDummy(defaultRelativeX : Float, defaultRelativeY : Float) : ControllerConfiguration {
override var enabled = true override var enabled = true
override var globalScale = 1f override var globalScale = 1f

View File

@ -25,12 +25,10 @@ import kotlin.math.roundToLong
typealias OnButtonStateChangedListener = (buttonId : ButtonId, state : ButtonState) -> Unit typealias OnButtonStateChangedListener = (buttonId : ButtonId, state : ButtonState) -> Unit
typealias OnStickStateChangedListener = (buttonId : ButtonId, position : PointF) -> Unit typealias OnStickStateChangedListener = (buttonId : ButtonId, position : PointF) -> Unit
class OnScreenControllerView @JvmOverloads constructor( /**
context : Context, * Renders On-Screen Controls as a single view, handles touch inputs and button toggling
attrs : AttributeSet? = null, */
defStyleAttr : Int = 0, class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = 0, defStyleRes : Int = 0) : View(context, attrs, defStyleAttr, defStyleRes) {
defStyleRes : Int = 0
) : View(context, attrs, defStyleAttr, defStyleRes) {
private val controls = Controls(this) private val controls = Controls(this)
private var onButtonStateChangedListener : OnButtonStateChangedListener? = null private var onButtonStateChangedListener : OnButtonStateChangedListener? = null
private var onStickStateChangedListener : OnStickStateChangedListener? = null private var onStickStateChangedListener : OnStickStateChangedListener? = null

View File

@ -34,10 +34,13 @@ open class CircularButton(
) { ) {
val radius get() = itemWidth / 2f val radius get() = itemWidth / 2f
/**
* Checks if [x] and [y] are within circle
*/
override fun isTouched(x : Float, y : Float) : Boolean = PointF(currentX, currentY).minus(PointF(x, y)).length() <= radius override fun isTouched(x : Float, y : Float) : Boolean = PointF(currentX, currentY).minus(PointF(x, y)).length() <= radius
override fun onFingerDown(x : Float, y : Float) { override fun onFingerDown(x : Float, y : Float) {
drawable.alpha = (255 * 0.5f).roundToInt() drawable.alpha = 125
} }
override fun onFingerUp(x : Float, y : Float) { override fun onFingerUp(x : Float, y : Float) {
@ -81,19 +84,21 @@ class JoystickButton(
override fun onFingerDown(x : Float, y : Float) { override fun onFingerDown(x : Float, y : Float) {
val relativeX = x / width val relativeX = x / width
val relativeY = (y - heightDiff) / adjustedHeight val relativeY = (y - heightDiff) / adjustedHeight
if (!recenterSticks) { if (recenterSticks) {
this.relativeX = relativeX this.relativeX = relativeX
this.relativeY = relativeY this.relativeY = relativeY
} }
innerButton.relativeX = relativeX innerButton.relativeX = relativeX
innerButton.relativeY = relativeY innerButton.relativeY = relativeY
// If first and second tap occur within 500 mills, then trigger stick press
val currentTime = SystemClock.elapsedRealtime() val currentTime = SystemClock.elapsedRealtime()
initialTapPosition = PointF(x, y) 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) {
shortDoubleTapped = true shortDoubleTapped = true
// Indicate stick being pressed with lower alpha value
drawable.alpha = 50 drawable.alpha = 50
} }
fingerDownTime = currentTime fingerDownTime = currentTime
@ -115,6 +120,7 @@ class JoystickButton(
val outerToInner = finger.minus(position) val outerToInner = finger.minus(position)
val distance = outerToInner.length() val distance = outerToInner.length()
if (distance > radius) { if (distance > radius) {
// Limit distance to radius
finger = position.add(outerToInner.multiply(1f / distance * radius)) finger = position.add(outerToInner.multiply(1f / distance * radius))
} }
@ -168,7 +174,7 @@ open class RectangularButton(
override fun isTouched(x : Float, y : Float) = currentBounds.contains(x.roundToInt(), y.roundToInt()) override fun isTouched(x : Float, y : Float) = currentBounds.contains(x.roundToInt(), y.roundToInt())
override fun onFingerDown(x : Float, y : Float) { override fun onFingerDown(x : Float, y : Float) {
drawable.alpha = (255 * 0.5f).roundToInt() drawable.alpha = 125
} }
override fun onFingerUp(x : Float, y : Float) { override fun onFingerUp(x : Float, y : Float) {

View File

@ -80,6 +80,7 @@ class AppEntry(var name : String, var author : String?, var icon : Bitmap?, var
output.writeInt(loaderResult.value) output.writeInt(loaderResult.value)
output.writeBoolean(icon != null) output.writeBoolean(icon != null)
icon?.let { icon?.let {
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
it.compress(Bitmap.CompressFormat.WEBP_LOSSY, 100, output) it.compress(Bitmap.CompressFormat.WEBP_LOSSY, 100, output)
else else

View File

@ -24,7 +24,7 @@ class Settings(context : Context) {
var onScreenControl by sharedPreferences(context, false) var onScreenControl by sharedPreferences(context, false)
var onScreenControlRecenterSticks by sharedPreferences(context, false) var onScreenControlRecenterSticks by sharedPreferences(context, true)
var logCompact by sharedPreferences(context, false) var logCompact by sharedPreferences(context, false)

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:id="@+id/button_layout" android:id="@+id/button_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -39,7 +40,7 @@
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" /> app:tint="?android:attr/textColorPrimary" />
<TextView <TextView
android:id="@+id/button_text" android:id="@+id/button_text"

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:id="@+id/stick_layout" android:id="@+id/stick_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -51,7 +52,7 @@
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" /> app:tint="?android:attr/textColorPrimary" />
<RelativeLayout <RelativeLayout
@ -72,7 +73,7 @@
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" /> app:tint="?android:attr/textColorPrimary" />
<TextView <TextView
android:id="@+id/stick_name" android:id="@+id/stick_name"