Implemented setting banks' display order
This commit is contained in:
parent
f75db3f827
commit
34cb8617f8
|
@ -19,7 +19,7 @@ open class Customer(
|
||||||
open var userId: String = customerId,
|
open var userId: String = customerId,
|
||||||
open var iconUrl: String? = null,
|
open var iconUrl: String? = null,
|
||||||
open var accounts: List<BankAccount> = listOf()
|
open var accounts: List<BankAccount> = listOf()
|
||||||
) {
|
) : OrderedDisplayable {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
@ -45,9 +45,11 @@ open class Customer(
|
||||||
|
|
||||||
open var userSetDisplayName: String? = null
|
open var userSetDisplayName: String? = null
|
||||||
|
|
||||||
open val displayName: String
|
override val displayName: String
|
||||||
get() = userSetDisplayName ?: bankName
|
get() = userSetDisplayName ?: bankName
|
||||||
|
|
||||||
|
override var displayIndex: Int = 0
|
||||||
|
|
||||||
|
|
||||||
open val balance: BigDecimal
|
open val balance: BigDecimal
|
||||||
get() = accounts.map { it.balance }.sum()
|
get() = accounts.map { it.balance }.sum()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
|
|
||||||
|
interface Displayable {
|
||||||
|
|
||||||
|
val displayName: String
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
|
|
||||||
|
interface OrderedDisplayable : Displayable {
|
||||||
|
|
||||||
|
var displayIndex: Int
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package net.dankito.banking.ui.model.tan
|
package net.dankito.banking.ui.model.tan
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.Displayable
|
||||||
|
|
||||||
|
|
||||||
open class TanMedium(
|
open class TanMedium(
|
||||||
val displayName: String,
|
override val displayName: String,
|
||||||
val status: TanMediumStatus
|
val status: TanMediumStatus
|
||||||
) {
|
) : Displayable {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", TanMediumStatus.Available) // for object deserializers
|
internal constructor() : this("", TanMediumStatus.Available) // for object deserializers
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package net.dankito.banking.ui.model.tan
|
package net.dankito.banking.ui.model.tan
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.Displayable
|
||||||
|
|
||||||
|
|
||||||
open class TanProcedure(
|
open class TanProcedure(
|
||||||
val displayName: String,
|
override val displayName: String,
|
||||||
val type: TanProcedureType,
|
val type: TanProcedureType,
|
||||||
val bankInternalProcedureCode: String,
|
val bankInternalProcedureCode: String,
|
||||||
val maxTanInputLength: Int? = null,
|
val maxTanInputLength: Int? = null,
|
||||||
val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
|
||||||
) {
|
) : Displayable {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers
|
||||||
|
|
|
@ -381,6 +381,12 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun allAccountsUpdated() {
|
||||||
|
customers.forEach { account ->
|
||||||
|
accountUpdated(account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun accountUpdated(account: Customer) {
|
open fun accountUpdated(account: Customer) {
|
||||||
persistAccount(account)
|
persistAccount(account)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package net.dankito.banking.util
|
package net.dankito.banking.util
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.OrderedDisplayable
|
||||||
|
|
||||||
|
|
||||||
fun String.ofMaxLength(maxLength: Int): String {
|
fun String.ofMaxLength(maxLength: Int): String {
|
||||||
if(this.length > maxLength && maxLength > 0) {
|
if(this.length > maxLength && maxLength > 0) {
|
||||||
|
@ -26,4 +28,9 @@ fun <T> Collection<T>.containsExactly(otherCollection: Collection<T>): Boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <T : OrderedDisplayable> Collection<T>.sortedByDisplayIndex(): Collection<T> {
|
||||||
|
return this.sortedBy { it.displayIndex }
|
||||||
}
|
}
|
|
@ -42,6 +42,7 @@
|
||||||
<attribute name="balance" attributeType="Decimal" defaultValueString="0.0"/>
|
<attribute name="balance" attributeType="Decimal" defaultValueString="0.0"/>
|
||||||
<attribute name="currency" attributeType="String"/>
|
<attribute name="currency" attributeType="String"/>
|
||||||
<attribute name="customerId" attributeType="String"/>
|
<attribute name="customerId" attributeType="String"/>
|
||||||
|
<attribute name="displayIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="haveAllTransactionsBeenFetched" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
<attribute name="haveAllTransactionsBeenFetched" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
<attribute name="iban" optional="YES" attributeType="String"/>
|
<attribute name="iban" optional="YES" attributeType="String"/>
|
||||||
<attribute name="identifier" attributeType="String"/>
|
<attribute name="identifier" attributeType="String"/>
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
<attribute name="bic" attributeType="String"/>
|
<attribute name="bic" attributeType="String"/>
|
||||||
<attribute name="customerId" attributeType="String"/>
|
<attribute name="customerId" attributeType="String"/>
|
||||||
<attribute name="customerName" attributeType="String"/>
|
<attribute name="customerName" attributeType="String"/>
|
||||||
|
<attribute name="displayIndex" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="finTsServerAddress" attributeType="String"/>
|
<attribute name="finTsServerAddress" attributeType="String"/>
|
||||||
<attribute name="iconUrl" optional="YES" attributeType="String"/>
|
<attribute name="iconUrl" optional="YES" attributeType="String"/>
|
||||||
<attribute name="password" attributeType="String"/>
|
<attribute name="password" attributeType="String"/>
|
||||||
|
|
|
@ -7,6 +7,7 @@ class AppData : ObservableObject {
|
||||||
@Inject private var presenter: BankingPresenterSwift
|
@Inject private var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
@Published var banks: [Customer] = []
|
@Published var banks: [Customer] = []
|
||||||
|
@Published var banksSorted: [Customer] = []
|
||||||
|
|
||||||
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
|
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
|
||||||
|
|
||||||
|
@ -24,9 +25,15 @@ class AppData : ObservableObject {
|
||||||
|
|
||||||
private func setFieldsForBanks(_ banks: [Customer]) {
|
private func setFieldsForBanks(_ banks: [Customer]) {
|
||||||
self.banks = presenter.customers
|
self.banks = presenter.customers
|
||||||
|
self.banksSorted = banks.sortedByDisplayIndex()
|
||||||
|
|
||||||
hasAtLeastOneAccountBeenAdded = banks.isNotEmpty
|
hasAtLeastOneAccountBeenAdded = banks.isNotEmpty
|
||||||
hasAccountsThatSupportTransferringMoney = banks.flatMap { $0.accounts }.first(where: { $0.supportsTransferringMoney }) != nil
|
hasAccountsThatSupportTransferringMoney = banks.flatMap { $0.accounts }.first(where: { $0.supportsTransferringMoney }) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func banksDisplayIndexChanged() {
|
||||||
|
self.banksSorted = banks.sortedByDisplayIndex()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,27 @@ extension Array where Element == AccountTransaction {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Array where Element: OrderedDisplayable {
|
||||||
|
|
||||||
|
func sortedByDisplayIndex() -> [Element] {
|
||||||
|
return self.sorted { $0.displayIndex <= $1.displayIndex }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func reorder(from sourceIndices: IndexSet, to destinationIndex: Int) -> [Element] {
|
||||||
|
var elements = self
|
||||||
|
|
||||||
|
elements.move(fromOffsets: sourceIndices, toOffset: destinationIndex)
|
||||||
|
|
||||||
|
for (index, element) in elements.enumerated() {
|
||||||
|
element.displayIndex = Int32(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements.sortedByDisplayIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extension BankInfo : Identifiable {
|
extension BankInfo : Identifiable {
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import BankingUiSwift
|
||||||
|
|
||||||
|
|
||||||
class Mapper {
|
class Mapper {
|
||||||
|
|
||||||
/* Cache mapped object to not save them twice */
|
/* Cache mapped object to not save them twice */
|
||||||
private var mappedBanks = [Customer:PersistedCustomer]()
|
private var mappedBanks = [Customer:PersistedCustomer]()
|
||||||
|
|
||||||
|
@ -19,14 +19,17 @@ class Mapper {
|
||||||
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
|
||||||
|
|
||||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||||
|
mapped.displayIndex = customer.displayIndex
|
||||||
|
|
||||||
mapped.accounts = map(mapped, customer.accounts?.array as? [PersistedBankAccount])
|
mapped.accounts = map(mapped, customer.accounts?.array as? [PersistedBankAccount])
|
||||||
|
|
||||||
mappedBanks[mapped] = customer
|
|
||||||
|
|
||||||
mapped.supportedTanProcedures = map(customer.supportedTanProcedures?.array as? [PersistedTanProcedure])
|
mapped.supportedTanProcedures = map(customer.supportedTanProcedures?.array as? [PersistedTanProcedure])
|
||||||
mapped.selectedTanProcedure = mapped.supportedTanProcedures.first(where: { $0.bankInternalProcedureCode == customer.selectedTanProcedureCode })
|
mapped.selectedTanProcedure = mapped.supportedTanProcedures.first(where: { $0.bankInternalProcedureCode == customer.selectedTanProcedureCode })
|
||||||
|
|
||||||
|
mapped.technicalId = customer.objectIDAsString
|
||||||
|
|
||||||
|
mappedBanks[mapped] = customer
|
||||||
|
|
||||||
return mapped
|
return mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +47,7 @@ class Mapper {
|
||||||
mapped.iconUrl = customer.iconUrl
|
mapped.iconUrl = customer.iconUrl
|
||||||
|
|
||||||
mapped.userSetDisplayName = customer.userSetDisplayName
|
mapped.userSetDisplayName = customer.userSetDisplayName
|
||||||
|
mapped.displayIndex = customer.displayIndex
|
||||||
|
|
||||||
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
|
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
|
||||||
|
|
||||||
|
@ -66,9 +70,12 @@ class Mapper {
|
||||||
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
||||||
|
|
||||||
mapped.userSetDisplayName = account.userSetDisplayName
|
mapped.userSetDisplayName = account.userSetDisplayName
|
||||||
|
mapped.displayIndex = account.displayIndex
|
||||||
|
|
||||||
mapped.bookedTransactions = map(mapped, account.transactions as? Set<PersistedAccountTransaction>)
|
mapped.bookedTransactions = map(mapped, account.transactions as? Set<PersistedAccountTransaction>)
|
||||||
|
|
||||||
|
mapped.technicalId = account.objectIDAsString
|
||||||
|
|
||||||
mappedAccounts[mapped] = account
|
mappedAccounts[mapped] = account
|
||||||
|
|
||||||
return mapped
|
return mapped
|
||||||
|
@ -101,6 +108,7 @@ class Mapper {
|
||||||
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
|
||||||
|
|
||||||
mapped.userSetDisplayName = account.userSetDisplayName
|
mapped.userSetDisplayName = account.userSetDisplayName
|
||||||
|
mapped.displayIndex = account.displayIndex
|
||||||
|
|
||||||
mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context))
|
mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context))
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct AccountsTab: View {
|
||||||
Form {
|
Form {
|
||||||
AllBanksListItem(banks: data.banks)
|
AllBanksListItem(banks: data.banks)
|
||||||
|
|
||||||
ForEach(data.banks) { bank in
|
ForEach(data.banks.sortedByDisplayIndex()) { bank in
|
||||||
BankListItem(bank: bank)
|
BankListItem(bank: bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,6 @@ struct SettingsDialog: View {
|
||||||
@Inject var presenter: BankingPresenterSwift
|
@Inject var presenter: BankingPresenterSwift
|
||||||
|
|
||||||
|
|
||||||
private var banksSorted: [Customer] {
|
|
||||||
return data.banks.sorted { $0.displayIndex <= $1.displayIndex }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@State private var askToDeleteAccountMessage: Message? = nil
|
@State private var askToDeleteAccountMessage: Message? = nil
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,11 +16,12 @@ struct SettingsDialog: View {
|
||||||
Form {
|
Form {
|
||||||
Section(header: EditButton().frame(maxWidth: .infinity, alignment: .trailing)
|
Section(header: EditButton().frame(maxWidth: .infinity, alignment: .trailing)
|
||||||
.overlay(Text("Bank Credentials"), alignment: .leading)) {
|
.overlay(Text("Bank Credentials"), alignment: .leading)) {
|
||||||
ForEach(banksSorted) { bank in
|
ForEach(data.banksSorted) { bank in
|
||||||
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
|
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
|
||||||
IconedTitleView(bank)
|
IconedTitleView(bank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onMove(perform: reorderBanks)
|
||||||
.onDelete(perform: deleteBanks)
|
.onDelete(perform: deleteBanks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,9 +32,17 @@ struct SettingsDialog: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func reorderBanks(from sourceIndices: IndexSet, to destinationIndex: Int) {
|
||||||
|
let _ = data.banksSorted.reorder(from: sourceIndices, to: destinationIndex)
|
||||||
|
|
||||||
|
data.banksDisplayIndexChanged()
|
||||||
|
|
||||||
|
presenter.allAccountsUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
func deleteBanks(at offsets: IndexSet) {
|
func deleteBanks(at offsets: IndexSet) {
|
||||||
for offset in offsets {
|
for offset in offsets {
|
||||||
let bankToDelete = banksSorted[offset]
|
let bankToDelete = data.banksSorted[offset]
|
||||||
askUserToDeleteAccount(bankToDelete)
|
askUserToDeleteAccount(bankToDelete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,13 @@ open class fints4kModelMapper {
|
||||||
|
|
||||||
|
|
||||||
open fun mapBankAccounts(customer: Customer, accountData: List<AccountData>): List<BankAccount> {
|
open fun mapBankAccounts(customer: Customer, accountData: List<AccountData>): List<BankAccount> {
|
||||||
return accountData.map { mapBankAccount(customer, it) }
|
return accountData.mapIndexed { index, account ->
|
||||||
|
val mappedAccount = mapBankAccount(customer, account)
|
||||||
|
|
||||||
|
mappedAccount.displayIndex = index
|
||||||
|
|
||||||
|
mappedAccount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapBankAccount(customer: Customer, accountData: AccountData): BankAccount {
|
open fun mapBankAccount(customer: Customer, accountData: AccountData): BankAccount {
|
||||||
|
|
Loading…
Reference in New Issue