taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit c3d3295ee7f96215077b4b796b4b85c74add3ca0
parent d13d6da9e69a3e347f3d98d37c075dde36004861
Author: Marc Stibane <marc@taler.net>
Date:   Tue, 15 Apr 2025 19:40:22 +0200

sortByValue, checkStacks

Diffstat:
MTalerWallet1/Views/OIM/OIMcash.swift | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MTalerWallet1/Views/OIM/OIMlayout.swift | 30++++++++++++++++++++++++------
2 files changed, 106 insertions(+), 6 deletions(-)

diff --git a/TalerWallet1/Views/OIM/OIMcash.swift b/TalerWallet1/Views/OIM/OIMcash.swift @@ -8,6 +8,8 @@ import SwiftUI import taler_swift +let MAXSTACK = 4 + enum FundState: Int { case idle case shouldFly @@ -47,6 +49,86 @@ class OIMcash: ObservableObject { } } + func sortByValue() -> OIMfunds { + // sorts ASCENDING - we check small values first + funds.sorted(by: { ($0.value < $1.value) || + ( ($0.value == $1.value) && ($0.id > $1.id) ) }) + } + + func checkStacks(_ max: Int = MAXSTACK) -> UInt64? { + /// same algorithm as OIMlayout.computeSpaces + /// result is 0 if all stacks have 4 or less items + /// returns highest value with more than 4 items + + let sorted = sortByValue() + let count = sorted.count + + var stackIndex = 0 + var lastValue: UInt64 = 0 + for (index, fund) in sorted.enumerated() { + let value = fund.value + let state = fund.state + if state == .shouldFly || state == .isFlying { // flying can not go on the stack + lastValue = 0 // let the next subview... + stackIndex = 0 // ...start a new stack + } else if lastValue != value { // different value? + lastValue = value // save this value for the next subview + stackIndex = 0 // start a new stack + } else { + stackIndex += 1 // Yay, we found one to add to this stack + if stackIndex == max { // stack is full + return value // <<= compact this stack + } } + } + return nil + } + +// func compactStacks(_ value: UInt64) -> Bool { +// let denominations = currency.bankNotes + currency.bankCoins +// if let index = denominations.firstIndex(where: { $0 == value }) { +// if index > 0 { // does a bigger denomination exist? +// let nextIndex = index-1 +// let nextValue = denominations[nextIndex] // let next = next_bigger_denomination +// if nextValue != value * 5 { +// if nextValue.isMultiple(of: value) { // counter example: value=10, next=25 +// let hasNextIdx = funds.firstIndex(where: { $0.value == nextValue }) +// let has5xDenom +// // if funds.contains(next) +// +// // || denom(5*value) doesn't exist e.g. 50->2.50 or 25->1.25 +// // flip&remove X items of value, insert 1 next +// +// +// // let next2 = even_bigger_denomination +// +// // else if funds.contains(next2) +// // +// // else +// // flip&remove 5 items of value, insert 1 next +// +// +// +// +// +// } +// +// +// var newVal = 5 * value +// if currency.bankCoins.contains(newVal) || +// currency.bankNotes.contains(newVal) +// { +// let sorted = sortByValue() +// // find 5 cash items of 'value' +// var toRemove: OIMfunds = [] +// +// } +// if { +// +// return true +// } +// return false +// } + func notes() -> OIMfunds { let firstCoinVal = currency.bankCoins[0] return funds.filter { $0.value > firstCoinVal } diff --git a/TalerWallet1/Views/OIM/OIMlayout.swift b/TalerWallet1/Views/OIM/OIMlayout.swift @@ -50,6 +50,7 @@ struct OIMlayoutView: View { @EnvironmentObject private var cash: OIMcash @EnvironmentObject private var wrapper: NamespaceWrapper + @State private var checkStacks: UInt64 = 0 var body: some View { OIMlayout { @@ -104,6 +105,9 @@ struct OIMlayoutView: View { fund.state = .idle cash.updateFund(fund) } + DispatchQueue.main.asyncAfter(deadline: .now() + (fastAnimations ? 0.6 : 1.0)) { + checkStacks = value + } } } else if isFlipped { withAnimation(.fly1) { @@ -117,6 +121,19 @@ struct OIMlayoutView: View { } } } + .onChange(of: checkStacks) { value in + if value > 0 { + print("*** check:", value) + var firstCheck = value +// while let moreThan4 = cash.checkStacks(firstCheck) { +// firstCheck = 0 +// withAnimation(.fly1) { +// cash.compact(moreThan4) +// } +// } + checkStacks = 0 + } + } } } // MARK: - @@ -153,11 +170,12 @@ struct OIMlayout: Layout { // } func sortByValue(_ subviews: LayoutSubviews) -> [LayoutSubview] { + // sorts DESCENDING - we render the denominations top-down subviews.sorted(by: { ($0.oimValue > $1.oimValue) || ( ($0.oimValue == $1.oimValue) && ($0.oimID < $1.oimID) ) }) } - func computeSpaces(_ proposal: ProposedViewSize, _ sorted: [LayoutSubview], _ max: Int = 3) -> [Int] { + func computeSpaces(_ sorted: [LayoutSubview], _ max: Int = MAXSTACK) -> [Int] { /// returns array of stackIndexes /// 0 ==> next view starts a new stack /// 1..3 ==> next view is on the stack @@ -176,11 +194,11 @@ struct OIMlayout: Layout { } else if lastValue != value { // different value? lastValue = value // save this value for the next subview stackIndex = 0 // start a new stack - } else if stackIndex == max { // max 4 subviews per stack - stackIndex = 0 // stack is full, start a new one but keep the value } else { stackIndex += 1 // Yay, we found one to add to this stack - } + if stackIndex == max { // max 4 subviews per stack + stackIndex = 0 // stack is full, start a new one but keep the value + } } if index > 0 { spaces.append(stackIndex) } @@ -220,7 +238,7 @@ struct OIMlayout: Layout { let viewWidths = viewSizes.reduce(0) { $0 + $1.width } // add up all widths let maxHeight = viewSizes.reduce(0) { max($0, $1.height) } // get the max height - let spaces = computeSpaces(proposal, sorted) + let spaces = computeSpaces(sorted) let maxStackIndex = spaces.reduce(0) { max($0, $1) } var accumulatedSpaces: CGFloat = .zero @@ -270,7 +288,7 @@ struct OIMlayout: Layout { func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { let (spacing, offset) = spacing(for: proposal) let sorted = sortByValue(subviews) - let spaces = computeSpaces(proposal, sorted) + let spaces = computeSpaces(sorted) let isMax = proposal == .infinity var pt = CGPoint(x: bounds.minX, y: bounds.minY)