make it work

This commit is contained in:
Minecon724 2024-07-25 18:02:38 +02:00
parent 0ca0cbe723
commit 127a31841e
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
16 changed files with 234 additions and 137 deletions

View file

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View file

@ -13,4 +13,6 @@ I'm making this to learn stuff please don't rely on this app
- material you supported - material you supported
- dashboard - dashboard
home and instances icons are from font awesome
TODO TODO

View file

@ -7,6 +7,7 @@ import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
@ -15,7 +16,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@ -102,7 +105,8 @@ fun MyNavigationBar(items: List<Screen>, navController: NavHostController) {
}, },
icon = { icon = {
Icon( Icon(
screen.icon, painterResource(screen.icon),
modifier = Modifier.size(24.dp),
contentDescription = stringResource(screen.resourceId) contentDescription = stringResource(screen.resourceId)
) )
}, },

View file

@ -32,7 +32,7 @@ class DashboardViewModel(private val _user: User, val vastApi: VastApi) : ViewMo
} }
} }
fun refreshData() { fun refresh() {
val request = vastApi.buildRequest( val request = vastApi.buildRequest(
ApiRoute.SHOW_USER, ApiRoute.SHOW_USER,
UserUrlRequestCallback({ user -> UserUrlRequestCallback({ user ->
@ -41,5 +41,8 @@ class DashboardViewModel(private val _user: User, val vastApi: VastApi) : ViewMo
_uiState.value = _uiState.value.copy(isRefreshing = false, error = apiFailure.errorMessage) _uiState.value = _uiState.value.copy(isRefreshing = false, error = apiFailure.errorMessage)
}) })
) )
_uiState.value = _uiState.value.copy(isRefreshing = true)
request.start()
} }
} }

View file

@ -1,5 +1,6 @@
package eu.m724.vastapp.activity.dashboard.screen package eu.m724.vastapp.activity.dashboard.screen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -8,15 +9,24 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text 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.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -34,13 +44,24 @@ class Dashboard {
} }
@OptIn(ExperimentalMaterial3Api::class) // for pullRefresh
@Composable @Composable
fun DashboardScreen(dashboardViewModel: DashboardViewModel) { fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
var balance by rememberSaveable { mutableDoubleStateOf(user.credit) } val uiState by dashboardViewModel.uiState.collectAsState()
var remainingTime by rememberSaveable { mutableIntStateOf(0) }
val user by remember(uiState) { derivedStateOf { uiState.user } }
val remainingTime by rememberSaveable { mutableIntStateOf(0) }
val scrollState = rememberScrollState()
PullToRefreshBox(
isRefreshing = uiState.isRefreshing,
state = rememberPullToRefreshState(),
onRefresh = { dashboardViewModel.refresh() }
) {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.verticalScroll(scrollState)
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@ -60,7 +81,7 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
.padding(16.dp) .padding(16.dp)
.weight(1f), .weight(1f),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = balanceCardColor(balance) containerColor = balanceCardColor(user.credit)
) )
) { ) {
Row( Row(
@ -68,7 +89,7 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.baseline_account_balance_wallet_24), painter = painterResource(id = R.drawable.baseline_monetization_on_24),
contentDescription = "Balance" contentDescription = "Balance"
) )
Spacer(modifier = Modifier Spacer(modifier = Modifier
@ -76,9 +97,9 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
.weight(1f) .weight(1f)
) )
Text( Text(
text = "$%.2f".format(balance), text = "$%.2f".format(user.credit),
fontSize = 22.sp, fontSize = 22.sp,
color = balanceColor(balance, user.balanceThreshold) color = balanceColor(user.credit, user.balanceThreshold)
) )
} }
} }
@ -109,68 +130,22 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
} }
} }
Row( val instance = JSONObject()
modifier = Modifier.width(340.dp) instance.put("id", 234523)
) { instance.put("machine_id", 1121323)
Card( instance.put("host_id", 5924)
modifier = Modifier instance.put("gpu_name", "RTX 4090")
.fillMaxWidth() instance.put("num_gpus", 2)
.padding(16.dp) instance.put("gpu_util", 70)
.weight(1f), instance.put("gpu_ram", 24564)
colors = CardDefaults.cardColors( instance.put("vmem_usage", 0.339843)
containerColor = balanceCardColor(balance)
)
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.baseline_account_balance_wallet_24),
contentDescription = "Balance"
)
Spacer(modifier = Modifier
.fillMaxWidth()
.weight(1f)
)
Text(
text = "$%.2f".format(balance),
fontSize = 22.sp,
color = balanceColor(balance, user.balanceThreshold)
)
}
}
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.weight(1f),
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.drawable.baseline_access_time_filled_24),
contentDescription = "Remaining time"
)
Spacer(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
)
Text(
text = formatTime(remainingTime),
fontSize = 22.sp
)
}
}
}
Column( Column(
modifier = Modifier.width(340.dp) modifier = Modifier.width(340.dp)
) { ) {
InstanceCard(instance = instance, modifier = Modifier.padding(16.dp))
}
} }
} }
} }

View file

@ -1,15 +1,23 @@
package eu.m724.vastapp.activity.dashboard.screen 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.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.m724.vastapp.activity.dashboard.DashboardViewModel import eu.m724.vastapp.activity.dashboard.DashboardViewModel
import org.json.JSONObject import org.json.JSONObject
@ -25,11 +33,61 @@ fun InstancesScreen(dashboardViewModel: DashboardViewModel) {
@Composable @Composable
fun InstanceCard(instance: JSONObject, modifier: Modifier = Modifier) { fun InstanceCard(instance: JSONObject, modifier: Modifier = Modifier) {
val gpuUsage = instance.getInt("gpu_util")
val vramGb = instance.getInt("gpu_ram") / 1000.0
val vramGbUsed = vramGb * instance.getDouble("vmem_usage")
Card(modifier = modifier) { Card(modifier = modifier) {
Row( Column(
modifier = Modifier.fillMaxWidth() modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) { ) {
Text(text = instance.getString("id")) Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(text = instance.getString("id"), fontSize = 14.sp)
Text(text = "m:" + instance.getString("machine_id"), fontSize = 14.sp)
Text(text = "h:" + instance.getString("host_id"), fontSize = 14.sp)
}
Row {
Column {
Row(
modifier = Modifier.fillMaxWidth(0.5f),
verticalAlignment = Alignment.Bottom
) {
Text(text = instance.getString("gpu_name"), fontSize = 24.sp)
if (instance.getInt("num_gpus") > 1) {
Text(text = "x" + instance.getString("num_gpus"), modifier = Modifier.padding(start = 2.dp))
}
}
Row(
modifier = Modifier.fillMaxWidth(0.5f)
) {
Column(
modifier = Modifier.fillMaxWidth().weight(1f)
) {
Text(text = "GPU: $gpuUsage%", fontSize = 12.sp)
LinearProgressIndicator(
progress = { gpuUsage / 100f }
)
}
Column(
modifier = Modifier.fillMaxWidth().weight(1f)
) {
Text(text = "%.1f / %.1f G".format(vramGbUsed, vramGb), fontSize = 12.sp)
LinearProgressIndicator(
progress = { instance.getDouble("vmem_usage").toFloat() }
)
}
}
}
}
} }
} }
} }

View file

@ -1,15 +1,21 @@
package eu.m724.vastapp.activity.dashboard.screen package eu.m724.vastapp.activity.dashboard.screen
import android.media.Image
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.Menu import androidx.compose.material.icons.outlined.Menu
import androidx.compose.material.icons.outlined.ShoppingCart import androidx.compose.material.icons.outlined.ShoppingCart
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import eu.m724.vastapp.R import eu.m724.vastapp.R
sealed class Screen(val route: String, @StringRes val resourceId: Int, val icon: ImageVector) { sealed class Screen(val route: String, @StringRes val resourceId: Int, val icon: Int) {
object Dashboard : Screen("dashboard", R.string.nav_dashboard, Icons.Outlined.Home) data object Dashboard : Screen("dashboard", R.string.nav_dashboard, R.drawable.house_solid)
object Instances : Screen("instances", R.string.nav_instances, Icons.Outlined.Menu) data object Instances : Screen("instances", R.string.nav_instances, R.drawable.server_solid)
object Billing : Screen("billing", R.string.nav_billing, Icons.Outlined.ShoppingCart) data object Billing : Screen("billing", R.string.nav_billing, R.drawable.baseline_monetization_on_24)
data object Help : Screen("help", R.string.nav_help, R.drawable.baseline_help_outline_24)
} }

View file

@ -9,7 +9,11 @@ import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColor
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -31,6 +35,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@ -50,6 +55,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -60,6 +68,7 @@ import eu.m724.vastapp.ui.theme.VastappTheme
import eu.m724.vastapp.vastai.data.User import eu.m724.vastapp.vastai.data.User
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.chromium.net.CronetEngine import org.chromium.net.CronetEngine
import org.w3c.dom.Text
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.random.Random import kotlin.random.Random
@ -136,8 +145,9 @@ fun LoginApp(loginViewModel: LoginViewModel) {
if (state) 180f else 0f if (state) 180f else 0f
} }
Column( Column(
modifier = Modifier.width(300.dp), modifier = Modifier.width(300.dp).animateContentSize(spring(stiffness = Spring.StiffnessMedium)), // TODO double animation
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
@ -149,6 +159,7 @@ fun LoginApp(loginViewModel: LoginViewModel) {
label = { Text(text = "API key") }, label = { Text(text = "API key") },
visualTransformation = PasswordVisualTransformation(), visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
textStyle = if (uiState is LoginUiState.Success) rainbowTextStyle() else LocalTextStyle.current,
singleLine = true, singleLine = true,
isError = loginErrorMessage != null isError = loginErrorMessage != null
) )
@ -188,7 +199,20 @@ fun LoginApp(loginViewModel: LoginViewModel) {
} }
@Composable @Composable
fun AdvancedOptions() { fun rainbowTextStyle(): TextStyle {
return LocalTextStyle.current.copy(brush = Brush.linearGradient(colors = listOf(
Color.Red,
Color(255,127,0),
Color.Yellow,
Color.Green,
Color.Blue,
Color(75, 0, 130), // Indigo
Color(143, 0, 255) // Violet
)))
}
@Composable
fun AdvancedOptions() { // TODO put this in viewmodel
var checked by rememberSaveable { mutableStateOf(true) } var checked by rememberSaveable { mutableStateOf(true) }
var clicks by rememberSaveable { mutableIntStateOf(0) } var clicks by rememberSaveable { mutableIntStateOf(0) }
var checkboxLabel by rememberSaveable { mutableStateOf("here's a checkbox for you") } var checkboxLabel by rememberSaveable { mutableStateOf("here's a checkbox for you") }

View file

@ -4,6 +4,7 @@ import android.widget.Toast
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import eu.m724.vastapp.vastai.ApiFailure import eu.m724.vastapp.vastai.ApiFailure
import eu.m724.vastapp.vastai.ApiRoute import eu.m724.vastapp.vastai.ApiRoute
import eu.m724.vastapp.vastai.VastApi import eu.m724.vastapp.vastai.VastApi
@ -33,7 +34,7 @@ class LoginViewModel(val cronetEngine: CronetEngine, val executor: Executor) : V
_uiState.value = LoginUiState.Success(user) _uiState.value = LoginUiState.Success(user)
}, { apiFailure -> }, { apiFailure ->
_uiState.value = LoginUiState.Idle _uiState.value = LoginUiState.Idle
_error.value = apiFailure.errorMessage _error.postValue(apiFailure.errorMessage)
}) })
) )

View file

@ -1,5 +0,0 @@
<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="M21,18v1c0,1.1 -0.9,2 -2,2L5,21c-1.11,0 -2,-0.9 -2,-2L3,5c0,-1.1 0.89,-2 2,-2h14c1.1,0 2,0.9 2,2v1h-9c-1.11,0 -2,0.9 -2,2v8c0,1.1 0.89,2 2,2h9zM12,16h10L22,8L12,8v8zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
</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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13.41,18.09L13.41,20h-2.67v-1.93c-1.71,-0.36 -3.16,-1.46 -3.27,-3.4h1.96c0.1,1.05 0.82,1.87 2.65,1.87 1.96,0 2.4,-0.98 2.4,-1.59 0,-0.83 -0.44,-1.61 -2.67,-2.14 -2.48,-0.6 -4.18,-1.62 -4.18,-3.67 0,-1.72 1.39,-2.84 3.11,-3.21L10.74,4h2.67v1.95c1.86,0.45 2.79,1.86 2.85,3.39L14.3,9.34c-0.05,-1.11 -0.64,-1.87 -2.22,-1.87 -1.5,0 -2.4,0.68 -2.4,1.64 0,0.84 0.65,1.39 2.67,1.91s4.18,1.39 4.18,3.91c-0.01,1.83 -1.38,2.83 -3.12,3.16z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="576dp"
android:height="512dp"
android:viewportWidth="576"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M575.8,255.5c0,18 -15,32.1 -32,32.1l-32,0 0.7,160.2c0,2.7 -0.2,5.4 -0.5,8.1l0,16.2c0,22.1 -17.9,40 -40,40l-16,0c-1.1,0 -2.2,0 -3.3,-0.1c-1.4,0.1 -2.8,0.1 -4.2,0.1L416,512l-24,0c-22.1,0 -40,-17.9 -40,-40l0,-24 0,-64c0,-17.7 -14.3,-32 -32,-32l-64,0c-17.7,0 -32,14.3 -32,32l0,64 0,24c0,22.1 -17.9,40 -40,40l-24,0 -31.9,0c-1.5,0 -3,-0.1 -4.5,-0.2c-1.2,0.1 -2.4,0.2 -3.6,0.2l-16,0c-22.1,0 -40,-17.9 -40,-40l0,-112c0,-0.9 0,-1.9 0.1,-2.8l0,-69.7 -32,0c-18,0 -32,-14 -32,-32.1c0,-9 3,-17 10,-24L266.4,8c7,-7 15,-8 22,-8s15,2 21,7L564.8,231.5c8,7 12,15 11,24z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M64,32C28.7,32 0,60.7 0,96l0,64c0,35.3 28.7,64 64,64l384,0c35.3,0 64,-28.7 64,-64l0,-64c0,-35.3 -28.7,-64 -64,-64L64,32zM344,104a24,24 0,1 1,0 48,24 24,0 1,1 0,-48zM392,128a24,24 0,1 1,48 0,24 24,0 1,1 -48,0zM64,288c-35.3,0 -64,28.7 -64,64l0,64c0,35.3 28.7,64 64,64l384,0c35.3,0 64,-28.7 64,-64l0,-64c0,-35.3 -28.7,-64 -64,-64L64,288zM344,360a24,24 0,1 1,0 48,24 24,0 1,1 0,-48zM400,384a24,24 0,1 1,48 0,24 24,0 1,1 -48,0z"/>
</vector>

View file

@ -6,4 +6,5 @@
<string name="nav_dashboard">Dashboard</string> <string name="nav_dashboard">Dashboard</string>
<string name="nav_billing">Billing</string> <string name="nav_billing">Billing</string>
<string name="nav_instances">Instances</string> <string name="nav_instances">Instances</string>
<string name="nav_help">Help</string>
</resources> </resources>

View file

@ -7,13 +7,14 @@ junitVersion = "1.2.1"
espressoCore = "3.6.1" espressoCore = "3.6.1"
appcompat = "1.7.0" appcompat = "1.7.0"
material = "1.12.0" material = "1.12.0"
lifecycleRuntimeKtx = "2.8.3" lifecycleRuntimeKtx = "2.8.4"
activityCompose = "1.9.0" activityCompose = "1.9.1"
composeBom = "2024.06.00" composeBom = "2024.06.00"
playServicesCronet = "18.1.0" playServicesCronet = "18.1.0"
navigationCompose = "2.7.7" navigationCompose = "2.7.7"
secretsGradlePlugin = "2.0.1" secretsGradlePlugin = "2.0.1"
runtimeLivedata = "1.6.8" runtimeLivedata = "1.6.8"
material3 = "1.3.0-beta05" # for pulltorefresh
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -31,7 +32,7 @@ androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
play-services-cronet = { module = "com.google.android.gms:play-services-cronet", version.ref = "playServicesCronet" } play-services-cronet = { module = "com.google.android.gms:play-services-cronet", version.ref = "playServicesCronet" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
androidx-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" } androidx-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" }