fixed downloading galleris with long title, [wip] transfer data
This commit is contained in:
@@ -38,7 +38,7 @@ android {
|
|||||||
compileSdk 34
|
compileSdk 34
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 69
|
versionCode 69
|
||||||
versionName "5.3.13"
|
versionName "5.3.14"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"filters": [],
|
"filters": [],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 69,
|
"versionCode": 69,
|
||||||
"versionName": "5.3.12",
|
"versionName": "5.3.14",
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ class DownloadService : Service() {
|
|||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
notification[galleryID]?.setContentTitle(galleryInfo.title?.ellipsize(30))
|
notification[galleryID]?.setContentTitle(galleryInfo.title.ellipsize(32))
|
||||||
notify(galleryID)
|
notify(galleryID)
|
||||||
|
|
||||||
val queued = mutableSetOf<Int>()
|
val queued = mutableSetOf<Int>()
|
||||||
@@ -408,7 +408,7 @@ class DownloadService : Service() {
|
|||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
||||||
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
||||||
} else {
|
} else {
|
||||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (intent?.getStringExtra(KEY_COMMAND)) {
|
when (intent?.getStringExtra(KEY_COMMAND)) {
|
||||||
@@ -433,7 +433,7 @@ class DownloadService : Service() {
|
|||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
||||||
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
startForeground(R.id.downloader_notification_id, serviceNotification.build())
|
||||||
} else {
|
} else {
|
||||||
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
startForeground(R.id.downloader_notification_id, serviceNotification.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
|
||||||
}
|
}
|
||||||
interceptors[Tag::class] = interceptor
|
interceptors[Tag::class] = interceptor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,18 +12,21 @@ import io.ktor.network.selector.SelectorManager
|
|||||||
import io.ktor.network.sockets.aSocket
|
import io.ktor.network.sockets.aSocket
|
||||||
import io.ktor.network.sockets.openReadChannel
|
import io.ktor.network.sockets.openReadChannel
|
||||||
import io.ktor.network.sockets.openWriteChannel
|
import io.ktor.network.sockets.openWriteChannel
|
||||||
import io.ktor.utils.io.writeStringUtf8
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.trySendBlocking
|
import kotlinx.coroutines.channels.trySendBlocking
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import kotlin.coroutines.Continuation
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
class TransferClientService : Service() {
|
class TransferClientService : Service() {
|
||||||
private val selectorManager = SelectorManager(Dispatchers.IO)
|
private val selectorManager = SelectorManager(Dispatchers.IO)
|
||||||
private val channel = Channel<String>()
|
private val channel = Channel<Pair<TransferPacket, Continuation<TransferPacket>>>()
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
|
|
||||||
private fun startForeground() = runCatching {
|
private fun startForeground() = runCatching {
|
||||||
@@ -64,13 +67,28 @@ class TransferClientService : Service() {
|
|||||||
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
|
TransferPacket.Hello().writeToChannel(writeChannel)
|
||||||
|
val handshake = TransferPacket.readFromChannel(readChannel)
|
||||||
|
|
||||||
|
if (handshake !is TransferPacket.Hello || handshake.version != TRANSFER_PROTOCOL_VERSION) {
|
||||||
|
throw IllegalStateException("Invalid handshake")
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
val message = channel.receive()
|
val (packet, continuation) = channel.receive()
|
||||||
Log.d("PUPILD", "Sending message $message!")
|
|
||||||
writeChannel.writeStringUtf8(message)
|
Log.d("PUPILD", "Sending packet $packet")
|
||||||
Log.d("PUPILD", readChannel.readUTF8Line(4).toString())
|
|
||||||
|
packet.writeToChannel(writeChannel)
|
||||||
|
|
||||||
|
val response = TransferPacket.readFromChannel(readChannel).also {
|
||||||
|
Log.d("PUPILD", "Received packet $it")
|
||||||
|
}
|
||||||
|
|
||||||
|
continuation.resume(response)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
Log.d("PUPILD", "Connection closed with error $it")
|
||||||
socket.close()
|
socket.close()
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
}
|
}
|
||||||
@@ -85,9 +103,14 @@ class TransferClientService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class Binder: android.os.Binder() {
|
inner class Binder: android.os.Binder() {
|
||||||
fun sendMessage(message: String) {
|
|
||||||
Log.d("PUPILD", "Sending message $message")
|
|
||||||
channel.trySendBlocking(message + '\n')
|
suspend fun sendPacket(packet: TransferPacket): Result<TransferPacket.ListResponse> = runCatching {
|
||||||
|
val response = withTimeout(1000) { suspendCoroutine { continuation ->
|
||||||
|
channel.trySendBlocking(packet to continuation)
|
||||||
|
} }
|
||||||
|
|
||||||
|
response as? TransferPacket.ListResponse ?: throw IllegalStateException("Invalid response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package xyz.quaver.pupil.services
|
||||||
|
|
||||||
|
import io.ktor.utils.io.ByteReadChannel
|
||||||
|
import io.ktor.utils.io.ByteWriteChannel
|
||||||
|
|
||||||
|
const val TRANSFER_PROTOCOL_VERSION: UByte = 1u
|
||||||
|
|
||||||
|
enum class TransferType(val value: UByte) {
|
||||||
|
INVALID(255u),
|
||||||
|
HELLO(0u),
|
||||||
|
PING(1u),
|
||||||
|
PONG(2u),
|
||||||
|
LIST_REQUEST(3u),
|
||||||
|
LIST_RESPONSE(4u),
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface TransferPacket {
|
||||||
|
val type: TransferType
|
||||||
|
|
||||||
|
suspend fun writeToChannel(channel: ByteWriteChannel)
|
||||||
|
|
||||||
|
data class Hello(val version: UByte = TRANSFER_PROTOCOL_VERSION): TransferPacket {
|
||||||
|
override val type = TransferType.HELLO
|
||||||
|
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
channel.writeByte(version.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object Ping: TransferPacket {
|
||||||
|
override val type = TransferType.PING
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object Pong: TransferPacket {
|
||||||
|
override val type = TransferType.PONG
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object ListRequest: TransferPacket {
|
||||||
|
override val type = TransferType.LIST_REQUEST
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object Invalid: TransferPacket {
|
||||||
|
override val type = TransferType.INVALID
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ListResponse(
|
||||||
|
val favoritesCount: Int,
|
||||||
|
val historyCount: Int,
|
||||||
|
val downloadsCount: Int,
|
||||||
|
): TransferPacket {
|
||||||
|
override val type = TransferType.LIST_RESPONSE
|
||||||
|
|
||||||
|
override suspend fun writeToChannel(channel: ByteWriteChannel) {
|
||||||
|
channel.writeByte(type.value.toByte())
|
||||||
|
channel.writeInt(favoritesCount)
|
||||||
|
channel.writeInt(historyCount)
|
||||||
|
channel.writeInt(downloadsCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
suspend fun readFromChannel(channel: ByteReadChannel): TransferPacket {
|
||||||
|
return when(val type = channel.readByte().toUByte()) {
|
||||||
|
TransferType.HELLO.value -> {
|
||||||
|
val version = channel.readByte().toUByte()
|
||||||
|
Hello(version)
|
||||||
|
}
|
||||||
|
TransferType.PING.value -> Ping
|
||||||
|
TransferType.PONG.value -> Pong
|
||||||
|
TransferType.LIST_REQUEST.value -> ListRequest
|
||||||
|
TransferType.LIST_RESPONSE.value -> {
|
||||||
|
val favoritesCount = channel.readInt()
|
||||||
|
val historyCount = channel.readInt()
|
||||||
|
val downloadsCount = channel.readInt()
|
||||||
|
ListResponse(favoritesCount, historyCount, downloadsCount)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Unknown packet type: $type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,12 +14,15 @@ import io.ktor.network.sockets.Socket
|
|||||||
import io.ktor.network.sockets.aSocket
|
import io.ktor.network.sockets.aSocket
|
||||||
import io.ktor.network.sockets.openReadChannel
|
import io.ktor.network.sockets.openReadChannel
|
||||||
import io.ktor.network.sockets.openWriteChannel
|
import io.ktor.network.sockets.openWriteChannel
|
||||||
import io.ktor.utils.io.writeStringUtf8
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.favorites
|
||||||
|
import xyz.quaver.pupil.histories
|
||||||
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
|
|
||||||
class TransferServerService : Service() {
|
class TransferServerService : Service() {
|
||||||
private val selectorManager = SelectorManager(Dispatchers.IO)
|
private val selectorManager = SelectorManager(Dispatchers.IO)
|
||||||
@@ -43,15 +46,33 @@ class TransferServerService : Service() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateListResponse(): TransferPacket.ListResponse {
|
||||||
|
val favoritesCount = favorites.size
|
||||||
|
val historyCount = histories.size
|
||||||
|
val downloadsCount = DownloadManager.getInstance(this).downloadFolderMap.size
|
||||||
|
return TransferPacket.ListResponse(favoritesCount, historyCount, downloadsCount)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun handleConnection(socket: Socket) {
|
private suspend fun handleConnection(socket: Socket) {
|
||||||
val readChannel = socket.openReadChannel()
|
val readChannel = socket.openReadChannel()
|
||||||
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
val writeChannel = socket.openWriteChannel(autoFlush = true)
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (readChannel.readUTF8Line(8) == "ping") {
|
val packet = TransferPacket.readFromChannel(readChannel)
|
||||||
writeChannel.writeStringUtf8("pong\n")
|
|
||||||
|
Log.d("PUPILD", "Received packet $packet")
|
||||||
|
|
||||||
|
binder.channel.trySend(packet)
|
||||||
|
|
||||||
|
val response = when (packet) {
|
||||||
|
is TransferPacket.Hello -> TransferPacket.Hello()
|
||||||
|
is TransferPacket.Ping -> TransferPacket.Pong
|
||||||
|
is TransferPacket.ListRequest -> generateListResponse()
|
||||||
|
else -> TransferPacket.Invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.writeToChannel(writeChannel)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
socket.close()
|
socket.close()
|
||||||
@@ -93,7 +114,7 @@ class TransferServerService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class Binder: android.os.Binder() {
|
inner class Binder: android.os.Binder() {
|
||||||
fun getService() = this@TransferServerService
|
val channel = Channel<TransferPacket>()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val binder = Binder()
|
private val binder = Binder()
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import kotlinx.coroutines.channels.consumeEach
|
import kotlinx.coroutines.channels.consumeEach
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.cancellable
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@@ -44,6 +43,7 @@ import kotlinx.coroutines.launch
|
|||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.receiver.WifiDirectBroadcastReceiver
|
import xyz.quaver.pupil.receiver.WifiDirectBroadcastReceiver
|
||||||
import xyz.quaver.pupil.services.TransferClientService
|
import xyz.quaver.pupil.services.TransferClientService
|
||||||
|
import xyz.quaver.pupil.services.TransferPacket
|
||||||
import xyz.quaver.pupil.services.TransferServerService
|
import xyz.quaver.pupil.services.TransferServerService
|
||||||
import xyz.quaver.pupil.ui.fragment.TransferConnectedFragment
|
import xyz.quaver.pupil.ui.fragment.TransferConnectedFragment
|
||||||
import xyz.quaver.pupil.ui.fragment.TransferDirectionFragment
|
import xyz.quaver.pupil.ui.fragment.TransferDirectionFragment
|
||||||
@@ -81,15 +81,15 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var serviceBinder: TransferClientService.Binder? = null
|
private var clientServiceBinder: TransferClientService.Binder? = null
|
||||||
|
|
||||||
private val serviceConnection = object : ServiceConnection {
|
private val clientServiceConnection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
serviceBinder = service as TransferClientService.Binder
|
clientServiceBinder = service as TransferClientService.Binder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
serviceBinder = null
|
clientServiceBinder = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +118,17 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleServerResponse(response: TransferPacket?) {
|
||||||
|
when (response) {
|
||||||
|
is TransferPacket.ListResponse -> {
|
||||||
|
Log.d("PUPILD", "Received list response $response")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Log.d("PUPILD", "Received invalid response $response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -146,11 +157,12 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
}
|
}
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.messageQueue.consumeEach {
|
viewModel.messageQueue.consumeEach {
|
||||||
serviceBinder?.sendMessage(it)
|
clientServiceBinder?.sendPacket(it)?.getOrNull()?.let(::handleServerResponse)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.step.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).cancellable().collect step@{ step ->
|
lifecycleScope.launch {
|
||||||
Log.d("PUPILD", "Step: $step")
|
viewModel.step.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).collectLatest step@{ step ->
|
||||||
when (step) {
|
when (step) {
|
||||||
TransferStep.TARGET,
|
TransferStep.TARGET,
|
||||||
TransferStep.TARGET_FORCE -> {
|
TransferStep.TARGET_FORCE -> {
|
||||||
@@ -176,7 +188,8 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
val intent = Intent(this@TransferActivity, TransferClientService::class.java).also {
|
val intent = Intent(this@TransferActivity, TransferClientService::class.java).also {
|
||||||
it.putExtra("address", hostAddress)
|
it.putExtra("address", hostAddress)
|
||||||
}
|
}
|
||||||
bindService(intent, serviceConnection, BIND_AUTO_CREATE)
|
ContextCompat.startForegroundService(this@TransferActivity, intent)
|
||||||
|
bindService(intent, clientServiceConnection, BIND_AUTO_CREATE)
|
||||||
|
|
||||||
viewModel.setStep(TransferStep.SELECT_DATA)
|
viewModel.setStep(TransferStep.SELECT_DATA)
|
||||||
}
|
}
|
||||||
@@ -243,6 +256,16 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
it.putExtra("address", address)
|
it.putExtra("address", address)
|
||||||
}
|
}
|
||||||
ContextCompat.startForegroundService(this@TransferActivity, intent)
|
ContextCompat.startForegroundService(this@TransferActivity, intent)
|
||||||
|
val binder: TransferServerService.Binder = suspendCoroutine { continuation ->
|
||||||
|
bindService(intent, object: ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
|
continuation.resume(service as TransferServerService.Binder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) { }
|
||||||
|
}, BIND_AUTO_CREATE)
|
||||||
|
}
|
||||||
|
binder.channel.receive()
|
||||||
|
|
||||||
viewModel.setStep(TransferStep.CONNECTED)
|
viewModel.setStep(TransferStep.CONNECTED)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
@@ -271,6 +294,7 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
bindService(Intent(this, TransferClientService::class.java), clientServiceConnection, BIND_AUTO_CREATE)
|
||||||
WifiDirectBroadcastReceiver(manager, channel, viewModel).also {
|
WifiDirectBroadcastReceiver(manager, channel, viewModel).also {
|
||||||
receiver = it
|
receiver = it
|
||||||
registerReceiver(it, intentFilter)
|
registerReceiver(it, intentFilter)
|
||||||
@@ -279,6 +303,7 @@ class TransferActivity : AppCompatActivity(R.layout.transfer_activity) {
|
|||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
unbindService(clientServiceConnection)
|
||||||
receiver?.let { unregisterReceiver(it) }
|
receiver?.let { unregisterReceiver(it) }
|
||||||
receiver = null
|
receiver = null
|
||||||
}
|
}
|
||||||
@@ -313,7 +338,7 @@ class TransferViewModel : ViewModel() {
|
|||||||
private val _peerToConnect: MutableLiveData<WifiP2pDevice?> = MutableLiveData(null)
|
private val _peerToConnect: MutableLiveData<WifiP2pDevice?> = MutableLiveData(null)
|
||||||
val peerToConnect: LiveData<WifiP2pDevice?> = _peerToConnect
|
val peerToConnect: LiveData<WifiP2pDevice?> = _peerToConnect
|
||||||
|
|
||||||
val messageQueue: Channel<String> = Channel()
|
val messageQueue: Channel<TransferPacket> = Channel()
|
||||||
|
|
||||||
fun setStep(step: TransferStep) {
|
fun setStep(step: TransferStep) {
|
||||||
Log.d("PUPILD", "Set step: $step")
|
Log.d("PUPILD", "Set step: $step")
|
||||||
@@ -345,6 +370,10 @@ class TransferViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ping() {
|
fun ping() {
|
||||||
messageQueue.trySend("ping")
|
messageQueue.trySend(TransferPacket.Ping)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list() {
|
||||||
|
messageQueue.trySend(TransferPacket.ListRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ class TransferSelectDataFragment: Fragment() {
|
|||||||
_binding = TransferSelectDataFragmentBinding.inflate(inflater, container, false)
|
_binding = TransferSelectDataFragmentBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
binding.checkAll.setOnCheckedChangeListener { _, isChecked ->
|
binding.checkAll.setOnCheckedChangeListener { _, isChecked ->
|
||||||
viewModel.ping()
|
viewModel.list()
|
||||||
}
|
}
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package xyz.quaver.pupil.util.downloader
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.app.Activity
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
@@ -136,18 +137,20 @@ fun byteCount(codePoint: Int): Int = when (codePoint) {
|
|||||||
fun String.ellipsize(n: Int): String = buildString {
|
fun String.ellipsize(n: Int): String = buildString {
|
||||||
var count = 0
|
var count = 0
|
||||||
var index = 0
|
var index = 0
|
||||||
val codePointLength = this.codePointCount(0, this.length)
|
val codePointLength = this@ellipsize.codePointCount(0, this@ellipsize.length)
|
||||||
|
|
||||||
while (index < codePointLength) {
|
while (index < codePointLength) {
|
||||||
val next = this.codePointAt(index)
|
val nextCodePoint = this@ellipsize.codePointAt(index)
|
||||||
if (count + next > 124) {
|
val nextByte = byteCount(nextCodePoint)
|
||||||
|
if (count + nextByte > 124) {
|
||||||
append("…")
|
append("…")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
appendCodePoint(next)
|
appendCodePoint(nextCodePoint)
|
||||||
count += next
|
count += nextByte
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun JsonElement.get(index: Int) =
|
operator fun JsonElement.get(index: Int) =
|
||||||
|
|||||||
@@ -52,9 +52,9 @@
|
|||||||
app:defaultValue="8"
|
app:defaultValue="8"
|
||||||
app:useSimpleSummaryProvider="true"/>
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
|
||||||
<Preference
|
<!-- <Preference-->
|
||||||
app:key="transfer_data"
|
<!-- app:key="transfer_data"-->
|
||||||
app:title="@string/settings_transfer_data"/>
|
<!-- app:title="@string/settings_transfer_data"/>-->
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
app:key="nomedia"
|
app:key="nomedia"
|
||||||
|
|||||||
Reference in New Issue
Block a user