add start stop delete

This commit is contained in:
Minecon724 2024-08-06 15:45:23 +02:00
parent 6da971ef21
commit 784879393f
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
8 changed files with 183 additions and 20 deletions

View file

@ -49,7 +49,7 @@ fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
// TODO actually get instances
if (rentedInstances.size > 0) {
if (rentedInstances.isNotEmpty()) {
ContextualFlowRow(
modifier = Modifier
.fillMaxWidth()
@ -66,6 +66,12 @@ fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
sshButtonClick = {
dashboardViewModel.sshButtonClick(activity, it)
},
actionButtonClick = {
dashboardViewModel.toggleInstance(it)
},
deleteButtonClick = {
dashboardViewModel.deleteInstance(it)
}
)
}
} else {
@ -89,6 +95,8 @@ fun RentedInstanceCard(
rentedInstance: RentedInstance,
termuxAvailable: Int,
sshButtonClick: (RentedInstance) -> Unit,
actionButtonClick: (RentedInstance) -> Unit,
deleteButtonClick: (RentedInstance) -> Unit,
) {
val instance by remember(rentedInstance) { derivedStateOf { rentedInstance.instance } }
val label by remember(instance) { derivedStateOf {
@ -103,7 +111,45 @@ fun RentedInstanceCard(
Column(
horizontalAlignment = Alignment.End
) {
Button( // TODO consider other buttons
Row {
Button(
modifier = Modifier.size(24.dp),
contentPadding = PaddingValues(0.dp),
onClick = { deleteButtonClick(rentedInstance) },
) {
Icon(
modifier = Modifier.size(16.dp),
painter = painterResource(id = R.drawable.baseline_delete_24),
contentDescription = "Delete instance"
)
}
Spacer(modifier = Modifier.width(4.dp))
Button(
modifier = Modifier.size(24.dp),
contentPadding = PaddingValues(0.dp),
onClick = { actionButtonClick(rentedInstance) },
enabled = rentedInstance.status == rentedInstance.targetStatus
) {
if (rentedInstance.status == "running") {
Icon(
modifier = Modifier.size(16.dp),
painter = painterResource(id = R.drawable.baseline_stop_24),
contentDescription = "Stop instance"
)
} else {
Icon(
modifier = Modifier.size(16.dp),
painter = painterResource(id = R.drawable.baseline_play_arrow_24),
contentDescription = "Start instance"
)
}
}
Spacer(modifier = Modifier.width(4.dp))
Button(
modifier = Modifier.height(24.dp),
contentPadding = PaddingValues(0.dp),
onClick = { sshButtonClick(rentedInstance) }
@ -126,6 +172,7 @@ fun RentedInstanceCard(
Text("ssh")
}
}
}
Spacer(modifier = Modifier.height(6.dp))
Icon(

View file

@ -0,0 +1,16 @@
package eu.m724.vastapp.vastai.api
import eu.m724.vastapp.vastai.ApiFailure
import org.json.JSONObject
class JsonUrlRequestCallback(
onSuccess: (JSONObject) -> Unit,
onFailure: (ApiFailure) -> Unit
) : StringUrlRequestCallback({ stringResponse ->
try {
val jsonResponse = JSONObject(stringResponse)
onSuccess(jsonResponse)
} catch (e: Exception) {
onFailure(ApiFailure(e.message))
}
}, onFailure)

View file

@ -0,0 +1,51 @@
package eu.m724.vastapp.vastai.api
import eu.m724.vastapp.vastai.ApiFailure
import org.chromium.net.CronetException
import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo
import java.nio.ByteBuffer
import java.nio.charset.CodingErrorAction
open class StringUrlRequestCallback(
val onSuccess: (String) -> Unit,
val onFailure: (ApiFailure) -> Unit
) : UrlRequest.Callback() {
protected val stringResponse = StringBuilder()
override fun onRedirectReceived(
request: UrlRequest?,
info: UrlResponseInfo?,
newLocationUrl: String?
) {
request?.followRedirect()
}
override fun onResponseStarted(request: UrlRequest?, info: UrlResponseInfo?) {
request?.read(ByteBuffer.allocateDirect(102400))
}
override fun onReadCompleted(
request: UrlRequest?,
info: UrlResponseInfo?,
byteBuffer: ByteBuffer?
) {
byteBuffer?.clear()
request?.read(byteBuffer)
stringResponse.append(Charsets.UTF_8.newDecoder().onUnmappableCharacter(CodingErrorAction.IGNORE).decode(byteBuffer))
}
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
if (info?.httpStatusCode == 200) {
onSuccess(stringResponse.toString())
} else {
onFailure(ApiFailure("${info?.httpStatusCode} ${info?.httpStatusText}"))
println("API error: ${stringResponse.toString()}")
}
}
override fun onFailed(request: UrlRequest?, info: UrlResponseInfo?, error: CronetException?) {
onFailure(ApiFailure("Network error: ${error?.message ?: "Unknown"}"))
}
}

View file

@ -0,0 +1,9 @@
package eu.m724.vastapp.vastai.api.upload
import org.json.JSONObject
class JsonUploadDataProvider(
jsonObject: JSONObject
) : StringUploadDataProvider(
jsonObject.toString()
)

View file

@ -0,0 +1,25 @@
package eu.m724.vastapp.vastai.api.upload
import org.chromium.net.UploadDataProvider
import org.chromium.net.UploadDataSink
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
open class StringUploadDataProvider(
val data: String
) : UploadDataProvider() {
override fun getLength(): Long {
return data.length.toLong()
}
override fun read(uploadDataSink: UploadDataSink?, byteBuffer: ByteBuffer?) {
byteBuffer!!.put(data.toByteArray(StandardCharsets.UTF_8))
uploadDataSink!!.onReadSucceeded(false)
}
override fun rewind(uploadDataSink: UploadDataSink?) {
// TODO look into it
uploadDataSink!!.onRewindSucceeded()
}
}

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M6,6h12v12H6z"/>
</vector>