commit c3d3295ee7f96215077b4b796b4b85c74add3ca0
parent d13d6da9e69a3e347f3d98d37c075dde36004861
Author: Marc Stibane <marc@taler.net>
Date: Tue, 15 Apr 2025 19:40:22 +0200
sortByValue, checkStacks
Diffstat:
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)