Compare commits

...

7 commits

Author SHA1 Message Date
5f1787d6ff
remove unnecessary class 2024-07-26 18:53:36 +02:00
3d405adc6e
clean imports 2024-07-26 18:53:16 +02:00
8d7268f194
prepare instances page 2024-07-26 18:52:47 +02:00
fbde1a502b
prepare billing page 2024-07-26 18:41:29 +02:00
8c9e4c0328
remove unused imports 2024-07-25 18:57:31 +02:00
3e49fc30bc
fix warnings 2024-07-25 18:56:43 +02:00
d3d3c9f59e
add help page 2024-07-25 18:51:40 +02:00
7 changed files with 145 additions and 36 deletions

View file

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"

View file

@ -29,6 +29,7 @@ import androidx.navigation.compose.rememberNavController
import eu.m724.vastapp.activity.dashboard.screen.Screen
import eu.m724.vastapp.activity.dashboard.screen.BillingScreen
import eu.m724.vastapp.activity.dashboard.screen.DashboardScreen
import eu.m724.vastapp.activity.dashboard.screen.HelpScreen
import eu.m724.vastapp.activity.dashboard.screen.InstancesScreen
import eu.m724.vastapp.ui.theme.VastappTheme
import eu.m724.vastapp.vastai.VastApi
@ -54,7 +55,8 @@ class DashboardActivity : ComponentActivity() {
val items = listOf(
Screen.Dashboard,
Screen.Instances,
Screen.Billing
Screen.Billing,
Screen.Help
)
val navController = rememberNavController()
@ -70,6 +72,7 @@ class DashboardActivity : ComponentActivity() {
composable("dashboard") { DashboardScreen(dashboardViewModel) }
composable("instances") { InstancesScreen(dashboardViewModel) }
composable("billing") { BillingScreen(dashboardViewModel) }
composable("help") { HelpScreen(dashboardViewModel) }
}
}
}

View file

@ -1,37 +1,21 @@
package eu.m724.vastapp.activity.dashboard
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import eu.m724.vastapp.activity.login.LoginUiState
import eu.m724.vastapp.vastai.ApiRoute
import eu.m724.vastapp.vastai.VastApi
import eu.m724.vastapp.vastai.api.UserUrlRequestCallback
import eu.m724.vastapp.vastai.data.User
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
class DashboardViewModel(private val _user: User, val vastApi: VastApi) : ViewModel() {
class DashboardViewModel(initialUser: User, private val vastApi: VastApi) : ViewModel() { // TODO do something with the user
private val _uiState: MutableStateFlow<DashboardUiState> =
MutableStateFlow(DashboardUiState(false, _user, null))
MutableStateFlow(DashboardUiState(false, initialUser, null))
val uiState: StateFlow<DashboardUiState> =
_uiState.asStateFlow()
private val _navigationEvent = MutableSharedFlow<String>()
val navigationEvent: SharedFlow<String> = _navigationEvent.asSharedFlow()
fun navigateTo(route: String) {
viewModelScope.launch {
_navigationEvent.emit(route)
}
}
fun refresh() {
val request = vastApi.buildRequest(
ApiRoute.SHOW_USER,

View file

@ -1,12 +1,70 @@
package eu.m724.vastapp.activity.dashboard.screen
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.m724.vastapp.R
import eu.m724.vastapp.activity.dashboard.DashboardViewModel
class Billing {
}
@Composable
fun BillingScreen(dashboardViewModel: DashboardViewModel) {
val uiState by dashboardViewModel.uiState.collectAsState()
val user by remember(uiState) { derivedStateOf { uiState.user } }
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(
modifier = Modifier.height(30.dp)
)
Card(
modifier = Modifier.width(160.dp)
) {
Row(
modifier = Modifier.padding(16.dp, 8.dp).height(IntrinsicSize.Min)
) {
Icon(
modifier = Modifier.fillMaxHeight().aspectRatio(1f),
painter = painterResource(id = R.drawable.baseline_monetization_on_24),
contentDescription = "Balance"
)
Spacer(modifier = Modifier
.fillMaxWidth()
.weight(1f)
)
Text(
text = "$%.2f".format(user.credit),
fontSize = 24.sp,
color = balanceColor(user.credit, user.balanceThreshold)
)
}
}
}
}

View file

@ -1,6 +1,5 @@
package eu.m724.vastapp.activity.dashboard.screen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@ -18,17 +17,14 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.pullToRefresh
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -37,13 +33,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.m724.vastapp.R
import eu.m724.vastapp.activity.dashboard.DashboardViewModel
import eu.m724.vastapp.vastai.data.User
import org.json.JSONObject
class Dashboard {
}
@OptIn(ExperimentalMaterial3Api::class) // for pullRefresh
@Composable
fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
@ -130,6 +121,8 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
}
}
// TODO maybe reuse that from Instances?
val instance = JSONObject()
instance.put("id", 234523)
instance.put("machine_id", 1121323)
@ -140,7 +133,6 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
instance.put("gpu_ram", 24564)
instance.put("vmem_usage", 0.339843)
Column(
modifier = Modifier.width(340.dp)
) {

View file

@ -0,0 +1,34 @@
package eu.m724.vastapp.activity.dashboard.screen
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.sp
import eu.m724.vastapp.activity.dashboard.DashboardViewModel
@Composable
fun HelpScreen(dashboardViewModel: DashboardViewModel) { // TODO make this a webview
val context = LocalContext.current
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(onClick = {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"))
context.startActivity(browserIntent)
}) {
Text(text = "https://vast.ai/docs")
}
Text(text = "(this will be a webview)", fontSize = 12.sp)
}
}

View file

@ -3,16 +3,26 @@ package eu.m724.vastapp.activity.dashboard.screen
import android.widget.ProgressBar
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ContextualFlowRow
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
@ -24,13 +34,35 @@ import org.json.JSONObject
class Instances {
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
Column {
val uiState by dashboardViewModel.uiState.collectAsState()
// TODO actually get instances
ContextualFlowRow(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
itemCount = 10,
horizontalArrangement = Arrangement.Center
) {
val instance = JSONObject()
instance.put("id", 234523)
instance.put("machine_id", 1121323)
instance.put("host_id", 5924)
instance.put("gpu_name", "RTX 4090")
instance.put("num_gpus", 2)
instance.put("gpu_util", 70)
instance.put("gpu_ram", 24564)
instance.put("vmem_usage", 0.339843)
InstanceCard(instance = instance, modifier = Modifier.width(340.dp).padding(8.dp))
}
}
// TODO maybe move this?
@Composable
fun InstanceCard(instance: JSONObject, modifier: Modifier = Modifier) {
val gpuUsage = instance.getInt("gpu_util")
@ -68,7 +100,9 @@ fun InstanceCard(instance: JSONObject, modifier: Modifier = Modifier) {
modifier = Modifier.fillMaxWidth(0.5f)
) {
Column(
modifier = Modifier.fillMaxWidth().weight(1f)
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
Text(text = "GPU: $gpuUsage%", fontSize = 12.sp)
LinearProgressIndicator(
@ -77,7 +111,9 @@ fun InstanceCard(instance: JSONObject, modifier: Modifier = Modifier) {
}
Column(
modifier = Modifier.fillMaxWidth().weight(1f)
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
Text(text = "%.1f / %.1f G".format(vramGbUsed, vramGb), fontSize = 12.sp)
LinearProgressIndicator(