mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-14 10:46:51 -07:00
Show Discovered Hosts in MainActivity on Android
This commit is contained in:
parent
df6d0a7ede
commit
53fe9e50e4
12 changed files with 149 additions and 213 deletions
|
@ -23,6 +23,8 @@ sealed class DisplayHost
|
|||
{
|
||||
abstract val registeredHost: RegisteredHost?
|
||||
abstract val host: String
|
||||
abstract val name: String?
|
||||
abstract val id: String?
|
||||
}
|
||||
|
||||
class DiscoveredDisplayHost(
|
||||
|
@ -31,6 +33,8 @@ class DiscoveredDisplayHost(
|
|||
): DisplayHost()
|
||||
{
|
||||
override val host get() = discoveredHost.hostAddr ?: ""
|
||||
override val name get() = discoveredHost.hostName ?: registeredHost?.ps4Nickname
|
||||
override val id get() = discoveredHost.hostId ?: registeredHost?.ps4Mac?.toString()
|
||||
}
|
||||
|
||||
class ManualDisplayHost(
|
||||
|
@ -39,4 +43,6 @@ class ManualDisplayHost(
|
|||
): DisplayHost()
|
||||
{
|
||||
override val host get() = manualHost.host
|
||||
override val name get() = registeredHost?.ps4Nickname
|
||||
override val id get() = registeredHost?.ps4Mac?.toString()
|
||||
}
|
|
@ -18,6 +18,9 @@
|
|||
package com.metallic.chiaki.common.ext
|
||||
|
||||
import androidx.lifecycle.LiveDataReactiveStreams
|
||||
import io.reactivex.BackpressureStrategy
|
||||
import io.reactivex.Observable
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
fun <T> Publisher<T>.toLiveData() = LiveDataReactiveStreams.fromPublisher(this)
|
||||
fun <T> Publisher<T>.toLiveData() = LiveDataReactiveStreams.fromPublisher(this)
|
||||
fun <T> Observable<T>.toLiveData() = this.toFlowable(BackpressureStrategy.LATEST).toLiveData()
|
|
@ -19,8 +19,12 @@ package com.metallic.chiaki.discovery
|
|||
|
||||
import android.util.Log
|
||||
import com.metallic.chiaki.lib.CreateError
|
||||
import com.metallic.chiaki.lib.DiscoveryHost
|
||||
import com.metallic.chiaki.lib.DiscoveryService
|
||||
import com.metallic.chiaki.lib.DiscoveryServiceOptions
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import io.reactivex.subjects.Subject
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
class DiscoveryManager
|
||||
|
@ -35,26 +39,61 @@ class DiscoveryManager
|
|||
|
||||
private var discoveryService: DiscoveryService? = null
|
||||
|
||||
fun start()
|
||||
private val discoveryActiveSubject: Subject<Boolean> = BehaviorSubject.create<Boolean>().also { it.onNext(false) }
|
||||
val discoveryActive: Observable<Boolean> get() = discoveryActiveSubject
|
||||
var active = false
|
||||
set(value)
|
||||
{
|
||||
field = value
|
||||
discoveryActiveSubject.onNext(value)
|
||||
updateService()
|
||||
}
|
||||
private var paused = false
|
||||
|
||||
private var discoveredHostsSubject: Subject<List<DiscoveryHost>> = BehaviorSubject.create<List<DiscoveryHost>>().also {
|
||||
it.onNext(listOf())
|
||||
}.toSerialized()
|
||||
val discoveredHosts: Observable<List<DiscoveryHost>> get() = discoveredHostsSubject
|
||||
|
||||
fun resume()
|
||||
{
|
||||
if(discoveryService != null)
|
||||
return
|
||||
try
|
||||
{
|
||||
discoveryService = DiscoveryService(DiscoveryServiceOptions(
|
||||
HOSTS_MAX, DROP_PINGS, PING_MS, InetSocketAddress("255.255.255.255", PORT)
|
||||
))
|
||||
}
|
||||
catch(e: CreateError)
|
||||
{
|
||||
Log.e("DiscoveryManager", "Failed to start Discovery Service: $e")
|
||||
}
|
||||
paused = false
|
||||
updateService()
|
||||
}
|
||||
|
||||
fun stop()
|
||||
fun pause()
|
||||
{
|
||||
val service = discoveryService ?: return
|
||||
service.dispose()
|
||||
discoveryService = null
|
||||
paused = true
|
||||
updateService()
|
||||
}
|
||||
|
||||
fun dispose()
|
||||
{
|
||||
active = false
|
||||
}
|
||||
|
||||
private fun updateService()
|
||||
{
|
||||
if(active && !paused && discoveryService == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
discoveryService = DiscoveryService(DiscoveryServiceOptions(
|
||||
HOSTS_MAX, DROP_PINGS, PING_MS, InetSocketAddress("255.255.255.255", PORT)
|
||||
), discoveredHostsSubject::onNext)
|
||||
}
|
||||
catch(e: CreateError)
|
||||
{
|
||||
Log.e("DiscoveryManager", "Failed to start Discovery Service: $e")
|
||||
}
|
||||
}
|
||||
else if(discoveryService != null)
|
||||
{
|
||||
val service = discoveryService ?: return
|
||||
service.dispose()
|
||||
discoveryService = null
|
||||
discoveredHostsSubject.onNext(listOf())
|
||||
discoveryActiveSubject.onNext(false)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -212,7 +212,7 @@ data class DiscoveryServiceOptions(
|
|||
|
||||
class DiscoveryService(
|
||||
options: DiscoveryServiceOptions,
|
||||
val callback: ((hosts: List<DiscoveryHost>) -> Unit)? = null)
|
||||
val callback: ((hosts: List<DiscoveryHost>) -> Unit)?)
|
||||
{
|
||||
private var nativePtr: Long
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.common.DiscoveredDisplayHost
|
||||
import com.metallic.chiaki.common.DisplayHost
|
||||
import com.metallic.chiaki.common.ext.inflate
|
||||
import com.metallic.chiaki.lib.DiscoveryHost
|
||||
import kotlinx.android.synthetic.main.item_display_host.view.*
|
||||
|
||||
class DisplayHostRecyclerViewAdapter: RecyclerView.Adapter<DisplayHostRecyclerViewAdapter.ViewHolder>()
|
||||
|
@ -43,9 +45,24 @@ class DisplayHostRecyclerViewAdapter: RecyclerView.Adapter<DisplayHostRecyclerVi
|
|||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int)
|
||||
{
|
||||
val context = holder.itemView.context
|
||||
val host = hosts[position]
|
||||
holder.itemView.also {
|
||||
it.hostTextView.text = host.host
|
||||
it.nameTextView.text = host.name
|
||||
it.hostTextView.text = context.getString(R.string.display_host_host, host.host)
|
||||
val id = host.id
|
||||
it.idTextView.text = if(id != null) context.getString(R.string.display_host_id, id) else ""
|
||||
it.discoveredIndicatorLayout.visibility = if(host is DiscoveredDisplayHost) View.VISIBLE else View.GONE
|
||||
it.stateIndicatorImageView.setImageResource(
|
||||
if(host is DiscoveredDisplayHost)
|
||||
when(host.discoveredHost.state)
|
||||
{
|
||||
DiscoveryHost.State.STANDBY -> R.drawable.ic_console_standby
|
||||
DiscoveryHost.State.READY -> R.drawable.ic_console_ready
|
||||
else -> R.drawable.ic_console
|
||||
}
|
||||
else
|
||||
R.drawable.ic_console)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,10 @@ class MainActivity : AppCompatActivity()
|
|||
{
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
private var discoveryMenuItem: MenuItem? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?)
|
||||
{
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -46,7 +50,6 @@ class MainActivity : AppCompatActivity()
|
|||
title = ""
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
|
||||
addButton.setOnClickListener {
|
||||
Intent(this, TestStartActivity::class.java).also {
|
||||
it.putExtra(TestStartActivity.EXTRA_REVEAL_X, addButton.x + addButton.width * 0.5f)
|
||||
|
@ -55,7 +58,7 @@ class MainActivity : AppCompatActivity()
|
|||
}
|
||||
}
|
||||
|
||||
val viewModel = ViewModelProviders
|
||||
viewModel = ViewModelProviders
|
||||
.of(this, viewModelFactory { MainViewModel(getDatabase(this)) })
|
||||
.get(MainViewModel::class.java)
|
||||
|
||||
|
@ -63,6 +66,10 @@ class MainActivity : AppCompatActivity()
|
|||
hostsRecyclerView.adapter = recyclerViewAdapter
|
||||
hostsRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
viewModel.displayHosts.observe(this, Observer { recyclerViewAdapter.hosts = it })
|
||||
|
||||
viewModel.discoveryActive.observe(this, Observer { active ->
|
||||
discoveryMenuItem?.let { updateDiscoveryMenuItem(it, active) }
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDestroy()
|
||||
|
@ -71,14 +78,29 @@ class MainActivity : AppCompatActivity()
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean
|
||||
{
|
||||
menuInflater.inflate(R.menu.main, menu)
|
||||
val discoveryItem = menu.findItem(R.id.action_discover)
|
||||
discoveryMenuItem = discoveryItem
|
||||
updateDiscoveryMenuItem(discoveryItem, viewModel.discoveryActive.value ?: false)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateDiscoveryMenuItem(item: MenuItem, active: Boolean)
|
||||
{
|
||||
item.isChecked = active
|
||||
item.setIcon(if(active) R.drawable.ic_discover_on else R.drawable.ic_discover_off)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = when(item.itemId)
|
||||
{
|
||||
R.id.action_discover ->
|
||||
{
|
||||
viewModel.discoveryManager.active = !(viewModel.discoveryActive.value ?: false)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_settings ->
|
||||
{
|
||||
Intent(this, SettingsActivity::class.java).also {
|
||||
|
|
|
@ -19,27 +19,36 @@ package com.metallic.chiaki.main
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.metallic.chiaki.common.AppDatabase
|
||||
import com.metallic.chiaki.common.DiscoveredDisplayHost
|
||||
import com.metallic.chiaki.common.ManualDisplayHost
|
||||
import com.metallic.chiaki.common.ext.toLiveData
|
||||
import com.metallic.chiaki.discovery.DiscoveryManager
|
||||
import io.reactivex.rxkotlin.Observables
|
||||
|
||||
class MainViewModel(val database: AppDatabase): ViewModel()
|
||||
{
|
||||
val discoveryManager = DiscoveryManager().also { it.active = true /* TODO: from shared preferences */ }
|
||||
|
||||
val displayHosts by lazy {
|
||||
database.manualHostDao().getAll()
|
||||
.map {
|
||||
it.map { manualHost ->
|
||||
ManualDisplayHost(null, manualHost)
|
||||
Observables.combineLatest(database.manualHostDao().getAll().toObservable(), discoveryManager.discoveredHosts)
|
||||
{ manualHosts, discoveredHosts ->
|
||||
discoveredHosts.map {
|
||||
DiscoveredDisplayHost(null /* TODO */, it)
|
||||
} +
|
||||
manualHosts.map {
|
||||
ManualDisplayHost(null /* TODO */, it)
|
||||
}
|
||||
}
|
||||
.toLiveData()
|
||||
}
|
||||
|
||||
val discoveryManager = DiscoveryManager().also { it.start() }
|
||||
val discoveryActive by lazy {
|
||||
discoveryManager.discoveryActive.toLiveData()
|
||||
}
|
||||
|
||||
override fun onCleared()
|
||||
{
|
||||
super.onCleared()
|
||||
discoveryManager.stop()
|
||||
discoveryManager.dispose()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<vector android:height="32dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<vector android:height="24dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnSurface" android:pathData="M22.99,9C19.15,5.16 13.8,3.76 8.84,4.78l2.52,2.52c3.47,-0.17 6.99,1.05 9.63,3.7l2,-2zM18.99,13c-1.29,-1.29 -2.84,-2.13 -4.49,-2.56l3.53,3.53 0.96,-0.97zM2,3.05L5.07,6.1C3.6,6.82 2.22,7.78 1,9l1.99,2c1.24,-1.24 2.67,-2.16 4.2,-2.77l2.24,2.24C7.81,10.89 6.27,11.73 5,13v0.01L6.99,15c1.36,-1.36 3.14,-2.04 4.92,-2.06L18.98,20l1.27,-1.26L3.29,1.79 2,3.05zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0z"/>
|
||||
</vector>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<vector android:height="32dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<vector android:height="24dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnSurface" android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
|
||||
</vector>
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
|
@ -17,22 +17,29 @@
|
|||
android:layout_marginBottom="0dp"
|
||||
android:elevation="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:src="@drawable/ic_triangle"
|
||||
android:layout_gravity="left|top" />
|
||||
<FrameLayout
|
||||
android:id="@+id/discoveredIndicatorLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|top" >
|
||||
<ImageView
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:src="@drawable/ic_triangle"/>
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_discovered_on_secondary"
|
||||
android:layout_gravity="left|top"
|
||||
android:layout_margin="8dp" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_discovered_on_secondary" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/nameTextView"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -67,6 +74,7 @@
|
|||
android:textColor="?attr/colorOnSurface"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/stateIndicatorImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_console"
|
||||
|
|
|
@ -10,4 +10,6 @@
|
|||
<string name="action_login_pin_connect">Connect</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="action_discover">Discover Consoles Automatically</string>
|
||||
<string name="display_host_host">Address: %s</string>
|
||||
<string name="display_host_id">ID: %s</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue