mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-14 10:46:51 -07:00
Add On-Screen Controls Toggle to Android
This commit is contained in:
parent
042e698749
commit
088414798e
9 changed files with 137 additions and 17 deletions
|
@ -69,6 +69,11 @@ class Preferences(context: Context)
|
|||
get() = sharedPreferences.getBoolean(discoveryEnabledKey, true)
|
||||
set(value) { sharedPreferences.edit().putBoolean(discoveryEnabledKey, value).apply() }
|
||||
|
||||
val onScreenControlsEnabledKey get() = resources.getString(R.string.preferences_on_screen_controls_enabled_key)
|
||||
var onScreenControlsEnabled
|
||||
get() = sharedPreferences.getBoolean(onScreenControlsEnabledKey, true)
|
||||
set(value) { sharedPreferences.edit().putBoolean(onScreenControlsEnabledKey, value).apply() }
|
||||
|
||||
val logVerboseKey get() = resources.getString(R.string.preferences_log_verbose_key)
|
||||
var logVerbose
|
||||
get() = sharedPreferences.getBoolean(logVerboseKey, false)
|
||||
|
|
|
@ -17,22 +17,30 @@
|
|||
|
||||
package com.metallic.chiaki.stream
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Matrix
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.text.method.Touch
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.*
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.metallic.chiaki.*
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.common.Preferences
|
||||
import com.metallic.chiaki.common.ext.viewModelFactory
|
||||
import com.metallic.chiaki.lib.ConnectInfo
|
||||
import com.metallic.chiaki.lib.LoginPinRequestEvent
|
||||
import com.metallic.chiaki.lib.QuitReason
|
||||
|
@ -44,20 +52,22 @@ private object StreamQuitDialog: DialogContents()
|
|||
private object CreateErrorDialog: DialogContents()
|
||||
private object PinRequestDialog: DialogContents()
|
||||
|
||||
class StreamActivity : AppCompatActivity()
|
||||
class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListener
|
||||
{
|
||||
companion object
|
||||
{
|
||||
const val EXTRA_CONNECT_INFO = "connect_info"
|
||||
private const val HIDE_UI_TIMEOUT_MS = 2000L
|
||||
}
|
||||
|
||||
private lateinit var viewModel: StreamViewModel
|
||||
private val uiVisibilityHandler = Handler()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?)
|
||||
{
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProviders.of(this)[StreamViewModel::class.java]
|
||||
viewModel = ViewModelProviders.of(this, viewModelFactory { StreamViewModel(Preferences(this)) })[StreamViewModel::class.java]
|
||||
if(!viewModel.isInitialized)
|
||||
{
|
||||
val connectInfo = intent.getParcelableExtra<ConnectInfo>(EXTRA_CONNECT_INFO)
|
||||
|
@ -70,11 +80,19 @@ class StreamActivity : AppCompatActivity()
|
|||
}
|
||||
|
||||
setContentView(R.layout.activity_stream)
|
||||
window.decorView.setOnSystemUiVisibilityChangeListener(this)
|
||||
|
||||
viewModel.onScreenControlsEnabled.observe(this, Observer {
|
||||
if(onScreenControlsSwitch.isChecked != it)
|
||||
onScreenControlsSwitch.isChecked = it
|
||||
})
|
||||
onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
viewModel.setOnScreenControlsEnabled(isChecked)
|
||||
showOverlay()
|
||||
}
|
||||
|
||||
viewModel.session.attachToTextureView(textureView)
|
||||
|
||||
viewModel.session.state.observe(this, Observer { this.stateChanged(it) })
|
||||
|
||||
textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
||||
adjustTextureViewAspect()
|
||||
}
|
||||
|
@ -83,7 +101,11 @@ class StreamActivity : AppCompatActivity()
|
|||
override fun onAttachFragment(fragment: Fragment)
|
||||
{
|
||||
super.onAttachFragment(fragment)
|
||||
(fragment as? TouchControlsFragment)?.controllerStateCallback = viewModel.session::updateTouchControllerState
|
||||
if(fragment is TouchControlsFragment)
|
||||
{
|
||||
fragment.controllerStateCallback = viewModel.session::updateTouchControllerState
|
||||
fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume()
|
||||
|
@ -105,6 +127,45 @@ class StreamActivity : AppCompatActivity()
|
|||
viewModel.session.resume()
|
||||
}
|
||||
|
||||
private val hideSystemUIRunnable = Runnable { hideSystemUI() }
|
||||
|
||||
override fun onSystemUiVisibilityChange(visibility: Int)
|
||||
{
|
||||
if(visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0)
|
||||
showOverlay()
|
||||
else
|
||||
hideOverlay()
|
||||
}
|
||||
|
||||
private fun showOverlay()
|
||||
{
|
||||
overlay.isVisible = true
|
||||
overlay.animate()
|
||||
.alpha(1.0f)
|
||||
.setListener(object: AnimatorListenerAdapter()
|
||||
{
|
||||
override fun onAnimationEnd(animation: Animator?)
|
||||
{
|
||||
overlay.alpha = 1.0f
|
||||
}
|
||||
})
|
||||
uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable)
|
||||
uiVisibilityHandler.postDelayed(hideSystemUIRunnable, HIDE_UI_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
private fun hideOverlay()
|
||||
{
|
||||
overlay.animate()
|
||||
.alpha(0.0f)
|
||||
.setListener(object: AnimatorListenerAdapter()
|
||||
{
|
||||
override fun onAnimationEnd(animation: Animator?)
|
||||
{
|
||||
overlay.isGone = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean)
|
||||
{
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
|
@ -114,7 +175,7 @@ class StreamActivity : AppCompatActivity()
|
|||
|
||||
private fun hideSystemUI()
|
||||
{
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
|
|
|
@ -17,17 +17,23 @@
|
|||
|
||||
package com.metallic.chiaki.stream
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.metallic.chiaki.StreamSession
|
||||
import com.metallic.chiaki.common.Preferences
|
||||
import com.metallic.chiaki.lib.*
|
||||
|
||||
class StreamViewModel: ViewModel()
|
||||
class StreamViewModel(val preferences: Preferences): ViewModel()
|
||||
{
|
||||
private var connectInfo: ConnectInfo? = null
|
||||
private var _session: StreamSession? = null
|
||||
val session: StreamSession get() = _session ?: throw UninitializedPropertyAccessException("StreamViewModel not initialized")
|
||||
val isInitialized get() = connectInfo != null
|
||||
|
||||
private var _onScreenControlsEnabled = MutableLiveData<Boolean>(preferences.onScreenControlsEnabled)
|
||||
val onScreenControlsEnabled: LiveData<Boolean> get() = _onScreenControlsEnabled
|
||||
|
||||
fun init(connectInfo: ConnectInfo)
|
||||
{
|
||||
if(isInitialized)
|
||||
|
@ -40,4 +46,10 @@ class StreamViewModel: ViewModel()
|
|||
super.onCleared()
|
||||
_session?.shutdown()
|
||||
}
|
||||
|
||||
fun setOnScreenControlsEnabled(enabled: Boolean)
|
||||
{
|
||||
preferences.onScreenControlsEnabled = enabled
|
||||
_onScreenControlsEnabled.value = enabled
|
||||
}
|
||||
}
|
|
@ -23,13 +23,15 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.lib.ControllerState
|
||||
import kotlinx.android.synthetic.main.fragment_controls.*
|
||||
|
||||
class TouchControlsFragment : Fragment()
|
||||
{
|
||||
var controllerState = ControllerState()
|
||||
private var controllerState = ControllerState()
|
||||
private set(value)
|
||||
{
|
||||
val diff = field != value
|
||||
|
@ -39,6 +41,7 @@ class TouchControlsFragment : Fragment()
|
|||
}
|
||||
|
||||
var controllerStateCallback: ((ControllerState) -> Unit)? = null
|
||||
var onScreenControlsEnabled: LiveData<Boolean>? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
|
||||
= inflater.inflate(R.layout.fragment_controls, container, false)
|
||||
|
@ -74,6 +77,10 @@ class TouchControlsFragment : Fragment()
|
|||
rightX = quantizeStick(it.x)
|
||||
rightY = quantizeStick(it.y)
|
||||
}}
|
||||
|
||||
onScreenControlsEnabled?.observe(this, Observer {
|
||||
view.visibility = if(it) View.VISIBLE else View.GONE
|
||||
})
|
||||
}
|
||||
|
||||
private fun dpadStateChanged(direction: DPadView.Direction?)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".stream.StreamActivity">
|
||||
|
||||
<TextureView
|
||||
|
@ -15,15 +15,45 @@
|
|||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/controlsFragment"
|
||||
android:name="com.metallic.chiaki.touchcontrols.TouchControlsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom"
|
||||
tools:paddingRight="48dp"
|
||||
tools:paddingTop="25dp"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:background="@color/stream_overlay_background"
|
||||
android:padding="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="false">
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/onScreenControlsSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:text="On-Screen Controls"
|
||||
app:switchPadding="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:textColor="@color/stream_text"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
<color name="stream_text">@android:color/white</color>
|
||||
<color name="stream_background">@android:color/black</color>
|
||||
<color name="stream_overlay_background">#77000000</color>
|
||||
|
||||
<color name="floating_action_button_speed_dial_background">#fafafa</color>
|
||||
<color name="floating_action_button_speed_dial_tint">#333333</color>
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
|
||||
<!-- Don't localize these -->
|
||||
<string name="preferences_discovery_enabled_key">discovery_enabled</string>
|
||||
<string name="preferences_on_screen_controls_enabled_key">on_screen_controls_enabled</string>
|
||||
<string name="preferences_log_verbose_key">log_verbose</string>
|
||||
<string name="preferences_resolution_key">stream_resolution</string>
|
||||
<string name="preferences_resolution_title_360p">360p</string>
|
||||
|
|
|
@ -109,5 +109,7 @@
|
|||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="materialAlertDialogTheme">@style/AppTheme.AlertDialog</item>
|
||||
<item name="android:windowBackground">@color/stream_background</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue