TokenManager.kt (3071B)
1 /* 2 * This file is part of GNU Taler 3 * (C) 2026 Taler Systems S.A. 4 * 5 * GNU Taler is free software; you can redistribute it and/or modify it under the 6 * terms of the GNU General Public License as published by the Free Software 7 * Foundation; either version 3, or (at your option) any later version. 8 * 9 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY 10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 package net.taler.wallet.tokens 18 19 import kotlinx.coroutines.ExperimentalCoroutinesApi 20 import kotlinx.coroutines.flow.Flow 21 import kotlinx.coroutines.flow.MutableSharedFlow 22 import kotlinx.coroutines.flow.flatMapLatest 23 import kotlinx.coroutines.flow.flow 24 import net.taler.common.Timestamp 25 import net.taler.wallet.backend.TalerErrorInfo 26 import net.taler.wallet.backend.WalletBackendApi 27 import net.taler.wallet.backend.WalletResponse 28 29 sealed class UiState<out T> { 30 object Loading: UiState<Nothing>() 31 data class Success<out T>(val data: T): UiState<T>() 32 data class Error(val error: TalerErrorInfo): UiState<Nothing>() 33 } 34 35 fun <T, U> WalletResponse<T>.toUiState(transform: (r: T) -> U): UiState<U> = when(this) { 36 is WalletResponse.Success -> UiState.Success(transform(this.result)) 37 is WalletResponse.Error -> UiState.Error(this.error) 38 } 39 40 sealed class TokenFilter() { 41 // data object All: TokenFilter() 42 data object Valid: TokenFilter() 43 data object Expired: TokenFilter() 44 } 45 46 class TokenManager(private val api: WalletBackendApi){ 47 private val refreshTrigger = 48 MutableSharedFlow<Unit>(replay = 1).apply { tryEmit(Unit) } 49 50 @OptIn(ExperimentalCoroutinesApi::class) 51 val discounts: Flow<UiState<List<DiscountListDetail>>> = refreshTrigger.flatMapLatest { 52 flow { 53 emit(UiState.Loading) 54 emit(api.request("listDiscounts", ListDiscountsResponse.serializer()) 55 .toUiState { it.discounts }) 56 } 57 } 58 59 @OptIn(ExperimentalCoroutinesApi::class) 60 val passes: Flow<UiState<List<SubscriptionListDetail>>> = refreshTrigger.flatMapLatest { 61 flow { 62 emit(UiState.Loading) 63 emit(api.request("listSubscriptions", ListSubscriptionsResponse.serializer()) 64 .toUiState { it.subscriptions }) 65 } 66 } 67 68 fun refresh() { refreshTrigger.tryEmit(Unit) } 69 } 70 71 fun List<DiscountListDetail>.filterDiscounts(filter: TokenFilter): List<DiscountListDetail> { 72 return when(filter) { 73 TokenFilter.Valid -> filter { !it.isExpired } 74 TokenFilter.Expired -> filter { it.isExpired } 75 } 76 } 77 78 fun List<SubscriptionListDetail>.filterPasses(filter: TokenFilter): List<SubscriptionListDetail> { 79 return when(filter) { 80 TokenFilter.Valid -> filter { !it.isExpired } 81 TokenFilter.Expired -> filter { it.isExpired } 82 } 83 }