Replace Deprecated Android Kotlin Extensions and Others

This commit is contained in:
Florian Märkl 2021-01-15 14:36:29 +01:00
commit 402782b4af
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
17 changed files with 215 additions and 184 deletions

View file

@ -1,6 +1,6 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
def rootCMakeLists = "../../CMakeLists.txt" def rootCMakeLists = "../../CMakeLists.txt"
@ -38,6 +38,9 @@ android {
} }
} }
} }
buildFeatures {
viewBinding true
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
@ -61,6 +64,7 @@ android {
} }
} }
Properties properties = new Properties() Properties properties = new Properties()
def propertiesFile = file("../local.properties") def propertiesFile = file("../local.properties")
if (propertiesFile.exists()) { if (propertiesFile.exists()) {
@ -86,11 +90,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
} }
} }
androidExtensions {
// for @Parcelize
experimental = true
}
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

View file

@ -3,8 +3,7 @@ package com.metallic.chiaki.lib
import android.os.Parcelable import android.os.Parcelable
import android.util.Log import android.util.Log
import android.view.Surface import android.view.Surface
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.parcelize.Parcelize
import kotlinx.android.parcel.Parcelize
import java.lang.Exception import java.lang.Exception
import java.net.InetSocketAddress import java.net.InetSocketAddress
import kotlin.math.abs import kotlin.math.abs

View file

@ -3,6 +3,7 @@
package com.metallic.chiaki.main package com.metallic.chiaki.main
import android.util.Log import android.util.Log
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
@ -16,8 +17,8 @@ import com.metallic.chiaki.common.DiscoveredDisplayHost
import com.metallic.chiaki.common.DisplayHost import com.metallic.chiaki.common.DisplayHost
import com.metallic.chiaki.common.ManualDisplayHost import com.metallic.chiaki.common.ManualDisplayHost
import com.metallic.chiaki.common.ext.inflate import com.metallic.chiaki.common.ext.inflate
import com.metallic.chiaki.databinding.ItemDisplayHostBinding
import com.metallic.chiaki.lib.DiscoveryHost import com.metallic.chiaki.lib.DiscoveryHost
import kotlinx.android.synthetic.main.item_display_host.view.*
class DisplayHostDiffCallback(val old: List<DisplayHost>, val new: List<DisplayHost>): DiffUtil.Callback() class DisplayHostDiffCallback(val old: List<DisplayHost>, val new: List<DisplayHost>): DiffUtil.Callback()
{ {
@ -42,10 +43,10 @@ class DisplayHostRecyclerViewAdapter(
diff.dispatchUpdatesTo(this) diff.dispatchUpdatesTo(this)
} }
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) class ViewHolder(val binding: ItemDisplayHostBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= ViewHolder(parent.inflate(R.layout.item_display_host)) = ViewHolder(ItemDisplayHostBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun getItemCount() = hosts.count() override fun getItemCount() = hosts.count()
@ -53,7 +54,7 @@ class DisplayHostRecyclerViewAdapter(
{ {
val context = holder.itemView.context val context = holder.itemView.context
val host = hosts[position] val host = hosts[position]
holder.itemView.also { holder.binding.also {
it.nameTextView.text = host.name it.nameTextView.text = host.name
it.hostTextView.text = context.getString(R.string.display_host_host, host.host) it.hostTextView.text = context.getString(R.string.display_host_host, host.host)
val id = host.id val id = host.id
@ -87,7 +88,7 @@ class DisplayHostRecyclerViewAdapter(
else -> R.drawable.ic_console else -> R.drawable.ic_console
} }
) )
it.setOnClickListener { clickCallback(host) } it.root.setOnClickListener { clickCallback(host) }
val canWakeup = host.registeredHost != null val canWakeup = host.registeredHost != null
val canEditDelete = host is ManualDisplayHost val canEditDelete = host is ManualDisplayHost

View file

@ -17,52 +17,54 @@ import com.metallic.chiaki.R
import com.metallic.chiaki.common.* import com.metallic.chiaki.common.*
import com.metallic.chiaki.common.ext.putRevealExtra import com.metallic.chiaki.common.ext.putRevealExtra
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.databinding.ActivityMainBinding
import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.lib.DiscoveryHost import com.metallic.chiaki.lib.DiscoveryHost
import com.metallic.chiaki.manualconsole.EditManualConsoleActivity import com.metallic.chiaki.manualconsole.EditManualConsoleActivity
import com.metallic.chiaki.regist.RegistActivity import com.metallic.chiaki.regist.RegistActivity
import com.metallic.chiaki.settings.SettingsActivity import com.metallic.chiaki.settings.SettingsActivity
import com.metallic.chiaki.stream.StreamActivity import com.metallic.chiaki.stream.StreamActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() class MainActivity : AppCompatActivity()
{ {
private lateinit var viewModel: MainViewModel private lateinit var viewModel: MainViewModel
private lateinit var binding: ActivityMainBinding
private var discoveryMenuItem: MenuItem? = null private var discoveryMenuItem: MenuItem? = null
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
{ {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
title = "" title = ""
setSupportActionBar(toolbar) setSupportActionBar(binding.toolbar)
floatingActionButton.setOnClickListener { binding.floatingActionButton.setOnClickListener {
expandFloatingActionButton(!floatingActionButton.isExpanded) expandFloatingActionButton(!binding.floatingActionButton.isExpanded)
} }
floatingActionButtonDialBackground.setOnClickListener { binding.floatingActionButtonDialBackground.setOnClickListener {
expandFloatingActionButton(false) expandFloatingActionButton(false)
} }
addManualButton.setOnClickListener { addManualConsole() } binding.addManualButton.setOnClickListener { addManualConsole() }
addManualLabelButton.setOnClickListener { addManualConsole() } binding.addManualLabelButton.setOnClickListener { addManualConsole() }
registerButton.setOnClickListener { showRegistration() } binding.registerButton.setOnClickListener { showRegistration() }
registerLabelButton.setOnClickListener { showRegistration() } binding.registerLabelButton.setOnClickListener { showRegistration() }
viewModel = ViewModelProvider(this, viewModelFactory { MainViewModel(getDatabase(this), Preferences(this)) }) viewModel = ViewModelProvider(this, viewModelFactory { MainViewModel(getDatabase(this), Preferences(this)) })
.get(MainViewModel::class.java) .get(MainViewModel::class.java)
val recyclerViewAdapter = DisplayHostRecyclerViewAdapter(this::hostTriggered, this::wakeupHost, this::editHost, this::deleteHost) val recyclerViewAdapter = DisplayHostRecyclerViewAdapter(this::hostTriggered, this::wakeupHost, this::editHost, this::deleteHost)
hostsRecyclerView.adapter = recyclerViewAdapter binding.hostsRecyclerView.adapter = recyclerViewAdapter
hostsRecyclerView.layoutManager = LinearLayoutManager(this) binding.hostsRecyclerView.layoutManager = LinearLayoutManager(this)
viewModel.displayHosts.observe(this, Observer { viewModel.displayHosts.observe(this, Observer {
val top = hostsRecyclerView.computeVerticalScrollOffset() == 0 val top = binding.hostsRecyclerView.computeVerticalScrollOffset() == 0
recyclerViewAdapter.hosts = it recyclerViewAdapter.hosts = it
if(top) if(top)
hostsRecyclerView.scrollToPosition(0) binding.hostsRecyclerView.scrollToPosition(0)
updateEmptyInfo() updateEmptyInfo()
}) })
@ -76,19 +78,19 @@ class MainActivity : AppCompatActivity()
{ {
if(viewModel.displayHosts.value?.isEmpty() ?: true) if(viewModel.displayHosts.value?.isEmpty() ?: true)
{ {
emptyInfoLayout.visibility = View.VISIBLE binding.emptyInfoLayout.visibility = View.VISIBLE
val discoveryActive = viewModel.discoveryActive.value ?: false val discoveryActive = viewModel.discoveryActive.value ?: false
emptyInfoImageView.setImageResource(if(discoveryActive) R.drawable.ic_discover_on else R.drawable.ic_discover_off) binding.emptyInfoImageView.setImageResource(if(discoveryActive) R.drawable.ic_discover_on else R.drawable.ic_discover_off)
emptyInfoTextView.setText(if(discoveryActive) R.string.display_hosts_empty_discovery_on_info else R.string.display_hosts_empty_discovery_off_info) binding.emptyInfoTextView.setText(if(discoveryActive) R.string.display_hosts_empty_discovery_on_info else R.string.display_hosts_empty_discovery_off_info)
} }
else else
emptyInfoLayout.visibility = View.GONE binding.emptyInfoLayout.visibility = View.GONE
} }
private fun expandFloatingActionButton(expand: Boolean) private fun expandFloatingActionButton(expand: Boolean)
{ {
floatingActionButton.isExpanded = expand binding.floatingActionButton.isExpanded = expand
floatingActionButton.isActivated = floatingActionButton.isExpanded binding.floatingActionButton.isActivated = binding.floatingActionButton.isExpanded
} }
override fun onStart() override fun onStart()
@ -105,7 +107,7 @@ class MainActivity : AppCompatActivity()
override fun onBackPressed() override fun onBackPressed()
{ {
if(floatingActionButton.isExpanded) if(binding.floatingActionButton.isExpanded)
{ {
expandFloatingActionButton(false) expandFloatingActionButton(false)
return return
@ -151,7 +153,7 @@ class MainActivity : AppCompatActivity()
private fun addManualConsole() private fun addManualConsole()
{ {
Intent(this, EditManualConsoleActivity::class.java).also { Intent(this, EditManualConsoleActivity::class.java).also {
it.putRevealExtra(addManualButton, rootLayout) it.putRevealExtra(binding.addManualButton, binding.rootLayout)
startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
} }
} }
@ -159,7 +161,7 @@ class MainActivity : AppCompatActivity()
private fun showRegistration() private fun showRegistration()
{ {
Intent(this, RegistActivity::class.java).also { Intent(this, RegistActivity::class.java).also {
it.putRevealExtra(registerButton, rootLayout) it.putRevealExtra(binding.registerButton, binding.rootLayout)
startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
} }
} }

View file

@ -16,10 +16,10 @@ import com.metallic.chiaki.common.RegisteredHost
import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.common.ext.RevealActivity
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.databinding.ActivityEditManualBinding
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.addTo
import kotlinx.android.synthetic.main.activity_edit_manual.*
class EditManualConsoleActivity: AppCompatActivity(), RevealActivity class EditManualConsoleActivity: AppCompatActivity(), RevealActivity
{ {
@ -28,18 +28,20 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity
const val EXTRA_MANUAL_HOST_ID = "manual_host_id" const val EXTRA_MANUAL_HOST_ID = "manual_host_id"
} }
override val revealIntent: Intent get() = intent
override val revealRootLayout: View get() = rootLayout
override val revealWindow: Window get() = window
private lateinit var viewModel: EditManualConsoleViewModel private lateinit var viewModel: EditManualConsoleViewModel
private lateinit var binding: ActivityEditManualBinding
override val revealIntent: Intent get() = intent
override val revealRootLayout: View get() = binding.rootLayout
override val revealWindow: Window get() = window
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
{ {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_manual) binding = ActivityEditManualBinding.inflate(layoutInflater)
setContentView(binding.root)
handleReveal() handleReveal()
viewModel = ViewModelProvider(this, viewModelFactory { viewModel = ViewModelProvider(this, viewModelFactory {
@ -52,17 +54,17 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity
.get(EditManualConsoleViewModel::class.java) .get(EditManualConsoleViewModel::class.java)
viewModel.existingHost?.observe(this, Observer { viewModel.existingHost?.observe(this, Observer {
hostEditText.setText(it.host) binding.hostEditText.setText(it.host)
}) })
viewModel.selectedRegisteredHost.observe(this, Observer { viewModel.selectedRegisteredHost.observe(this, Observer {
registeredHostTextView.setText(titleForRegisteredHost(it)) binding.registeredHostTextView.setText(titleForRegisteredHost(it))
}) })
viewModel.registeredHosts.observe(this, Observer { hosts -> viewModel.registeredHosts.observe(this, Observer { hosts ->
registeredHostTextView.setAdapter(ArrayAdapter<String>(this, R.layout.dropdown_menu_popup_item, binding.registeredHostTextView.setAdapter(ArrayAdapter<String>(this, R.layout.dropdown_menu_popup_item,
hosts.map { titleForRegisteredHost(it) })) hosts.map { titleForRegisteredHost(it) }))
registeredHostTextView.onItemClickListener = object: AdapterView.OnItemClickListener { binding.registeredHostTextView.onItemClickListener = object: AdapterView.OnItemClickListener {
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long)
{ {
if(position >= hosts.size) if(position >= hosts.size)
@ -73,8 +75,7 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity
} }
}) })
binding.saveButton.setOnClickListener { saveHost() }
saveButton.setOnClickListener { saveHost() }
} }
private fun titleForRegisteredHost(registeredHost: RegisteredHost?) = private fun titleForRegisteredHost(registeredHost: RegisteredHost?) =
@ -85,14 +86,14 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity
private fun saveHost() private fun saveHost()
{ {
val host = hostEditText.text.toString().trim() val host = binding.hostEditText.text.toString().trim()
if(host.isEmpty()) if(host.isEmpty())
{ {
hostEditText.error = getString(R.string.entered_host_invalid) binding.hostEditText.error = getString(R.string.entered_host_invalid)
return return
} }
saveButton.isEnabled = false binding.saveButton.isEnabled = false
viewModel.saveHost(host) viewModel.saveHost(host)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {

View file

@ -12,9 +12,9 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.common.ext.RevealActivity
import com.metallic.chiaki.databinding.ActivityRegistBinding
import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.RegistInfo
import com.metallic.chiaki.lib.Target import com.metallic.chiaki.lib.Target
import kotlinx.android.synthetic.main.activity_regist.*
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
class RegistActivity: AppCompatActivity(), RevealActivity class RegistActivity: AppCompatActivity(), RevealActivity
@ -30,33 +30,35 @@ class RegistActivity: AppCompatActivity(), RevealActivity
private const val REQUEST_REGIST = 1 private const val REQUEST_REGIST = 1
} }
private lateinit var viewModel: RegistViewModel
private lateinit var binding: ActivityRegistBinding
override val revealWindow: Window get() = window override val revealWindow: Window get() = window
override val revealIntent: Intent get() = intent override val revealIntent: Intent get() = intent
override val revealRootLayout: View get() = rootLayout override val revealRootLayout: View get() = binding.rootLayout
private lateinit var viewModel: RegistViewModel
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
{ {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityRegistBinding.inflate(layoutInflater)
setContentView(R.layout.activity_regist) setContentView(R.layout.activity_regist)
handleReveal() handleReveal()
viewModel = ViewModelProvider(this).get(RegistViewModel::class.java) viewModel = ViewModelProvider(this).get(RegistViewModel::class.java)
hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255") binding.hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255")
broadcastCheckBox.isChecked = intent.getBooleanExtra(EXTRA_BROADCAST, true) binding.broadcastCheckBox.isChecked = intent.getBooleanExtra(EXTRA_BROADCAST, true)
registButton.setOnClickListener { doRegist() } binding.registButton.setOnClickListener { doRegist() }
ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5) { binding.ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5) {
RegistViewModel.ConsoleVersion.PS5 -> R.id.ps5RadioButton RegistViewModel.ConsoleVersion.PS5 -> R.id.ps5RadioButton
RegistViewModel.ConsoleVersion.PS4_GE_8 -> R.id.ps4VersionGE8RadioButton RegistViewModel.ConsoleVersion.PS4_GE_8 -> R.id.ps4VersionGE8RadioButton
RegistViewModel.ConsoleVersion.PS4_GE_7 -> R.id.ps4VersionGE7RadioButton RegistViewModel.ConsoleVersion.PS4_GE_7 -> R.id.ps4VersionGE7RadioButton
RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.id.ps4VersionLT7RadioButton RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.id.ps4VersionLT7RadioButton
}) })
ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> binding.ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId ->
viewModel.ps4Version.value = when(checkedId) viewModel.ps4Version.value = when(checkedId)
{ {
R.id.ps5RadioButton -> RegistViewModel.ConsoleVersion.PS5 R.id.ps5RadioButton -> RegistViewModel.ConsoleVersion.PS5
@ -68,14 +70,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity
} }
viewModel.ps4Version.observe(this, Observer { viewModel.ps4Version.observe(this, Observer {
psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE binding.psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE
psnIdTextInputLayout.hint = getString(when(it!!) binding.psnIdTextInputLayout.hint = getString(when(it!!)
{ {
RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.string.hint_regist_psn_online_id RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.string.hint_regist_psn_online_id
else -> R.string.hint_regist_psn_account_id else -> R.string.hint_regist_psn_account_id
}) })
pinHelpBeforeTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_before else R.string.regist_pin_instructions_ps4_before) binding.pinHelpBeforeTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_before else R.string.regist_pin_instructions_ps4_before)
pinHelpNavigationTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_navigation else R.string.regist_pin_instructions_ps4_navigation) binding.pinHelpNavigationTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_navigation else R.string.regist_pin_instructions_ps4_navigation)
}) })
} }
@ -83,11 +85,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity
{ {
val ps4Version = viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5 val ps4Version = viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5
val host = hostEditText.text.toString().trim() val host = binding.hostEditText.text.toString().trim()
val hostValid = host.isNotEmpty() val hostValid = host.isNotEmpty()
val broadcast = broadcastCheckBox.isChecked val broadcast = binding.broadcastCheckBox.isChecked
val psnId = psnIdEditText.text.toString().trim() val psnId = binding.psnIdEditText.text.toString().trim()
val psnOnlineId: String? = if(ps4Version == RegistViewModel.ConsoleVersion.PS4_LT_7) psnId else null val psnOnlineId: String? = if(ps4Version == RegistViewModel.ConsoleVersion.PS4_LT_7) psnId else null
val psnAccountId: ByteArray? = val psnAccountId: ByteArray? =
if(ps4Version != RegistViewModel.ConsoleVersion.PS4_LT_7) if(ps4Version != RegistViewModel.ConsoleVersion.PS4_LT_7)
@ -101,11 +103,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity
} }
val pin = pinEditText.text.toString() val pin = binding.pinEditText.text.toString()
val pinValid = pin.length == PIN_LENGTH val pinValid = pin.length == PIN_LENGTH
hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null binding.hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null
psnIdEditText.error = binding.psnIdEditText.error =
if(!psnIdValid) if(!psnIdValid)
getString(when(ps4Version) getString(when(ps4Version)
{ {
@ -114,7 +116,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity
}) })
else else
null null
pinEditText.error = if(!pinValid) getString(R.string.regist_pin_invalid, PIN_LENGTH) else null binding.pinEditText.error = if(!pinValid) getString(R.string.regist_pin_invalid, PIN_LENGTH) else null
if(!hostValid || !psnIdValid || !pinValid) if(!hostValid || !psnIdValid || !pinValid)
return return

View file

@ -16,8 +16,8 @@ import com.metallic.chiaki.R
import com.metallic.chiaki.common.MacAddress import com.metallic.chiaki.common.MacAddress
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.databinding.ActivityRegistExecuteBinding
import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.RegistInfo
import kotlinx.android.synthetic.main.activity_regist_execute.*
import kotlin.math.max import kotlin.math.max
class RegistExecuteActivity: AppCompatActivity() class RegistExecuteActivity: AppCompatActivity()
@ -31,55 +31,57 @@ class RegistExecuteActivity: AppCompatActivity()
} }
private lateinit var viewModel: RegistExecuteViewModel private lateinit var viewModel: RegistExecuteViewModel
private lateinit var binding: ActivityRegistExecuteBinding
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
{ {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_regist_execute) binding = ActivityRegistExecuteBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(this, viewModelFactory { RegistExecuteViewModel(getDatabase(this)) }) viewModel = ViewModelProvider(this, viewModelFactory { RegistExecuteViewModel(getDatabase(this)) })
.get(RegistExecuteViewModel::class.java) .get(RegistExecuteViewModel::class.java)
logTextView.setHorizontallyScrolling(true) binding.logTextView.setHorizontallyScrolling(true)
logTextView.movementMethod = ScrollingMovementMethod() binding.logTextView.movementMethod = ScrollingMovementMethod()
viewModel.logText.observe(this, Observer { viewModel.logText.observe(this, Observer {
val textLayout = logTextView.layout ?: return@Observer val textLayout = binding.logTextView.layout ?: return@Observer
val lineCount = textLayout.lineCount val lineCount = textLayout.lineCount
if(lineCount < 1) if(lineCount < 1)
return@Observer return@Observer
logTextView.text = it binding.logTextView.text = it
val scrollY = textLayout.getLineBottom(lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom val scrollY = textLayout.getLineBottom(lineCount - 1) - binding.logTextView.height + binding.logTextView.paddingTop + binding.logTextView.paddingBottom
logTextView.scrollTo(0, max(scrollY, 0)) binding.logTextView.scrollTo(0, max(scrollY, 0))
}) })
viewModel.state.observe(this, Observer { viewModel.state.observe(this, Observer {
progressBar.visibility = if(it == RegistExecuteViewModel.State.RUNNING) View.VISIBLE else View.GONE binding.progressBar.visibility = if(it == RegistExecuteViewModel.State.RUNNING) View.VISIBLE else View.GONE
when(it) when(it)
{ {
RegistExecuteViewModel.State.FAILED -> RegistExecuteViewModel.State.FAILED ->
{ {
infoTextView.visibility = View.VISIBLE binding.infoTextView.visibility = View.VISIBLE
infoTextView.setText(R.string.regist_info_failed) binding.infoTextView.setText(R.string.regist_info_failed)
setResult(RESULT_FAILED) setResult(RESULT_FAILED)
} }
RegistExecuteViewModel.State.SUCCESSFUL, RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE -> RegistExecuteViewModel.State.SUCCESSFUL, RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE ->
{ {
infoTextView.visibility = View.VISIBLE binding.infoTextView.visibility = View.VISIBLE
infoTextView.setText(R.string.regist_info_success) binding.infoTextView.setText(R.string.regist_info_success)
setResult(RESULT_OK) setResult(RESULT_OK)
if(it == RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE) if(it == RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE)
showDuplicateDialog() showDuplicateDialog()
} }
RegistExecuteViewModel.State.STOPPED -> RegistExecuteViewModel.State.STOPPED ->
{ {
infoTextView.visibility = View.GONE binding.infoTextView.visibility = View.GONE
setResult(Activity.RESULT_CANCELED) setResult(Activity.RESULT_CANCELED)
} }
else -> infoTextView.visibility = View.GONE else -> binding.infoTextView.visibility = View.GONE
} }
}) })
shareLogButton.setOnClickListener { binding.shareLogButton.setOnClickListener {
val log = viewModel.logText.value ?: "" val log = viewModel.logText.value ?: ""
Intent(Intent.ACTION_SEND).also { Intent(Intent.ACTION_SEND).also {
it.type = "text/plain" it.type = "text/plain"

View file

@ -19,6 +19,7 @@ class StreamInput(val context: Context, val preferences: Preferences)
val controllerState = sensorControllerState or keyControllerState or motionControllerState val controllerState = sensorControllerState or keyControllerState or motionControllerState
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
@Suppress("DEPRECATION")
when(windowManager.defaultDisplay.rotation) when(windowManager.defaultDisplay.rotation)
{ {
Surface.ROTATION_90 -> { Surface.ROTATION_90 -> {
@ -175,7 +176,7 @@ class StreamInput(val context: Context, val preferences: Preferences)
{ {
if(event.source and InputDevice.SOURCE_CLASS_JOYSTICK != InputDevice.SOURCE_CLASS_JOYSTICK) if(event.source and InputDevice.SOURCE_CLASS_JOYSTICK != InputDevice.SOURCE_CLASS_JOYSTICK)
return false return false
fun Float.signedAxis() = (this * Short.MAX_VALUE).toShort() fun Float.signedAxis() = (this * Short.MAX_VALUE).toInt().toShort()
fun Float.unsignedAxis() = (this * UByte.MAX_VALUE.toFloat()).toUInt().toUByte() fun Float.unsignedAxis() = (this * UByte.MAX_VALUE.toFloat()).toUInt().toUByte()
motionControllerState.leftX = event.getAxisValue(MotionEvent.AXIS_X).signedAxis() motionControllerState.leftX = event.getAxisValue(MotionEvent.AXIS_X).signedAxis()
motionControllerState.leftY = event.getAxisValue(MotionEvent.AXIS_Y).signedAxis() motionControllerState.leftY = event.getAxisValue(MotionEvent.AXIS_Y).signedAxis()

View file

@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.metallic.chiaki.R import com.metallic.chiaki.R
import kotlinx.android.synthetic.main.activity_settings.* import com.metallic.chiaki.databinding.ActivitySettingsBinding
interface TitleFragment interface TitleFragment
{ {
@ -18,20 +18,23 @@ interface TitleFragment
class SettingsActivity: AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback class SettingsActivity: AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{ {
private lateinit var binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
{ {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings) binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
title = "" title = ""
setSupportActionBar(toolbar) setSupportActionBar(binding.toolbar)
val rootFragment = SettingsFragment() val rootFragment = SettingsFragment()
replaceFragment(rootFragment, false) replaceFragment(rootFragment, false)
supportFragmentManager.addOnBackStackChangedListener { supportFragmentManager.addOnBackStackChangedListener {
val titleFragment = supportFragmentManager.findFragmentById(R.id.settingsFragment) as? TitleFragment ?: return@addOnBackStackChangedListener val titleFragment = supportFragmentManager.findFragmentById(R.id.settingsFragment) as? TitleFragment ?: return@addOnBackStackChangedListener
titleTextView.text = titleFragment.getTitle(resources) binding.titleTextView.text = titleFragment.getTitle(resources)
} }
titleTextView.text = rootFragment.getTitle(resources) binding.titleTextView.text = rootFragment.getTitle(resources)
} }
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference) = when(pref.fragment) override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference) = when(pref.fragment)

View file

@ -16,7 +16,6 @@ import com.metallic.chiaki.common.exportAndShareAllSettings
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.common.importSettingsFromUri import com.metallic.chiaki.common.importSettingsFromUri
import com.metallic.chiaki.lib.Codec
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.addTo

View file

@ -2,13 +2,13 @@
package com.metallic.chiaki.settings package com.metallic.chiaki.settings
import android.view.View import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.common.LogFile import com.metallic.chiaki.common.LogFile
import com.metallic.chiaki.common.ext.inflate import com.metallic.chiaki.common.ext.inflate
import kotlinx.android.synthetic.main.item_log_file.view.* import com.metallic.chiaki.databinding.ItemLogFileBinding
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -20,7 +20,7 @@ class SettingsLogsAdapter: RecyclerView.Adapter<SettingsLogsAdapter.ViewHolder>(
private val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT) private val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
private val timeFormat = SimpleDateFormat("HH:mm:ss:SSS", Locale.getDefault()) private val timeFormat = SimpleDateFormat("HH:mm:ss:SSS", Locale.getDefault())
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) class ViewHolder(val binding: ItemLogFileBinding): RecyclerView.ViewHolder(binding.root)
var logFiles: List<LogFile> = listOf() var logFiles: List<LogFile> = listOf()
set(value) set(value)
@ -29,16 +29,16 @@ class SettingsLogsAdapter: RecyclerView.Adapter<SettingsLogsAdapter.ViewHolder>(
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_log_file)) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
ViewHolder(ItemLogFileBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun getItemCount() = logFiles.size override fun getItemCount() = logFiles.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) override fun onBindViewHolder(holder: ViewHolder, position: Int)
{ {
val view = holder.itemView
val logFile = logFiles[position] val logFile = logFiles[position]
view.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}" holder.binding.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}"
view.summaryTextView.text = logFile.filename holder.binding.summaryTextView.text = logFile.filename
view.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } } holder.binding.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } }
} }
} }

View file

@ -21,29 +21,35 @@ import com.metallic.chiaki.common.LogFile
import com.metallic.chiaki.common.LogManager import com.metallic.chiaki.common.LogManager
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.fileProviderAuthority import com.metallic.chiaki.common.fileProviderAuthority
import kotlinx.android.synthetic.main.fragment_settings_logs.* import com.metallic.chiaki.databinding.FragmentSettingsLogsBinding
class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment
{ {
private lateinit var viewModel: SettingsLogsViewModel private lateinit var viewModel: SettingsLogsViewModel
private var _binding: FragmentSettingsLogsBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
inflater.inflate(R.layout.fragment_settings_logs, container, false) FragmentSettingsLogsBinding.inflate(inflater, container, false).let {
_binding = it
it.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{ {
val context = context!! val context = requireContext()
viewModel = ViewModelProvider(this, viewModelFactory { SettingsLogsViewModel(LogManager(context)) }) viewModel = ViewModelProvider(this, viewModelFactory { SettingsLogsViewModel(LogManager(context)) })
.get(SettingsLogsViewModel::class.java) .get(SettingsLogsViewModel::class.java)
val adapter = SettingsLogsAdapter() val adapter = SettingsLogsAdapter()
logsRecyclerView.layoutManager = LinearLayoutManager(context) binding.logsRecyclerView.layoutManager = LinearLayoutManager(context)
logsRecyclerView.adapter = adapter binding.logsRecyclerView.adapter = adapter
adapter.shareCallback = this::shareLogFile adapter.shareCallback = this::shareLogFile
viewModel.sessionLogs.observe(viewLifecycleOwner, Observer { viewModel.sessionLogs.observe(viewLifecycleOwner, Observer {
adapter.logFiles = it adapter.logFiles = it
emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE binding.emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE
}) })
val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context) val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context)
@ -55,7 +61,7 @@ class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment
viewModel.deleteLog(file) viewModel.deleteLog(file)
} }
} }
ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(logsRecyclerView) ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(binding.logsRecyclerView)
} }
override fun getTitle(resources: Resources): String = resources.getString(R.string.preferences_logs_title) override fun getTitle(resources: Resources): String = resources.getString(R.string.preferences_logs_title)

View file

@ -2,17 +2,15 @@
package com.metallic.chiaki.settings package com.metallic.chiaki.settings
import android.view.View import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.metallic.chiaki.R
import com.metallic.chiaki.common.RegisteredHost import com.metallic.chiaki.common.RegisteredHost
import com.metallic.chiaki.common.ext.inflate import com.metallic.chiaki.databinding.ItemRegisteredHostBinding
import kotlinx.android.synthetic.main.item_registered_host.view.*
class SettingsRegisteredHostsAdapter: RecyclerView.Adapter<SettingsRegisteredHostsAdapter.ViewHolder>() class SettingsRegisteredHostsAdapter: RecyclerView.Adapter<SettingsRegisteredHostsAdapter.ViewHolder>()
{ {
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) class ViewHolder(val binding: ItemRegisteredHostBinding): RecyclerView.ViewHolder(binding.root)
var hosts: List<RegisteredHost> = listOf() var hosts: List<RegisteredHost> = listOf()
set(value) set(value)
@ -21,15 +19,15 @@ class SettingsRegisteredHostsAdapter: RecyclerView.Adapter<SettingsRegisteredHos
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_registered_host)) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
= ViewHolder(ItemRegisteredHostBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun getItemCount() = hosts.size override fun getItemCount() = hosts.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) override fun onBindViewHolder(holder: ViewHolder, position: Int)
{ {
val view = holder.itemView
val host = hosts[position] val host = hosts[position]
view.nameTextView.text = "${host.serverNickname} (${if(host.target.isPS5) "PS5" else "PS4"})" holder.binding.nameTextView.text = "${host.serverNickname} (${if(host.target.isPS5) "PS5" else "PS4"})"
view.summaryTextView.text = host.serverMac.toString() holder.binding.summaryTextView.text = host.serverMac.toString()
} }
} }

View file

@ -20,25 +20,32 @@ import com.metallic.chiaki.R
import com.metallic.chiaki.common.ext.putRevealExtra import com.metallic.chiaki.common.ext.putRevealExtra
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.databinding.FragmentSettingsRegisteredHostsBinding
import com.metallic.chiaki.regist.RegistActivity import com.metallic.chiaki.regist.RegistActivity
import kotlinx.android.synthetic.main.fragment_settings_registered_hosts.*
class SettingsRegisteredHostsFragment: AppCompatDialogFragment(), TitleFragment class SettingsRegisteredHostsFragment: AppCompatDialogFragment(), TitleFragment
{ {
private lateinit var viewModel: SettingsRegisteredHostsViewModel private lateinit var viewModel: SettingsRegisteredHostsViewModel
private var _binding: FragmentSettingsRegisteredHostsBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
inflater.inflate(R.layout.fragment_settings_registered_hosts, container, false) FragmentSettingsRegisteredHostsBinding.inflate(inflater, container, false).let {
_binding = it
it.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{ {
viewModel = ViewModelProvider(this, viewModelFactory { SettingsRegisteredHostsViewModel(getDatabase(context!!)) }) val context = requireContext()
viewModel = ViewModelProvider(this, viewModelFactory { SettingsRegisteredHostsViewModel(getDatabase(context)) })
.get(SettingsRegisteredHostsViewModel::class.java) .get(SettingsRegisteredHostsViewModel::class.java)
val adapter = SettingsRegisteredHostsAdapter() val adapter = SettingsRegisteredHostsAdapter()
hostsRecyclerView.layoutManager = LinearLayoutManager(context) binding.hostsRecyclerView.layoutManager = LinearLayoutManager(context)
hostsRecyclerView.adapter = adapter binding.hostsRecyclerView.adapter = adapter
val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context!!) val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context)
{ {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int)
{ {
@ -56,15 +63,15 @@ class SettingsRegisteredHostsFragment: AppCompatDialogFragment(), TitleFragment
.show() .show()
} }
} }
ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(hostsRecyclerView) ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(binding.hostsRecyclerView)
viewModel.registeredHosts.observe(this, Observer { viewModel.registeredHosts.observe(this, Observer {
adapter.hosts = it adapter.hosts = it
emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE binding.emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE
}) })
floatingActionButton.setOnClickListener { binding.floatingActionButton.setOnClickListener {
Intent(context, RegistActivity::class.java).also { Intent(context, RegistActivity::class.java).also {
it.putRevealExtra(floatingActionButton, rootLayout) it.putRevealExtra(binding.floatingActionButton, binding.rootLayout)
startActivity(it, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle()) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle())
} }
} }

View file

@ -7,12 +7,9 @@ import android.animation.AnimatorListenerAdapter
import android.app.AlertDialog import android.app.AlertDialog
import android.graphics.Matrix import android.graphics.Matrix
import android.os.* import android.os.*
import android.transition.TransitionManager
import android.view.* import android.view.*
import android.widget.EditText import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -21,12 +18,12 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.databinding.ActivityStreamBinding
import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.lib.ConnectVideoProfile import com.metallic.chiaki.lib.ConnectVideoProfile
import com.metallic.chiaki.session.* import com.metallic.chiaki.session.*
import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment
import com.metallic.chiaki.touchcontrols.TouchControlsFragment import com.metallic.chiaki.touchcontrols.TouchControlsFragment
import kotlinx.android.synthetic.main.activity_stream.* import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment
import kotlin.math.min import kotlin.math.min
private sealed class DialogContents private sealed class DialogContents
@ -43,6 +40,8 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
} }
private lateinit var viewModel: StreamViewModel private lateinit var viewModel: StreamViewModel
private lateinit var binding: ActivityStreamBinding
private val uiVisibilityHandler = Handler() private val uiVisibilityHandler = Handler()
override fun onCreate(savedInstanceState: Bundle?) override fun onCreate(savedInstanceState: Bundle?)
@ -62,38 +61,39 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
viewModel.input.observe(this) viewModel.input.observe(this)
setContentView(R.layout.activity_stream) binding = ActivityStreamBinding.inflate(layoutInflater)
setContentView(binding.root)
window.decorView.setOnSystemUiVisibilityChangeListener(this) window.decorView.setOnSystemUiVisibilityChangeListener(this)
viewModel.onScreenControlsEnabled.observe(this, Observer { viewModel.onScreenControlsEnabled.observe(this, Observer {
if(onScreenControlsSwitch.isChecked != it) if(binding.onScreenControlsSwitch.isChecked != it)
onScreenControlsSwitch.isChecked = it binding.onScreenControlsSwitch.isChecked = it
if(onScreenControlsSwitch.isChecked) if(binding.onScreenControlsSwitch.isChecked)
touchpadOnlySwitch.isChecked = false binding.touchpadOnlySwitch.isChecked = false
}) })
onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked -> binding.onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked ->
viewModel.setOnScreenControlsEnabled(isChecked) viewModel.setOnScreenControlsEnabled(isChecked)
showOverlay() showOverlay()
} }
viewModel.touchpadOnlyEnabled.observe(this, Observer { viewModel.touchpadOnlyEnabled.observe(this, Observer {
if(touchpadOnlySwitch.isChecked != it) if(binding.touchpadOnlySwitch.isChecked != it)
touchpadOnlySwitch.isChecked = it binding.touchpadOnlySwitch.isChecked = it
if(touchpadOnlySwitch.isChecked) if(binding.touchpadOnlySwitch.isChecked)
onScreenControlsSwitch.isChecked = false binding.onScreenControlsSwitch.isChecked = false
}) })
touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked -> binding.touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked ->
viewModel.setTouchpadOnlyEnabled(isChecked) viewModel.setTouchpadOnlyEnabled(isChecked)
showOverlay() showOverlay()
} }
displayModeToggle.addOnButtonCheckedListener { _, _, _ -> binding.displayModeToggle.addOnButtonCheckedListener { _, _, _ ->
adjustStreamViewAspect() adjustStreamViewAspect()
showOverlay() showOverlay()
} }
//viewModel.session.attachToTextureView(textureView) //viewModel.session.attachToTextureView(textureView)
viewModel.session.attachToSurfaceView(surfaceView) viewModel.session.attachToSurfaceView(binding.surfaceView)
viewModel.session.state.observe(this, Observer { this.stateChanged(it) }) viewModel.session.state.observe(this, Observer { this.stateChanged(it) })
adjustStreamViewAspect() adjustStreamViewAspect()
@ -159,14 +159,14 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun showOverlay() private fun showOverlay()
{ {
overlay.isVisible = true binding.overlay.isVisible = true
overlay.animate() binding.overlay.animate()
.alpha(1.0f) .alpha(1.0f)
.setListener(object: AnimatorListenerAdapter() .setListener(object: AnimatorListenerAdapter()
{ {
override fun onAnimationEnd(animation: Animator?) override fun onAnimationEnd(animation: Animator?)
{ {
overlay.alpha = 1.0f binding.overlay.alpha = 1.0f
} }
}) })
uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable) uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable)
@ -175,13 +175,13 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun hideOverlay() private fun hideOverlay()
{ {
overlay.animate() binding.overlay.animate()
.alpha(0.0f) .alpha(0.0f)
.setListener(object: AnimatorListenerAdapter() .setListener(object: AnimatorListenerAdapter()
{ {
override fun onAnimationEnd(animation: Animator?) override fun onAnimationEnd(animation: Animator?)
{ {
overlay.isGone = true binding.overlay.isGone = true
} }
}) })
} }
@ -214,7 +214,7 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun stateChanged(state: StreamState) private fun stateChanged(state: StreamState)
{ {
progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE binding.progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE
when(state) when(state)
{ {
@ -302,7 +302,7 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun adjustTextureViewAspect(textureView: TextureView) private fun adjustTextureViewAspect(textureView: TextureView)
{ {
val trans = TextureViewTransform(viewModel.session.connectInfo.videoProfile, textureView) val trans = TextureViewTransform(viewModel.session.connectInfo.videoProfile, textureView)
val resolution = trans.resolutionFor(TransformMode.fromButton(displayModeToggle.checkedButtonId)) val resolution = trans.resolutionFor(TransformMode.fromButton(binding.displayModeToggle.checkedButtonId))
Matrix().also { Matrix().also {
textureView.getTransform(it) textureView.getTransform(it)
it.setScale(resolution.width / trans.viewWidth, resolution.height / trans.viewHeight) it.setScale(resolution.width / trans.viewWidth, resolution.height / trans.viewHeight)
@ -314,8 +314,8 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe
private fun adjustSurfaceViewAspect() private fun adjustSurfaceViewAspect()
{ {
val videoProfile = viewModel.session.connectInfo.videoProfile val videoProfile = viewModel.session.connectInfo.videoProfile
aspectRatioLayout.aspectRatio = videoProfile.width.toFloat() / videoProfile.height.toFloat() binding.aspectRatioLayout.aspectRatio = videoProfile.width.toFloat() / videoProfile.height.toFloat()
aspectRatioLayout.mode = TransformMode.fromButton(displayModeToggle.checkedButtonId) binding.aspectRatioLayout.mode = TransformMode.fromButton(binding.displayModeToggle.checkedButtonId)
} }
private fun adjustStreamViewAspect() = adjustSurfaceViewAspect() private fun adjustStreamViewAspect() = adjustSurfaceViewAspect()

View file

@ -3,16 +3,14 @@
package com.metallic.chiaki.touchcontrols package com.metallic.chiaki.touchcontrols
import android.os.Bundle import android.os.Bundle
import android.util.Log
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.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.metallic.chiaki.R import com.metallic.chiaki.databinding.FragmentControlsBinding
import com.metallic.chiaki.lib.ControllerState import com.metallic.chiaki.lib.ControllerState
import kotlinx.android.synthetic.main.fragment_controls.*
class TouchControlsFragment : Fragment() class TouchControlsFragment : Fragment()
{ {
@ -28,44 +26,50 @@ class TouchControlsFragment : Fragment()
var controllerStateCallback: ((ControllerState) -> Unit)? = null var controllerStateCallback: ((ControllerState) -> Unit)? = null
var onScreenControlsEnabled: LiveData<Boolean>? = null var onScreenControlsEnabled: LiveData<Boolean>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View private var _binding: FragmentControlsBinding? = null
= inflater.inflate(R.layout.fragment_controls, container, false) private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
FragmentControlsBinding.inflate(inflater, container, false).let {
_binding = it
it.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{ {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
dpadView.stateChangeCallback = this::dpadStateChanged binding.dpadView.stateChangeCallback = this::dpadStateChanged
crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS) binding.crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS)
moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON) binding.moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON)
pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID) binding.pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID)
boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX) binding.boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX)
l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1) binding.l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1)
r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1) binding.r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1)
l3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L3) binding.l3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L3)
r3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R3) binding.r3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R3)
optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS) binding.optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS)
shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE) binding.shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE)
psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) binding.psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS)
touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) binding.touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD)
l2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { l2State = if(it) 255U else 0U } } binding.l2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { l2State = if(it) 255U else 0U } }
r2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { r2State = if(it) 255U else 0U } } binding.r2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { r2State = if(it) 255U else 0U } }
val quantizeStick = { f: Float -> val quantizeStick = { f: Float ->
(Short.MAX_VALUE * f).toShort() (Short.MAX_VALUE * f).toInt().toShort()
} }
leftAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { binding.leftAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply {
leftX = quantizeStick(it.x) leftX = quantizeStick(it.x)
leftY = quantizeStick(it.y) leftY = quantizeStick(it.y)
}} }}
rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { binding.rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply {
rightX = quantizeStick(it.x) rightX = quantizeStick(it.x)
rightY = quantizeStick(it.y) rightY = quantizeStick(it.y)
}} }}
onScreenControlsEnabled?.observe(this, Observer { onScreenControlsEnabled?.observe(viewLifecycleOwner, Observer {
view.visibility = if(it) View.VISIBLE else View.GONE view.visibility = if(it) View.VISIBLE else View.GONE
}) })
} }

View file

@ -10,8 +10,9 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.databinding.FragmentControlsBinding
import com.metallic.chiaki.databinding.FragmentTouchpadOnlyBinding
import com.metallic.chiaki.lib.ControllerState import com.metallic.chiaki.lib.ControllerState
import kotlinx.android.synthetic.main.fragment_controls.*
class TouchpadOnlyFragment : Fragment() class TouchpadOnlyFragment : Fragment()
{ {
@ -27,16 +28,22 @@ class TouchpadOnlyFragment : Fragment()
var controllerStateCallback: ((ControllerState) -> Unit)? = null var controllerStateCallback: ((ControllerState) -> Unit)? = null
var touchpadOnlyEnabled: LiveData<Boolean>? = null var touchpadOnlyEnabled: LiveData<Boolean>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View private var _binding: FragmentTouchpadOnlyBinding? = null
= inflater.inflate(R.layout.fragment_touchpad_only, container, false) private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
FragmentTouchpadOnlyBinding.inflate(inflater, container, false).let {
_binding = it
it.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{ {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) binding.touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD)
touchpadOnlyEnabled?.observe(this, Observer { touchpadOnlyEnabled?.observe(viewLifecycleOwner, Observer {
view.visibility = if(it) View.VISIBLE else View.GONE view.visibility = if(it) View.VISIBLE else View.GONE
}) })
} }