Skip to content
Snippets Groups Projects
Unverified Commit 4e156733 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

wip: progress

parent fc6492ad
No related branches found
No related tags found
No related merge requests found
Showing
with 121 additions and 36 deletions
......@@ -29,16 +29,31 @@ import de.chaosdorf.mete.model.MeteApiFactory
import de.chaosdorf.meteroid.model.AccountInfo
import de.chaosdorf.meteroid.model.Drink
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.model.ServerRepository
import de.chaosdorf.meteroid.model.User
import de.chaosdorf.meteroid.util.newServer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import java.math.BigDecimal
import javax.inject.Inject
class SyncManager @Inject constructor(
private val factory: MeteApiFactory,
private val serverRepository: ServerRepository,
private val userSyncHandler: UserSyncHandler,
private val drinkSyncHandler: DrinkSyncHandler,
private val transactionSyncHandler: TransactionSyncHandler
) {
suspend fun checkOffline(server: Server): Boolean {
val updated = factory.newServer(server.serverId, server.url)
return if (updated == null) {
true
} else {
serverRepository.save(updated)
false
}
}
suspend fun sync(server: Server, user: User?) {
try {
userSyncHandler.sync(server)
......
......@@ -43,7 +43,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
import de.chaosdorf.meteroid.ui.Transactions.TransactionListScreen
import de.chaosdorf.meteroid.ui.transactions.TransactionListScreen
import de.chaosdorf.meteroid.ui.drinks.DrinkListScreen
import de.chaosdorf.meteroid.ui.drinks.DrinkListViewModel
import de.chaosdorf.meteroid.ui.money.MoneyListScreen
......
......@@ -34,7 +34,11 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
......@@ -63,6 +67,18 @@ fun DrinkListScreen(
val account by viewModel.account.collectAsState()
val drinks by viewModel.drinks.collectAsState()
val filters by viewModel.filters.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(account) {
val offline = viewModel.checkOffline(account?.server)
snackbarHostState.currentSnackbarData?.dismiss()
if (offline) {
snackbarHostState.showSnackbar(
message = "Unable to connect to server",
duration = SnackbarDuration.Indefinite
)
}
}
Scaffold(
topBar = { MeteroidTopBar(account, onNavigate, viewModel::togglePin) },
......@@ -72,6 +88,9 @@ fun DrinkListScreen(
historyEnabled = account?.user?.audit == true,
navigateTo = onNavigate
)
},
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) { paddingValues: PaddingValues ->
Column(Modifier.padding(paddingValues)) {
......
......@@ -31,6 +31,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import de.chaosdorf.meteroid.model.AccountInfo
import de.chaosdorf.meteroid.model.Drink
import de.chaosdorf.meteroid.model.DrinkRepository
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.sync.AccountProvider
import de.chaosdorf.meteroid.sync.SyncManager
import de.chaosdorf.meteroid.util.update
......@@ -97,6 +98,10 @@ class DrinkListViewModel @Inject constructor(
}
}
suspend fun checkOffline(server: Server?): Boolean =
if (server == null) true
else syncManager.checkOffline(server)
enum class Filter {
CaffeineFree,
Active;
......
......@@ -32,7 +32,11 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
......@@ -58,6 +62,18 @@ fun MoneyListScreen(
}
}
val account by viewModel.account.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(account) {
val offline = viewModel.checkOffline(account?.server)
snackbarHostState.currentSnackbarData?.dismiss()
if (offline) {
snackbarHostState.showSnackbar(
message = "Unable to connect to server",
duration = SnackbarDuration.Indefinite
)
}
}
Scaffold(
topBar = { MeteroidTopBar(account, onNavigate, viewModel::togglePin) },
......@@ -67,6 +83,9 @@ fun MoneyListScreen(
historyEnabled = account?.user?.audit == true,
navigateTo = onNavigate
)
},
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) { paddingValues: PaddingValues ->
Column {
......
......@@ -30,6 +30,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import de.chaosdorf.meteroid.R
import de.chaosdorf.meteroid.model.AccountInfo
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.sync.AccountProvider
import de.chaosdorf.meteroid.sync.SyncManager
import kotlinx.coroutines.flow.SharingStarted
......@@ -79,4 +80,8 @@ class MoneyListViewModel @Inject constructor(
}
}
}
suspend fun checkOffline(server: Server?): Boolean =
if (server == null) true
else syncManager.checkOffline(server)
}
......@@ -31,8 +31,7 @@ import de.chaosdorf.mete.model.MeteApiFactory
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.model.ServerId
import de.chaosdorf.meteroid.model.ServerRepository
import de.chaosdorf.meteroid.util.findBestIcon
import de.chaosdorf.meteroid.util.resolve
import de.chaosdorf.meteroid.util.newServer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
......@@ -49,32 +48,15 @@ class AddServerViewModel @Inject constructor(
) : ViewModel() {
val url = MutableStateFlow("")
private suspend fun buildServer(
id: ServerId,
url: String
): Server? = try {
val api = factory.newInstance(url)
val manifest = api.getManifest()
val icon = manifest?.findBestIcon()
Server(
id,
manifest?.name,
url,
icon?.resolve(url)
)
} catch (_: Exception) {
null
}
val server: StateFlow<Server?> = url
.debounce(300.milliseconds)
.mapLatest { buildServer(ServerId(-1), it) }
.mapLatest { factory.newServer(ServerId(-1), it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
suspend fun addServer() {
val highestServerId = repository.getAll().maxOfOrNull { it.serverId.value } ?: 0
val serverId = ServerId(highestServerId + 1)
val server = buildServer(serverId, url.value)
val server = factory.newServer(serverId, url.value)
if (server != null) {
repository.save(server)
}
......
......@@ -22,23 +22,24 @@
* THE SOFTWARE.
*/
package de.chaosdorf.meteroid.ui.Transactions
package de.chaosdorf.meteroid.ui.transactions
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.runtime.remember
import androidx.navigation.NavOptions
import de.chaosdorf.meteroid.ui.navigation.HomeSections
import de.chaosdorf.meteroid.ui.navigation.MeteroidBottomBar
import de.chaosdorf.meteroid.ui.navigation.MeteroidTopBar
import de.chaosdorf.meteroid.ui.transactions.TransactionListItem
import de.chaosdorf.meteroid.ui.transactions.TransactionViewModel
@Composable
fun TransactionListScreen(
......@@ -47,6 +48,18 @@ fun TransactionListScreen(
) {
val account by viewModel.account.collectAsState()
val transactions by viewModel.transactions.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(account) {
val offline = viewModel.checkOffline(account?.server)
snackbarHostState.currentSnackbarData?.dismiss()
if (offline) {
snackbarHostState.showSnackbar(
message = "Unable to connect to server",
duration = SnackbarDuration.Indefinite
)
}
}
Scaffold(
topBar = { MeteroidTopBar(account, onNavigate, viewModel::togglePin) },
......@@ -56,6 +69,9 @@ fun TransactionListScreen(
historyEnabled = account?.user?.audit == true,
navigateTo = onNavigate
)
},
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) { paddingValues: PaddingValues ->
LazyColumn(contentPadding = paddingValues) {
......
......@@ -29,9 +29,11 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import de.chaosdorf.meteroid.model.AccountInfo
import de.chaosdorf.meteroid.model.DrinkRepository
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.model.TransactionRepository
import de.chaosdorf.meteroid.sync.AccountProvider
import de.chaosdorf.meteroid.sync.SyncHandler
import de.chaosdorf.meteroid.sync.SyncManager
import de.chaosdorf.meteroid.sync.TransactionSyncHandler
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
......@@ -49,7 +51,8 @@ import kotlin.time.Duration.Companion.minutes
class TransactionViewModel @Inject constructor(
private val accountProvider: AccountProvider,
repository: TransactionRepository,
drinkRepository: DrinkRepository
drinkRepository: DrinkRepository,
private val syncManager: SyncManager
) : ViewModel() {
val account: StateFlow<AccountInfo?> = accountProvider.account
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
......@@ -85,6 +88,10 @@ class TransactionViewModel @Inject constructor(
}
}
}
suspend fun checkOffline(server: Server?): Boolean =
if (server == null) true
else syncManager.checkOffline(server)
}
fun List<TransactionInfo>.mergeAdjecentDeposits(): List<TransactionInfo> {
......
......@@ -24,13 +24,30 @@
package de.chaosdorf.meteroid.util
import de.chaosdorf.mete.model.PwaIcon
import de.chaosdorf.mete.model.PwaManifest
import okhttp3.HttpUrl.Companion.toHttpUrl
import de.chaosdorf.mete.model.MeteApiFactory
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.model.ServerId
import java.net.URI
fun PwaManifest.findBestIcon(): PwaIcon? = icons.maxByOrNull {
it.sizes?.split("x")?.firstOrNull()?.toIntOrNull() ?: 0
}
suspend fun MeteApiFactory.newServer(serverId: ServerId, baseUrl: String): Server? = try {
val api = newInstance(baseUrl)
val manifest = api.getManifest()
val icon = manifest?.icons?.maxByOrNull {
it.sizes?.split("x")
?.mapNotNull(String::toIntOrNull)
?.reduce(Int::times)
?: 0
}
fun PwaIcon.resolve(baseUrl: String): String? =
this.src?.let { baseUrl.toHttpUrl().resolve(it) }?.toString()
val iconUrl = icon?.src?.let { URI(baseUrl).resolve(it).toString() }
Server(
serverId,
manifest?.name,
baseUrl,
iconUrl
)
} catch (_: Exception) {
null
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment