Implemented setting banks' display order

This commit is contained in:
dankito 2020-08-30 23:14:44 +02:00
parent f75db3f827
commit 34cb8617f8
14 changed files with 101 additions and 18 deletions

View File

@ -19,7 +19,7 @@ open class Customer(
open var userId: String = customerId,
open var iconUrl: String? = null,
open var accounts: List<BankAccount> = listOf()
) {
) : OrderedDisplayable {
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
@ -45,9 +45,11 @@ open class Customer(
open var userSetDisplayName: String? = null
open val displayName: String
override val displayName: String
get() = userSetDisplayName ?: bankName
override var displayIndex: Int = 0
open val balance: BigDecimal
get() = accounts.map { it.balance }.sum()

View File

@ -0,0 +1,8 @@
package net.dankito.banking.ui.model
interface Displayable {
val displayName: String
}

View File

@ -0,0 +1,8 @@
package net.dankito.banking.ui.model
interface OrderedDisplayable : Displayable {
var displayIndex: Int
}

View File

@ -1,10 +1,12 @@
package net.dankito.banking.ui.model.tan
import net.dankito.banking.ui.model.Displayable
open class TanMedium(
val displayName: String,
override val displayName: String,
val status: TanMediumStatus
) {
) : Displayable {
internal constructor() : this("", TanMediumStatus.Available) // for object deserializers

View File

@ -1,13 +1,15 @@
package net.dankito.banking.ui.model.tan
import net.dankito.banking.ui.model.Displayable
open class TanProcedure(
val displayName: String,
override val displayName: String,
val type: TanProcedureType,
val bankInternalProcedureCode: String,
val maxTanInputLength: Int? = null,
val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
) {
) : Displayable {
internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers

View File

@ -381,6 +381,12 @@ open class BankingPresenter(
}
open fun allAccountsUpdated() {
customers.forEach { account ->
accountUpdated(account)
}
}
open fun accountUpdated(account: Customer) {
persistAccount(account)
}

View File

@ -1,5 +1,7 @@
package net.dankito.banking.util
import net.dankito.banking.ui.model.OrderedDisplayable
fun String.ofMaxLength(maxLength: Int): String {
if(this.length > maxLength && maxLength > 0) {
@ -26,4 +28,9 @@ fun <T> Collection<T>.containsExactly(otherCollection: Collection<T>): Boolean {
}
return true
}
fun <T : OrderedDisplayable> Collection<T>.sortedByDisplayIndex(): Collection<T> {
return this.sortedBy { it.displayIndex }
}

View File

@ -42,6 +42,7 @@
<attribute name="balance" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="currency" 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="iban" optional="YES" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
@ -63,6 +64,7 @@
<attribute name="bic" attributeType="String"/>
<attribute name="customerId" attributeType="String"/>
<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="password" attributeType="String"/>

View File

@ -7,6 +7,7 @@ class AppData : ObservableObject {
@Inject private var presenter: BankingPresenterSwift
@Published var banks: [Customer] = []
@Published var banksSorted: [Customer] = []
@Published var hasAtLeastOneAccountBeenAdded: Bool = false
@ -24,9 +25,15 @@ class AppData : ObservableObject {
private func setFieldsForBanks(_ banks: [Customer]) {
self.banks = presenter.customers
self.banksSorted = banks.sortedByDisplayIndex()
hasAtLeastOneAccountBeenAdded = banks.isNotEmpty
hasAccountsThatSupportTransferringMoney = banks.flatMap { $0.accounts }.first(where: { $0.supportsTransferringMoney }) != nil
}
func banksDisplayIndexChanged() {
self.banksSorted = banks.sortedByDisplayIndex()
}
}

View File

@ -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 {

View File

@ -4,7 +4,7 @@ import BankingUiSwift
class Mapper {
/* Cache mapped object to not save them twice */
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: [])
mapped.userSetDisplayName = customer.userSetDisplayName
mapped.displayIndex = customer.displayIndex
mapped.accounts = map(mapped, customer.accounts?.array as? [PersistedBankAccount])
mappedBanks[mapped] = customer
mapped.supportedTanProcedures = map(customer.supportedTanProcedures?.array as? [PersistedTanProcedure])
mapped.selectedTanProcedure = mapped.supportedTanProcedures.first(where: { $0.bankInternalProcedureCode == customer.selectedTanProcedureCode })
mapped.technicalId = customer.objectIDAsString
mappedBanks[mapped] = customer
return mapped
}
@ -44,6 +47,7 @@ class Mapper {
mapped.iconUrl = customer.iconUrl
mapped.userSetDisplayName = customer.userSetDisplayName
mapped.displayIndex = customer.displayIndex
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
@ -66,9 +70,12 @@ class Mapper {
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
mapped.userSetDisplayName = account.userSetDisplayName
mapped.displayIndex = account.displayIndex
mapped.bookedTransactions = map(mapped, account.transactions as? Set<PersistedAccountTransaction>)
mapped.technicalId = account.objectIDAsString
mappedAccounts[mapped] = account
return mapped
@ -101,6 +108,7 @@ class Mapper {
mapped.haveAllTransactionsBeenFetched = account.haveAllTransactionsBeenFetched
mapped.userSetDisplayName = account.userSetDisplayName
mapped.displayIndex = account.displayIndex
mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context))

View File

@ -22,7 +22,7 @@ struct AccountsTab: View {
Form {
AllBanksListItem(banks: data.banks)
ForEach(data.banks) { bank in
ForEach(data.banks.sortedByDisplayIndex()) { bank in
BankListItem(bank: bank)
}

View File

@ -9,11 +9,6 @@ struct SettingsDialog: View {
@Inject var presenter: BankingPresenterSwift
private var banksSorted: [Customer] {
return data.banks.sorted { $0.displayIndex <= $1.displayIndex }
}
@State private var askToDeleteAccountMessage: Message? = nil
@ -21,11 +16,12 @@ struct SettingsDialog: View {
Form {
Section(header: EditButton().frame(maxWidth: .infinity, alignment: .trailing)
.overlay(Text("Bank Credentials"), alignment: .leading)) {
ForEach(banksSorted) { bank in
ForEach(data.banksSorted) { bank in
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
IconedTitleView(bank)
}
}
.onMove(perform: reorderBanks)
.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) {
for offset in offsets {
let bankToDelete = banksSorted[offset]
let bankToDelete = data.banksSorted[offset]
askUserToDeleteAccount(bankToDelete)
}
}

View File

@ -91,7 +91,13 @@ open class fints4kModelMapper {
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 {