diff --git a/app/src/main/java/eu/m724/vastapp/activity/dashboard/screen/Instances.kt b/app/src/main/java/eu/m724/vastapp/activity/dashboard/screen/Instances.kt
index f3c71c0..921c78f 100644
--- a/app/src/main/java/eu/m724/vastapp/activity/dashboard/screen/Instances.kt
+++ b/app/src/main/java/eu/m724/vastapp/activity/dashboard/screen/Instances.kt
@@ -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,27 +111,66 @@ fun RentedInstanceCard(
Column(
horizontalAlignment = Alignment.End
) {
- Button( // TODO consider other buttons
- modifier = Modifier.height(24.dp),
- contentPadding = PaddingValues(0.dp),
- onClick = { sshButtonClick(rentedInstance) }
- ) {
- if (termuxAvailable > -1) {
+ Row {
+ Button(
+ modifier = Modifier.size(24.dp),
+ contentPadding = PaddingValues(0.dp),
+ onClick = { deleteButtonClick(rentedInstance) },
+ ) {
Icon(
- painter = painterResource(id = R.drawable.termux_icon),
- contentDescription = "Run in Termux"
+ modifier = Modifier.size(16.dp),
+ 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.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")
+ }
+
+ 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) }
+ ) {
+ 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")
+ }
}
}
diff --git a/app/src/main/java/eu/m724/vastapp/vastai/api/JsonUrlRequestCallback.kt b/app/src/main/java/eu/m724/vastapp/vastai/api/JsonUrlRequestCallback.kt
new file mode 100644
index 0000000..807ea35
--- /dev/null
+++ b/app/src/main/java/eu/m724/vastapp/vastai/api/JsonUrlRequestCallback.kt
@@ -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)
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/vastapp/vastai/api/StringUrlRequestCallback.kt b/app/src/main/java/eu/m724/vastapp/vastai/api/StringUrlRequestCallback.kt
new file mode 100644
index 0000000..dd9085d
--- /dev/null
+++ b/app/src/main/java/eu/m724/vastapp/vastai/api/StringUrlRequestCallback.kt
@@ -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"}"))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/vastapp/vastai/api/upload/JsonUploadDataProvider.kt b/app/src/main/java/eu/m724/vastapp/vastai/api/upload/JsonUploadDataProvider.kt
new file mode 100644
index 0000000..e14bbf7
--- /dev/null
+++ b/app/src/main/java/eu/m724/vastapp/vastai/api/upload/JsonUploadDataProvider.kt
@@ -0,0 +1,9 @@
+package eu.m724.vastapp.vastai.api.upload
+
+import org.json.JSONObject
+
+class JsonUploadDataProvider(
+ jsonObject: JSONObject
+) : StringUploadDataProvider(
+ jsonObject.toString()
+)
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/vastapp/vastai/api/upload/StringUploadDataProvider.kt b/app/src/main/java/eu/m724/vastapp/vastai/api/upload/StringUploadDataProvider.kt
new file mode 100644
index 0000000..1724866
--- /dev/null
+++ b/app/src/main/java/eu/m724/vastapp/vastai/api/upload/StringUploadDataProvider.kt
@@ -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()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_delete_24.xml b/app/src/main/res/drawable/baseline_delete_24.xml
new file mode 100644
index 0000000..883bcaa
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_delete_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_play_arrow_24.xml b/app/src/main/res/drawable/baseline_play_arrow_24.xml
new file mode 100644
index 0000000..b176182
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_play_arrow_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_stop_24.xml b/app/src/main/res/drawable/baseline_stop_24.xml
new file mode 100644
index 0000000..817d57b
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_stop_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+