Keeping now bank icon's bytes directly on BankData so that we can persist is to database -> attackers don't see in filesystem added accounts anymore
This commit is contained in:
parent
7f14215907
commit
fa1c2a0ddf
|
@ -13,8 +13,7 @@ import net.dankito.banking.ui.model.TypedBankData
|
|||
import net.dankito.banking.ui.model.settings.AppSettings
|
||||
import net.dankito.banking.ui.model.tan.MobilePhoneTanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||
import net.dankito.banking.util.persistence.doSaveUrlToFile
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.util.persistence.downloadIcon
|
||||
import net.sqlcipher.database.SQLiteDatabase
|
||||
import net.sqlcipher.database.SupportFactory
|
||||
|
||||
|
@ -197,8 +196,13 @@ open class RoomBankingPersistence(applicationContext: Context, password: String?
|
|||
}
|
||||
|
||||
|
||||
override fun saveUrlToFile(url: String, file: File) {
|
||||
doSaveUrlToFile(url, file)
|
||||
override fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?) {
|
||||
val iconData = downloadIcon(iconUrl)
|
||||
bank.iconData = iconData
|
||||
|
||||
(bank as? Bank)?.let {
|
||||
db.bankDao().saveOrUpdate(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ open class Bank(
|
|||
override var customerName: String,
|
||||
|
||||
override var userId: String = userName,
|
||||
override var iconUrl: String? = null,
|
||||
override var iconData: ByteArray? = null,
|
||||
|
||||
@Ignore
|
||||
override var accounts: List<TypedBankAccount> = listOf(),
|
||||
|
|
|
@ -12,10 +12,12 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class RoomModelCreator : IModelCreator {
|
||||
|
||||
override fun createBank(bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String,
|
||||
bic: String, customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
override fun createBank(
|
||||
bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String,
|
||||
bic: String, customerName: String, userId: String, iconData: ByteArray?
|
||||
): TypedBankData {
|
||||
|
||||
return Bank(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||
return Bank(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconData)
|
||||
}
|
||||
|
||||
override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
|
||||
|
|
|
@ -5,7 +5,7 @@ import net.dankito.banking.ui.model.*
|
|||
import net.dankito.banking.ui.model.settings.AppSettings
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.util.ISerializer
|
||||
import net.dankito.banking.util.persistence.doSaveUrlToFile
|
||||
import net.dankito.banking.util.persistence.downloadIcon
|
||||
|
||||
|
||||
open class BankingPersistenceJson(
|
||||
|
@ -24,6 +24,8 @@ open class BankingPersistenceJson(
|
|||
|
||||
protected val appSettingsJsonFile: File
|
||||
|
||||
protected var readBanks: List<TypedBankData>? = null
|
||||
|
||||
|
||||
init {
|
||||
databaseFolder.mkdirs()
|
||||
|
@ -42,7 +44,11 @@ open class BankingPersistenceJson(
|
|||
}
|
||||
|
||||
override fun readPersistedBanks(): List<TypedBankData> {
|
||||
return serializer.deserializeListOr(banksJsonFile, BankDataEntity::class).map { it as TypedBankData }
|
||||
val banks = serializer.deserializeListOr(banksJsonFile, BankDataEntity::class).map { it as TypedBankData }
|
||||
|
||||
this.readBanks = banks
|
||||
|
||||
return banks
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,8 +72,12 @@ open class BankingPersistenceJson(
|
|||
}
|
||||
|
||||
|
||||
override fun saveUrlToFile(url: String, file: File) {
|
||||
doSaveUrlToFile(url, file)
|
||||
override fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?) {
|
||||
bank.iconData = downloadIcon(iconUrl)
|
||||
|
||||
readBanks?.let {
|
||||
saveOrUpdateBank(bank, it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,10 +13,12 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class EntitiesModelCreator : IModelCreator {
|
||||
|
||||
override fun createBank(bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
override fun createBank(
|
||||
bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconData: ByteArray?
|
||||
): TypedBankData {
|
||||
|
||||
return BankDataEntity(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl) as TypedBankData
|
||||
return BankDataEntity(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconData) as TypedBankData
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ open class BankDataEntity(
|
|||
override var bic: String,
|
||||
override var customerName: String,
|
||||
override var userId: String = userName,
|
||||
override var iconUrl: String? = null,
|
||||
override var iconData: ByteArray? = null,
|
||||
override var accounts: List<BankAccountEntity> = listOf(),
|
||||
override var supportedTanMethods: List<TanMethod> = listOf(),
|
||||
override var selectedTanMethod: TanMethod? = null,
|
||||
|
|
|
@ -34,8 +34,6 @@ class BankingPersistenceJsonTest {
|
|||
|
||||
const val UserId = CustomerId
|
||||
|
||||
const val IconUrl = "http://i-do-not-exist.fail/favicon.ico"
|
||||
|
||||
val NowMillis = System.currentTimeMillis()
|
||||
|
||||
val TwoYearsAgoMillis = NowMillis - (2 * 365 * 24 * 60 * 60 * 1000L)
|
||||
|
@ -116,7 +114,7 @@ class BankingPersistenceJsonTest {
|
|||
|
||||
|
||||
private fun createBank(countAccounts: Int = 0, customerId: String = CustomerId): BankDataEntity {
|
||||
val result = BankDataEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, IconUrl)
|
||||
val result = BankDataEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, null)
|
||||
|
||||
result.accounts = createAccounts(countAccounts, result)
|
||||
|
||||
|
@ -180,7 +178,7 @@ class BankingPersistenceJsonTest {
|
|||
assertThat(deserializedBank.bic).isEqualTo(bank.bic)
|
||||
assertThat(deserializedBank.customerName).isEqualTo(bank.customerName)
|
||||
assertThat(deserializedBank.userId).isEqualTo(bank.userId)
|
||||
assertThat(deserializedBank.iconUrl).isEqualTo(bank.iconUrl)
|
||||
assertThat(deserializedBank.iconData).isEqualTo(bank.iconData)
|
||||
|
||||
assertAccountsEqual(deserializedBank.accounts, bank.accounts)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package net.dankito.banking.ui.android.adapter
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.ContextMenu
|
||||
import android.view.View
|
||||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.android.adapter.viewholder.AccountTransactionViewHolder
|
||||
import net.dankito.banking.ui.android.extensions.setIcon
|
||||
import net.dankito.banking.ui.android.extensions.showAmount
|
||||
import net.dankito.banking.ui.model.IAccountTransaction
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
@ -39,10 +39,10 @@ open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
|
|||
|
||||
viewHolder.txtvwAmount.showAmount(presenter, item.amount, item.currency)
|
||||
|
||||
val iconUrl = item.account.bank.iconUrl
|
||||
if (iconUrl != null && presenter.areAllAccountSelected) {
|
||||
if (presenter.areAllAccountSelected) {
|
||||
viewHolder.imgvwBankIcon.setIcon(item.account.bank)
|
||||
// TODO: if bank icon isn't set: Show default icon? show at least an empty space to that amount and date don't shift up causing an inconsistent view?
|
||||
viewHolder.imgvwBankIcon.visibility = View.VISIBLE
|
||||
viewHolder.imgvwBankIcon.setImageURI(Uri.parse(iconUrl))
|
||||
}
|
||||
else {
|
||||
viewHolder.imgvwBankIcon.visibility = View.GONE
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package net.dankito.banking.ui.android.extensions
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
|
||||
fun ByteArray.toBitmap(): Bitmap {
|
||||
return BitmapFactory.decodeByteArray(this, 0, this.size)
|
||||
}
|
||||
|
||||
fun ByteArray.toDrawable(resources: Resources): Drawable {
|
||||
return BitmapDrawable(resources, this.toBitmap())
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package net.dankito.banking.ui.android.extensions
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import net.dankito.banking.ui.model.IBankData
|
||||
|
@ -8,10 +7,21 @@ import net.dankito.banking.ui.model.IBankData
|
|||
|
||||
fun ImageView.setIcon(bank: IBankData<*, *>) {
|
||||
try {
|
||||
val iconUrl = bank.iconUrl
|
||||
this.visibility = if (iconUrl == null) View.GONE else View.VISIBLE
|
||||
this.setImageURI(Uri.parse(iconUrl))
|
||||
val iconData = bank.iconData
|
||||
|
||||
if (iconData != null) {
|
||||
this.visibility = View.VISIBLE
|
||||
this.setImageFromBytes(iconData)
|
||||
}
|
||||
else {
|
||||
this.visibility = View.GONE
|
||||
this.setImageURI(null)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
this.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun ImageView.setImageFromBytes(data: ByteArray) {
|
||||
this.setImageBitmap(data.toBitmap())
|
||||
}
|
|
@ -21,6 +21,7 @@ import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
|||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.android.dialogs.settings.BankSettingsDialog
|
||||
import net.dankito.banking.ui.android.dialogs.settings.SettingsDialog
|
||||
import net.dankito.banking.ui.android.extensions.toDrawable
|
||||
import net.dankito.banking.ui.android.extensions.withIcon
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
@ -87,6 +88,7 @@ open class DrawerView(
|
|||
.withIdentifier(AllAccountsId)
|
||||
.withLevel(BankLevel)
|
||||
.withSelected(true)
|
||||
// TODO: set default account icon (here and below if bank.iconUrl isn't set
|
||||
.withIcon(activity, GoogleMaterial.Icon.gmd_account_balance, R.color.primaryTextColor_Dark)
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAllAccounts() } }
|
||||
,
|
||||
|
@ -150,12 +152,13 @@ open class DrawerView(
|
|||
.withSecondaryIcon(R.drawable.ic_baseline_settings_24)
|
||||
.withSecondaryIconColor(activity, R.color.primaryTextColor_Dark)
|
||||
.withOnSecondaryIconClickedListener { closeDrawerAndEditAccount(bank) }
|
||||
.withIcon(bank.iconUrl ?: "")
|
||||
.withIcon(bank.iconData?.toDrawable(activity.resources))
|
||||
.withSelected(presenter.isSingleSelectedBank(bank))
|
||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedBank(bank) } }
|
||||
|
||||
if (bank.iconUrl == null) {
|
||||
accountItem.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
|
||||
if (bank.iconData == null) {
|
||||
// TODO: use better default icon
|
||||
accountItem.withIcon(activity, GoogleMaterial.Icon.gmd_account_balance, R.color.primaryTextColor_Dark)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:textAlignment="gravity"
|
||||
android:textSize="@dimen/view_real_time_transfer_info_text_size"
|
||||
android:textSize="@dimen/view_info_popup_text_size"
|
||||
android:text="@string/dialog_transfer_money_real_time_transfer"
|
||||
/>
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import net.dankito.banking.ui.presenter.BankingPresenter
|
|||
import net.dankito.banking.util.InputValidator
|
||||
import net.dankito.banking.bankfinder.BankInfo
|
||||
import net.dankito.banking.search.TransactionParty
|
||||
import net.dankito.banking.ui.javafx.extensions.createBankIconImageView
|
||||
import net.dankito.utils.multiplatform.toBigDecimal
|
||||
import net.dankito.banking.ui.javafx.extensions.focusNextControl
|
||||
import net.dankito.utils.javafx.ui.controls.AutoCompletionSearchTextField
|
||||
|
@ -115,15 +116,8 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
|||
cellFormat {
|
||||
text = it.displayName
|
||||
|
||||
it.bank.iconUrl?.let { iconUrl ->
|
||||
graphic = ImageView(iconUrl)?.apply {
|
||||
this.fitHeight = BankIconSize
|
||||
this.fitWidth = BankIconSize
|
||||
this.isPreserveRatio = true
|
||||
}
|
||||
contentDisplay = ContentDisplay.LEFT
|
||||
}
|
||||
?: run { contentDisplay = ContentDisplay.TEXT_ONLY }
|
||||
graphic = it.bank.createBankIconImageView(BankIconSize)
|
||||
contentDisplay = ContentDisplay.LEFT
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package net.dankito.banking.ui.javafx.extensions
|
||||
|
||||
import javafx.scene.image.ImageView
|
||||
import net.dankito.banking.ui.model.IBankData
|
||||
|
||||
|
||||
fun IBankData<*, *>.createBankIconImageView(iconSize: Double): ImageView {
|
||||
// TODO: set default icon if iconData is null
|
||||
val image = iconData?.toImage()
|
||||
val iconImageView = ImageView(image)
|
||||
|
||||
iconImageView.fitHeight = iconSize
|
||||
iconImageView.fitWidth = iconSize
|
||||
iconImageView.isPreserveRatio = true
|
||||
|
||||
return iconImageView
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.dankito.banking.ui.javafx.extensions
|
||||
|
||||
import javafx.scene.image.Image
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
|
||||
fun ByteArray.toImage(): Image {
|
||||
return Image(ByteArrayInputStream(this))
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.ui.javafx.model
|
||||
|
||||
import javafx.scene.Node
|
||||
import javafx.scene.image.ImageView
|
||||
import net.dankito.banking.ui.javafx.extensions.createBankIconImageView
|
||||
import net.dankito.banking.ui.model.TypedBankData
|
||||
|
||||
|
||||
|
@ -23,18 +23,7 @@ open class AccountsAccountTreeItem(val bank: TypedBankData) : AccountsTreeItemBa
|
|||
}
|
||||
|
||||
protected open fun createIconImageView(): Node? {
|
||||
bank.iconUrl?.let {
|
||||
val iconImageView = ImageView(it)
|
||||
|
||||
iconImageView.fitHeight = IconSize
|
||||
iconImageView.fitWidth = IconSize
|
||||
iconImageView.isPreserveRatio = true
|
||||
|
||||
return iconImageView
|
||||
}
|
||||
|
||||
// TODO: otherwise set default icon
|
||||
return null
|
||||
return bank.createBankIconImageView(IconSize)
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,6 @@ interface IBankingPersistence {
|
|||
fun readPersistedAppSettings(): AppSettings?
|
||||
|
||||
|
||||
fun saveUrlToFile(url: String, file: File)
|
||||
fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?)
|
||||
|
||||
}
|
|
@ -2,7 +2,6 @@ package net.dankito.banking.persistence
|
|||
|
||||
import net.dankito.banking.ui.model.*
|
||||
import net.dankito.banking.ui.model.settings.AppSettings
|
||||
import net.dankito.utils.multiplatform.File
|
||||
|
||||
|
||||
open class NoOpBankingPersistence : IBankingPersistence {
|
||||
|
@ -34,7 +33,7 @@ open class NoOpBankingPersistence : IBankingPersistence {
|
|||
}
|
||||
|
||||
|
||||
override fun saveUrlToFile(url: String, file: File) {
|
||||
override fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ open class BankData(
|
|||
override var bic: String,
|
||||
override var customerName: String,
|
||||
override var userId: String = userName,
|
||||
override var iconUrl: String? = null,
|
||||
override var iconData: ByteArray? = null,
|
||||
override var accounts: List<TypedBankAccount> = listOf()
|
||||
) : TypedBankData {
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ interface IBankData<TAccount: IBankAccount<TAccountTransaction>, TAccountTransac
|
|||
var customerName: String
|
||||
var userId: String
|
||||
|
||||
var iconUrl: String?
|
||||
var iconData: ByteArray?
|
||||
|
||||
var accounts: List<TAccount>
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ import net.dankito.utils.multiplatform.Date
|
|||
|
||||
open class DefaultModelCreator : IModelCreator {
|
||||
|
||||
override fun createBank(bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconUrl: String?): TypedBankData {
|
||||
override fun createBank(
|
||||
bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String, userId: String, iconData: ByteArray?
|
||||
): TypedBankData {
|
||||
|
||||
return BankData(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl)
|
||||
return BankData(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconData)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import net.dankito.utils.multiplatform.Date
|
|||
interface IModelCreator {
|
||||
|
||||
fun createBank(bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
|
||||
customerName: String = "", userId: String = userName, iconUrl: String? = null): TypedBankData
|
||||
customerName: String = "", userId: String = userName, iconData: ByteArray? = null): TypedBankData
|
||||
|
||||
|
||||
fun createAccount(bank: TypedBankData, productName: String?, identifier: String) : TypedBankAccount
|
||||
|
|
|
@ -209,33 +209,15 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
protected open fun handleFindIconForBankResult(bank: TypedBankData, bankIconUrl: String) {
|
||||
val bankIconFile = saveBankIconToDisk(bank, bankIconUrl)
|
||||
|
||||
var iconFilePath = bankIconFile.getAbsolutePath()
|
||||
|
||||
if (iconFilePath.startsWith("file://", true) == false) {
|
||||
iconFilePath = "file://" + iconFilePath // without 'file://' Android will not find it
|
||||
try {
|
||||
persister.saveBankIcon(bank, bankIconUrl, getIconFileExtension(bankIconUrl))
|
||||
} catch (e: Exception) {
|
||||
log.error(e) { "Could not download bank icon from url $bankIconUrl" }
|
||||
}
|
||||
|
||||
bank.iconUrl = iconFilePath
|
||||
|
||||
persistBankOffUiThread(bank)
|
||||
|
||||
callBanksChangedListeners()
|
||||
}
|
||||
|
||||
protected open fun saveBankIconToDisk(bank: TypedBankData, bankIconUrl: String): File {
|
||||
val bankIconsDir = File(dataFolder, "bank_icons")
|
||||
bankIconsDir.mkdirs()
|
||||
|
||||
val extension = getIconFileExtension(bankIconUrl)
|
||||
val bankIconFile = File(bankIconsDir, bank.bankCode + if (extension != null) (".$extension") else "")
|
||||
|
||||
persister.saveUrlToFile(bankIconUrl, bankIconFile)
|
||||
|
||||
return bankIconFile
|
||||
}
|
||||
|
||||
protected open fun getIconFileExtension(bankIconUrl: String): String? {
|
||||
try {
|
||||
var iconFilename = File(bankIconUrl).filename
|
||||
|
|
|
@ -12,4 +12,10 @@ fun IBankingPersistence.doSaveUrlToFile(url: String, file: File) {
|
|||
iconInputStream.copyTo(fileOutputStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun IBankingPersistence.downloadIcon(url: String): ByteArray {
|
||||
URL(url).openConnection().getInputStream().buffered().use { iconInputStream ->
|
||||
return iconInputStream.readBytes()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package net.dankito.banking
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import platform.Foundation.*
|
||||
|
||||
|
||||
/**
|
||||
* Swift doesn't see the ByteArray- and NSData extension methods from Common (why?) -> redefine them here in a way Swift sees them.
|
||||
*/
|
||||
class ByteArrayExtensions {
|
||||
|
||||
companion object {
|
||||
|
||||
fun toNSData(array: ByteArray): NSData {
|
||||
return NSMutableData().apply {
|
||||
if (array.isEmpty()) return@apply
|
||||
array.usePinned {
|
||||
appendBytes(it.addressOf(0), array.size.convert())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fromNSData(data: NSData): ByteArray {
|
||||
val bytes: CPointer<ByteVar> = data.bytes!!.reinterpret()
|
||||
|
||||
return ByteArray(data.length.toInt()) { index -> bytes[index] }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@
|
|||
<attribute name="customerName" attributeType="String"/>
|
||||
<attribute name="displayIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="finTsServerAddress" attributeType="String"/>
|
||||
<attribute name="iconUrl" optional="YES" attributeType="String"/>
|
||||
<attribute name="iconData" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="password" attributeType="String"/>
|
||||
<attribute name="savePassword" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="selectedTanMethodCode" optional="YES" attributeType="String"/>
|
||||
|
|
|
@ -16,7 +16,7 @@ let previewFlickerCodeTanChallenge = FlickerCodeTanChallenge(flickerCode: Flicke
|
|||
|
||||
|
||||
func createPreviewBanks() -> [IBankData] {
|
||||
let bank1 = BankData(bankCode: "", userName: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
let bank1 = BankData(bankCode: "", userName: "", password: "", finTsServerAddress: "", bankName: "Abzockbank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconData: nil, accounts: [])
|
||||
|
||||
bank1.accounts = [
|
||||
BankAccount(bank: bank1, productName: "Girokonto", identifier: "1234567890"),
|
||||
|
@ -25,7 +25,7 @@ func createPreviewBanks() -> [IBankData] {
|
|||
]
|
||||
|
||||
|
||||
let bank2 = BankData(bankCode: "", userName: "", password: "", finTsServerAddress: "", bankName: "Kundenverarschebank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconUrl: "", accounts: [])
|
||||
let bank2 = BankData(bankCode: "", userName: "", password: "", finTsServerAddress: "", bankName: "Kundenverarschebank", bic: "", customerName: "Marieke Musterfrau", userId: "", iconData: nil, accounts: [])
|
||||
|
||||
bank2.accounts = [
|
||||
BankAccount(bank: bank2, productName: "Girokonto", identifier: "1234567890")
|
||||
|
|
|
@ -147,6 +147,19 @@ class CoreDataBankingPersistence: IBankingPersistence, ITransactionPartySearcher
|
|||
}
|
||||
|
||||
|
||||
func saveBankIcon(bank: IBankData, iconUrl: String, fileExtension: String?) {
|
||||
do {
|
||||
if let remoteUrl = URL.encoded(iconUrl) {
|
||||
let iconData = try Data(contentsOf: remoteUrl)
|
||||
bank.iconData = mapper.map(iconData)
|
||||
|
||||
saveOrUpdateBank(bank: bank, allBanks: [])
|
||||
}
|
||||
} catch {
|
||||
NSLog("Could not get icon for bank \(bank) from url \(iconUrl): \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func saveUrlToFile(url: String, file: URL) {
|
||||
if let remoteUrl = URL.encoded(url) {
|
||||
if let fileData = try? Data(contentsOf: remoteUrl) {
|
||||
|
|
|
@ -6,8 +6,8 @@ import BankingUiSwift
|
|||
class Mapper {
|
||||
|
||||
func map(_ bank: PersistedBankData) -> IBankData {
|
||||
let mapped = BankData(bankCode: map(bank.bankCode), userName: map(bank.userName), password: map(bank.password), finTsServerAddress: map(bank.finTsServerAddress), bankName: map(bank.bankName), bic: map(bank.bic), customerName: map(bank.customerName), userId: map(bank.userId), iconUrl: bank.iconUrl, accounts: [])
|
||||
|
||||
let mapped = BankData(bankCode: map(bank.bankCode), userName: map(bank.userName), password: map(bank.password), finTsServerAddress: map(bank.finTsServerAddress), bankName: map(bank.bankName), bic: map(bank.bic), customerName: map(bank.customerName), userId: map(bank.userId), iconData: map(bank.iconData), accounts: [])
|
||||
|
||||
mapped.wrongCredentialsEntered = bank.wrongCredentialsEntered
|
||||
mapped.savePassword = bank.savePassword
|
||||
mapped.userSetDisplayName = bank.userSetDisplayName
|
||||
|
@ -36,8 +36,8 @@ class Mapper {
|
|||
mapped.bic = bank.bic
|
||||
mapped.customerName = bank.customerName
|
||||
mapped.userId = bank.userId
|
||||
mapped.iconUrl = bank.iconUrl
|
||||
|
||||
mapped.iconData = map(bank.iconData)
|
||||
|
||||
mapped.wrongCredentialsEntered = bank.wrongCredentialsEntered
|
||||
mapped.savePassword = bank.savePassword
|
||||
mapped.userSetDisplayName = bank.userSetDisplayName
|
||||
|
@ -448,4 +448,20 @@ class Mapper {
|
|||
return string ?? ""
|
||||
}
|
||||
|
||||
func map(_ array: KotlinByteArray?) -> Data? {
|
||||
if let array = array {
|
||||
return ByteArrayExtensions.Companion().toNSData(array: array)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func map(_ data: Data?) -> KotlinByteArray? {
|
||||
if let data = data {
|
||||
return ByteArrayExtensions.Companion().fromNSData(data: data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import SwiftUI
|
||||
import BankingUiSwift
|
||||
|
||||
|
||||
struct IconView: View {
|
||||
|
||||
let iconUrl: String?
|
||||
let iconData: KotlinByteArray?
|
||||
|
||||
let defaultIconName: String
|
||||
|
||||
|
@ -12,22 +13,22 @@ struct IconView: View {
|
|||
|
||||
|
||||
var body: some View {
|
||||
getBankIcon(self.iconUrl)
|
||||
getBankIcon(self.iconData)
|
||||
.renderingMode(Image.TemplateRenderingMode.original)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: Styles.AccountsIconWidth)
|
||||
}
|
||||
|
||||
private func getBankIcon(_ iconUrl: String?) -> Image {
|
||||
if let iconUrl = iconUrl {
|
||||
if let iconData = persistence.readContentOfFile(iconUrl) {
|
||||
if let uiImage = UIImage(data: iconData) {
|
||||
return Image(uiImage: uiImage)
|
||||
}
|
||||
private func getBankIcon(_ iconData: KotlinByteArray?) -> Image {
|
||||
if let iconData = iconData {
|
||||
let nsData = ByteArrayExtensions.Companion().toNSData(array: iconData)
|
||||
|
||||
if let uiImage = UIImage(data: nsData) {
|
||||
return Image(uiImage: uiImage)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Image(defaultIconName)
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,7 @@ struct IconView: View {
|
|||
struct IconView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
IconView(iconUrl: nil, defaultIconName: "")
|
||||
IconView(iconData: nil, defaultIconName: "")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ struct IconedTitleView: View {
|
|||
|
||||
private var title: String
|
||||
|
||||
private var iconUrl: String?
|
||||
private var iconData: KotlinByteArray?
|
||||
|
||||
private var defaultIconName: String
|
||||
|
||||
|
@ -14,16 +14,16 @@ struct IconedTitleView: View {
|
|||
|
||||
|
||||
init(_ bank: IBankData, titleFont: Font? = nil) {
|
||||
self.init(accountTitle: bank.displayName, iconUrl: bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
self.init(accountTitle: bank.displayName, iconData: bank.iconData, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
}
|
||||
|
||||
init(_ account: IBankAccount, titleFont: Font? = nil) {
|
||||
self.init(accountTitle: account.displayName, iconUrl: account.bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
self.init(accountTitle: account.displayName, iconData: account.bank.iconData, defaultIconName: Styles.AccountFallbackIcon, titleFont: titleFont)
|
||||
}
|
||||
|
||||
init(accountTitle: String, iconUrl: String?, defaultIconName: String, titleFont: Font? = nil) {
|
||||
init(accountTitle: String, iconData: KotlinByteArray?, defaultIconName: String, titleFont: Font? = nil) {
|
||||
self.title = accountTitle
|
||||
self.iconUrl = iconUrl
|
||||
self.iconData = iconData
|
||||
|
||||
self.defaultIconName = defaultIconName
|
||||
self.titleFont = titleFont
|
||||
|
@ -32,7 +32,7 @@ struct IconedTitleView: View {
|
|||
|
||||
var body: some View {
|
||||
HStack {
|
||||
IconView(iconUrl: self.iconUrl, defaultIconName: self.defaultIconName)
|
||||
IconView(iconData: self.iconData, defaultIconName: self.defaultIconName)
|
||||
|
||||
Spacer()
|
||||
.frame(width: Styles.DefaultSpaceBetweenIconAndText)
|
||||
|
@ -58,7 +58,7 @@ struct IconedTitleView: View {
|
|||
struct IconedAccountTitle_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
IconedTitleView(accountTitle: "Abzockbank", iconUrl: nil, defaultIconName: Styles.AccountFallbackIcon)
|
||||
IconedTitleView(accountTitle: "Abzockbank", iconData: nil, defaultIconName: Styles.AccountFallbackIcon)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ struct AccountTransactionListItem: View {
|
|||
if areMoreThanOneBanksTransactionsDisplayed {
|
||||
Spacer()
|
||||
|
||||
IconView(iconUrl: transaction.account.bank.iconUrl, defaultIconName: Styles.AccountFallbackIcon)
|
||||
IconView(iconData: transaction.account.bank.iconData, defaultIconName: Styles.AccountFallbackIcon)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
|
|
@ -16,7 +16,7 @@ struct AllBanksListItem: View {
|
|||
Section {
|
||||
NavigationLink(destination: EmptyView(), isActive: .constant(false)) { // NavigationLink navigated to AccountTransactionsDialog twice. So i disabled NavigationLink and implemented manual navigation
|
||||
HStack {
|
||||
IconedTitleView(accountTitle: "All accounts".localize(), iconUrl: nil, defaultIconName: Styles.AccountFallbackIcon, titleFont: .headline)
|
||||
IconedTitleView(accountTitle: "All accounts".localize(), iconData: nil, defaultIconName: Styles.AccountFallbackIcon, titleFont: .headline)
|
||||
|
||||
Spacer()
|
||||
|
||||
|
|
Loading…
Reference in New Issue