diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt index 9f16c1c..58cfce5 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt @@ -1,6 +1,11 @@ package net.codinux.banking.ui import android.os.Build +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +actual val Dispatchers.IOorDefault: CoroutineDispatcher + get() = Dispatchers.IO class AndroidPlatform : Platform { override val name: String = "Android ${Build.VERSION.SDK_INT}" diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt index a5cf275..4f238e9 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt @@ -3,6 +3,10 @@ package net.codinux.banking.ui.service import android.graphics.BitmapFactory import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap +import java.net.URL actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap = - BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size).asImageBitmap() \ No newline at end of file + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size).asImageBitmap() + +actual fun fetchBytesFromUrl(url: String): ByteArray = + URL(url).openStream().buffered().use { it.readBytes() } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt index e58badf..5bfcf2e 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt @@ -1,5 +1,10 @@ package net.codinux.banking.ui +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + + +expect val Dispatchers.IOorDefault: CoroutineDispatcher expect fun getPlatform(): Platform diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt new file mode 100644 index 0000000..b47ff6d --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt @@ -0,0 +1,50 @@ +package net.codinux.banking.ui.composables + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import net.codinux.banking.client.model.UserAccount +import net.codinux.banking.client.model.UserAccountViewInfo +import net.codinux.banking.ui.config.DI +import net.codinux.banking.ui.model.BankInfo +import net.dankito.banking.banklistcreator.prettifier.BankingGroupMapper + +private val bankIconService = DI.bankIconService + +@Composable +fun BankIcon(userAccount: UserAccount?, modifier: Modifier = Modifier) { + val iconUrl by remember(userAccount?.bic) { mutableStateOf(userAccount?.let { bankIconService.findIconForBank(it) }) } + + BankIcon(iconUrl, modifier) +} + +private val bankingGroupMapper = BankingGroupMapper() + +@Composable +fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier) { + val iconUrl by remember(bank.bic) { mutableStateOf(bankIconService.findIconForBank(bank.name, bankingGroupMapper.getBankingGroup(bank.name, bank.bic))) } + + BankIcon(iconUrl, modifier) +} + +@Composable +fun BankIcon(userAccount: UserAccountViewInfo?, modifier: Modifier = Modifier) { + val iconUrl = userAccount?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) } + + BankIcon(iconUrl, modifier) +} + +@Composable +fun BankIcon(iconUrl: String?, modifier: Modifier = Modifier) { + Column(modifier) { + iconUrl?.let { + IconForUrl(iconUrl, "Favicon of this bank", Modifier.width(16.dp).height(16.dp)) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/IconFromUrl.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/IconFromUrl.kt new file mode 100644 index 0000000..e2da819 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/IconFromUrl.kt @@ -0,0 +1,35 @@ +package net.codinux.banking.ui.composables + +import androidx.compose.foundation.Image +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.codinux.banking.ui.IOorDefault +import net.codinux.banking.ui.config.DI + +private val imageCache = DI.imageCache + +@Composable +fun IconForUrl(iconUrl: String, contentDescription: String, modifier: Modifier = Modifier) { + var imageBitmap by remember(iconUrl) { mutableStateOf(null) } + + val coroutineScope = rememberCoroutineScope() + + if (iconUrl.endsWith(".svg") == false) { // SVG is not supported on Android + coroutineScope.launch(Dispatchers.IOorDefault) { + val received = imageCache.getImageBitmap(iconUrl) + + withContext(Dispatchers.Main) { + imageBitmap = received + } + } + } + + + imageBitmap?.let { imageBitmap -> + Image(imageBitmap, contentDescription, modifier) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionListItem.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionListItem.kt index 554d9b7..e50fdc3 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionListItem.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionListItem.kt @@ -9,25 +9,30 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import net.codinux.banking.client.model.UserAccount import net.codinux.banking.ui.config.DI import net.codinux.banking.ui.model.AccountTransactionViewModel private val formatUtil = DI.formatUtil @Composable -fun TransactionListItem(transaction: AccountTransactionViewModel, backgroundColor: Color) { +fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransactionViewModel, backgroundColor: Color) { Row( modifier = Modifier.fillMaxWidth() .background(color = backgroundColor) .padding(horizontal = 6.dp, vertical = 6.dp) ) { Column(Modifier.weight(1f)) { - Text( - text = transaction.otherPartyName ?: "", - Modifier.fillMaxWidth(), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) + Row { + BankIcon(userAccount, Modifier.padding(end = 6.dp)) + + Text( + text = transaction.otherPartyName ?: "", + Modifier.fillMaxWidth(), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } Spacer(modifier = Modifier.height(6.dp)) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt index 1598a77..b3a229a 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/TransactionsList.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.datetime.LocalDate -import net.codinux.banking.client.model.AccountTransaction import net.codinux.banking.client.model.Amount import net.codinux.banking.ui.extensions.toBigDecimal import net.codinux.banking.ui.forms.RoundedCornersCard @@ -28,6 +27,11 @@ private val formatUtil = DI.formatUtil @Composable fun TransactionsList(uiState: UiState) { + val users by uiState.userAccounts.collectAsState() + val usersById by remember(users) { + derivedStateOf { users.associateBy { it.id } } + } + val transactions by uiState.transactions.collectAsState() val groupedByMonth by remember(transactions) { @@ -53,7 +57,8 @@ fun TransactionsList(uiState: UiState) { RoundedCornersCard { Column(Modifier.background(Color.White)) { // LazyColumn inside LazyColumn is not allowed monthTransactions.forEachIndexed { index, transaction -> - TransactionListItem(transaction, if (index % 2 == 1) Colors.Zinc100_50 else Color.Transparent) + val backgroundColor = if (index % 2 == 1) Colors.Zinc100_50 else Color.Transparent + TransactionListItem(usersById[transaction.userAccountId], transaction, backgroundColor) if (index < monthTransactions.size - 1) { Divider(color = Colors.Zinc200, thickness = 1.dp) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt index 8495fd1..1025a04 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt @@ -18,8 +18,11 @@ object DI { val formatUtil = FormatUtil() + val imageCache = ImageCache() + val bankFinder = BankFinder() + val bankIconService = BankIconService() var bankingRepository: BankingRepository = InMemoryBankingRepository(emptyList()) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt index 9a5a881..8e3c549 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt @@ -1,24 +1,20 @@ package net.codinux.banking.ui.dialogs -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close +import androidx.compose.material.Text import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import net.codinux.banking.ui.forms.* -import net.codinux.banking.ui.model.BankInfo +import net.codinux.banking.ui.composables.BankIcon import net.codinux.banking.ui.config.Colors import net.codinux.banking.ui.config.DI -import net.codinux.banking.ui.config.Style +import net.codinux.banking.ui.forms.* +import net.codinux.banking.ui.model.BankInfo private val bankingService = DI.bankingService @@ -72,7 +68,16 @@ fun AddAccountDialog( getItemTitle = { bank -> bank.name }, fetchSuggestions = { query -> bankingService.findBanks(query) } ) { bank -> - Text(bank.name) + Row { + BankIcon(bank, Modifier.padding(end = 6.dp)) + + Text( + bank.name, + Modifier.fillMaxWidth(), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } Row(Modifier.fillMaxWidth().padding(top = 8.dp)) { Text(bank.bankCode) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialog.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialog.kt index 5957fb2..bb65794 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialog.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialog.kt @@ -20,7 +20,7 @@ import bankmeister.composeapp.generated.resources.zoom_in import bankmeister.composeapp.generated.resources.zoom_out import net.codinux.banking.client.model.tan.AllowedTanFormat import net.codinux.banking.client.model.tan.EnterTanResult -import net.codinux.banking.ui.config.DI +import net.codinux.banking.ui.composables.BankIcon import net.codinux.banking.ui.config.Internationalization import net.codinux.banking.ui.forms.OutlinedTextField import net.codinux.banking.ui.model.TanChallengeReceived @@ -63,6 +63,8 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () -> Column(Modifier.fillMaxWidth()) { Column(Modifier.fillMaxWidth()) { Row { + BankIcon(challenge.user, Modifier.padding(end = 6.dp)) + Text("${challenge.user.bankName}, Nutzer ${challenge.user.loginName}${challenge.account?.let { ", Konto ${it.productName ?: it.identifier}" } ?: ""}") } Text( diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankIconService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankIconService.kt new file mode 100644 index 0000000..51548db --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankIconService.kt @@ -0,0 +1,39 @@ +package net.codinux.banking.ui.service + +import net.codinux.banking.client.model.BankingGroup +import net.codinux.banking.client.model.UserAccount + +class BankIconService { // TODO: extract to a common library + + fun findIconForBank(user: UserAccount) = findIconForBank(user.bankName, user.bankingGroup) + + fun findIconForBank(bankName: String, bankingGroup: BankingGroup? = null): String? = when (bankingGroup) { + BankingGroup.Sparkasse -> "https://sparkasse.de/favicon-32x32.png" + BankingGroup.DKB -> "https://www.ib.dkb.de/favicon.ico" + BankingGroup.OldenburgischeLandesbank -> "https://olb.de/assets/img/icon/olb/favicon-32x32.png" + + BankingGroup.VolksUndRaiffeisenbanken -> "https://vr.de/favicon.ico" + BankingGroup.Sparda -> "https://www.sparda.de/hidden/layout/images/touchicons/favicon-32x32.png" + BankingGroup.PSD -> "https://www.psd-muenchen.de/favicon.ico" + BankingGroup.GLS -> "https://gls.de/assets/dist/img/icons/v2/favicon-32x32.png" // "https://gls.de/favicon.ico" + + BankingGroup.DeutscheBank -> "https://www.deutsche-bank.de/etc/designs/db-eccs-pws-pwcc/assets/db-favicon-167x167.png" // "https://www.deutsche-bank.de/etc/designs/db-eccs-pws-pwcc/assets/favicon.svg" // https://master.dwebcms.db.com/application/themes/default/favicon/favicon-32x32.png + BankingGroup.Postbank -> "https://postbank.de/etc/designs/pb-eccs-pb/icons/pb-favicon-167x167.png" // "https://postbank.de/etc/designs/pb-eccs-pb/icons/favicon.svg" + + BankingGroup.Commerzbank -> "https://commerzbank.de/ms/media/favicons/apple-touch-icon-57x57_A.png" + BankingGroup.Comdirect -> "https://comdirect.de/favicon.ico" + + BankingGroup.Unicredit -> "https://hypovereinsbank.de/etc/designs/hypovereinsbank/img/favicon/favicon.ico" + BankingGroup.Targobank -> "https://targobank.de/de/images/favicon/favicon.png" // https://targobank.de/favicon.ico + BankingGroup.ING -> "https://ing.de/favicon.ico" // "https://cdn.ing.de/ing-cms-ui/129.0.2/assets/favicons/apple-touch-icon.png" + BankingGroup.Santander -> "https://www.santander.de/ressourcen/img/favicons/favicon.ico" + + BankingGroup.Norisbank -> "https://norisbank.de/etc/designs/db-eccs-nb/assets/nb-favicon-167x167.png" // ""https://norisbank.de/etc/designs/db-eccs-nb/assets/favicon.svg" + BankingGroup.Degussa -> "https://www.degussa-bank.de/o/degussa-bank-theme/images/favicon.ico" + + BankingGroup.N26 -> "https://n26.de/favicon.ico" + + else -> null // TODO: call Favicon web service + } + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageCache.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageCache.kt new file mode 100644 index 0000000..4f939d0 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageCache.kt @@ -0,0 +1,69 @@ +package net.codinux.banking.ui.service + +import androidx.compose.ui.graphics.ImageBitmap +import kotlinx.coroutines.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import net.codinux.log.logger + +// TODO: save retrieved bytes to disk so that they don't have to be retrieved on the next app start again +class ImageCache { + + private val mutex = Mutex() + + private val imageBytesCache = mutableMapOf>() + + private val imageBitmapCache = mutableMapOf>() + + private val log by logger() + + // would be create but didn't get it to work with Ktor. Had therefor to introduce platform specific URL loading with loadImageBytes() + // simply re-using KtorWebClient as it already has all platform specific engines set up +// private val webClient = object : KtorWebClient() { +// +// val ktorClient = client +// init { +// client +// } +// } + + suspend fun getImageBytes(url: String): ByteArray? = coroutineScope { + mutex.withLock { + var cached = imageBytesCache[url] + if (cached == null || cached.isCancelled) { + //LAZY - to free the mutex lock as fast as possible + val loadJob = async(start = CoroutineStart.LAZY) { + loadImage(url) // TODO: in case of failure, remove url from cache and try again? + } + + imageBytesCache[url] = loadJob + loadJob + } else { + cached + } + }.await() + } + + suspend fun getImageBitmap(url: String): ImageBitmap? = coroutineScope { + getImageBytes(url)?.let { + createImageBitmap(it) + } + } + + private suspend fun loadImage(url: String): ByteArray? { + return try { +// val clientResponse = webClient.ktorClient.get(url) +// if (clientResponse.status.isSuccess()) { +// clientResponse.readBytes() +// } else { +// null +// } + + fetchBytesFromUrl(url) + } catch (e: Throwable) { + log.error(e) { "Failed to load image from url '$url'" } + null + } + } + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageService.kt index 09cf5dc..87ee1b4 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageService.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/ImageService.kt @@ -2,4 +2,6 @@ package net.codinux.banking.ui.service import androidx.compose.ui.graphics.ImageBitmap -expect fun createImageBitmap(imageBytes: ByteArray): ImageBitmap \ No newline at end of file +expect fun createImageBitmap(imageBytes: ByteArray): ImageBitmap + +expect fun fetchBytesFromUrl(url: String): ByteArray \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt new file mode 100644 index 0000000..8297a7c --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt @@ -0,0 +1,16 @@ +package net.codinux.banking.ui + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +actual val Dispatchers.IOorDefault: CoroutineDispatcher + get() = Dispatchers.IO + + +class JVMPlatform: Platform { + override val name: String = "Java ${System.getProperty("java.version")}" + + override val type: PlatformType = PlatformType.JVM +} + +actual fun getPlatform(): Platform = JVMPlatform() \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.jvm.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.jvm.kt deleted file mode 100644 index bd69891..0000000 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.jvm.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.codinux.banking.ui - -class JVMPlatform: Platform { - override val name: String = "Java ${System.getProperty("java.version")}" - - override val type: PlatformType = PlatformType.JVM -} - -actual fun getPlatform(): Platform = JVMPlatform() \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialogPreview.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialogPreview.kt index 58a5be6..e4ab417 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialogPreview.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/dialogs/EnterTanDialogPreview.kt @@ -2,6 +2,7 @@ package net.codinux.banking.ui.dialogs import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.runtime.Composable +import net.codinux.banking.client.model.BankingGroup import net.codinux.banking.client.model.UserAccountViewInfo import net.codinux.banking.client.model.tan.* import net.codinux.banking.ui.model.TanChallengeReceived @@ -10,7 +11,7 @@ import net.codinux.banking.ui.model.TanChallengeReceived @Composable fun EnterTanDialogPreview_EnterTan() { val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902")) - val user = UserAccountViewInfo("12345678", "SupiDupiNutzer", "Abzockbank") + val user = UserAccountViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank) val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user) EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { } @@ -24,7 +25,7 @@ fun EnterTanDialogPreview_TanImage() { val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric) val tanImage = TanImage("image/png", tanImageBytes) - val user = UserAccountViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank") + val user = UserAccountViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect) val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, user) diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt index 0853520..227fa10 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt @@ -3,6 +3,10 @@ package net.codinux.banking.ui.service import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.toComposeImageBitmap import org.jetbrains.skia.Image +import java.net.URL actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap = - Image.makeFromEncoded(imageBytes).toComposeImageBitmap() \ No newline at end of file + Image.makeFromEncoded(imageBytes).toComposeImageBitmap() + +actual fun fetchBytesFromUrl(url: String): ByteArray = + URL(url).openStream().buffered().use { it.readAllBytes() } \ No newline at end of file diff --git a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt index 2ef636e..9696004 100644 --- a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt +++ b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt @@ -1,5 +1,12 @@ package net.codinux.banking.ui +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +actual val Dispatchers.IOorDefault: CoroutineDispatcher + get() = Dispatchers.Default + + class JsPlatform: Platform { override val name: String = "Web with Kotlin/Js" diff --git a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/service/ImageService.js.kt b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/service/ImageService.js.kt index 0853520..2ab4070 100644 --- a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/service/ImageService.js.kt +++ b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/service/ImageService.js.kt @@ -5,4 +5,6 @@ import androidx.compose.ui.graphics.toComposeImageBitmap import org.jetbrains.skia.Image actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap = - Image.makeFromEncoded(imageBytes).toComposeImageBitmap() \ No newline at end of file + Image.makeFromEncoded(imageBytes).toComposeImageBitmap() + +actual fun fetchBytesFromUrl(url: String): ByteArray = ByteArray(0) \ No newline at end of file