diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt index def22f4..fd07ff4 100644 --- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt @@ -24,6 +24,8 @@ import com.metallic.chiaki.lib.ConnectVideoProfile import com.metallic.chiaki.session.* import com.metallic.chiaki.touchcontrols.TouchControlsFragment import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo import kotlin.math.min private sealed class DialogContents @@ -113,18 +115,25 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe } } + private val controlsDisposable = CompositeDisposable() + override fun onAttachFragment(fragment: Fragment) { super.onAttachFragment(fragment) - if(fragment is TouchControlsFragment) + when(fragment) { - fragment.controllerStateCallback = { viewModel.input.touchControllerState = it } - fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled - } - if(fragment is TouchpadOnlyFragment) - { - fragment.controllerStateCallback = { viewModel.input.touchControllerState = it } - fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled + is TouchControlsFragment -> + { + fragment.controllerState + .subscribe { viewModel.input.touchControllerState = it } + .addTo(controlsDisposable) + fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled + } + is TouchpadOnlyFragment -> + { + fragment.controllerStateCallback = { viewModel.input.touchControllerState = it } + fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled + } } } @@ -141,6 +150,12 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe viewModel.session.pause() } + override fun onDestroy() + { + super.onDestroy() + controlsDisposable.dispose() + } + private fun reconnect() { viewModel.session.shutdown() diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt index d3ab155..ad734ce 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt @@ -11,19 +11,31 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.metallic.chiaki.databinding.FragmentControlsBinding import com.metallic.chiaki.lib.ControllerState +import io.reactivex.Observable +import io.reactivex.Observable.combineLatest +import io.reactivex.subjects.BehaviorSubject +import io.reactivex.subjects.Subject class TouchControlsFragment : Fragment() { - private var controllerState = ControllerState() + private var ownControllerState = ControllerState() private set(value) { val diff = field != value field = value if(diff) - controllerStateCallback?.let { it(value) } + ownControllerStateSubject.onNext(ownControllerState) } - var controllerStateCallback: ((ControllerState) -> Unit)? = null + private val ownControllerStateSubject: Subject + = BehaviorSubject.create().also { it.onNext(ownControllerState) } + + // to delay attaching to the touchpadView until it's available + private val controllerStateProxy: Subject> + = BehaviorSubject.create>().also { it.onNext(ownControllerStateSubject) } + val controllerState: Observable get() = + controllerStateProxy.flatMap { it } + var onScreenControlsEnabled: LiveData? = null private var _binding: FragmentControlsBinding? = null @@ -32,6 +44,9 @@ class TouchControlsFragment : Fragment() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = FragmentControlsBinding.inflate(inflater, container, false).let { _binding = it + controllerStateProxy.onNext( + combineLatest(ownControllerStateSubject, binding.touchpadView.controllerState) { a, b -> a or b } + ) it.root } @@ -52,19 +67,19 @@ class TouchControlsFragment : Fragment() binding.psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) binding.touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) - binding.l2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { l2State = if(it) 255U else 0U } } - binding.r2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { r2State = if(it) 255U else 0U } } + binding.l2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { l2State = if(it) 255U else 0U } } + binding.r2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { r2State = if(it) 255U else 0U } } val quantizeStick = { f: Float -> (Short.MAX_VALUE * f).toInt().toShort() } - binding.leftAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { + binding.leftAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply { leftX = quantizeStick(it.x) leftY = quantizeStick(it.y) }} - binding.rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { + binding.rightAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply { rightX = quantizeStick(it.x) rightY = quantizeStick(it.y) }} @@ -76,7 +91,7 @@ class TouchControlsFragment : Fragment() private fun dpadStateChanged(direction: DPadView.Direction?) { - controllerState = controllerState.copy().apply { + ownControllerState = ownControllerState.copy().apply { buttons = ((buttons and ControllerState.BUTTON_DPAD_LEFT.inv() and ControllerState.BUTTON_DPAD_RIGHT.inv() @@ -98,7 +113,7 @@ class TouchControlsFragment : Fragment() } private fun buttonStateChanged(buttonMask: UInt) = { pressed: Boolean -> - controllerState = controllerState.copy().apply { + ownControllerState = ownControllerState.copy().apply { buttons = if(pressed) buttons or buttonMask diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt index 292351b..8c8f44f 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt @@ -10,15 +10,20 @@ import android.view.MotionEvent import android.view.View import com.metallic.chiaki.R import com.metallic.chiaki.lib.ControllerState +import io.reactivex.Observable +import io.reactivex.subjects.BehaviorSubject +import io.reactivex.subjects.Subject class TouchpadView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - val state: ControllerState = ControllerState() + private val state: ControllerState = ControllerState() private val pointerTouchIds = mutableMapOf() - var stateChangeCallback: ((ControllerState) -> Unit)? = null + private val stateSubject: Subject + = BehaviorSubject.create().also { it.onNext(state) } + val controllerState: Observable get() = stateSubject private val drawable: Drawable? @@ -81,6 +86,6 @@ class TouchpadView @JvmOverloads constructor( private fun triggerStateChanged() { - stateChangeCallback?.let { it(state) } + stateSubject.onNext(state) } } \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_controls.xml b/android/app/src/main/res/layout/fragment_controls.xml index 1f33197..ee2a4a8 100644 --- a/android/app/src/main/res/layout/fragment_controls.xml +++ b/android/app/src/main/res/layout/fragment_controls.xml @@ -48,6 +48,7 @@ />