diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 23cc959e..8af2e2f5 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -49,9 +49,23 @@ We encourage developers to write their own plugins. Please refer to the "Getting ## Contributing to Core -**We are currently not accepting contributions to the core.** -The core is currently licensed under the FUTO Temporary License (FTL). The licensing and ownership of contributions to the core are complex topics that we are still working on. We'll update these guidelines when we have more clarity. +### License + +The core is currently licensed under the [Source First License 1.1](./LICENSE.md). All contributors have to sign FUTO Individual Contributor License Agreement before contributions can be accepted. You can read more about it at [https://cla.futo.org/](https://cla.futo.org/). + +### How to Contribute + +1. Fork the core repository. +2. Clone your fork. +3. Make your changes. +4. Commit and push your changes. +5. Open a pull request. + +### Guidelines + +- Ensure your code adheres to the existing style. +- Include documentation and unit tests (where applicable). --- diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt index 6c73aaec..b90c3849 100644 --- a/app/src/main/java/com/futo/platformplayer/Settings.kt +++ b/app/src/main/java/com/futo/platformplayer/Settings.kt @@ -144,7 +144,6 @@ class Settings : FragmentedStorageFileJson() { fun import() { val act = SettingsActivity.getActivity() ?: return; val intent = MainActivity.getImportOptionsIntent(act); - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK; act.startActivity(intent); } @@ -906,7 +905,7 @@ class Settings : FragmentedStorageFileJson() { var enabled: Boolean = true; @FormField(R.string.broadcast, FieldForm.TOGGLE, R.string.broadcast_description, 1) - var broadcast: Boolean = true; + var broadcast: Boolean = false; @FormField(R.string.connect_discovered, FieldForm.TOGGLE, R.string.connect_discovered_description, 2) var connectDiscovered: Boolean = true; diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt index 4142c4d4..33e60287 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -1233,28 +1233,28 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { val sourcesIntent = Intent(context, MainActivity::class.java); sourcesIntent.action = "TAB"; sourcesIntent.putExtra("TAB", tab); - sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return sourcesIntent; } fun getVideoIntent(context: Context, videoUrl: String) : Intent { val sourcesIntent = Intent(context, MainActivity::class.java); sourcesIntent.action = "VIDEO"; sourcesIntent.putExtra("VIDEO", videoUrl); - sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return sourcesIntent; } fun getActionIntent(context: Context, action: String) : Intent { val sourcesIntent = Intent(context, MainActivity::class.java); sourcesIntent.action = "ACTION"; sourcesIntent.putExtra("ACTION", action); - sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return sourcesIntent; } fun getImportOptionsIntent(context: Context): Intent { val sourcesIntent = Intent(context, MainActivity::class.java); sourcesIntent.action = "IMPORT_OPTIONS"; - sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return sourcesIntent; } } diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index 73571123..84d8709f 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -933,7 +933,7 @@ class VideoDetailView : ConstraintLayout { val device = devices.first(); UIDialogs.showConfirmationDialog(context, "Would you like to open\n[${videoToSend.name}]\non ${device.remotePublicKey}" , { fragment.lifecycleScope.launch(Dispatchers.IO) { - device.sendJson(GJSyncOpcodes.sendToDevices, SendToDevicePackage(videoToSend.url, (lastPositionMilliseconds/1000).toInt())); + device.sendJsonData(GJSyncOpcodes.sendToDevices, SendToDevicePackage(videoToSend.url, (lastPositionMilliseconds/1000).toInt())); } }) } @@ -1759,7 +1759,7 @@ class VideoDetailView : ConstraintLayout { }); else _player.setArtwork(null); - _player.setSource(videoSource, audioSource, _playWhenReady, false); + _player.setSource(videoSource, audioSource, _playWhenReady, false, resume = resumePositionMs > 0); if(subtitleSource != null) _player.swapSubtitles(fragment.lifecycleScope, subtitleSource); _player.seekTo(resumePositionMs); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt index acd92a67..cf2c032c 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt @@ -89,7 +89,7 @@ class StateHistory { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { if(StateSync.instance.hasAtLeastOneOnlineDevice()) { Logger.i(TAG, "SyncHistory playback broadcasted (${liveObj.name}: ${position})"); - StateSync.instance.broadcastJson( + StateSync.instance.broadcastJsonData( GJSyncOpcodes.syncHistory, listOf(historyVideo) ); diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt index 2826cb91..f5a033ab 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt @@ -198,7 +198,7 @@ class StatePlaylists { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { if(StateSync.instance.hasAtLeastOneOnlineDevice()) { Logger.i(StateSubscriptionGroups.TAG, "SyncPlaylist (${playlist.name})"); - StateSync.instance.broadcastJson( + StateSync.instance.broadcastJsonData( GJSyncOpcodes.syncPlaylists, SyncPlaylistsPackage(listOf(playlist), mapOf()) ); @@ -217,7 +217,7 @@ class StatePlaylists { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { if(StateSync.instance.hasAtLeastOneOnlineDevice()) { Logger.i(StateSubscriptionGroups.TAG, "SyncPlaylist (${playlist.name})"); - StateSync.instance.broadcastJson( + StateSync.instance.broadcastJsonData( GJSyncOpcodes.syncPlaylists, SyncPlaylistsPackage(listOf(), mapOf(Pair(playlist.id, OffsetDateTime.now().toEpochSecond()))) ); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptionGroups.kt b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptionGroups.kt index 2b4883da..5ca521ec 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptionGroups.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptionGroups.kt @@ -81,7 +81,7 @@ class StateSubscriptionGroups { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { if(StateSync.instance.hasAtLeastOneOnlineDevice()) { Logger.i(TAG, "SyncSubscriptionGroup (${subGroup.name})"); - StateSync.instance.broadcastJson( + StateSync.instance.broadcastJsonData( GJSyncOpcodes.syncSubscriptionGroups, SyncSubscriptionGroupsPackage(listOf(subGroup), mapOf()) ); @@ -100,7 +100,7 @@ class StateSubscriptionGroups { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { if(StateSync.instance.hasAtLeastOneOnlineDevice()) { Logger.i(TAG, "SyncSubscriptionGroup delete (${group.name})"); - StateSync.instance.broadcastJson( + StateSync.instance.broadcastJsonData( GJSyncOpcodes.syncSubscriptionGroups, SyncSubscriptionGroupsPackage(listOf(), mapOf(Pair(id, OffsetDateTime.now().toEpochSecond()))) ); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt index df680fed..52fb9f2e 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt @@ -250,7 +250,7 @@ class StateSubscriptions { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { try { - StateSync.instance.broadcast( + StateSync.instance.broadcastData( GJSyncOpcodes.syncSubscriptions, Json.encodeToString( SyncSubscriptionsPackage( listOf(subObj), @@ -299,7 +299,7 @@ class StateSubscriptions { StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { try { - StateSync.instance.broadcast( + StateSync.instance.broadcastData( GJSyncOpcodes.syncSubscriptions, Json.encodeToString( SyncSubscriptionsPackage( listOf(), diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt index b6bf0ca8..4de1b41c 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt @@ -370,26 +370,29 @@ class StateSync { Logger.i(TAG, "Connection authorized for ${remotePublicKey} because initiator") } }, - onData = { s, opcode, data -> - session?.handlePacket(s, opcode, data) + onData = { s, opcode, subOpcode, data -> + session?.handlePacket(s, opcode, subOpcode, data) }) } - inline fun broadcastJson(opcode: UByte, data: T) { - broadcast(opcode, Json.encodeToString(data)); + inline fun broadcastJsonData(subOpcode: UByte, data: T) { + broadcast(SyncSocketSession.Opcode.DATA.value, subOpcode, Json.encodeToString(data)); } - fun broadcast(opcode: UByte, data: String) { - broadcast(opcode, data.toByteArray(Charsets.UTF_8)); + fun broadcastData(subOpcode: UByte, data: String) { + broadcast(SyncSocketSession.Opcode.DATA.value, subOpcode, data.toByteArray(Charsets.UTF_8)); } - fun broadcast(opcode: UByte, data: ByteArray) { + fun broadcast(opcode: UByte, subOpcode: UByte, data: String) { + broadcast(opcode, subOpcode, data.toByteArray(Charsets.UTF_8)); + } + fun broadcast(opcode: UByte, subOpcode: UByte, data: ByteArray) { for(session in getSessions()) { try { if (session.isAuthorized && session.connected) { - session.send(opcode, data); + session.send(opcode, subOpcode, data); } } catch(ex: Exception) { - Logger.w(TAG, "Failed to broadcast ${opcode} to ${session.remotePublicKey}: ${ex.message}}", ex); + Logger.w(TAG, "Failed to broadcast (opcode = ${opcode}, subOpcode = ${subOpcode}) to ${session.remotePublicKey}: ${ex.message}}", ex); } } } @@ -398,7 +401,7 @@ class StateSync { val time = measureTimeMillis { //val export = StateBackup.export(); //session.send(GJSyncOpcodes.syncExport, export.asZip()); - session.send(GJSyncOpcodes.syncStateExchange, getSyncSessionDataString(session.remotePublicKey)); + session.sendData(GJSyncOpcodes.syncStateExchange, getSyncSessionDataString(session.remotePublicKey)); } Logger.i(TAG, "Generated and sent sync export in ${time}ms"); } diff --git a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSession.kt b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSession.kt index 6c46f59d..cca42a54 100644 --- a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSession.kt +++ b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSession.kt @@ -45,6 +45,7 @@ class SyncSession : IAuthorizable { private val _onConnectedChanged: (session: SyncSession, connected: Boolean) -> Unit val remotePublicKey: String override val isAuthorized get() = _authorized && _remoteAuthorized + private var _wasAuthorized = false var connected: Boolean = false private set(v) { @@ -94,8 +95,10 @@ class SyncSession : IAuthorizable { } private fun checkAuthorized() { - if (isAuthorized) + if (!_wasAuthorized && isAuthorized) { + _wasAuthorized = true _onAuthorized.invoke(this) + } } fun removeSocketSession(socketSession: SyncSocketSession) { @@ -117,29 +120,34 @@ class SyncSession : IAuthorizable { _onClose.invoke(this) } - fun handlePacket(socketSession: SyncSocketSession, opcode: UByte, data: ByteBuffer) { - Logger.i(TAG, "Handle packet (opcode: ${opcode}, data.length: ${data.remaining()})") - - when (opcode) { - Opcode.NOTIFY_AUTHORIZED.value -> { - _remoteAuthorized = true - checkAuthorized() - } - Opcode.NOTIFY_UNAUTHORIZED.value -> { - _remoteAuthorized = false - _onUnauthorized(this) - } - //TODO: Handle any kind of packet (that is not necessarily authorized) - } - - if (!isAuthorized) { - return - } - - Logger.i(TAG, "Received ${opcode} (${data.remaining()} bytes)") - //TODO: Abstract this out + fun handlePacket(socketSession: SyncSocketSession, opcode: UByte, subOpcode: UByte, data: ByteBuffer) { try { + Logger.i(TAG, "Handle packet (opcode: ${opcode}, subOpcode: ${subOpcode}, data.length: ${data.remaining()})") + when (opcode) { + Opcode.NOTIFY_AUTHORIZED.value -> { + _remoteAuthorized = true + checkAuthorized() + } + Opcode.NOTIFY_UNAUTHORIZED.value -> { + _remoteAuthorized = false + _onUnauthorized(this) + } + //TODO: Handle any kind of packet (that is not necessarily authorized) + } + + if (!isAuthorized) { + return + } + + if (opcode != Opcode.DATA.value) { + Logger.w(TAG, "Unknown opcode received: (opcode = ${opcode}, subOpcode = ${subOpcode})}") + return + } + + Logger.i(TAG, "Received (opcode = ${opcode}, subOpcode = ${subOpcode}) (${data.remaining()} bytes)") + //TODO: Abstract this out + when (subOpcode) { GJSyncOpcodes.sendToDevices -> { StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { val context = StateApp.instance.contextOrNull; @@ -164,13 +172,13 @@ class SyncSession : IAuthorizable { Logger.i(TAG, "Received SyncSessionData from " + remotePublicKey); - send(GJSyncOpcodes.syncSubscriptions, StateSubscriptions.instance.getSyncSubscriptionsPackageString()); - send(GJSyncOpcodes.syncSubscriptionGroups, StateSubscriptionGroups.instance.getSyncSubscriptionGroupsPackageString()); - send(GJSyncOpcodes.syncPlaylists, StatePlaylists.instance.getSyncPlaylistsPackageString()) + sendData(GJSyncOpcodes.syncSubscriptions, StateSubscriptions.instance.getSyncSubscriptionsPackageString()); + sendData(GJSyncOpcodes.syncSubscriptionGroups, StateSubscriptionGroups.instance.getSyncSubscriptionGroupsPackageString()); + sendData(GJSyncOpcodes.syncPlaylists, StatePlaylists.instance.getSyncPlaylistsPackageString()) val recentHistory = StateHistory.instance.getRecentHistory(syncSessionData.lastHistory); if(recentHistory.size > 0) - sendJson(GJSyncOpcodes.syncHistory, recentHistory); + sendJsonData(GJSyncOpcodes.syncHistory, recentHistory); } GJSyncOpcodes.syncExport -> { @@ -338,16 +346,19 @@ class SyncSession : IAuthorizable { } - inline fun sendJson(opcode: UByte, data: T) { - send(opcode, Json.encodeToString(data)); + inline fun sendJsonData(subOpcode: UByte, data: T) { + send(Opcode.DATA.value, subOpcode, Json.encodeToString(data)); } - fun send(opcode: UByte, data: String) { - send(opcode, data.toByteArray(Charsets.UTF_8)); + fun sendData(subOpcode: UByte, data: String) { + send(Opcode.DATA.value, subOpcode, data.toByteArray(Charsets.UTF_8)); } - fun send(opcode: UByte, data: ByteArray) { + fun send(opcode: UByte, subOpcode: UByte, data: String) { + send(opcode, subOpcode, data.toByteArray(Charsets.UTF_8)); + } + fun send(opcode: UByte, subOpcode: UByte, data: ByteArray) { val sock = _socketSessions.firstOrNull(); if(sock != null){ - sock.send(opcode, ByteBuffer.wrap(data)); + sock.send(opcode, subOpcode, ByteBuffer.wrap(data)); } else throw IllegalStateException("Session has no active sockets"); diff --git a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt index b7b5ab79..8b5f305a 100644 --- a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt +++ b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncSocketSession.kt @@ -2,6 +2,7 @@ package com.futo.platformplayer.sync.internal import com.futo.platformplayer.LittleEndianDataInputStream import com.futo.platformplayer.LittleEndianDataOutputStream +import com.futo.platformplayer.ensureNotMainThread import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.noise.protocol.CipherStatePair import com.futo.platformplayer.noise.protocol.DHState @@ -18,7 +19,8 @@ class SyncSocketSession { NOTIFY_UNAUTHORIZED(3u), STREAM_START(4u), STREAM_DATA(5u), - STREAM_END(6u) + STREAM_END(6u), + DATA(7u) } private val _inputStream: LittleEndianDataInputStream @@ -41,12 +43,12 @@ class SyncSocketSession { private val _localKeyPair: DHState private var _localPublicKey: String val localPublicKey: String get() = _localPublicKey - private val _onData: (session: SyncSocketSession, opcode: UByte, data: ByteBuffer) -> Unit + private val _onData: (session: SyncSocketSession, opcode: UByte, subOpcode: UByte, data: ByteBuffer) -> Unit var authorizable: IAuthorizable? = null val remoteAddress: String - constructor(remoteAddress: String, localKeyPair: DHState, inputStream: LittleEndianDataInputStream, outputStream: LittleEndianDataOutputStream, onClose: (session: SyncSocketSession) -> Unit, onHandshakeComplete: (session: SyncSocketSession) -> Unit, onData: (session: SyncSocketSession, opcode: UByte, data: ByteBuffer) -> Unit) { + constructor(remoteAddress: String, localKeyPair: DHState, inputStream: LittleEndianDataInputStream, outputStream: LittleEndianDataOutputStream, onClose: (session: SyncSocketSession) -> Unit, onHandshakeComplete: (session: SyncSocketSession) -> Unit, onData: (session: SyncSocketSession, opcode: UByte, subOpcode: UByte, data: ByteBuffer) -> Unit) { _inputStream = inputStream _outputStream = outputStream _onClose = onClose @@ -159,10 +161,11 @@ class SyncSocketSession { } private fun performVersionCheck() { - _outputStream.writeInt(1) + val CURRENT_VERSION = 2 + _outputStream.writeInt(CURRENT_VERSION) val version = _inputStream.readInt() Logger.i(TAG, "performVersionCheck (version = $version)") - if (version != 1) + if (version != CURRENT_VERSION) throw Exception("Invalid version") } @@ -205,8 +208,9 @@ class SyncSocketSession { throw Exception("Handshake finished without completing") } + fun send(opcode: UByte, subOpcode: UByte, data: ByteBuffer) { + ensureNotMainThread() - fun send(opcode: UByte, data: ByteBuffer) { if (data.remaining() + HEADER_SIZE > MAXIMUM_PACKET_SIZE) { val segmentSize = MAXIMUM_PACKET_SIZE - HEADER_SIZE val segmentData = ByteArray(segmentSize) @@ -223,8 +227,8 @@ class SyncSocketSession { if (sendOffset == 0) { segmentOpcode = Opcode.STREAM_START.value - bytesToSend = segmentSize - 4 - 4 - 1 - segmentPacketSize = bytesToSend + 4 + 4 + 1 + bytesToSend = segmentSize - 4 - 4 - 1 - 1 + segmentPacketSize = bytesToSend + 4 + 4 + 1 + 1 } else { bytesToSend = minOf(segmentSize - 4 - 4, bytesRemaining) segmentOpcode = if (bytesToSend >= bytesRemaining) Opcode.STREAM_END.value else Opcode.STREAM_DATA.value @@ -236,18 +240,20 @@ class SyncSocketSession { putInt(if (segmentOpcode == Opcode.STREAM_START.value) data.remaining() else sendOffset) if (segmentOpcode == Opcode.STREAM_START.value) { put(opcode.toByte()) + put(subOpcode.toByte()) } put(data.array(), data.position() + sendOffset, bytesToSend) } - send(segmentOpcode, ByteBuffer.wrap(segmentData, 0, segmentPacketSize)) + send(segmentOpcode, 0u, ByteBuffer.wrap(segmentData, 0, segmentPacketSize)) sendOffset += bytesToSend } } else { synchronized(_sendLockObject) { ByteBuffer.wrap(_sendBuffer).order(ByteOrder.LITTLE_ENDIAN).apply { - putInt(data.remaining() + 1) + putInt(data.remaining() + 2) put(opcode.toByte()) + put(subOpcode.toByte()) put(data.array(), data.position(), data.remaining()) } @@ -260,12 +266,15 @@ class SyncSocketSession { } } - fun send(opcode: UByte) { - synchronized(_sendLockObject) { - ByteBuffer.wrap(_sendBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(1) - _sendBuffer.asUByteArray()[4] = opcode + fun send(opcode: UByte, subOpcode: UByte = 0u) { + ensureNotMainThread() - //Logger.i(TAG, "Encrypting message (size = ${HEADER_SIZE})") + synchronized(_sendLockObject) { + ByteBuffer.wrap(_sendBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(2) + _sendBuffer.asUByteArray()[4] = opcode + _sendBuffer.asUByteArray()[5] = subOpcode + + //Logger.i(TAG, "Encrypting message (opcode = ${opcode}, subOpcode = ${subOpcode}, size = ${HEADER_SIZE})") val len = _cipherStatePair!!.sender.encryptWithAd(null, _sendBuffer, 0, _sendBufferEncrypted, 0, HEADER_SIZE) //Logger.i(TAG, "Sending encrypted message (size = ${len})") @@ -277,19 +286,19 @@ class SyncSocketSession { private fun handleData(data: ByteArray, length: Int) { if (length < HEADER_SIZE) - throw Exception("Packet must be at least 5 bytes (header size)") + throw Exception("Packet must be at least 6 bytes (header size)") val size = ByteBuffer.wrap(data, 0, 4).order(ByteOrder.LITTLE_ENDIAN).int if (size != length - 4) throw Exception("Incomplete packet received") val opcode = data.asUByteArray()[4] - val packetData = ByteBuffer.wrap(data, HEADER_SIZE, size - 1) - - handlePacket(opcode, packetData.order(ByteOrder.LITTLE_ENDIAN)) + val subOpcode = data.asUByteArray()[5] + val packetData = ByteBuffer.wrap(data, HEADER_SIZE, size - 2) + handlePacket(opcode, subOpcode, packetData.order(ByteOrder.LITTLE_ENDIAN)) } - private fun handlePacket(opcode: UByte, data: ByteBuffer) { + private fun handlePacket(opcode: UByte, subOpcode: UByte, data: ByteBuffer) { when (opcode) { Opcode.PING.value -> { send(Opcode.PONG.value) @@ -302,7 +311,7 @@ class SyncSocketSession { } Opcode.NOTIFY_AUTHORIZED.value, Opcode.NOTIFY_UNAUTHORIZED.value -> { - _onData.invoke(this, opcode, data) + _onData.invoke(this, opcode, subOpcode, data) return } } @@ -316,8 +325,9 @@ class SyncSocketSession { val id = data.int val expectedSize = data.int val op = data.get().toUByte() + val subOp = data.get().toUByte() - val syncStream = SyncStream(expectedSize, op) + val syncStream = SyncStream(expectedSize, op, subOp) if (data.remaining() > 0) { syncStream.add(data.array(), data.position(), data.remaining()) } @@ -362,10 +372,13 @@ class SyncSocketSession { throw Exception("After sync stream end, the stream must be complete") } - handlePacket(syncStream.opcode, syncStream.getBytes().let { ByteBuffer.wrap(it).order(ByteOrder.LITTLE_ENDIAN) }) + handlePacket(syncStream.opcode, syncStream.subOpcode, syncStream.getBytes().let { ByteBuffer.wrap(it).order(ByteOrder.LITTLE_ENDIAN) }) + } + Opcode.DATA.value -> { + _onData.invoke(this, opcode, subOpcode, data) } else -> { - _onData.invoke(this, opcode, data) + Logger.w(TAG, "Unknown opcode received (opcode = ${opcode}, subOpcode = ${subOpcode})") } } } @@ -374,6 +387,6 @@ class SyncSocketSession { private const val TAG = "SyncSocketSession" const val MAXIMUM_PACKET_SIZE = 65535 - 16 const val MAXIMUM_PACKET_SIZE_ENCRYPTED = MAXIMUM_PACKET_SIZE + 16 - const val HEADER_SIZE = 5 + const val HEADER_SIZE = 6 } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncStream.kt b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncStream.kt index 5a60e295..d558feef 100644 --- a/app/src/main/java/com/futo/platformplayer/sync/internal/SyncStream.kt +++ b/app/src/main/java/com/futo/platformplayer/sync/internal/SyncStream.kt @@ -1,6 +1,6 @@ package com.futo.platformplayer.sync.internal -class SyncStream(expectedSize: Int, val opcode: UByte) { +class SyncStream(expectedSize: Int, val opcode: UByte, val subOpcode: UByte) { companion object { const val MAXIMUM_SIZE = 10_000_000 } diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 82ad7944..fcc6dc6d 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -327,8 +327,8 @@ abstract class FutoVideoPlayerBase : RelativeLayout { return _chapters?.let { chaps -> chaps.find { pos.toDouble() / 1000 > it.timeStart && pos.toDouble() / 1000 < it.timeEnd && (toIgnore.isEmpty() || !toIgnore.contains(it)) } }; } - fun setSource(videoSource: IVideoSource?, audioSource: IAudioSource? = null, play: Boolean = false, keepSubtitles: Boolean = false) { - swapSources(videoSource, audioSource,false, play, keepSubtitles); + fun setSource(videoSource: IVideoSource?, audioSource: IAudioSource? = null, play: Boolean = false, keepSubtitles: Boolean = false, resume: Boolean = false) { + swapSources(videoSource, audioSource,resume, play, keepSubtitles); } fun swapSources(videoSource: IVideoSource?, audioSource: IAudioSource?, resume: Boolean = true, play: Boolean = true, keepSubtitles: Boolean = false): Boolean { var videoSourceUsed = videoSource; diff --git a/app/src/main/res/layout/activity_add_source.xml b/app/src/main/res/layout/activity_add_source.xml index 9adf25ed..469a4508 100644 --- a/app/src/main/res/layout/activity_add_source.xml +++ b/app/src/main/res/layout/activity_add_source.xml @@ -22,6 +22,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingRight="20dp" app:srcCompat="@drawable/ic_back_thin_white_16dp" /> diff --git a/app/src/main/res/layout/activity_add_source_options.xml b/app/src/main/res/layout/activity_add_source_options.xml index 28752940..541d489d 100644 --- a/app/src/main/res/layout/activity_add_source_options.xml +++ b/app/src/main/res/layout/activity_add_source_options.xml @@ -22,6 +22,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingRight="20dp" app:srcCompat="@drawable/ic_back_thin_white_16dp" /> diff --git a/app/src/main/res/layout/activity_dev.xml b/app/src/main/res/layout/activity_dev.xml index 1780ede6..c1caef04 100644 --- a/app/src/main/res/layout/activity_dev.xml +++ b/app/src/main/res/layout/activity_dev.xml @@ -22,6 +22,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingRight="20dp" app:srcCompat="@drawable/ic_back_thin_white_16dp" /> diff --git a/app/src/main/res/layout/activity_fcast_guide.xml b/app/src/main/res/layout/activity_fcast_guide.xml index 4d6a2b89..5ccd0fa7 100644 --- a/app/src/main/res/layout/activity_fcast_guide.xml +++ b/app/src/main/res/layout/activity_fcast_guide.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index fd35ed06..6f8fe755 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -14,6 +14,7 @@ android:id="@+id/button_close" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_close" android:scaleType="fitCenter" android:padding="10dp" app:layout_constraintLeft_toLeftOf="parent" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 34f54a1f..1708eeb4 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -75,6 +75,7 @@ android:id="@+id/incognito_button" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_incognito_button" android:src="@drawable/ic_disabled_visible_purple" android:background="@drawable/background_button_round_black" android:scaleType="fitCenter" diff --git a/app/src/main/res/layout/activity_manage_tabs.xml b/app/src/main/res/layout/activity_manage_tabs.xml index 7a4a1e1f..986dfa11 100644 --- a/app/src/main/res/layout/activity_manage_tabs.xml +++ b/app/src/main/res/layout/activity_manage_tabs.xml @@ -21,6 +21,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingRight="20dp" app:srcCompat="@drawable/ic_back_thin_white_16dp" /> diff --git a/app/src/main/res/layout/activity_polycentric_backup.xml b/app/src/main/res/layout/activity_polycentric_backup.xml index 3f437667..e31e8584 100644 --- a/app/src/main/res/layout/activity_polycentric_backup.xml +++ b/app/src/main/res/layout/activity_polycentric_backup.xml @@ -9,6 +9,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" @@ -19,6 +20,7 @@ android:id="@+id/button_help" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_help" app:srcCompat="@drawable/ic_help" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/activity_polycentric_create_profile.xml b/app/src/main/res/layout/activity_polycentric_create_profile.xml index 93583944..53ef19c2 100644 --- a/app/src/main/res/layout/activity_polycentric_create_profile.xml +++ b/app/src/main/res/layout/activity_polycentric_create_profile.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:layout_constraintLeft_toLeftOf="parent" @@ -20,6 +21,8 @@ android:id="@+id/button_help" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_help" + app:srcCompat="@drawable/ic_help" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/ic_help" /> diff --git a/app/src/main/res/layout/activity_polycentric_home.xml b/app/src/main/res/layout/activity_polycentric_home.xml index 36e206cd..a948d54b 100644 --- a/app/src/main/res/layout/activity_polycentric_home.xml +++ b/app/src/main/res/layout/activity_polycentric_home.xml @@ -9,6 +9,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" @@ -19,6 +20,7 @@ android:id="@+id/button_help" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_help" app:srcCompat="@drawable/ic_help" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/activity_polycentric_import_profile.xml b/app/src/main/res/layout/activity_polycentric_import_profile.xml index 992395cf..b7013f40 100644 --- a/app/src/main/res/layout/activity_polycentric_import_profile.xml +++ b/app/src/main/res/layout/activity_polycentric_import_profile.xml @@ -9,6 +9,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" @@ -19,6 +20,7 @@ android:id="@+id/button_help" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_help" app:srcCompat="@drawable/ic_help" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/activity_polycentric_profile.xml b/app/src/main/res/layout/activity_polycentric_profile.xml index e4b81d5d..d9266fd0 100644 --- a/app/src/main/res/layout/activity_polycentric_profile.xml +++ b/app/src/main/res/layout/activity_polycentric_profile.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" @@ -20,6 +21,7 @@ android:id="@+id/button_help" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_help" app:srcCompat="@drawable/ic_help" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -28,6 +30,7 @@ android:id="@+id/image_polycentric" android:layout_height="80dp" android:layout_width="80dp" + android:contentDescription="@string/cd_image_polycentric" android:scaleType="centerCrop" app:shapeAppearanceOverlay="@style/roundedCorners_40dp" app:srcCompat="@drawable/placeholder_profile" diff --git a/app/src/main/res/layout/activity_polycentric_why.xml b/app/src/main/res/layout/activity_polycentric_why.xml index 1f4a8872..63d8f19c 100644 --- a/app/src/main/res/layout/activity_polycentric_why.xml +++ b/app/src/main/res/layout/activity_polycentric_why.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index b0bf134b..0c815387 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -24,6 +24,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingRight="20dp" app:srcCompat="@drawable/ic_back_thin_white_16dp" /> diff --git a/app/src/main/res/layout/activity_sync_home.xml b/app/src/main/res/layout/activity_sync_home.xml index 6cb4872c..0f353fb4 100644 --- a/app/src/main/res/layout/activity_sync_home.xml +++ b/app/src/main/res/layout/activity_sync_home.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" diff --git a/app/src/main/res/layout/activity_sync_pair.xml b/app/src/main/res/layout/activity_sync_pair.xml index e95f324b..e5355ecc 100644 --- a/app/src/main/res/layout/activity_sync_pair.xml +++ b/app/src/main/res/layout/activity_sync_pair.xml @@ -10,6 +10,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" diff --git a/app/src/main/res/layout/activity_sync_show_pairing_code.xml b/app/src/main/res/layout/activity_sync_show_pairing_code.xml index a7d5631a..4d92980a 100644 --- a/app/src/main/res/layout/activity_sync_show_pairing_code.xml +++ b/app/src/main/res/layout/activity_sync_show_pairing_code.xml @@ -14,6 +14,7 @@ android:id="@+id/button_back" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_back" android:padding="10dp" android:scaleType="fitCenter" app:srcCompat="@drawable/ic_back_thin_white_16dp" diff --git a/app/src/main/res/layout/dialog_automatic_backup.xml b/app/src/main/res/layout/dialog_automatic_backup.xml index 1f570c4b..bfa7c0f6 100644 --- a/app/src/main/res/layout/dialog_automatic_backup.xml +++ b/app/src/main/res/layout/dialog_automatic_backup.xml @@ -27,6 +27,7 @@ android:id="@+id/button_cancel" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_button_close" app:srcCompat="@drawable/ic_close_thin" app:tint="#888888" android:layout_marginEnd="30dp" /> diff --git a/app/src/main/res/layout/dialog_casting_connect.xml b/app/src/main/res/layout/dialog_casting_connect.xml index 24777828..e76b8c65 100644 --- a/app/src/main/res/layout/dialog_casting_connect.xml +++ b/app/src/main/res/layout/dialog_casting_connect.xml @@ -97,6 +97,7 @@ android:id="@+id/button_scan_qr" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_scan_qr" android:scaleType="centerCrop" app:srcCompat="@drawable/ic_qr" app:tint="@color/primary" /> @@ -109,6 +110,7 @@ android:id="@+id/button_add" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_add" android:scaleType="centerCrop" app:srcCompat="@drawable/ic_add" app:tint="@color/primary" diff --git a/app/src/main/res/layout/dialog_casting_connected.xml b/app/src/main/res/layout/dialog_casting_connected.xml index 8b593e9d..027db929 100644 --- a/app/src/main/res/layout/dialog_casting_connected.xml +++ b/app/src/main/res/layout/dialog_casting_connected.xml @@ -58,6 +58,7 @@ android:id="@+id/image_device" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_image_device" app:srcCompat="@drawable/ic_chromecast" android:scaleType="fitCenter" app:layout_constraintLeft_toLeftOf="parent" @@ -197,6 +198,7 @@ android:id="@id/button_previous" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_previous" android:scaleType="centerCrop" android:clickable="true" android:padding="10dp" @@ -206,6 +208,7 @@ android:id="@+id/button_play" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_play" android:padding="20dp" android:scaleType="fitCenter" android:clickable="true" @@ -215,6 +218,7 @@ android:id="@+id/button_pause" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_pause" android:padding="10dp" android:scaleType="fitCenter" android:clickable="true" @@ -224,6 +228,7 @@ android:id="@+id/button_stop" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_stop" android:scaleType="fitCenter" android:padding="5dp" android:clickable="true" @@ -233,6 +238,7 @@ android:id="@id/button_next" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_next" android:clickable="true" android:scaleType="centerCrop" android:padding="10dp" diff --git a/app/src/main/res/layout/dialog_update.xml b/app/src/main/res/layout/dialog_update.xml index 051a604c..9dceccd4 100644 --- a/app/src/main/res/layout/dialog_update.xml +++ b/app/src/main/res/layout/dialog_update.xml @@ -23,6 +23,7 @@ android:id="@+id/update_spinner" android:layout_width="100dp" android:layout_height="100dp" + android:contentDescription="@string/cd_update_spinner" app:srcCompat="@drawable/ic_update_animated" /> diff --git a/app/src/main/res/layout/fragment_navigation_top_bar.xml b/app/src/main/res/layout/fragment_navigation_top_bar.xml index ab8d8f87..f7317f6a 100644 --- a/app/src/main/res/layout/fragment_navigation_top_bar.xml +++ b/app/src/main/res/layout/fragment_navigation_top_bar.xml @@ -11,6 +11,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingLeft="16dp" android:paddingRight="8dp" app:srcCompat="@drawable/ic_back_nav" /> @@ -34,6 +35,7 @@ android:id="@+id/button_cast" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_cast_button" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="9dp" diff --git a/app/src/main/res/layout/fragment_overview_top_bar.xml b/app/src/main/res/layout/fragment_overview_top_bar.xml index c87619bf..1fe9e047 100644 --- a/app/src/main/res/layout/fragment_overview_top_bar.xml +++ b/app/src/main/res/layout/fragment_overview_top_bar.xml @@ -10,6 +10,7 @@ android:id="@+id/app_icon" android:layout_width="35dp" android:layout_height="35dp" + android:contentDescription="@string/cd_app_icon" android:layout_marginStart="16dp" android:layout_marginEnd="4dp" android:scaleType="fitCenter" @@ -37,6 +38,7 @@ android:id="@+id/button_cast" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_cast_button" android:paddingStart="16dp" android:paddingEnd="12dp" android:paddingTop="12dp" @@ -49,6 +51,7 @@ android:id="@+id/button_search" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_search" android:paddingStart="5dp" android:paddingEnd="12dp" android:paddingTop="11dp" diff --git a/app/src/main/res/layout/fragment_playlists.xml b/app/src/main/res/layout/fragment_playlists.xml index b86cfe68..cd2050b6 100644 --- a/app/src/main/res/layout/fragment_playlists.xml +++ b/app/src/main/res/layout/fragment_playlists.xml @@ -34,6 +34,7 @@ android:id="@+id/image_history" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_icon_history" app:srcCompat="@drawable/ic_clock_white" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -119,6 +120,7 @@ android:id="@+id/button_create_playlist" android:layout_width="35dp" android:layout_height="20dp" + android:contentDescription="@string/cd_button_create_playlist" app:srcCompat="@drawable/ic_add_white_16dp" android:paddingEnd="15dp" android:paddingStart="15dp" diff --git a/app/src/main/res/layout/fragment_remote_playlist.xml b/app/src/main/res/layout/fragment_remote_playlist.xml index bee1f714..42b38fb5 100644 --- a/app/src/main/res/layout/fragment_remote_playlist.xml +++ b/app/src/main/res/layout/fragment_remote_playlist.xml @@ -58,6 +58,7 @@ android:id="@+id/button_share" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_share" android:background="@drawable/background_button_round" android:gravity="center" android:layout_marginStart="5dp" diff --git a/app/src/main/res/layout/fragment_search_top_bar.xml b/app/src/main/res/layout/fragment_search_top_bar.xml index f4b64615..277eb133 100644 --- a/app/src/main/res/layout/fragment_search_top_bar.xml +++ b/app/src/main/res/layout/fragment_search_top_bar.xml @@ -13,6 +13,7 @@ android:id="@+id/button_back" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_back" android:paddingLeft="16dp" android:paddingRight="16dp" app:srcCompat="@drawable/ic_back_white_24dp" /> @@ -27,6 +28,7 @@ android:id="@+id/edit_search" android:layout_width="fill_parent" android:layout_height="wrap_content" + android:hint="Search" android:layout_weight="1" android:inputType="text" android:imeOptions="actionDone" @@ -37,6 +39,7 @@ android:id="@+id/button_clear_search" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_clear_search" android:paddingStart="18dp" android:paddingEnd="18dp" android:layout_gravity="right|center_vertical" @@ -48,6 +51,7 @@ android:id="@+id/button_filter" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_filter" android:paddingStart="8dp" android:paddingEnd="8dp" android:scaleType="fitCenter" diff --git a/app/src/main/res/layout/fragment_subscriptions_group.xml b/app/src/main/res/layout/fragment_subscriptions_group.xml index a26789cc..31c8d5fa 100644 --- a/app/src/main/res/layout/fragment_subscriptions_group.xml +++ b/app/src/main/res/layout/fragment_subscriptions_group.xml @@ -43,6 +43,7 @@ android:id="@+id/button_delete" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_delete" android:layout_marginLeft="5dp" android:layout_marginRight="0dp" android:src="@drawable/ic_trash" @@ -56,6 +57,7 @@ android:id="@+id/button_settings" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_settings" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:src="@drawable/ic_settings" @@ -69,6 +71,7 @@ android:id="@+id/image_group" android:layout_width="110dp" android:layout_height="70dp" + android:contentDescription="@string/cd_image_group" android:adjustViewBounds="true" app:circularflow_defaultRadius="10dp" android:layout_marginLeft="30dp" @@ -90,6 +93,7 @@ + android:layout_height="27dp" + android:contentDescription="@string/cd_creator_thumbnail" /> @@ -285,6 +288,7 @@ android:id="@+id/button_share" android:layout_width="32dp" android:layout_height="32dp" + android:contentDescription="@string/cd_button_share" android:background="@drawable/background_button_round" android:gravity="center" android:layout_marginStart="5dp" diff --git a/app/src/main/res/layout/fragview_video_detail.xml b/app/src/main/res/layout/fragview_video_detail.xml index 71ad3869..d5062c06 100644 --- a/app/src/main/res/layout/fragview_video_detail.xml +++ b/app/src/main/res/layout/fragview_video_detail.xml @@ -103,6 +103,7 @@ android:id="@+id/minimize_play" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_minimize_play" android:padding="10dp" android:clickable="true" android:scaleType="fitCenter" @@ -111,6 +112,7 @@ android:id="@+id/minimize_pause" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_minimize_pause" android:padding="5dp" android:scaleType="fitCenter" android:clickable="true" @@ -119,6 +121,7 @@ android:id="@+id/minimize_close" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_minimize_close" android:padding="5dp" android:scaleType="fitCenter" android:layout_marginStart="2dp" @@ -337,7 +340,8 @@ + android:layout_height="35dp" + android:contentDescription="@string/cd_creator_thumbnail" /> diff --git a/app/src/main/res/layout/list_comment.xml b/app/src/main/res/layout/list_comment.xml index 2141bf7f..ea2c861a 100644 --- a/app/src/main/res/layout/list_comment.xml +++ b/app/src/main/res/layout/list_comment.xml @@ -100,6 +100,7 @@ android:id="@+id/image_like_icon" android:layout_width="18dp" android:layout_height="18dp" + android:contentDescription="@string/cd_image_like_icon" app:srcCompat="@drawable/ic_thumb_up" /> @@ -134,6 +136,7 @@ android:id="@+id/button_replies" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_replies" app:pillIcon="@drawable/ic_forum" app:pillText="55 Replies" android:layout_marginStart="15dp" /> diff --git a/app/src/main/res/layout/list_comment_with_reference.xml b/app/src/main/res/layout/list_comment_with_reference.xml index 2e828255..73d53a3f 100644 --- a/app/src/main/res/layout/list_comment_with_reference.xml +++ b/app/src/main/res/layout/list_comment_with_reference.xml @@ -91,6 +91,7 @@ android:id="@+id/button_replies" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_replies" app:pillIcon="@drawable/ic_forum" app:pillText="55 Replies" android:layout_marginStart="15dp" /> @@ -112,6 +113,7 @@ android:id="@+id/pill_text" android:layout_width="wrap_content" android:layout_height="match_parent" + android:contentDescription="@string/cd_button_delete" android:textColor="@color/white" android:textSize="13dp" android:gravity="center_vertical" diff --git a/app/src/main/res/layout/list_creator.xml b/app/src/main/res/layout/list_creator.xml index d14ad856..5237ccd9 100644 --- a/app/src/main/res/layout/list_creator.xml +++ b/app/src/main/res/layout/list_creator.xml @@ -56,6 +56,7 @@ android:id="@+id/button_subscribe" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/cd_button_subscribe" android:layout_marginTop="10dp" app:layout_constraintTop_toBottomOf="@id/text_channel_metadata" app:layout_constraintLeft_toLeftOf="parent" @@ -65,6 +66,7 @@ android:id="@+id/platform_indicator" android:layout_width="24dp" android:layout_height="24dp" + android:contentDescription="@string/cd_platform_indicator" android:layout_marginTop="18dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" diff --git a/app/src/main/res/layout/list_device.xml b/app/src/main/res/layout/list_device.xml index 874adba9..534a9f2f 100644 --- a/app/src/main/res/layout/list_device.xml +++ b/app/src/main/res/layout/list_device.xml @@ -10,6 +10,7 @@ android:id="@+id/image_device" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_image_device" app:srcCompat="@drawable/ic_chromecast" android:scaleType="fitCenter" app:layout_constraintLeft_toLeftOf="parent" @@ -63,6 +64,7 @@ android:id="@+id/image_loader" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_image_loader" app:srcCompat="@drawable/ic_loader_animated" android:layout_marginEnd="8dp"/> diff --git a/app/src/main/res/layout/list_donation.xml b/app/src/main/res/layout/list_donation.xml index 921cd87a..cf0a05f1 100644 --- a/app/src/main/res/layout/list_donation.xml +++ b/app/src/main/res/layout/list_donation.xml @@ -20,6 +20,7 @@ android:id="@+id/donation_author_image" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_donation_author_image" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/list_history.xml b/app/src/main/res/layout/list_history.xml index ec1d943c..88a10b81 100644 --- a/app/src/main/res/layout/list_history.xml +++ b/app/src/main/res/layout/list_history.xml @@ -173,6 +173,7 @@ android:id="@+id/image_trash" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_delete" app:srcCompat="@drawable/ic_trash_18dp" android:scaleType="fitCenter" android:paddingTop="10dp" diff --git a/app/src/main/res/layout/list_import_subscription.xml b/app/src/main/res/layout/list_import_subscription.xml index 15424fc3..9d30ead2 100644 --- a/app/src/main/res/layout/list_import_subscription.xml +++ b/app/src/main/res/layout/list_import_subscription.xml @@ -45,7 +45,8 @@ + android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" /> \ No newline at end of file diff --git a/app/src/main/res/layout/list_locked_preview.xml b/app/src/main/res/layout/list_locked_preview.xml index 59cb602a..2413c98c 100644 --- a/app/src/main/res/layout/list_locked_preview.xml +++ b/app/src/main/res/layout/list_locked_preview.xml @@ -194,6 +194,7 @@ android:id="@+id/creator_thumbnail" android:layout_width="32dp" android:layout_height="32dp" + android:contentDescription="@string/cd_creator_thumbnail" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="10dp" @@ -272,6 +273,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" tools:src="@drawable/ic_peertube"/> diff --git a/app/src/main/res/layout/list_locked_thumbnail.xml b/app/src/main/res/layout/list_locked_thumbnail.xml index f5fe8a57..462d65d4 100644 --- a/app/src/main/res/layout/list_locked_thumbnail.xml +++ b/app/src/main/res/layout/list_locked_thumbnail.xml @@ -306,6 +306,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" android:layout_margin="4dp" /> diff --git a/app/src/main/res/layout/list_playlist.xml b/app/src/main/res/layout/list_playlist.xml index 3a46a6be..d51cdfc5 100644 --- a/app/src/main/res/layout/list_playlist.xml +++ b/app/src/main/res/layout/list_playlist.xml @@ -14,6 +14,7 @@ android:id="@+id/image_drag_drop" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_drag_drop" app:srcCompat="@drawable/ic_dragdrop_white" android:scaleType="fitCenter" android:paddingTop="10dp" @@ -116,6 +117,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" + android:contentDescription="@string/cd_download_indicator" app:srcCompat="@drawable/download_for_offline" /> @@ -174,6 +176,7 @@ android:id="@+id/image_trash" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_delete" app:srcCompat="@drawable/ic_trash_18dp" android:scaleType="fitCenter" android:paddingTop="10dp" diff --git a/app/src/main/res/layout/list_playlist_feed.xml b/app/src/main/res/layout/list_playlist_feed.xml index f2f30845..14a01d39 100644 --- a/app/src/main/res/layout/list_playlist_feed.xml +++ b/app/src/main/res/layout/list_playlist_feed.xml @@ -41,6 +41,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" android:layout_alignParentStart="true" android:layout_alignParentBottom="true" android:layout_gravity="end" diff --git a/app/src/main/res/layout/list_playlist_feed_preview.xml b/app/src/main/res/layout/list_playlist_feed_preview.xml index 6ce90101..6be094b0 100644 --- a/app/src/main/res/layout/list_playlist_feed_preview.xml +++ b/app/src/main/res/layout/list_playlist_feed_preview.xml @@ -108,6 +108,7 @@ android:id="@+id/creator_thumbnail" android:layout_width="32dp" android:layout_height="32dp" + android:contentDescription="@string/cd_creator_thumbnail" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="10dp" @@ -161,6 +162,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" /> diff --git a/app/src/main/res/layout/list_playlists.xml b/app/src/main/res/layout/list_playlists.xml index 52ada168..a180d134 100644 --- a/app/src/main/res/layout/list_playlists.xml +++ b/app/src/main/res/layout/list_playlists.xml @@ -72,6 +72,7 @@ android:id="@+id/button_trash" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_delete" app:srcCompat="@drawable/ic_trash" android:padding="10dp" android:scaleType="fitCenter" diff --git a/app/src/main/res/layout/list_post_preview.xml b/app/src/main/res/layout/list_post_preview.xml index e298fd88..3eb61c55 100644 --- a/app/src/main/res/layout/list_post_preview.xml +++ b/app/src/main/res/layout/list_post_preview.xml @@ -90,6 +90,7 @@ android:id="@+id/platform_indicator" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" android:layout_marginEnd="8dp" app:layout_constraintTop_toTopOf="@id/image_author_thumbnail" @@ -157,6 +158,7 @@ android:id="@+id/image_like_icon" android:layout_width="18dp" android:layout_height="18dp" + android:contentDescription="@string/cd_image_like_icon" app:srcCompat="@drawable/ic_thumb_up" /> @@ -202,6 +205,7 @@ android:id="@+id/image_comments" android:layout_width="18dp" android:layout_height="18dp" + android:contentDescription="@string/Replies" android:layout_marginStart="8dp" android:layout_marginTop="2dp" app:srcCompat="@drawable/ic_forum" /> diff --git a/app/src/main/res/layout/list_post_thumbnail.xml b/app/src/main/res/layout/list_post_thumbnail.xml index e16ab48f..922e0f28 100644 --- a/app/src/main/res/layout/list_post_thumbnail.xml +++ b/app/src/main/res/layout/list_post_thumbnail.xml @@ -90,6 +90,7 @@ android:id="@+id/platform_indicator" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" tools:src="@drawable/ic_peertube" android:layout_marginEnd="8dp" diff --git a/app/src/main/res/layout/list_source_construction.xml b/app/src/main/res/layout/list_source_construction.xml index 8b5cf0af..0da89b04 100644 --- a/app/src/main/res/layout/list_source_construction.xml +++ b/app/src/main/res/layout/list_source_construction.xml @@ -24,6 +24,7 @@ android:id="@+id/image_source" android:layout_width="35dp" android:layout_height="35dp" + android:contentDescription="@string/cd_platform_indicator" app:srcCompat="@drawable/ic_peertube" android:scaleType="fitCenter" /> diff --git a/app/src/main/res/layout/list_source_disabled.xml b/app/src/main/res/layout/list_source_disabled.xml index 4ef72985..3a6de99d 100644 --- a/app/src/main/res/layout/list_source_disabled.xml +++ b/app/src/main/res/layout/list_source_disabled.xml @@ -24,6 +24,7 @@ android:id="@+id/image_source" android:layout_width="35dp" android:layout_height="35dp" + android:contentDescription="@string/cd_platform_indicator" app:srcCompat="@drawable/ic_peertube" android:scaleType="fitCenter" /> diff --git a/app/src/main/res/layout/list_source_enabled.xml b/app/src/main/res/layout/list_source_enabled.xml index 0223971f..630b2bcc 100644 --- a/app/src/main/res/layout/list_source_enabled.xml +++ b/app/src/main/res/layout/list_source_enabled.xml @@ -15,6 +15,7 @@ android:id="@+id/image_drag_drop" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_drag_drop" app:srcCompat="@drawable/ic_dragdrop_white" android:scaleType="fitCenter" android:paddingTop="10dp" @@ -34,6 +35,7 @@ android:id="@+id/image_source" android:layout_width="35dp" android:layout_height="35dp" + android:contentDescription="@string/cd_platform_indicator" app:srcCompat="@drawable/ic_peertube" android:scaleType="fitCenter" /> diff --git a/app/src/main/res/layout/list_subscription.xml b/app/src/main/res/layout/list_subscription.xml index 6abd51c7..ffbdf4ed 100644 --- a/app/src/main/res/layout/list_subscription.xml +++ b/app/src/main/res/layout/list_subscription.xml @@ -14,6 +14,7 @@ android:id="@+id/creator_thumbnail" android:layout_width="46dp" android:layout_height="46dp" + android:contentDescription="@string/cd_creator_thumbnail" android:layout_marginStart="20dp"/> + android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" /> @@ -213,6 +215,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" tools:src="@drawable/ic_peertube" /> @@ -230,6 +233,7 @@ android:id="@+id/button_add_to_watch_later" android:layout_width="30dp" android:layout_height="30dp" + android:contentDescription="@string/cd_button_add_to_watch_later" android:layout_marginEnd="5dp" android:background="@drawable/edit_text_background" app:srcCompat="@drawable/ic_clock_white" /> diff --git a/app/src/main/res/layout/list_video_preview_nested.xml b/app/src/main/res/layout/list_video_preview_nested.xml index c61c37e6..d321ed81 100644 --- a/app/src/main/res/layout/list_video_preview_nested.xml +++ b/app/src/main/res/layout/list_video_preview_nested.xml @@ -40,6 +40,7 @@ android:id="@+id/thumbnail_platform_nested" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" android:layout_margin="5dp" @@ -173,6 +174,7 @@ android:id="@+id/creator_thumbnail" android:layout_width="32dp" android:layout_height="32dp" + android:contentDescription="@string/cd_creator_thumbnail" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="10dp" @@ -242,6 +244,7 @@ @@ -250,6 +253,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="25dp" android:layout_height="25dp" + android:contentDescription="@string/cd_platform_indicator" android:scaleType="centerInside" tools:src="@drawable/ic_peertube"/> @@ -267,6 +271,7 @@ android:id="@+id/button_add_to_watch_later" android:layout_width="30dp" android:layout_height="30dp" + android:contentDescription="@string/cd_button_add_to_watch_later" android:layout_marginEnd="5dp" android:background="@drawable/edit_text_background" app:srcCompat="@drawable/ic_clock_white" /> diff --git a/app/src/main/res/layout/list_video_thumbnail.xml b/app/src/main/res/layout/list_video_thumbnail.xml index 51806a95..367730cc 100644 --- a/app/src/main/res/layout/list_video_thumbnail.xml +++ b/app/src/main/res/layout/list_video_thumbnail.xml @@ -104,6 +104,7 @@ @@ -112,6 +113,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" android:layout_alignParentStart="true" android:layout_alignParentBottom="true" android:layout_gravity="end" @@ -188,6 +190,7 @@ android:id="@+id/button_add_to_watch_later" android:layout_width="wrap_content" android:layout_height="27dp" + android:contentDescription="@string/cd_button_add_to_watch_later" android:src="@drawable/ic_clock_white" android:paddingTop="7dp" android:paddingBottom="6dp" diff --git a/app/src/main/res/layout/list_video_thumbnail_nested.xml b/app/src/main/res/layout/list_video_thumbnail_nested.xml index 4ddc8a61..82018ddb 100644 --- a/app/src/main/res/layout/list_video_thumbnail_nested.xml +++ b/app/src/main/res/layout/list_video_thumbnail_nested.xml @@ -104,6 +104,7 @@ @@ -112,6 +113,7 @@ android:id="@+id/thumbnail_platform" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" android:layout_alignParentStart="true" android:layout_alignParentBottom="true" android:layout_gravity="end" @@ -227,6 +229,7 @@ android:id="@+id/button_add_to_watch_later" android:layout_width="wrap_content" android:layout_height="27dp" + android:contentDescription="@string/cd_button_add_to_watch_later" android:src="@drawable/ic_clock_white" android:paddingTop="7dp" android:paddingBottom="6dp" @@ -320,6 +323,7 @@ android:id="@+id/thumbnail_platform_nested" android:layout_width="20dp" android:layout_height="20dp" + android:contentDescription="@string/cd_platform_indicator" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" android:layout_margin="4dp" /> diff --git a/app/src/main/res/layout/overlay_livechat.xml b/app/src/main/res/layout/overlay_livechat.xml index 9339c9a5..3e83d8e4 100644 --- a/app/src/main/res/layout/overlay_livechat.xml +++ b/app/src/main/res/layout/overlay_livechat.xml @@ -66,6 +66,7 @@ android:id="@+id/button_close" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_close" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_margin="7dp" @@ -126,6 +127,7 @@ android:scaleType="fitCenter" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_creator_thumbnail" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_margin="20dp" @@ -159,6 +161,7 @@ android:id="@+id/donation_amount" android:layout_width="match_parent" android:layout_height="wrap_content" + android:contentDescription="@string/cd_donation_amount" android:gravity="center" tools:text="$100" /> @@ -229,6 +232,7 @@ android:scaleType="fitCenter" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_creator_thumbnail" android:layout_marginEnd="10dp" android:layout_marginStart="-20dp" android:src="@drawable/placeholder_profile" /> diff --git a/app/src/main/res/layout/overlay_topbar.xml b/app/src/main/res/layout/overlay_topbar.xml index f7a9cae9..53ea310d 100644 --- a/app/src/main/res/layout/overlay_topbar.xml +++ b/app/src/main/res/layout/overlay_topbar.xml @@ -56,6 +56,7 @@ android:id="@+id/button_close" android:layout_width="40dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_close" android:padding="5dp" android:src="@drawable/ic_close" /> diff --git a/app/src/main/res/layout/thumbnail_player_ui.xml b/app/src/main/res/layout/thumbnail_player_ui.xml index a1df6ede..2b590856 100644 --- a/app/src/main/res/layout/thumbnail_player_ui.xml +++ b/app/src/main/res/layout/thumbnail_player_ui.xml @@ -25,6 +25,7 @@ android:id="@+id/thumbnail_player_unmute" android:layout_width="34dp" android:layout_height="34dp" + android:contentDescription="@string/cd_thumbnail_player_unmute" android:padding="7dp" android:layout_gravity="center_vertical" android:background="@color/transparent" diff --git a/app/src/main/res/layout/video_player_ui.xml b/app/src/main/res/layout/video_player_ui.xml index e849b942..486936a6 100644 --- a/app/src/main/res/layout/video_player_ui.xml +++ b/app/src/main/res/layout/video_player_ui.xml @@ -14,6 +14,7 @@ android:id="@+id/button_minimize" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_minimize" android:scaleType="fitCenter" android:clickable="true" android:padding="3dp" @@ -33,6 +34,7 @@ android:id="@+id/button_autoplay" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_autoplay" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -41,6 +43,7 @@ android:id="@+id/button_cast" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_cast_button" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -49,6 +52,7 @@ android:id="@+id/button_rotate_lock" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_rotate_lock" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -57,6 +61,7 @@ android:id="@+id/button_loop" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_loop" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -65,6 +70,7 @@ android:id="@+id/button_settings" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_settings" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -75,6 +81,7 @@ android:id="@+id/button_previous" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_previous" android:scaleType="centerCrop" android:clickable="true" android:layout_marginRight="40dp" @@ -118,6 +125,7 @@ android:id="@+id/button_next" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_next" android:clickable="true" android:scaleType="centerCrop" android:padding="5dp" @@ -131,6 +139,7 @@ android:id="@+id/button_fullscreen" android:layout_width="55dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_fullscreen" android:clickable="true" app:srcCompat="@drawable/ic_expand" app:layout_constraintRight_toRightOf="parent" diff --git a/app/src/main/res/layout/video_player_ui_fullscreen.xml b/app/src/main/res/layout/video_player_ui_fullscreen.xml index d4d93182..f291bc1c 100644 --- a/app/src/main/res/layout/video_player_ui_fullscreen.xml +++ b/app/src/main/res/layout/video_player_ui_fullscreen.xml @@ -13,6 +13,7 @@ android:id="@+id/button_minimize" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_minimize" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:scaleType="fitCenter" @@ -61,6 +62,7 @@ android:id="@+id/button_autoplay" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_autoplay" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -69,6 +71,7 @@ android:id="@+id/button_cast" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_cast_button" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -77,6 +80,7 @@ android:id="@+id/button_rotate_lock" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_rotate_lock" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -85,6 +89,7 @@ android:id="@+id/button_loop" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_loop" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -93,6 +98,7 @@ android:id="@+id/button_settings" android:layout_width="50dp" android:layout_height="50dp" + android:contentDescription="@string/cd_button_settings" android:scaleType="fitCenter" android:clickable="true" android:padding="12dp" @@ -103,6 +109,7 @@ android:id="@+id/button_previous" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_previous" android:scaleType="centerCrop" android:clickable="true" android:layout_marginRight="40dp" @@ -146,6 +153,7 @@ android:id="@+id/button_next" android:layout_width="60dp" android:layout_height="60dp" + android:contentDescription="@string/cd_button_next" android:clickable="true" android:scaleType="centerCrop" android:padding="5dp" @@ -159,6 +167,7 @@ android:id="@+id/button_fullscreen" android:layout_width="55dp" android:layout_height="40dp" + android:contentDescription="@string/cd_button_fullscreen" android:clickable="true" app:srcCompat="@drawable/ic_expand" app:layout_constraintRight_toRightOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2f1b02d7..cb7b7e67 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -811,6 +811,64 @@ Scroll to top Disable Battery Optimization Click to go to battery optimization settings. Disabling battery optimization will prevent the OS from killing media sessions. + Cast button + Incognito button + Creator thumbnail + Clear search + Search + Search icon + Back button + App icon + History icon + Create playlist + Share + Filter + Delete + Settings + Group image + Edit + Download + Close + Pause + Play + Donation amount + Replies + Like + Dislike + Subscribe + Platform indicator + Device icon + Loader + Donation author's image + Edit image + Add + Download indicator + Drag and drop + Add to Watch Later + Close + Unmute + Minimize + Lock rotation + Loop + Previous + Next + Fullscreen + Autoplay + Update spinner + Play + Pause + Stop + Scan QR code + Help + Change Polycentric profile picture + Settings + Settings + Settings + Settings + Settings + Settings + Settings + Settings Recommendations Subscriptions diff --git a/app/src/stable/assets/sources/twitch b/app/src/stable/assets/sources/twitch index 58ea7722..543a727d 160000 --- a/app/src/stable/assets/sources/twitch +++ b/app/src/stable/assets/sources/twitch @@ -1 +1 @@ -Subproject commit 58ea77229dcdb5c9ce8f1bd642baf29486d0bf21 +Subproject commit 543a727d781fe5780fd0e8f20d53f6a53b285446 diff --git a/app/src/stable/assets/sources/youtube b/app/src/stable/assets/sources/youtube index 80c9b4d3..0ce91be2 160000 --- a/app/src/stable/assets/sources/youtube +++ b/app/src/stable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 80c9b4d3b48739170b40b313be930329dcc59fe4 +Subproject commit 0ce91be276681ab82d26f9471523beab6b2a0a00 diff --git a/app/src/test/java/com/futo/platformplayer/NoiseProtocolTests.kt b/app/src/test/java/com/futo/platformplayer/NoiseProtocolTests.kt index 1597fd64..33b640f9 100644 --- a/app/src/test/java/com/futo/platformplayer/NoiseProtocolTests.kt +++ b/app/src/test/java/com/futo/platformplayer/NoiseProtocolTests.kt @@ -524,8 +524,8 @@ class NoiseProtocolTest { println("Initiator handshake complete") handshakeLatch.countDown() // Handshake complete for initiator }, - onData = { session, opcode, data -> - println("Initiator received: Opcode $opcode, Data Length: ${data.remaining()}") + onData = { session, opcode, subOpcode, data -> + println("Initiator received: Opcode: $opcode, SubOpcode: $subOpcode, Data Length: ${data.remaining()}") when (data.remaining()) { randomBytesExactlyOnePacket.remaining() -> { @@ -556,8 +556,8 @@ class NoiseProtocolTest { println("Responder handshake complete") handshakeLatch.countDown() // Handshake complete for responder }, - onData = { session, opcode, data -> - println("Responder received: Opcode $opcode, Data Length: ${data.remaining()}") + onData = { session, opcode, subOpcode, data -> + println("Responder received: Opcode $opcode, SubOpcode $subOpcode, Data Length: ${data.remaining()}") when (data.remaining()) { randomBytesExactlyOnePacket.remaining() -> { @@ -590,12 +590,12 @@ class NoiseProtocolTest { responderSession.send(SyncSocketSession.Opcode.PONG.value) // Test data transfer - responderSession.send(SyncSocketSession.Opcode.NOTIFY_AUTHORIZED.value, randomBytesExactlyOnePacket) - initiatorSession.send(SyncSocketSession.Opcode.NOTIFY_AUTHORIZED.value, randomBytes) + responderSession.send(SyncSocketSession.Opcode.DATA.value, 0u, randomBytesExactlyOnePacket) + initiatorSession.send(SyncSocketSession.Opcode.DATA.value, 1u, randomBytes) // Send large data to test stream handling val start = System.currentTimeMillis() - responderSession.send(SyncSocketSession.Opcode.NOTIFY_AUTHORIZED.value, randomBytesBig) + responderSession.send(SyncSocketSession.Opcode.DATA.value, 0u, randomBytesBig) println("Sent 10MB in ${System.currentTimeMillis() - start}ms") // Wait for a brief period to simulate delay and allow communication diff --git a/app/src/unstable/assets/sources/twitch b/app/src/unstable/assets/sources/twitch index 58ea7722..543a727d 160000 --- a/app/src/unstable/assets/sources/twitch +++ b/app/src/unstable/assets/sources/twitch @@ -1 +1 @@ -Subproject commit 58ea77229dcdb5c9ce8f1bd642baf29486d0bf21 +Subproject commit 543a727d781fe5780fd0e8f20d53f6a53b285446 diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index 80c9b4d3..0ce91be2 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 80c9b4d3b48739170b40b313be930329dcc59fe4 +Subproject commit 0ce91be276681ab82d26f9471523beab6b2a0a00