add start stop delete
This commit is contained in:
parent
6da971ef21
commit
784879393f
8 changed files with 183 additions and 20 deletions
|
@ -49,7 +49,7 @@ fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
|
||||||
|
|
||||||
// TODO actually get instances
|
// TODO actually get instances
|
||||||
|
|
||||||
if (rentedInstances.size > 0) {
|
if (rentedInstances.isNotEmpty()) {
|
||||||
ContextualFlowRow(
|
ContextualFlowRow(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -66,6 +66,12 @@ fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
|
||||||
sshButtonClick = {
|
sshButtonClick = {
|
||||||
dashboardViewModel.sshButtonClick(activity, it)
|
dashboardViewModel.sshButtonClick(activity, it)
|
||||||
},
|
},
|
||||||
|
actionButtonClick = {
|
||||||
|
dashboardViewModel.toggleInstance(it)
|
||||||
|
},
|
||||||
|
deleteButtonClick = {
|
||||||
|
dashboardViewModel.deleteInstance(it)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -89,6 +95,8 @@ fun RentedInstanceCard(
|
||||||
rentedInstance: RentedInstance,
|
rentedInstance: RentedInstance,
|
||||||
termuxAvailable: Int,
|
termuxAvailable: Int,
|
||||||
sshButtonClick: (RentedInstance) -> Unit,
|
sshButtonClick: (RentedInstance) -> Unit,
|
||||||
|
actionButtonClick: (RentedInstance) -> Unit,
|
||||||
|
deleteButtonClick: (RentedInstance) -> Unit,
|
||||||
) {
|
) {
|
||||||
val instance by remember(rentedInstance) { derivedStateOf { rentedInstance.instance } }
|
val instance by remember(rentedInstance) { derivedStateOf { rentedInstance.instance } }
|
||||||
val label by remember(instance) { derivedStateOf {
|
val label by remember(instance) { derivedStateOf {
|
||||||
|
@ -103,27 +111,66 @@ fun RentedInstanceCard(
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.End
|
horizontalAlignment = Alignment.End
|
||||||
) {
|
) {
|
||||||
Button( // TODO consider other buttons
|
Row {
|
||||||
modifier = Modifier.height(24.dp),
|
Button(
|
||||||
contentPadding = PaddingValues(0.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
onClick = { sshButtonClick(rentedInstance) }
|
contentPadding = PaddingValues(0.dp),
|
||||||
) {
|
onClick = { deleteButtonClick(rentedInstance) },
|
||||||
if (termuxAvailable > -1) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.termux_icon),
|
modifier = Modifier.size(16.dp),
|
||||||
contentDescription = "Run in Termux"
|
painter = painterResource(id = R.drawable.baseline_delete_24),
|
||||||
|
contentDescription = "Delete instance"
|
||||||
)
|
)
|
||||||
Text("ssh")
|
}
|
||||||
Spacer(modifier = Modifier.size(4.dp)) // necessary because TODO the termux icon has padding
|
|
||||||
} else {
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Spacer(modifier = Modifier.size(1.dp)) // TODO make this not needed?
|
|
||||||
Icon(
|
Button(
|
||||||
modifier = Modifier.size(12.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
painter = painterResource(id = R.drawable.copy_regular), // TODO copy icon here
|
contentPadding = PaddingValues(0.dp),
|
||||||
contentDescription = "Copy command"
|
onClick = { actionButtonClick(rentedInstance) },
|
||||||
)
|
enabled = rentedInstance.status == rentedInstance.targetStatus
|
||||||
Spacer(modifier = Modifier.size(6.dp))
|
) {
|
||||||
Text("ssh")
|
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) }
|
||||||
|
) {
|
||||||
|
if (termuxAvailable > -1) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.termux_icon),
|
||||||
|
contentDescription = "Run in Termux"
|
||||||
|
)
|
||||||
|
Text("ssh")
|
||||||
|
Spacer(modifier = Modifier.size(4.dp)) // necessary because TODO the termux icon has padding
|
||||||
|
} else {
|
||||||
|
Spacer(modifier = Modifier.size(1.dp)) // TODO make this not needed?
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.copy_regular), // TODO copy icon here
|
||||||
|
contentDescription = "Copy command"
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.size(6.dp))
|
||||||
|
Text("ssh")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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"}"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package eu.m724.vastapp.vastai.api.upload
|
||||||
|
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
class JsonUploadDataProvider(
|
||||||
|
jsonObject: JSONObject
|
||||||
|
) : StringUploadDataProvider(
|
||||||
|
jsonObject.toString()
|
||||||
|
)
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
app/src/main/res/drawable/baseline_delete_24.xml
Normal file
5
app/src/main/res/drawable/baseline_delete_24.xml
Normal 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>
|
5
app/src/main/res/drawable/baseline_play_arrow_24.xml
Normal file
5
app/src/main/res/drawable/baseline_play_arrow_24.xml
Normal 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>
|
5
app/src/main/res/drawable/baseline_stop_24.xml
Normal file
5
app/src/main/res/drawable/baseline_stop_24.xml
Normal 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>
|
Loading…
Reference in a new issue