Compare commits
8 commits
09f727c643
...
046e3147d9
Author | SHA1 | Date | |
---|---|---|---|
046e3147d9 | |||
2eb1bedf9b | |||
c8e3635232 | |||
f4b3760d84 | |||
c10484f698 | |||
a0ba813d5f | |||
5d7dd31354 | |||
9f72e6cc72 |
12 changed files with 90 additions and 295 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,3 +17,4 @@ local.properties
|
||||||
|
|
||||||
# useless
|
# useless
|
||||||
/.idea/deploymentTargetSelector.xml
|
/.idea/deploymentTargetSelector.xml
|
||||||
|
/.idea/other.xml
|
263
.idea/other.xml
263
.idea/other.xml
|
@ -1,263 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="direct_access_persist.xml">
|
|
||||||
<option name="deviceSelectionList">
|
|
||||||
<list>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="27" />
|
|
||||||
<option name="brand" value="DOCOMO" />
|
|
||||||
<option name="codename" value="F01L" />
|
|
||||||
<option name="id" value="F01L" />
|
|
||||||
<option name="manufacturer" value="FUJITSU" />
|
|
||||||
<option name="name" value="F-01L" />
|
|
||||||
<option name="screenDensity" value="360" />
|
|
||||||
<option name="screenX" value="720" />
|
|
||||||
<option name="screenY" value="1280" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="28" />
|
|
||||||
<option name="brand" value="DOCOMO" />
|
|
||||||
<option name="codename" value="SH-01L" />
|
|
||||||
<option name="id" value="SH-01L" />
|
|
||||||
<option name="manufacturer" value="SHARP" />
|
|
||||||
<option name="name" value="AQUOS sense2 SH-01L" />
|
|
||||||
<option name="screenDensity" value="480" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2160" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="31" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="a51" />
|
|
||||||
<option name="id" value="a51" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy A51" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="34" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="akita" />
|
|
||||||
<option name="id" value="akita" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 8a" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="b0q" />
|
|
||||||
<option name="id" value="b0q" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy S22 Ultra" />
|
|
||||||
<option name="screenDensity" value="600" />
|
|
||||||
<option name="screenX" value="1440" />
|
|
||||||
<option name="screenY" value="3088" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="32" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="bluejay" />
|
|
||||||
<option name="id" value="bluejay" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 6a" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="29" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="crownqlteue" />
|
|
||||||
<option name="id" value="crownqlteue" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy Note9" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="2220" />
|
|
||||||
<option name="screenY" value="1080" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="34" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="dm3q" />
|
|
||||||
<option name="id" value="dm3q" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy S23 Ultra" />
|
|
||||||
<option name="screenDensity" value="600" />
|
|
||||||
<option name="screenX" value="1440" />
|
|
||||||
<option name="screenY" value="3088" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="felix" />
|
|
||||||
<option name="id" value="felix" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel Fold" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="2208" />
|
|
||||||
<option name="screenY" value="1840" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="felix_camera" />
|
|
||||||
<option name="id" value="felix_camera" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel Fold (Camera-enabled)" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="2208" />
|
|
||||||
<option name="screenY" value="1840" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="gts8uwifi" />
|
|
||||||
<option name="id" value="gts8uwifi" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy Tab S8 Ultra" />
|
|
||||||
<option name="screenDensity" value="320" />
|
|
||||||
<option name="screenX" value="1848" />
|
|
||||||
<option name="screenY" value="2960" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="34" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="husky" />
|
|
||||||
<option name="id" value="husky" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 8 Pro" />
|
|
||||||
<option name="screenDensity" value="390" />
|
|
||||||
<option name="screenX" value="1008" />
|
|
||||||
<option name="screenY" value="2244" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="30" />
|
|
||||||
<option name="brand" value="motorola" />
|
|
||||||
<option name="codename" value="java" />
|
|
||||||
<option name="id" value="java" />
|
|
||||||
<option name="manufacturer" value="Motorola" />
|
|
||||||
<option name="name" value="G20" />
|
|
||||||
<option name="screenDensity" value="280" />
|
|
||||||
<option name="screenX" value="720" />
|
|
||||||
<option name="screenY" value="1600" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="lynx" />
|
|
||||||
<option name="id" value="lynx" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 7a" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="31" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="oriole" />
|
|
||||||
<option name="id" value="oriole" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 6" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="panther" />
|
|
||||||
<option name="id" value="panther" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 7" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="31" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="q2q" />
|
|
||||||
<option name="id" value="q2q" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy Z Fold3" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1768" />
|
|
||||||
<option name="screenY" value="2208" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="34" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="q5q" />
|
|
||||||
<option name="id" value="q5q" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy Z Fold5" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1812" />
|
|
||||||
<option name="screenY" value="2176" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="30" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="r11" />
|
|
||||||
<option name="id" value="r11" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel Watch" />
|
|
||||||
<option name="screenDensity" value="320" />
|
|
||||||
<option name="screenX" value="384" />
|
|
||||||
<option name="screenY" value="384" />
|
|
||||||
<option name="type" value="WEAR_OS" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="30" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="redfin" />
|
|
||||||
<option name="id" value="redfin" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 5" />
|
|
||||||
<option name="screenDensity" value="440" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2340" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="34" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="shiba" />
|
|
||||||
<option name="id" value="shiba" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel 8" />
|
|
||||||
<option name="screenDensity" value="420" />
|
|
||||||
<option name="screenX" value="1080" />
|
|
||||||
<option name="screenY" value="2400" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="33" />
|
|
||||||
<option name="brand" value="google" />
|
|
||||||
<option name="codename" value="tangorpro" />
|
|
||||||
<option name="id" value="tangorpro" />
|
|
||||||
<option name="manufacturer" value="Google" />
|
|
||||||
<option name="name" value="Pixel Tablet" />
|
|
||||||
<option name="screenDensity" value="320" />
|
|
||||||
<option name="screenX" value="1600" />
|
|
||||||
<option name="screenY" value="2560" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
<PersistentDeviceSelectionData>
|
|
||||||
<option name="api" value="29" />
|
|
||||||
<option name="brand" value="samsung" />
|
|
||||||
<option name="codename" value="x1q" />
|
|
||||||
<option name="id" value="x1q" />
|
|
||||||
<option name="manufacturer" value="Samsung" />
|
|
||||||
<option name="name" value="Galaxy S20" />
|
|
||||||
<option name="screenDensity" value="480" />
|
|
||||||
<option name="screenX" value="1440" />
|
|
||||||
<option name="screenY" value="3200" />
|
|
||||||
</PersistentDeviceSelectionData>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -15,4 +15,8 @@ I'm making this to learn stuff please don't rely on this app
|
||||||
|
|
||||||
home and instances icons are from font awesome
|
home and instances icons are from font awesome
|
||||||
|
|
||||||
TODO
|
### TODOs
|
||||||
|
- move todos to issues
|
||||||
|
- readme
|
||||||
|
- figure out the api
|
||||||
|
- gb gib mb mib
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.m724.vastapp.activity.dashboard
|
package eu.m724.vastapp.activity.dashboard
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
@ -19,6 +20,9 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
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.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
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
|
||||||
|
@ -26,14 +30,15 @@ import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
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.BillingScreen
|
||||||
import eu.m724.vastapp.activity.dashboard.screen.DashboardScreen
|
import eu.m724.vastapp.activity.dashboard.screen.DashboardScreen
|
||||||
import eu.m724.vastapp.activity.dashboard.screen.HelpScreen
|
import eu.m724.vastapp.activity.dashboard.screen.HelpScreen
|
||||||
import eu.m724.vastapp.activity.dashboard.screen.InstancesScreen
|
import eu.m724.vastapp.activity.dashboard.screen.InstancesScreen
|
||||||
|
import eu.m724.vastapp.activity.dashboard.screen.Screen
|
||||||
import eu.m724.vastapp.ui.theme.VastappTheme
|
import eu.m724.vastapp.ui.theme.VastappTheme
|
||||||
import eu.m724.vastapp.vastai.VastApi
|
import eu.m724.vastapp.vastai.VastApi
|
||||||
import eu.m724.vastapp.vastai.data.User
|
import eu.m724.vastapp.vastai.data.User
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.chromium.net.CronetEngine
|
import org.chromium.net.CronetEngine
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
@ -49,6 +54,17 @@ class DashboardActivity : ComponentActivity() {
|
||||||
|
|
||||||
val dashboardViewModel = DashboardViewModel(user, vastApi)
|
val dashboardViewModel = DashboardViewModel(user, vastApi)
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
dashboardViewModel.refreshError.collect {
|
||||||
|
it.forEach { errorMsg ->
|
||||||
|
Toast.makeText(baseContext, errorMsg, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
VastappTheme {
|
VastappTheme {
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package eu.m724.vastapp.activity.dashboard
|
package eu.m724.vastapp.activity.dashboard
|
||||||
|
|
||||||
import eu.m724.vastapp.vastai.data.User
|
|
||||||
|
|
||||||
data class DashboardUiState(
|
data class DashboardUiState(
|
||||||
val isRefreshing: Boolean,
|
val refreshing: Int = 0
|
||||||
val user: User,
|
) {
|
||||||
val error: String?
|
}
|
||||||
) { }
|
|
|
@ -3,30 +3,69 @@ package eu.m724.vastapp.activity.dashboard
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import eu.m724.vastapp.vastai.ApiRoute
|
import eu.m724.vastapp.vastai.ApiRoute
|
||||||
import eu.m724.vastapp.vastai.VastApi
|
import eu.m724.vastapp.vastai.VastApi
|
||||||
|
import eu.m724.vastapp.vastai.api.InstancesUrlRequestCallback
|
||||||
import eu.m724.vastapp.vastai.api.UserUrlRequestCallback
|
import eu.m724.vastapp.vastai.api.UserUrlRequestCallback
|
||||||
|
import eu.m724.vastapp.vastai.data.Instance
|
||||||
import eu.m724.vastapp.vastai.data.User
|
import eu.m724.vastapp.vastai.data.User
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
|
||||||
|
|
||||||
class DashboardViewModel(initialUser: User, private val vastApi: VastApi) : ViewModel() { // TODO do something with the user
|
class DashboardViewModel(initialUser: User, private val vastApi: VastApi) : ViewModel() { // TODO do something with the user
|
||||||
private val _uiState: MutableStateFlow<DashboardUiState> =
|
private val _uiState: MutableStateFlow<DashboardUiState> =
|
||||||
MutableStateFlow(DashboardUiState(false, initialUser, null))
|
MutableStateFlow(DashboardUiState(0))
|
||||||
val uiState: StateFlow<DashboardUiState> =
|
val uiState: StateFlow<DashboardUiState> =
|
||||||
_uiState.asStateFlow()
|
_uiState.asStateFlow()
|
||||||
|
|
||||||
|
private val _rentedInstances: MutableStateFlow<List<Instance>> = MutableStateFlow(emptyList())
|
||||||
|
val rentedInstances: StateFlow<List<Instance>> = _rentedInstances.asStateFlow()
|
||||||
|
|
||||||
|
private val _user: MutableStateFlow<User> = MutableStateFlow(initialUser)
|
||||||
|
val user: StateFlow<User> = _user.asStateFlow()
|
||||||
|
|
||||||
|
private val _refreshError: MutableStateFlow<List<String>> = MutableStateFlow(emptyList())
|
||||||
|
val refreshError: StateFlow<List<String>> = _refreshError.asStateFlow()
|
||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
val request = vastApi.buildRequest(
|
_uiState.value = _uiState.value.copy(refreshing = 2)
|
||||||
|
_refreshError.value = emptyList()
|
||||||
|
|
||||||
|
val userRequest = vastApi.buildRequest(
|
||||||
ApiRoute.SHOW_USER,
|
ApiRoute.SHOW_USER,
|
||||||
UserUrlRequestCallback({ user ->
|
UserUrlRequestCallback({ newUser ->
|
||||||
_uiState.value = _uiState.value.copy(isRefreshing = false, user = user)
|
_user.value = newUser
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(refreshing = it.refreshing - 1) // TODO I don't like how this looks
|
||||||
|
}
|
||||||
}, { apiFailure ->
|
}, { apiFailure ->
|
||||||
_uiState.value = _uiState.value.copy(isRefreshing = false, error = apiFailure.errorMessage)
|
_refreshError.update { it + apiFailure.errorMessage!! }
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(refreshing = it.refreshing - 1)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
_uiState.value = _uiState.value.copy(isRefreshing = true)
|
val instancesRequest = vastApi.buildRequest(
|
||||||
request.start()
|
ApiRoute.GET_INSTANCES,
|
||||||
|
InstancesUrlRequestCallback({ instances ->
|
||||||
|
_rentedInstances.value = instances // TODO better way?
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(refreshing = it.refreshing - 1)
|
||||||
|
}
|
||||||
|
}, { apiFailure ->
|
||||||
|
_refreshError.update { it + apiFailure.errorMessage!! }
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(refreshing = it.refreshing - 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
userRequest.start()
|
||||||
|
instancesRequest.start()
|
||||||
|
|
||||||
|
// TODO I don't like this function especially the last line
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,16 +9,13 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
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.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
@ -32,7 +29,7 @@ import eu.m724.vastapp.activity.dashboard.DashboardViewModel
|
||||||
fun BillingScreen(dashboardViewModel: DashboardViewModel) {
|
fun BillingScreen(dashboardViewModel: DashboardViewModel) {
|
||||||
val uiState by dashboardViewModel.uiState.collectAsState()
|
val uiState by dashboardViewModel.uiState.collectAsState()
|
||||||
|
|
||||||
val user by remember(uiState) { derivedStateOf { uiState.user } }
|
val user by dashboardViewModel.user.collectAsState()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
|
@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
@ -43,13 +44,15 @@ import eu.m724.vastapp.activity.dashboard.DashboardViewModel
|
||||||
fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
|
fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
|
||||||
val uiState by dashboardViewModel.uiState.collectAsState()
|
val uiState by dashboardViewModel.uiState.collectAsState()
|
||||||
|
|
||||||
val user by remember(uiState) { derivedStateOf { uiState.user } }
|
val user by dashboardViewModel.user.collectAsState()
|
||||||
|
val rentedInstances by dashboardViewModel.rentedInstances.collectAsState()
|
||||||
val remainingTime by rememberSaveable { mutableIntStateOf(6000000) }
|
val remainingTime by rememberSaveable { mutableIntStateOf(6000000) }
|
||||||
|
val isRefreshing by remember(uiState) { derivedStateOf { uiState.refreshing > 0 } }
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
PullToRefreshBox(
|
PullToRefreshBox(
|
||||||
isRefreshing = uiState.isRefreshing,
|
isRefreshing = isRefreshing,
|
||||||
state = rememberPullToRefreshState(),
|
state = rememberPullToRefreshState(),
|
||||||
onRefresh = { dashboardViewModel.refresh() }
|
onRefresh = { dashboardViewModel.refresh() }
|
||||||
) {
|
) {
|
||||||
|
@ -142,7 +145,7 @@ fun DashboardScreen(dashboardViewModel: DashboardViewModel) {
|
||||||
modifier = Modifier.width(12.dp)
|
modifier = Modifier.width(12.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "4",
|
text = rentedInstances.size.toString(),
|
||||||
fontSize = 22.sp
|
fontSize = 22.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package eu.m724.vastapp.vastai.api
|
package eu.m724.vastapp.vastai.api
|
||||||
|
|
||||||
import eu.m724.vastapp.vastai.ApiFailure
|
import eu.m724.vastapp.vastai.ApiFailure
|
||||||
import eu.m724.vastapp.vastai.data.User
|
import eu.m724.vastapp.vastai.data.Instance
|
||||||
import org.chromium.net.CronetException
|
import org.chromium.net.CronetException
|
||||||
import org.chromium.net.UrlRequest
|
import org.chromium.net.UrlRequest
|
||||||
import org.chromium.net.UrlResponseInfo
|
import org.chromium.net.UrlResponseInfo
|
||||||
|
@ -10,7 +10,7 @@ import java.nio.ByteBuffer
|
||||||
import java.nio.charset.CodingErrorAction
|
import java.nio.charset.CodingErrorAction
|
||||||
|
|
||||||
class InstancesUrlRequestCallback(
|
class InstancesUrlRequestCallback(
|
||||||
val onSuccess: (List<JSONObject>) -> Unit,
|
val onSuccess: (List<Instance>) -> Unit,
|
||||||
val onFailure: (ApiFailure) -> Unit
|
val onFailure: (ApiFailure) -> Unit
|
||||||
) : UrlRequest.Callback() {
|
) : UrlRequest.Callback() {
|
||||||
|
|
||||||
|
@ -40,16 +40,17 @@ class InstancesUrlRequestCallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
|
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
|
||||||
|
println(stringResponse) // TODO don't do that
|
||||||
if (info?.httpStatusCode == 200) {
|
if (info?.httpStatusCode == 200) {
|
||||||
val jsonResponse = JSONObject(stringResponse.toString())
|
val jsonResponse = JSONObject(stringResponse.toString())
|
||||||
val instances = ArrayList<JSONObject>()
|
val instances = ArrayList<Instance>()
|
||||||
|
|
||||||
val instancesJson = jsonResponse.getJSONArray("instances")
|
val instancesJson = jsonResponse.getJSONArray("instances")
|
||||||
for (i in 0..<instancesJson.length()) {
|
for (i in 0..<instancesJson.length()) {
|
||||||
instances.add(instancesJson.getJSONObject(i))
|
instances.add(Instance.fromJson(instancesJson.getJSONObject(i)))
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuccess(instances) // TODO make it better
|
onSuccess(instances) // TODO handle json errors
|
||||||
} else {
|
} else {
|
||||||
onFailure(ApiFailure("${info?.httpStatusCode} ${info?.httpStatusText}"))
|
onFailure(ApiFailure("${info?.httpStatusCode} ${info?.httpStatusText}"))
|
||||||
println("API error: $stringResponse")
|
println("API error: $stringResponse")
|
||||||
|
|
|
@ -41,9 +41,9 @@ class UserUrlRequestCallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
|
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
|
||||||
|
println(stringResponse) // TODO don't do that
|
||||||
if (info?.httpStatusCode == 200) {
|
if (info?.httpStatusCode == 200) {
|
||||||
val jsonResponse = JSONObject(stringResponse.toString())
|
val jsonResponse = JSONObject(stringResponse.toString())
|
||||||
println(jsonResponse)
|
|
||||||
onSuccess(User(
|
onSuccess(User(
|
||||||
id = jsonResponse.getString("id"),
|
id = jsonResponse.getString("id"),
|
||||||
username = jsonResponse.getString("username"),
|
username = jsonResponse.getString("username"),
|
||||||
|
|
|
@ -24,7 +24,7 @@ data class Instance(
|
||||||
* at least I think because it's recent and unavailable machines don't have that */
|
* at least I think because it's recent and unavailable machines don't have that */
|
||||||
val startDate: Long,
|
val startDate: Long,
|
||||||
/** when instance will expire as unix seconds, like 1861891577 */
|
/** when instance will expire as unix seconds, like 1861891577 */
|
||||||
val endDate: Long
|
val endDate: Long?
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJson(json: JSONObject): Instance {
|
fun fromJson(json: JSONObject): Instance {
|
||||||
|
@ -36,7 +36,7 @@ data class Instance(
|
||||||
json.getInt("num_gpus"),
|
json.getInt("num_gpus"),
|
||||||
json.getDouble("dlperf"),
|
json.getDouble("dlperf"),
|
||||||
json.getDouble("start_date").toLong(),
|
json.getDouble("start_date").toLong(),
|
||||||
json.getDouble("end_date").toLong()
|
json.optLong("end_date").takeIf { it > 0 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ data class Machine(
|
||||||
json.getString("mobo_name"),
|
json.getString("mobo_name"),
|
||||||
json.getInt("cpu_ram"),
|
json.getInt("cpu_ram"),
|
||||||
json.getDouble("reliability2"),
|
json.getDouble("reliability2"),
|
||||||
HostingClass.entries.getOrElse(json.getInt("hostingType")) { HostingClass.PRIVATE },
|
HostingClass.entries.getOrElse(json.optInt("hosting_type", 0)) { HostingClass.PRIVATE },
|
||||||
MachineVerification.fromString(json.getString("verification"))
|
MachineVerification.fromString(json.getString("verification"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue