Implemented sorting bank accounts; extracted SectionWithRightAlignedEditButton

This commit is contained in:
dankito 2020-08-30 23:37:49 +02:00
parent 34cb8617f8
commit 8914d83ec6
8 changed files with 68 additions and 6 deletions

View File

@ -25,7 +25,7 @@ open class BankAccount @JvmOverloads constructor(
open var supportsInstantPaymentMoneyTransfer: Boolean = false, open var supportsInstantPaymentMoneyTransfer: Boolean = false,
open var bookedTransactions: List<AccountTransaction> = listOf(), open var bookedTransactions: List<AccountTransaction> = listOf(),
open var unbookedTransactions: List<Any> = listOf() open var unbookedTransactions: List<Any> = listOf()
) { ) : OrderedDisplayable {
internal constructor() : this(Customer(), null, "") // for object deserializers internal constructor() : this(Customer(), null, "") // for object deserializers
@ -45,11 +45,13 @@ open class BankAccount @JvmOverloads constructor(
open var userSetDisplayName: String? = null open var userSetDisplayName: String? = null
open val displayName: String override val displayName: String
get() { get() {
return userSetDisplayName ?: productName ?: subAccountNumber ?: identifier return userSetDisplayName ?: productName ?: subAccountNumber ?: identifier
} }
override var displayIndex: Int = 0
open fun addBookedTransactions(retrievedBookedTransactions: List<AccountTransaction>) { open fun addBookedTransactions(retrievedBookedTransactions: List<AccountTransaction>) {
val uniqueTransactions = this.bookedTransactions.toMutableSet() val uniqueTransactions = this.bookedTransactions.toMutableSet()

View File

@ -5,6 +5,7 @@ import net.dankito.utils.multiplatform.sum
import net.dankito.banking.ui.model.tan.TanMedium import net.dankito.banking.ui.model.tan.TanMedium
import net.dankito.banking.ui.model.tan.TanMediumStatus import net.dankito.banking.ui.model.tan.TanMediumStatus
import net.dankito.banking.ui.model.tan.TanProcedure import net.dankito.banking.ui.model.tan.TanProcedure
import net.dankito.banking.util.sortedByDisplayIndex
import net.dankito.utils.multiplatform.UUID import net.dankito.utils.multiplatform.UUID
@ -51,6 +52,10 @@ open class Customer(
override var displayIndex: Int = 0 override var displayIndex: Int = 0
open val accountsSorted: List<BankAccount>
get() = accounts.sortedByDisplayIndex()
open val balance: BigDecimal open val balance: BigDecimal
get() = accounts.map { it.balance }.sum() get() = accounts.map { it.balance }.sum()

View File

@ -155,6 +155,7 @@ open class BankingPresenter(
newClient.addAccountAsync { response -> newClient.addAccountAsync { response ->
val account = response.customer val account = response.customer
account.displayIndex = customers.size
if (response.isSuccessful) { if (response.isSuccessful) {
addClientForAccount(account, newClient) addClientForAccount(account, newClient)

View File

@ -31,6 +31,10 @@ fun <T> Collection<T>.containsExactly(otherCollection: Collection<T>): Boolean {
} }
fun <T : OrderedDisplayable> List<T>.sortedByDisplayIndex(): List<T> {
return this.sortedBy { it.displayIndex }
}
fun <T : OrderedDisplayable> Collection<T>.sortedByDisplayIndex(): Collection<T> { fun <T : OrderedDisplayable> Collection<T>.sortedByDisplayIndex(): Collection<T> {
return this.sortedBy { it.displayIndex } return this.sortedBy { it.displayIndex }
} }

View File

@ -19,6 +19,7 @@
360782D324F429F80098FEFE /* FlickerCodeStripe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360782D224F429F70098FEFE /* FlickerCodeStripe.swift */; }; 360782D324F429F80098FEFE /* FlickerCodeStripe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360782D224F429F70098FEFE /* FlickerCodeStripe.swift */; };
3608D6C224FBA9C6006C93A8 /* TrianglePointingDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */; }; 3608D6C224FBA9C6006C93A8 /* TrianglePointingDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */; };
3608D6C624FBAB41006C93A8 /* TanGeneratorPositionMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */; }; 3608D6C624FBAB41006C93A8 /* TanGeneratorPositionMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */; };
366744E224FC4E96002B235A /* SectionWithRightAlignedEditButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366744E124FC4E96002B235A /* SectionWithRightAlignedEditButton.swift */; };
366FA4DA24C472A90094F009 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4D924C472A90094F009 /* Extensions.swift */; }; 366FA4DA24C472A90094F009 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4D924C472A90094F009 /* Extensions.swift */; };
366FA4DC24C479120094F009 /* BankInfoListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DB24C479120094F009 /* BankInfoListItem.swift */; }; 366FA4DC24C479120094F009 /* BankInfoListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DB24C479120094F009 /* BankInfoListItem.swift */; };
366FA4E024C4924A0094F009 /* RemitteeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */; }; 366FA4E024C4924A0094F009 /* RemitteeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */; };
@ -148,6 +149,7 @@
360782D224F429F70098FEFE /* FlickerCodeStripe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlickerCodeStripe.swift; sourceTree = "<group>"; }; 360782D224F429F70098FEFE /* FlickerCodeStripe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlickerCodeStripe.swift; sourceTree = "<group>"; };
3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrianglePointingDown.swift; sourceTree = "<group>"; }; 3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrianglePointingDown.swift; sourceTree = "<group>"; };
3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TanGeneratorPositionMarker.swift; sourceTree = "<group>"; }; 3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TanGeneratorPositionMarker.swift; sourceTree = "<group>"; };
366744E124FC4E96002B235A /* SectionWithRightAlignedEditButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionWithRightAlignedEditButton.swift; sourceTree = "<group>"; };
366FA4D924C472A90094F009 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; }; 366FA4D924C472A90094F009 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
366FA4DB24C479120094F009 /* BankInfoListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BankInfoListItem.swift; sourceTree = "<group>"; }; 366FA4DB24C479120094F009 /* BankInfoListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BankInfoListItem.swift; sourceTree = "<group>"; };
366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemitteeListItem.swift; sourceTree = "<group>"; }; 366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemitteeListItem.swift; sourceTree = "<group>"; };
@ -465,6 +467,7 @@
36E21EDE24DCCC2700649DC8 /* CheckmarkListItem.swift */, 36E21EDE24DCCC2700649DC8 /* CheckmarkListItem.swift */,
3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */, 3608D6C124FBA9C6006C93A8 /* TrianglePointingDown.swift */,
3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */, 3608D6C524FBAB41006C93A8 /* TanGeneratorPositionMarker.swift */,
366744E124FC4E96002B235A /* SectionWithRightAlignedEditButton.swift */,
); );
path = views; path = views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -638,6 +641,7 @@
36BE068D24CE41E700CBBB68 /* Styles.swift in Sources */, 36BE068D24CE41E700CBBB68 /* Styles.swift in Sources */,
36E21ECB24D88DF000649DC8 /* UIKitExtensions.swift in Sources */, 36E21ECB24D88DF000649DC8 /* UIKitExtensions.swift in Sources */,
360782C524E541970098FEFE /* ScaleImageView.swift in Sources */, 360782C524E541970098FEFE /* ScaleImageView.swift in Sources */,
366744E224FC4E96002B235A /* SectionWithRightAlignedEditButton.swift in Sources */,
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */, 366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */,
36FC92DC24B3A4A0002B12E9 /* AccountsTab.swift in Sources */, 36FC92DC24B3A4A0002B12E9 /* AccountsTab.swift in Sources */,
36BCF86E24BA691B005BEC29 /* DependencyInjector.swift in Sources */, 36BCF86E24BA691B005BEC29 /* DependencyInjector.swift in Sources */,

View File

@ -19,6 +19,8 @@ struct BankSettingsDialog: View {
@State private var selectedTanProcedure: TanProcedure? @State private var selectedTanProcedure: TanProcedure?
@State private var accountsSorted: [BankAccount]
@State private var askUserToDeleteAccountOrSaveChangesMessage: Message? = nil @State private var askUserToDeleteAccountOrSaveChangesMessage: Message? = nil
@ -39,6 +41,8 @@ struct BankSettingsDialog: View {
_password = State(initialValue: bank.password) _password = State(initialValue: bank.password)
_selectedTanProcedure = State(initialValue: bank.selectedTanProcedure) _selectedTanProcedure = State(initialValue: bank.selectedTanProcedure)
_accountsSorted = State(initialValue: bank.accountsSorted)
} }
@ -70,12 +74,13 @@ struct BankSettingsDialog: View {
LabelledUIKitTextField(label: "FinTS server address", value: bank.finTsServerAddress) // TODO: senseful? LabelledUIKitTextField(label: "FinTS server address", value: bank.finTsServerAddress) // TODO: senseful?
} }
Section(header: Text("Accounts")) { SectionWithRightAlignedEditButton(sectionTitle: "Accounts") {
ForEach(bank.accounts.sorted(by: { $0.displayIndex <= $1.displayIndex })) { account in ForEach(accountsSorted) { account in
NavigationLink(destination: LazyView(BankAccountSettingsDialog(account))) { NavigationLink(destination: LazyView(BankAccountSettingsDialog(account))) {
Text(account.displayName) Text(account.displayName)
} }
} }
.onMove(perform: reorderAccounts)
} }
HStack { HStack {
@ -96,6 +101,13 @@ struct BankSettingsDialog: View {
} }
func reorderAccounts(from source: IndexSet, to destination: Int) {
accountsSorted = accountsSorted.reorder(from: source, to: destination)
presenter.accountUpdated(account: bank)
}
func askUserToDeleteAccount() { func askUserToDeleteAccount() {
self.askUserToDeleteAccountOrSaveChangesMessage = Message(title: Text("Delete account?"), message: Text("Really delete account '\(bank.displayName)'? This cannot be undone and data will be lost."), primaryButton: .destructive(Text("Delete"), action: deleteAccount), secondaryButton: .cancel()) self.askUserToDeleteAccountOrSaveChangesMessage = Message(title: Text("Delete account?"), message: Text("Really delete account '\(bank.displayName)'? This cannot be undone and data will be lost."), primaryButton: .destructive(Text("Delete"), action: deleteAccount), secondaryButton: .cancel())
} }

View File

@ -0,0 +1,35 @@
import SwiftUI
struct SectionWithRightAlignedEditButton<Content: View>: View {
private let sectionTitle: String
private let content: Content
init(sectionTitle: String, @ViewBuilder content: () -> Content) {
self.sectionTitle = sectionTitle
self.content = content()
}
var body: some View {
Section(header: EditButton().frame(maxWidth: .infinity, alignment: .trailing)
.overlay(Text(sectionTitle), alignment: .leading)) {
content
}
}
}
struct SectionWithRightAlignedEditButton_Previews: PreviewProvider {
static var previews: some View {
SectionWithRightAlignedEditButton(sectionTitle: "Section") {
Text("Body")
}
}
}

View File

@ -14,8 +14,7 @@ struct SettingsDialog: View {
var body: some View { var body: some View {
Form { Form {
Section(header: EditButton().frame(maxWidth: .infinity, alignment: .trailing) SectionWithRightAlignedEditButton(sectionTitle: "Bank Credentials") {
.overlay(Text("Bank Credentials"), alignment: .leading)) {
ForEach(data.banksSorted) { bank in ForEach(data.banksSorted) { bank in
NavigationLink(destination: LazyView(BankSettingsDialog(bank))) { NavigationLink(destination: LazyView(BankSettingsDialog(bank))) {
IconedTitleView(bank) IconedTitleView(bank)