From ee7b89ec6e3de793f8d22590d09680031ee10ae7 Mon Sep 17 00:00:00 2001 From: Koen J Date: Tue, 29 Apr 2025 15:22:06 +0200 Subject: [PATCH] Added new casting dialog. --- .../platformplayer/casting/StateCasting.kt | 28 +-- .../dialogs/ConnectCastingDialog.kt | 214 ++++++++++-------- .../stores/CastingDeviceInfoStorage.kt | 5 + .../views/adapters/DeviceAdapter.kt | 18 +- .../views/adapters/DeviceViewHolder.kt | 135 +++++------ app/src/main/res/drawable/keep_24px.xml | 9 + .../res/layout/dialog_casting_connect.xml | 190 ++++++++++------ app/src/main/res/layout/list_device.xml | 113 +++------ app/src/main/res/values/strings.xml | 3 + 9 files changed, 375 insertions(+), 340 deletions(-) create mode 100644 app/src/main/res/drawable/keep_24px.xml diff --git a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt index 865af56f..f25cd410 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt @@ -69,7 +69,6 @@ class StateCasting { private var _started = false; var devices: HashMap = hashMapOf(); - var rememberedDevices: ArrayList = arrayListOf(); val onDeviceAdded = Event1(); val onDeviceChanged = Event1(); val onDeviceRemoved = Event1(); @@ -156,9 +155,6 @@ class StateCasting { Logger.i(TAG, "CastingService starting..."); - rememberedDevices.clear(); - rememberedDevices.addAll(_storage.deviceInfos.map { deviceFromCastingDeviceInfo(it) }); - _castServer.start(); enableDeveloper(true); @@ -370,9 +366,6 @@ class StateCasting { invokeInMainScopeIfRequired { onActiveDeviceTimeChanged.emit(it) }; }; - addRememberedDevice(device); - Logger.i(TAG, "Device added to active discovery. Active discovery now contains ${_storage.getDevicesCount()} devices.") - try { device.start(); } catch (e: Throwable) { @@ -394,21 +387,22 @@ class StateCasting { return addRememberedDevice(device); } + fun getRememberedCastingDevices(): List { + return _storage.getDevices().map { deviceFromCastingDeviceInfo(it) } + } + + fun getRememberedCastingDeviceNames(): List { + return _storage.getDeviceNames() + } + fun addRememberedDevice(device: CastingDevice): CastingDeviceInfo { val deviceInfo = device.getDeviceInfo() - val foundInfo = _storage.addDevice(deviceInfo) - if (foundInfo == deviceInfo) { - rememberedDevices.add(device); - return foundInfo; - } - - return foundInfo; + return _storage.addDevice(deviceInfo) } fun removeRememberedDevice(device: CastingDevice) { - val name = device.name ?: return; - _storage.removeDevice(name); - rememberedDevices.remove(device); + val name = device.name ?: return + _storage.removeDevice(name) } private fun invokeInMainScopeIfRequired(action: () -> Unit){ diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt index 8f3b836c..f00bd191 100644 --- a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt +++ b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt @@ -9,7 +9,9 @@ import android.view.View import android.widget.Button import android.widget.ImageButton import android.widget.ImageView +import android.widget.LinearLayout import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.futo.platformplayer.R @@ -21,22 +23,21 @@ import com.futo.platformplayer.casting.StateCasting import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.views.adapters.DeviceAdapter +import com.futo.platformplayer.views.adapters.DeviceAdapterEntry import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class ConnectCastingDialog(context: Context?) : AlertDialog(context) { private lateinit var _imageLoader: ImageView; private lateinit var _buttonClose: Button; - private lateinit var _buttonAdd: ImageButton; - private lateinit var _buttonScanQR: ImageButton; + private lateinit var _buttonAdd: LinearLayout; + private lateinit var _buttonScanQR: LinearLayout; private lateinit var _textNoDevicesFound: TextView; - private lateinit var _textNoDevicesRemembered: TextView; private lateinit var _recyclerDevices: RecyclerView; - private lateinit var _recyclerRememberedDevices: RecyclerView; private lateinit var _adapter: DeviceAdapter; - private lateinit var _rememberedAdapter: DeviceAdapter; - private val _devices: ArrayList = arrayListOf(); - private val _rememberedDevices: ArrayList = arrayListOf(); + private val _devices: MutableSet = mutableSetOf() + private val _rememberedDevices: MutableSet = mutableSetOf() + private val _unifiedDevices: MutableList = mutableListOf() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState); @@ -45,42 +46,40 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) { _imageLoader = findViewById(R.id.image_loader); _buttonClose = findViewById(R.id.button_close); _buttonAdd = findViewById(R.id.button_add); - _buttonScanQR = findViewById(R.id.button_scan_qr); + _buttonScanQR = findViewById(R.id.button_qr); _recyclerDevices = findViewById(R.id.recycler_devices); - _recyclerRememberedDevices = findViewById(R.id.recycler_remembered_devices); _textNoDevicesFound = findViewById(R.id.text_no_devices_found); - _textNoDevicesRemembered = findViewById(R.id.text_no_devices_remembered); - _adapter = DeviceAdapter(_devices, false); + _adapter = DeviceAdapter(_unifiedDevices) _recyclerDevices.adapter = _adapter; _recyclerDevices.layoutManager = LinearLayoutManager(context); - _rememberedAdapter = DeviceAdapter(_rememberedDevices, true); - _rememberedAdapter.onRemove.subscribe { d -> - if (StateCasting.instance.activeDevice == d) { - d.stopCasting(); + _adapter.onPin.subscribe { d -> + val isRemembered = _rememberedDevices.contains(d.name) + val newIsRemembered = !isRemembered + if (newIsRemembered) { + StateCasting.instance.addRememberedDevice(d) + val name = d.name + if (name != null) { + _rememberedDevices.add(name) + } + } else { + StateCasting.instance.removeRememberedDevice(d) + _rememberedDevices.remove(d.name) } - - StateCasting.instance.removeRememberedDevice(d); - val index = _rememberedDevices.indexOf(d); - if (index != -1) { - _rememberedDevices.removeAt(index); - _rememberedAdapter.notifyItemRemoved(index); - } - - _textNoDevicesRemembered.visibility = if (_rememberedDevices.isEmpty()) View.VISIBLE else View.GONE; - _recyclerRememberedDevices.visibility = if (_rememberedDevices.isNotEmpty()) View.VISIBLE else View.GONE; - }; - _rememberedAdapter.onConnect.subscribe { _ -> - dismiss() - //UIDialogs.showCastingDialog(context) + updateUnifiedList() } + + //TODO: Integrate remembered into the main list + //TODO: Add green indicator to indicate a device is oneline + //TODO: Add pinning + //TODO: Implement QR code as an option in add manually + //TODO: Remove start button + _adapter.onConnect.subscribe { _ -> dismiss() //UIDialogs.showCastingDialog(context) } - _recyclerRememberedDevices.adapter = _rememberedAdapter; - _recyclerRememberedDevices.layoutManager = LinearLayoutManager(context); _buttonClose.setOnClickListener { dismiss(); }; _buttonAdd.setOnClickListener { @@ -105,77 +104,112 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) { Logger.i(TAG, "Dialog shown."); StateCasting.instance.startDiscovering() - (_imageLoader.drawable as Animatable?)?.start(); - _devices.clear(); - synchronized (StateCasting.instance.devices) { - _devices.addAll(StateCasting.instance.devices.values); + synchronized(StateCasting.instance.devices) { + _devices.addAll(StateCasting.instance.devices.values.mapNotNull { it.name }) } - _rememberedDevices.clear(); - synchronized (StateCasting.instance.rememberedDevices) { - _rememberedDevices.addAll(StateCasting.instance.rememberedDevices); + _rememberedDevices.addAll(StateCasting.instance.getRememberedCastingDeviceNames()) + updateUnifiedList() + + StateCasting.instance.onDeviceAdded.subscribe(this) { d -> + val name = d.name + if (name != null) + _devices.add(name) + updateUnifiedList() + } + + StateCasting.instance.onDeviceChanged.subscribe(this) { d -> + val index = _unifiedDevices.indexOfFirst { it.castingDevice.name == d.name } + if (index != -1) { + _unifiedDevices[index] = DeviceAdapterEntry(d, _unifiedDevices[index].isPinnedDevice, _unifiedDevices[index].isOnlineDevice) + _adapter.notifyItemChanged(index) + } + } + + StateCasting.instance.onDeviceRemoved.subscribe(this) { d -> + _devices.remove(d.name) + updateUnifiedList() + } + + StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState -> + if (connectionState == CastConnectionState.CONNECTED) { + StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { + dismiss() + } + } } _textNoDevicesFound.visibility = if (_devices.isEmpty()) View.VISIBLE else View.GONE; _recyclerDevices.visibility = if (_devices.isNotEmpty()) View.VISIBLE else View.GONE; - _textNoDevicesRemembered.visibility = if (_rememberedDevices.isEmpty()) View.VISIBLE else View.GONE; - _recyclerRememberedDevices.visibility = if (_rememberedDevices.isNotEmpty()) View.VISIBLE else View.GONE; - - StateCasting.instance.onDeviceAdded.subscribe(this) { d -> - _devices.add(d); - _adapter.notifyItemInserted(_devices.size - 1); - _textNoDevicesFound.visibility = View.GONE; - _recyclerDevices.visibility = View.VISIBLE; - }; - - StateCasting.instance.onDeviceChanged.subscribe(this) { d -> - val index = _devices.indexOf(d); - if (index == -1) { - return@subscribe; - } - - _devices[index] = d; - _adapter.notifyItemChanged(index); - }; - - StateCasting.instance.onDeviceRemoved.subscribe(this) { d -> - val index = _devices.indexOf(d); - if (index == -1) { - return@subscribe; - } - - _devices.removeAt(index); - _adapter.notifyItemRemoved(index); - _textNoDevicesFound.visibility = if (_devices.isEmpty()) View.VISIBLE else View.GONE; - _recyclerDevices.visibility = if (_devices.isNotEmpty()) View.VISIBLE else View.GONE; - }; - - StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState -> - if (connectionState != CastConnectionState.CONNECTED) { - return@subscribe; - } - - StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { - dismiss(); - }; - }; - - _adapter.notifyDataSetChanged(); - _rememberedAdapter.notifyDataSetChanged(); } override fun dismiss() { - super.dismiss(); - - (_imageLoader.drawable as Animatable?)?.stop(); - + super.dismiss() + (_imageLoader.drawable as Animatable?)?.stop() StateCasting.instance.stopDiscovering() - StateCasting.instance.onDeviceAdded.remove(this); - StateCasting.instance.onDeviceChanged.remove(this); - StateCasting.instance.onDeviceRemoved.remove(this); - StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this); + StateCasting.instance.onDeviceAdded.remove(this) + StateCasting.instance.onDeviceChanged.remove(this) + StateCasting.instance.onDeviceRemoved.remove(this) + StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this) + } + + private fun updateUnifiedList() { + val oldList = ArrayList(_unifiedDevices) + val newList = buildUnifiedList() + + val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() { + override fun getOldListSize() = oldList.size + override fun getNewListSize() = newList.size + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldList[oldItemPosition] + val newItem = newList[newItemPosition] + return oldItem.castingDevice.name == newItem.castingDevice.name + && oldItem.castingDevice.isReady == newItem.castingDevice.isReady + && oldItem.isOnlineDevice == newItem.isOnlineDevice + && oldItem.isPinnedDevice == newItem.isPinnedDevice + } + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldList[oldItemPosition] + val newItem = newList[newItemPosition] + return oldItem.castingDevice.name == newItem.castingDevice.name + && oldItem.castingDevice.isReady == newItem.castingDevice.isReady + && oldItem.isOnlineDevice == newItem.isOnlineDevice + && oldItem.isPinnedDevice == newItem.isPinnedDevice + } + }) + + _unifiedDevices.clear() + _unifiedDevices.addAll(newList) + diffResult.dispatchUpdatesTo(_adapter) + + _textNoDevicesFound.visibility = if (_unifiedDevices.isEmpty()) View.VISIBLE else View.GONE + _recyclerDevices.visibility = if (_unifiedDevices.isNotEmpty()) View.VISIBLE else View.GONE + } + + private fun buildUnifiedList(): List { + val onlineDevices = StateCasting.instance.devices.values.associateBy { it.name } + val rememberedDevices = StateCasting.instance.getRememberedCastingDevices().associateBy { it.name } + + val unifiedList = mutableListOf() + + val intersectionNames = _devices.intersect(_rememberedDevices) + for (name in intersectionNames) { + onlineDevices[name]?.let { unifiedList.add(DeviceAdapterEntry(it, true, true)) } + } + + val onlineOnlyNames = _devices - _rememberedDevices + for (name in onlineOnlyNames) { + onlineDevices[name]?.let { unifiedList.add(DeviceAdapterEntry(it, false, true)) } + } + + val rememberedOnlyNames = _rememberedDevices - _devices + for (name in rememberedOnlyNames) { + rememberedDevices[name]?.let { unifiedList.add(DeviceAdapterEntry(it, true, false)) } + } + + return unifiedList } companion object { diff --git a/app/src/main/java/com/futo/platformplayer/stores/CastingDeviceInfoStorage.kt b/app/src/main/java/com/futo/platformplayer/stores/CastingDeviceInfoStorage.kt index 3ecff95a..bddbe862 100644 --- a/app/src/main/java/com/futo/platformplayer/stores/CastingDeviceInfoStorage.kt +++ b/app/src/main/java/com/futo/platformplayer/stores/CastingDeviceInfoStorage.kt @@ -19,6 +19,11 @@ class CastingDeviceInfoStorage : FragmentedStorageFileJson() { return deviceInfos.toList(); } + @Synchronized + fun getDeviceNames() : List { + return deviceInfos.map { it.name }.toList(); + } + @Synchronized fun addDevice(castingDeviceInfo: CastingDeviceInfo): CastingDeviceInfo { val foundDeviceInfo = deviceInfos.firstOrNull { d -> d.name == castingDeviceInfo.name } diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceAdapter.kt index 711a1675..a2ff2435 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceAdapter.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceAdapter.kt @@ -7,16 +7,16 @@ import com.futo.platformplayer.R import com.futo.platformplayer.casting.CastingDevice import com.futo.platformplayer.constructs.Event1 -class DeviceAdapter : RecyclerView.Adapter { - private val _devices: ArrayList; - private val _isRememberedDevice: Boolean; +data class DeviceAdapterEntry(val castingDevice: CastingDevice, val isPinnedDevice: Boolean, val isOnlineDevice: Boolean) - var onRemove = Event1(); +class DeviceAdapter : RecyclerView.Adapter { + private val _devices: List; + + var onPin = Event1(); var onConnect = Event1(); - constructor(devices: ArrayList, isRememberedDevice: Boolean) : super() { + constructor(devices: List) : super() { _devices = devices; - _isRememberedDevice = isRememberedDevice; } override fun getItemCount() = _devices.size; @@ -24,13 +24,13 @@ class DeviceAdapter : RecyclerView.Adapter { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): DeviceViewHolder { val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.list_device, viewGroup, false); val holder = DeviceViewHolder(view); - holder.setIsRememberedDevice(_isRememberedDevice); - holder.onRemove.subscribe { d -> onRemove.emit(d); }; + holder.onPin.subscribe { d -> onPin.emit(d); }; holder.onConnect.subscribe { d -> onConnect.emit(d); } return holder; } override fun onBindViewHolder(viewHolder: DeviceViewHolder, position: Int) { - viewHolder.bind(_devices[position]); + val p = _devices[position]; + viewHolder.bind(p.castingDevice, p.isOnlineDevice, p.isPinnedDevice); } } diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt index 3fa42219..d5060fe5 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt @@ -2,9 +2,11 @@ package com.futo.platformplayer.views.adapters import android.graphics.drawable.Animatable import android.view.View +import android.widget.FrameLayout import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.RecyclerView.ViewHolder import com.futo.platformplayer.R import com.futo.platformplayer.casting.AirPlayCastingDevice @@ -14,70 +16,62 @@ import com.futo.platformplayer.casting.ChromecastCastingDevice import com.futo.platformplayer.casting.FCastCastingDevice import com.futo.platformplayer.casting.StateCasting import com.futo.platformplayer.constructs.Event1 +import com.futo.platformplayer.constructs.Event2 +import androidx.core.view.isVisible class DeviceViewHolder : ViewHolder { + private val _layoutDevice: FrameLayout; private val _imageDevice: ImageView; private val _textName: TextView; private val _textType: TextView; private val _textNotReady: TextView; - private val _buttonDisconnect: LinearLayout; - private val _buttonConnect: LinearLayout; - private val _buttonRemove: LinearLayout; private val _imageLoader: ImageView; + private val _imageOnline: ImageView; + private val _root: ConstraintLayout; private var _animatableLoader: Animatable? = null; - private var _isRememberedDevice: Boolean = false; + private var _imagePin: ImageView; var device: CastingDevice? = null private set - var onRemove = Event1(); + var onPin = Event1(); val onConnect = Event1(); constructor(view: View) : super(view) { + _root = view.findViewById(R.id.layout_root); + _layoutDevice = view.findViewById(R.id.layout_device); _imageDevice = view.findViewById(R.id.image_device); _textName = view.findViewById(R.id.text_name); _textType = view.findViewById(R.id.text_type); _textNotReady = view.findViewById(R.id.text_not_ready); - _buttonDisconnect = view.findViewById(R.id.button_disconnect); - _buttonConnect = view.findViewById(R.id.button_connect); - _buttonRemove = view.findViewById(R.id.button_remove); _imageLoader = view.findViewById(R.id.image_loader); + _imageOnline = view.findViewById(R.id.image_online); + _imagePin = view.findViewById(R.id.image_pin); val d = _imageLoader.drawable; if (d is Animatable) { _animatableLoader = d; } - _buttonDisconnect.setOnClickListener { - StateCasting.instance.activeDevice?.stopCasting(); - updateButton(); - }; - - _buttonConnect.setOnClickListener { - val dev = device ?: return@setOnClickListener; - StateCasting.instance.activeDevice?.stopCasting(); - StateCasting.instance.connectDevice(dev); - onConnect.emit(dev); - }; - - _buttonRemove.setOnClickListener { - val dev = device ?: return@setOnClickListener; - onRemove.emit(dev); - }; - - StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, _ -> - updateButton(); + val connect = { + device?.let { dev -> + StateCasting.instance.activeDevice?.stopCasting(); + StateCasting.instance.connectDevice(dev); + onConnect.emit(dev); + } } - setIsRememberedDevice(false); + _textName.setOnClickListener { connect() }; + _textType.setOnClickListener { connect() }; + _layoutDevice.setOnClickListener { connect() }; + + _imagePin.setOnClickListener { + val dev = device ?: return@setOnClickListener; + onPin.emit(dev); + } } - fun setIsRememberedDevice(isRememberedDevice: Boolean) { - _isRememberedDevice = isRememberedDevice; - _buttonRemove.visibility = if (isRememberedDevice) View.VISIBLE else View.GONE; - } - - fun bind(d: CastingDevice) { + fun bind(d: CastingDevice, isOnlineDevice: Boolean, isPinnedDevice: Boolean) { if (d is ChromecastCastingDevice) { _imageDevice.setImageResource(R.drawable.ic_chromecast); _textType.text = "Chromecast"; @@ -90,54 +84,47 @@ class DeviceViewHolder : ViewHolder { } _textName.text = d.name; - device = d; - updateButton(); - } - - private fun updateButton() { - val d = device ?: return; + _imageOnline.visibility = if (isOnlineDevice) View.VISIBLE else View.GONE if (!d.isReady) { - _buttonConnect.visibility = View.GONE; - _buttonDisconnect.visibility = View.GONE; _imageLoader.visibility = View.GONE; _textNotReady.visibility = View.VISIBLE; - return; - } - - _textNotReady.visibility = View.GONE; - - val dev = StateCasting.instance.activeDevice; - if (dev == d) { - if (dev.connectionState == CastConnectionState.CONNECTED) { - _buttonConnect.visibility = View.GONE; - _buttonDisconnect.visibility = View.VISIBLE; - _imageLoader.visibility = View.GONE; - _textNotReady.visibility = View.GONE; - } else { - _buttonConnect.visibility = View.GONE; - _buttonDisconnect.visibility = View.VISIBLE; - _imageLoader.visibility = View.VISIBLE; - _textNotReady.visibility = View.GONE; - } + _imagePin.visibility = View.GONE; } else { - if (d.isReady) { - _buttonConnect.visibility = View.VISIBLE; - _buttonDisconnect.visibility = View.GONE; - _imageLoader.visibility = View.GONE; - _textNotReady.visibility = View.GONE; + _textNotReady.visibility = View.GONE; + + val dev = StateCasting.instance.activeDevice; + if (dev == d) { + if (dev.connectionState == CastConnectionState.CONNECTED) { + _imageLoader.visibility = View.GONE; + _textNotReady.visibility = View.GONE; + _imagePin.visibility = View.VISIBLE; + } else { + _imageLoader.visibility = View.VISIBLE; + _textNotReady.visibility = View.GONE; + _imagePin.visibility = View.VISIBLE; + } } else { - _buttonConnect.visibility = View.GONE; - _buttonDisconnect.visibility = View.GONE; - _imageLoader.visibility = View.GONE; - _textNotReady.visibility = View.VISIBLE; + if (d.isReady) { + _imageLoader.visibility = View.GONE; + _textNotReady.visibility = View.GONE; + _imagePin.visibility = View.VISIBLE; + } else { + _imageLoader.visibility = View.GONE; + _textNotReady.visibility = View.VISIBLE; + _imagePin.visibility = View.VISIBLE; + } + } + + _imagePin.setImageResource(if (isPinnedDevice) R.drawable.keep_24px else R.drawable.ic_pin) + + if (_imageLoader.isVisible) { + _animatableLoader?.start(); + } else { + _animatableLoader?.stop(); } } - if (_imageLoader.visibility == View.VISIBLE) { - _animatableLoader?.start(); - } else { - _animatableLoader?.stop(); - } + device = d; } } \ No newline at end of file diff --git a/app/src/main/res/drawable/keep_24px.xml b/app/src/main/res/drawable/keep_24px.xml new file mode 100644 index 00000000..767284d6 --- /dev/null +++ b/app/src/main/res/drawable/keep_24px.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/dialog_casting_connect.xml b/app/src/main/res/layout/dialog_casting_connect.xml index e76b8c65..becfa5c8 100644 --- a/app/src/main/res/layout/dialog_casting_connect.xml +++ b/app/src/main/res/layout/dialog_casting_connect.xml @@ -11,25 +11,48 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" - android:orientation="horizontal"> + android:orientation="horizontal" + android:layout_marginTop="12dp"> - + android:orientation="vertical"> - + + + + + + + + + + android:layout_marginEnd="20dp" + android:layout_marginTop="10dp" + android:layout_marginBottom="20dp"/> + + + + - - - - + android:orientation="horizontal" + android:layout_marginTop="12dp" + android:layout_marginBottom="12dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp"> - - - - - - + android:gravity="center"> - + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_device.xml b/app/src/main/res/layout/list_device.xml index 534a9f2f..a4ae00f7 100644 --- a/app/src/main/res/layout/list_device.xml +++ b/app/src/main/res/layout/list_device.xml @@ -4,18 +4,34 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="35dp" - android:clickable="true"> + android:clickable="true" + android:id="@+id/layout_root"> - + app:layout_constraintBottom_toBottomOf="parent"> + + + + + - - - - - - - - - - - - - - - - - + android:layout_height="25dp" + android:contentDescription="@string/cd_image_loader" + app:srcCompat="@drawable/ic_pin" + android:layout_marginEnd="8dp" + android:scaleType="fitEnd" + android:paddingStart="10dp" /> IP Port Discovered Devices + Available devices Remembered Devices + Unable to see the device you\'re looking for? Try to add the device manually. There are no remembered devices Connected to Volume @@ -204,6 +206,7 @@ Previous Next Comment + Add manually Comment is not empty, close anyway? Import My Playlist Name