diff --git a/android/app/build.gradle b/android/app/build.gradle index 2b2c248..48bf54c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' def rootCMakeLists = "../../CMakeLists.txt" @@ -38,6 +38,9 @@ android { } } } + buildFeatures { + viewBinding true + } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -61,6 +64,7 @@ android { } } + Properties properties = new Properties() def propertiesFile = file("../local.properties") if (propertiesFile.exists()) { @@ -86,11 +90,6 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { } } -androidExtensions { - // for @Parcelize - experimental = true -} - dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index b8d7204..9533c7c 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -3,8 +3,7 @@ package com.metallic.chiaki.lib import android.os.Parcelable import android.util.Log import android.view.Surface -import kotlinx.android.parcel.IgnoredOnParcel -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import java.lang.Exception import java.net.InetSocketAddress import kotlin.math.abs diff --git a/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt index 0bd844e..465a2a7 100644 --- a/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt @@ -3,6 +3,7 @@ package com.metallic.chiaki.main import android.util.Log +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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.ManualDisplayHost import com.metallic.chiaki.common.ext.inflate +import com.metallic.chiaki.databinding.ItemDisplayHostBinding import com.metallic.chiaki.lib.DiscoveryHost -import kotlinx.android.synthetic.main.item_display_host.view.* class DisplayHostDiffCallback(val old: List, val new: List): DiffUtil.Callback() { @@ -42,10 +43,10 @@ class DisplayHostRecyclerViewAdapter( 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) - = ViewHolder(parent.inflate(R.layout.item_display_host)) + = ViewHolder(ItemDisplayHostBinding.inflate(LayoutInflater.from(parent.context), parent, false)) override fun getItemCount() = hosts.count() @@ -53,7 +54,7 @@ class DisplayHostRecyclerViewAdapter( { val context = holder.itemView.context val host = hosts[position] - holder.itemView.also { + holder.binding.also { it.nameTextView.text = host.name it.hostTextView.text = context.getString(R.string.display_host_host, host.host) val id = host.id @@ -87,7 +88,7 @@ class DisplayHostRecyclerViewAdapter( else -> R.drawable.ic_console } ) - it.setOnClickListener { clickCallback(host) } + it.root.setOnClickListener { clickCallback(host) } val canWakeup = host.registeredHost != null val canEditDelete = host is ManualDisplayHost diff --git a/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt b/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt index 4fd8178..5bf1f49 100644 --- a/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt @@ -17,52 +17,54 @@ import com.metallic.chiaki.R import com.metallic.chiaki.common.* import com.metallic.chiaki.common.ext.putRevealExtra import com.metallic.chiaki.common.ext.viewModelFactory +import com.metallic.chiaki.databinding.ActivityMainBinding import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.DiscoveryHost import com.metallic.chiaki.manualconsole.EditManualConsoleActivity import com.metallic.chiaki.regist.RegistActivity import com.metallic.chiaki.settings.SettingsActivity import com.metallic.chiaki.stream.StreamActivity -import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel + private lateinit var binding: ActivityMainBinding private var discoveryMenuItem: MenuItem? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) title = "" - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) - floatingActionButton.setOnClickListener { - expandFloatingActionButton(!floatingActionButton.isExpanded) + binding.floatingActionButton.setOnClickListener { + expandFloatingActionButton(!binding.floatingActionButton.isExpanded) } - floatingActionButtonDialBackground.setOnClickListener { + binding.floatingActionButtonDialBackground.setOnClickListener { expandFloatingActionButton(false) } - addManualButton.setOnClickListener { addManualConsole() } - addManualLabelButton.setOnClickListener { addManualConsole() } + binding.addManualButton.setOnClickListener { addManualConsole() } + binding.addManualLabelButton.setOnClickListener { addManualConsole() } - registerButton.setOnClickListener { showRegistration() } - registerLabelButton.setOnClickListener { showRegistration() } + binding.registerButton.setOnClickListener { showRegistration() } + binding.registerLabelButton.setOnClickListener { showRegistration() } viewModel = ViewModelProvider(this, viewModelFactory { MainViewModel(getDatabase(this), Preferences(this)) }) .get(MainViewModel::class.java) val recyclerViewAdapter = DisplayHostRecyclerViewAdapter(this::hostTriggered, this::wakeupHost, this::editHost, this::deleteHost) - hostsRecyclerView.adapter = recyclerViewAdapter - hostsRecyclerView.layoutManager = LinearLayoutManager(this) + binding.hostsRecyclerView.adapter = recyclerViewAdapter + binding.hostsRecyclerView.layoutManager = LinearLayoutManager(this) viewModel.displayHosts.observe(this, Observer { - val top = hostsRecyclerView.computeVerticalScrollOffset() == 0 + val top = binding.hostsRecyclerView.computeVerticalScrollOffset() == 0 recyclerViewAdapter.hosts = it if(top) - hostsRecyclerView.scrollToPosition(0) + binding.hostsRecyclerView.scrollToPosition(0) updateEmptyInfo() }) @@ -76,19 +78,19 @@ class MainActivity : AppCompatActivity() { if(viewModel.displayHosts.value?.isEmpty() ?: true) { - emptyInfoLayout.visibility = View.VISIBLE + binding.emptyInfoLayout.visibility = View.VISIBLE val discoveryActive = viewModel.discoveryActive.value ?: false - 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.emptyInfoImageView.setImageResource(if(discoveryActive) R.drawable.ic_discover_on else R.drawable.ic_discover_off) + binding.emptyInfoTextView.setText(if(discoveryActive) R.string.display_hosts_empty_discovery_on_info else R.string.display_hosts_empty_discovery_off_info) } else - emptyInfoLayout.visibility = View.GONE + binding.emptyInfoLayout.visibility = View.GONE } private fun expandFloatingActionButton(expand: Boolean) { - floatingActionButton.isExpanded = expand - floatingActionButton.isActivated = floatingActionButton.isExpanded + binding.floatingActionButton.isExpanded = expand + binding.floatingActionButton.isActivated = binding.floatingActionButton.isExpanded } override fun onStart() @@ -105,7 +107,7 @@ class MainActivity : AppCompatActivity() override fun onBackPressed() { - if(floatingActionButton.isExpanded) + if(binding.floatingActionButton.isExpanded) { expandFloatingActionButton(false) return @@ -151,7 +153,7 @@ class MainActivity : AppCompatActivity() private fun addManualConsole() { Intent(this, EditManualConsoleActivity::class.java).also { - it.putRevealExtra(addManualButton, rootLayout) + it.putRevealExtra(binding.addManualButton, binding.rootLayout) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } } @@ -159,7 +161,7 @@ class MainActivity : AppCompatActivity() private fun showRegistration() { Intent(this, RegistActivity::class.java).also { - it.putRevealExtra(registerButton, rootLayout) + it.putRevealExtra(binding.registerButton, binding.rootLayout) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } } diff --git a/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt b/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt index 49e5f4d..bb64b87 100644 --- a/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt @@ -16,10 +16,10 @@ import com.metallic.chiaki.common.RegisteredHost import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase +import com.metallic.chiaki.databinding.ActivityEditManualBinding import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo -import kotlinx.android.synthetic.main.activity_edit_manual.* class EditManualConsoleActivity: AppCompatActivity(), RevealActivity { @@ -28,18 +28,20 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity 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 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() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_edit_manual) + binding = ActivityEditManualBinding.inflate(layoutInflater) + setContentView(binding.root) handleReveal() viewModel = ViewModelProvider(this, viewModelFactory { @@ -52,17 +54,17 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity .get(EditManualConsoleViewModel::class.java) viewModel.existingHost?.observe(this, Observer { - hostEditText.setText(it.host) + binding.hostEditText.setText(it.host) }) viewModel.selectedRegisteredHost.observe(this, Observer { - registeredHostTextView.setText(titleForRegisteredHost(it)) + binding.registeredHostTextView.setText(titleForRegisteredHost(it)) }) viewModel.registeredHosts.observe(this, Observer { hosts -> - registeredHostTextView.setAdapter(ArrayAdapter(this, R.layout.dropdown_menu_popup_item, + binding.registeredHostTextView.setAdapter(ArrayAdapter(this, R.layout.dropdown_menu_popup_item, 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) { if(position >= hosts.size) @@ -73,8 +75,7 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity } }) - - saveButton.setOnClickListener { saveHost() } + binding.saveButton.setOnClickListener { saveHost() } } private fun titleForRegisteredHost(registeredHost: RegisteredHost?) = @@ -85,14 +86,14 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity private fun saveHost() { - val host = hostEditText.text.toString().trim() + val host = binding.hostEditText.text.toString().trim() if(host.isEmpty()) { - hostEditText.error = getString(R.string.entered_host_invalid) + binding.hostEditText.error = getString(R.string.entered_host_invalid) return } - saveButton.isEnabled = false + binding.saveButton.isEnabled = false viewModel.saveHost(host) .observeOn(AndroidSchedulers.mainThread()) .subscribe { diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt index fb3ddaa..a8d06f6 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt @@ -12,9 +12,9 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import com.metallic.chiaki.R import com.metallic.chiaki.common.ext.RevealActivity +import com.metallic.chiaki.databinding.ActivityRegistBinding import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.Target -import kotlinx.android.synthetic.main.activity_regist.* import java.lang.IllegalArgumentException class RegistActivity: AppCompatActivity(), RevealActivity @@ -30,33 +30,35 @@ class RegistActivity: AppCompatActivity(), RevealActivity private const val REQUEST_REGIST = 1 } + private lateinit var viewModel: RegistViewModel + private lateinit var binding: ActivityRegistBinding + override val revealWindow: Window get() = window override val revealIntent: Intent get() = intent - override val revealRootLayout: View get() = rootLayout - - private lateinit var viewModel: RegistViewModel + override val revealRootLayout: View get() = binding.rootLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + binding = ActivityRegistBinding.inflate(layoutInflater) setContentView(R.layout.activity_regist) handleReveal() viewModel = ViewModelProvider(this).get(RegistViewModel::class.java) - hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255") - broadcastCheckBox.isChecked = intent.getBooleanExtra(EXTRA_BROADCAST, true) + binding.hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255") + 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.PS4_GE_8 -> R.id.ps4VersionGE8RadioButton RegistViewModel.ConsoleVersion.PS4_GE_7 -> R.id.ps4VersionGE7RadioButton RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.id.ps4VersionLT7RadioButton }) - ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> + binding.ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> viewModel.ps4Version.value = when(checkedId) { R.id.ps5RadioButton -> RegistViewModel.ConsoleVersion.PS5 @@ -68,14 +70,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity } viewModel.ps4Version.observe(this, Observer { - psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE - psnIdTextInputLayout.hint = getString(when(it!!) + binding.psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE + binding.psnIdTextInputLayout.hint = getString(when(it!!) { RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.string.hint_regist_psn_online_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) - pinHelpNavigationTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_navigation else R.string.regist_pin_instructions_ps4_navigation) + binding.pinHelpBeforeTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_before else R.string.regist_pin_instructions_ps4_before) + 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 host = hostEditText.text.toString().trim() + val host = binding.hostEditText.text.toString().trim() 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 psnAccountId: ByteArray? = 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 - hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null - psnIdEditText.error = + binding.hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null + binding.psnIdEditText.error = if(!psnIdValid) getString(when(ps4Version) { @@ -114,7 +116,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity }) else 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) return diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt index 870b67e..16f545a 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt @@ -16,8 +16,8 @@ import com.metallic.chiaki.R import com.metallic.chiaki.common.MacAddress import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase +import com.metallic.chiaki.databinding.ActivityRegistExecuteBinding import com.metallic.chiaki.lib.RegistInfo -import kotlinx.android.synthetic.main.activity_regist_execute.* import kotlin.math.max class RegistExecuteActivity: AppCompatActivity() @@ -31,55 +31,57 @@ class RegistExecuteActivity: AppCompatActivity() } private lateinit var viewModel: RegistExecuteViewModel + private lateinit var binding: ActivityRegistExecuteBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_regist_execute) + binding = ActivityRegistExecuteBinding.inflate(layoutInflater) + setContentView(binding.root) viewModel = ViewModelProvider(this, viewModelFactory { RegistExecuteViewModel(getDatabase(this)) }) .get(RegistExecuteViewModel::class.java) - logTextView.setHorizontallyScrolling(true) - logTextView.movementMethod = ScrollingMovementMethod() + binding.logTextView.setHorizontallyScrolling(true) + binding.logTextView.movementMethod = ScrollingMovementMethod() viewModel.logText.observe(this, Observer { - val textLayout = logTextView.layout ?: return@Observer + val textLayout = binding.logTextView.layout ?: return@Observer val lineCount = textLayout.lineCount if(lineCount < 1) return@Observer - logTextView.text = it - val scrollY = textLayout.getLineBottom(lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom - logTextView.scrollTo(0, max(scrollY, 0)) + binding.logTextView.text = it + val scrollY = textLayout.getLineBottom(lineCount - 1) - binding.logTextView.height + binding.logTextView.paddingTop + binding.logTextView.paddingBottom + binding.logTextView.scrollTo(0, max(scrollY, 0)) }) 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) { RegistExecuteViewModel.State.FAILED -> { - infoTextView.visibility = View.VISIBLE - infoTextView.setText(R.string.regist_info_failed) + binding.infoTextView.visibility = View.VISIBLE + binding.infoTextView.setText(R.string.regist_info_failed) setResult(RESULT_FAILED) } RegistExecuteViewModel.State.SUCCESSFUL, RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE -> { - infoTextView.visibility = View.VISIBLE - infoTextView.setText(R.string.regist_info_success) + binding.infoTextView.visibility = View.VISIBLE + binding.infoTextView.setText(R.string.regist_info_success) setResult(RESULT_OK) if(it == RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE) showDuplicateDialog() } RegistExecuteViewModel.State.STOPPED -> { - infoTextView.visibility = View.GONE + binding.infoTextView.visibility = View.GONE 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 ?: "" Intent(Intent.ACTION_SEND).also { it.type = "text/plain" diff --git a/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt b/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt index 2518ce1..6fbfc31 100644 --- a/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt +++ b/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt @@ -19,6 +19,7 @@ class StreamInput(val context: Context, val preferences: Preferences) val controllerState = sensorControllerState or keyControllerState or motionControllerState val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + @Suppress("DEPRECATION") when(windowManager.defaultDisplay.rotation) { 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) 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() motionControllerState.leftX = event.getAxisValue(MotionEvent.AXIS_X).signedAxis() motionControllerState.leftY = event.getAxisValue(MotionEvent.AXIS_Y).signedAxis() diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt index 3a87e1b..1cf224f 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt @@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.metallic.chiaki.R -import kotlinx.android.synthetic.main.activity_settings.* +import com.metallic.chiaki.databinding.ActivitySettingsBinding interface TitleFragment { @@ -18,20 +18,23 @@ interface TitleFragment class SettingsActivity: AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + private lateinit var binding: ActivitySettingsBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_settings) + binding = ActivitySettingsBinding.inflate(layoutInflater) + setContentView(binding.root) title = "" - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) val rootFragment = SettingsFragment() replaceFragment(rootFragment, false) supportFragmentManager.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) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt index 7a4506e..957d1d5 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt @@ -16,7 +16,6 @@ import com.metallic.chiaki.common.exportAndShareAllSettings import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.importSettingsFromUri -import com.metallic.chiaki.lib.Codec import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt index 46c8904..6acf547 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt @@ -2,13 +2,13 @@ package com.metallic.chiaki.settings -import android.view.View +import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.metallic.chiaki.R import com.metallic.chiaki.common.LogFile 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.SimpleDateFormat import java.util.* @@ -20,7 +20,7 @@ class SettingsLogsAdapter: RecyclerView.Adapter( private val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT) 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 = listOf() set(value) @@ -29,16 +29,16 @@ class SettingsLogsAdapter: RecyclerView.Adapter( 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 onBindViewHolder(holder: ViewHolder, position: Int) { - val view = holder.itemView val logFile = logFiles[position] - view.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}" - view.summaryTextView.text = logFile.filename - view.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } } + holder.binding.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}" + holder.binding.summaryTextView.text = logFile.filename + holder.binding.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } } } } \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt index 07e1e3f..0397172 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt @@ -21,29 +21,35 @@ import com.metallic.chiaki.common.LogFile import com.metallic.chiaki.common.LogManager import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.fileProviderAuthority -import kotlinx.android.synthetic.main.fragment_settings_logs.* +import com.metallic.chiaki.databinding.FragmentSettingsLogsBinding class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment { 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 = - 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?) { - val context = context!! + val context = requireContext() viewModel = ViewModelProvider(this, viewModelFactory { SettingsLogsViewModel(LogManager(context)) }) .get(SettingsLogsViewModel::class.java) val adapter = SettingsLogsAdapter() - logsRecyclerView.layoutManager = LinearLayoutManager(context) - logsRecyclerView.adapter = adapter + binding.logsRecyclerView.layoutManager = LinearLayoutManager(context) + binding.logsRecyclerView.adapter = adapter adapter.shareCallback = this::shareLogFile viewModel.sessionLogs.observe(viewLifecycleOwner, Observer { 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) @@ -55,7 +61,7 @@ class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment 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) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt index 57a06ce..509d594 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt @@ -2,17 +2,15 @@ package com.metallic.chiaki.settings -import android.view.View +import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.metallic.chiaki.R import com.metallic.chiaki.common.RegisteredHost -import com.metallic.chiaki.common.ext.inflate -import kotlinx.android.synthetic.main.item_registered_host.view.* +import com.metallic.chiaki.databinding.ItemRegisteredHostBinding class SettingsRegisteredHostsAdapter: RecyclerView.Adapter() { - class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) + class ViewHolder(val binding: ItemRegisteredHostBinding): RecyclerView.ViewHolder(binding.root) var hosts: List = listOf() set(value) @@ -21,15 +19,15 @@ class SettingsRegisteredHostsAdapter: RecyclerView.Adapter + binding.onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.setOnScreenControlsEnabled(isChecked) showOverlay() } viewModel.touchpadOnlyEnabled.observe(this, Observer { - if(touchpadOnlySwitch.isChecked != it) - touchpadOnlySwitch.isChecked = it - if(touchpadOnlySwitch.isChecked) - onScreenControlsSwitch.isChecked = false + if(binding.touchpadOnlySwitch.isChecked != it) + binding.touchpadOnlySwitch.isChecked = it + if(binding.touchpadOnlySwitch.isChecked) + binding.onScreenControlsSwitch.isChecked = false }) - touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked -> + binding.touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.setTouchpadOnlyEnabled(isChecked) showOverlay() } - displayModeToggle.addOnButtonCheckedListener { _, _, _ -> + binding.displayModeToggle.addOnButtonCheckedListener { _, _, _ -> adjustStreamViewAspect() showOverlay() } //viewModel.session.attachToTextureView(textureView) - viewModel.session.attachToSurfaceView(surfaceView) + viewModel.session.attachToSurfaceView(binding.surfaceView) viewModel.session.state.observe(this, Observer { this.stateChanged(it) }) adjustStreamViewAspect() @@ -159,14 +159,14 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun showOverlay() { - overlay.isVisible = true - overlay.animate() + binding.overlay.isVisible = true + binding.overlay.animate() .alpha(1.0f) .setListener(object: AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { - overlay.alpha = 1.0f + binding.overlay.alpha = 1.0f } }) uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable) @@ -175,13 +175,13 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun hideOverlay() { - overlay.animate() + binding.overlay.animate() .alpha(0.0f) .setListener(object: AnimatorListenerAdapter() { 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) { - progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE + binding.progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE when(state) { @@ -302,7 +302,7 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun adjustTextureViewAspect(textureView: 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 { textureView.getTransform(it) it.setScale(resolution.width / trans.viewWidth, resolution.height / trans.viewHeight) @@ -314,8 +314,8 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun adjustSurfaceViewAspect() { val videoProfile = viewModel.session.connectInfo.videoProfile - aspectRatioLayout.aspectRatio = videoProfile.width.toFloat() / videoProfile.height.toFloat() - aspectRatioLayout.mode = TransformMode.fromButton(displayModeToggle.checkedButtonId) + binding.aspectRatioLayout.aspectRatio = videoProfile.width.toFloat() / videoProfile.height.toFloat() + binding.aspectRatioLayout.mode = TransformMode.fromButton(binding.displayModeToggle.checkedButtonId) } private fun adjustStreamViewAspect() = adjustSurfaceViewAspect() 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 644f5f3..d3ab155 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 @@ -3,16 +3,14 @@ package com.metallic.chiaki.touchcontrols import android.os.Bundle -import android.util.Log 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.databinding.FragmentControlsBinding import com.metallic.chiaki.lib.ControllerState -import kotlinx.android.synthetic.main.fragment_controls.* class TouchControlsFragment : Fragment() { @@ -28,44 +26,50 @@ class TouchControlsFragment : Fragment() var controllerStateCallback: ((ControllerState) -> Unit)? = null var onScreenControlsEnabled: LiveData? = null - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View - = inflater.inflate(R.layout.fragment_controls, container, false) + private var _binding: FragmentControlsBinding? = null + 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?) { super.onViewCreated(view, savedInstanceState) - dpadView.stateChangeCallback = this::dpadStateChanged - crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS) - moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON) - pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID) - boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX) - l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1) - r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1) - l3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L3) - r3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R3) - optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS) - shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE) - psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) - touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) + binding.dpadView.stateChangeCallback = this::dpadStateChanged + binding.crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS) + binding.moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON) + binding.pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID) + binding.boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX) + binding.l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1) + binding.r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1) + binding.l3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L3) + binding.r3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R3) + binding.optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS) + binding.shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE) + binding.psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) + binding.touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) - 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.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 } } 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) leftY = quantizeStick(it.y) }} - rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { + binding.rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { rightX = quantizeStick(it.x) rightY = quantizeStick(it.y) }} - onScreenControlsEnabled?.observe(this, Observer { + onScreenControlsEnabled?.observe(viewLifecycleOwner, Observer { view.visibility = if(it) View.VISIBLE else View.GONE }) } diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt index 610c099..ef96b84 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt @@ -10,8 +10,9 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.metallic.chiaki.R +import com.metallic.chiaki.databinding.FragmentControlsBinding +import com.metallic.chiaki.databinding.FragmentTouchpadOnlyBinding import com.metallic.chiaki.lib.ControllerState -import kotlinx.android.synthetic.main.fragment_controls.* class TouchpadOnlyFragment : Fragment() { @@ -27,16 +28,22 @@ class TouchpadOnlyFragment : Fragment() var controllerStateCallback: ((ControllerState) -> Unit)? = null var touchpadOnlyEnabled: LiveData? = null - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View - = inflater.inflate(R.layout.fragment_touchpad_only, container, false) + private var _binding: FragmentTouchpadOnlyBinding? = null + 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?) { 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 }) }