Compare commits
7 commits
127a31841e
...
5f1787d6ff
Author | SHA1 | Date | |
---|---|---|---|
5f1787d6ff | |||
3d405adc6e | |||
8d7268f194 | |||
fbde1a502b | |||
8c9e4c0328 | |||
3e49fc30bc | |||
d3d3c9f59e |
7 changed files with 145 additions and 36 deletions
|
@ -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"
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue