mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 16:15:30 +03:00
Make UI fully usable using a controller
This commit focuses on making the UI completely usable using a controller so that a user won't have to switch between their device's touch screen and a controller constantly.
This commit is contained in:
parent
102f26d08e
commit
8e1f8ae7e9
@ -15,6 +15,9 @@ android {
|
||||
abiFilters "arm64-v8a"
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
disable 'IconLocation'
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
@ -52,11 +55,11 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.preference:preference:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.2.0-alpha05'
|
||||
implementation "androidx.core:core-ktx:1.2.0"
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||
implementation "androidx.core:core-ktx:1.3.1"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'info.debatty:java-string-similarity:1.2.1'
|
||||
|
@ -46,7 +46,7 @@ class AppDialog(val item : AppItem) : BottomSheetDialogFragment() {
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
|
||||
dialog?.setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BUTTON_B && event.action == KeyEvent.ACTION_DOWN) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BUTTON_B && event.action == KeyEvent.ACTION_UP) {
|
||||
dialog?.onBackPressed()
|
||||
return@setOnKeyListener true
|
||||
}
|
||||
@ -79,7 +79,7 @@ class AppDialog(val item : AppItem) : BottomSheetDialogFragment() {
|
||||
game_pin.setOnClickListener {
|
||||
val info = ShortcutInfo.Builder(context, item.title)
|
||||
info.setShortLabel(item.meta.name)
|
||||
info.setActivity(ComponentName(requireActivity(), EmulationActivity::class.java))
|
||||
info.setActivity(ComponentName(requireContext(), EmulationActivity::class.java))
|
||||
info.setIcon(Icon.createWithAdaptiveBitmap(item.icon ?: missingIcon))
|
||||
|
||||
val intent = Intent(context, EmulationActivity::class.java)
|
||||
|
@ -8,6 +8,7 @@ package emu.skyline
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
@ -176,4 +177,16 @@ class LogActivity : AppCompatActivity() {
|
||||
|
||||
shareThread.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles on calling [onBackPressed] when [KeyEvent.KEYCODE_BUTTON_B] is lifted
|
||||
*/
|
||||
override fun onKeyUp(keyCode : Int, event : KeyEvent?) : Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BUTTON_B) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
return super.onKeyUp(keyCode, event)
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
package emu.skyline
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ActivityInfo
|
||||
@ -17,6 +18,7 @@ import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
@ -169,6 +171,8 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
||||
else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
|
||||
})
|
||||
|
||||
refresh_fab.setOnClickListener(this)
|
||||
settings_fab.setOnClickListener(this)
|
||||
open_fab.setOnClickListener(this)
|
||||
log_fab.setOnClickListener(this)
|
||||
|
||||
@ -187,6 +191,24 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
}
|
||||
})
|
||||
|
||||
val controllerFabX = controller_fabs.translationX
|
||||
window.decorView.findViewById<View>(android.R.id.content).viewTreeObserver.addOnTouchModeChangeListener {
|
||||
if (!it) {
|
||||
toolbar_layout.setExpanded(false)
|
||||
|
||||
controller_fabs.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(controller_fabs, "translationX", 0f).apply {
|
||||
duration = 250
|
||||
start()
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator.ofFloat(controller_fabs, "translationX", controllerFabX).apply {
|
||||
duration = 250
|
||||
start()
|
||||
}.doOnEnd { controller_fabs.visibility = View.GONE }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupAppList() {
|
||||
@ -243,11 +265,16 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles on-click interaction with [R.id.log_fab], [R.id.open_fab]
|
||||
* This handles on-click interaction with [R.id.refresh_fab], [R.id.settings_fab], [R.id.log_fab], [R.id.open_fab]
|
||||
*/
|
||||
override fun onClick(view : View) {
|
||||
when (view.id) {
|
||||
R.id.refresh_fab -> refreshAdapter(false)
|
||||
|
||||
R.id.settings_fab -> startActivityForResult(Intent(this, SettingsActivity::class.java), 3)
|
||||
|
||||
R.id.log_fab -> startActivity(Intent(this, LogActivity::class.java))
|
||||
|
||||
R.id.open_fab -> {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
@ -7,6 +7,7 @@ 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 kotlinx.android.synthetic.main.titlebar.*
|
||||
@ -61,4 +62,16 @@ class SettingsActivity : AppCompatActivity() {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles on calling [onBackPressed] when [KeyEvent.KEYCODE_BUTTON_B] is lifted
|
||||
*/
|
||||
override fun onKeyUp(keyCode : Int, event : KeyEvent?) : Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BUTTON_B) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
return super.onKeyUp(keyCode, event)
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,7 @@ package emu.skyline.preference
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.*
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import emu.skyline.R
|
||||
import kotlinx.android.synthetic.main.license_dialog.*
|
||||
@ -26,7 +23,7 @@ class LicenseDialog : DialogFragment() {
|
||||
val layout = layoutInflater.inflate(R.layout.license_dialog, container)
|
||||
|
||||
val displayRectangle = Rect()
|
||||
val window : Window = activity!!.window
|
||||
val window : Window = requireActivity().window
|
||||
window.decorView.getWindowVisibleDisplayFrame(displayRectangle)
|
||||
|
||||
layout.minimumWidth = ((displayRectangle.width() * 0.9f).toInt())
|
||||
@ -43,5 +40,14 @@ class LicenseDialog : DialogFragment() {
|
||||
|
||||
license_url.text = arguments?.getString("libraryUrl")!!
|
||||
license_content.text = context?.getString(arguments?.getInt("libraryLicense")!!)!!
|
||||
|
||||
dialog?.setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BUTTON_B && event.action == KeyEvent.ACTION_UP) {
|
||||
dialog?.onBackPressed()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
package emu.skyline.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
@ -16,13 +18,21 @@ import com.google.android.material.snackbar.Snackbar.SnackbarLayout
|
||||
* Custom linear layout with support for [CoordinatorLayout] to move children, when [com.google.android.material.snackbar.Snackbar] shows up.
|
||||
*/
|
||||
class CustomLinearLayout : LinearLayout, CoordinatorLayout.AttachedBehavior {
|
||||
|
||||
constructor(context : Context) : this(context, null)
|
||||
constructor(context : Context, attrs : AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context : Context, attrs : AttributeSet?, defStyleAttr : Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
override fun getBehavior() : CoordinatorLayout.Behavior<CustomLinearLayout> = MoveUpwardBehavior()
|
||||
|
||||
override fun requestFocus(direction: Int, previouslyFocusedRect: Rect): Boolean = getChildAt(if (direction == View.FOCUS_UP) childCount - 1 else 0 )?.requestFocus() ?: false
|
||||
|
||||
/*
|
||||
override fun onRequestFocusInDescendants(dir : Int, rect : Rect?) : Boolean {
|
||||
Log.i("DESC", "$dir and $rect")
|
||||
return getChildAt(0).requestFocus()
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines behaviour when [com.google.android.material.snackbar.Snackbar] is shown.
|
||||
* Simply sets an offset to y translation to move children out of the way.
|
||||
|
@ -25,14 +25,15 @@
|
||||
android:id="@+id/game_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/game_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Display2"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="@android:color/tertiary_text_light"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -1,6 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
@ -13,6 +13,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fastScrollEnabled="true"
|
||||
android:focusedByDefault="true"
|
||||
android:transcriptMode="normal"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -23,6 +23,36 @@
|
||||
android:layout_gravity="bottom|end"
|
||||
android:orientation="vertical">
|
||||
|
||||
<emu.skyline.views.CustomLinearLayout
|
||||
android:id="@+id/controller_fabs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:translationX="72dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/refresh_fab"
|
||||
style="@style/Widget.MaterialComponents.FloatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:maxImageSize="26dp"
|
||||
app:srcCompat="@drawable/ic_refresh" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/settings_fab"
|
||||
style="@style/Widget.MaterialComponents.FloatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:maxImageSize="26dp"
|
||||
app:srcCompat="@drawable/ic_settings" />
|
||||
</emu.skyline.views.CustomLinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/open_fab"
|
||||
style="@style/Widget.MaterialComponents.FloatingActionButton"
|
||||
|
@ -19,7 +19,6 @@
|
||||
<string name="share">Share</string>
|
||||
<!-- Logger -->
|
||||
<string name="file_missing">The log file was not found</string>
|
||||
<string name="io_error">An I/O error has occurred</string>
|
||||
<string name="upload_logs">The logs are being uploaded</string>
|
||||
<string name="cleared">The logs have been cleared</string>
|
||||
<!-- Settings -->
|
||||
|
Loading…
Reference in New Issue
Block a user