commit 06f835ee747208403ad26559dc5c05957029aa8c
parent 03ddab6775770d78181ff36686758ec75b31581b
Author: Marc Stibane <marc@taler.net>
Date: Sat, 27 Sep 2025 18:21:03 +0200
add date, type
Diffstat:
2 files changed, 119 insertions(+), 42 deletions(-)
diff --git a/TalerWallet1/Views/OIM/OIMtransactions.swift b/TalerWallet1/Views/OIM/OIMtransactions.swift
@@ -23,6 +23,14 @@ enum OIMtransactionsState {
}
// MARK: -
+enum HistoryMarker: Int {
+ case none
+ case day
+ case week
+ case month
+ case year
+}
+
struct HistoryItem: Identifiable {
var id: String {
if let talerTX {
@@ -31,6 +39,7 @@ struct HistoryItem: Identifiable {
return UUID().uuidString
}
let distance: Int
+ let marker: HistoryMarker
let balance: Double
let talerTX: TalerTransaction?
}
@@ -179,6 +188,7 @@ struct OIMtransactions: View {
let scrollBack = count == computedItems.count
// let _ = print("calling HistoryView", count, maxIndex, scrollBack)
if oimChart {
+#if TALER_WALLET
ChartHistoryView(stack: stack.push(),
currency: cash.currency,
shownItems: $shownItems,
@@ -186,6 +196,15 @@ struct OIMtransactions: View {
scrollBack: scrollBack,
maxIndex: maxIndex,
maxValue: chartMaxY)
+#else
+ ArrowHistoryView(stack: stack.push(),
+ currency: cash.currency,
+ shownItems: $shownItems,
+ dataPointWidth: $dataPointWidth,
+ scrollBack: scrollBack,
+ maxIndex: maxIndex,
+ maxValue: chartMaxY)
+#endif
} else {
RiverHistoryView(stack: stack.push(),
currency: cash.currency,
@@ -241,7 +260,7 @@ extension OIMtransactions {
/// week differs: add another spacer
/// month differs: add one more spacer
/// year differs: add yet another spacer
- var historyItems: [HistoryItem] = [ HistoryItem(distance: 0, balance: balance, talerTX: nil) ]
+ var historyItems: [HistoryItem] = [ HistoryItem(distance: 0, marker: .none, balance: balance, talerTX: nil) ]
var balance = balance
var maxBalance = balance
let calendar = Calendar.current // or do we need (identifier: .gregorian) ?
@@ -257,17 +276,22 @@ extension OIMtransactions {
let date = try! Date(milliseconds: timestamp.milliseconds())
let components = calendar.dateComponents([.year, .month, .day, .weekOfMonth], from: date)
// add spacers
+ var marker: HistoryMarker = .none
let isFirst = xIndex == 0
if lastTx.year != components.year {
xIndex += isFirst ? 1 : 4
+ marker = .year
} else if lastTx.month != components.month {
xIndex += isFirst ? 1 : 3
+ marker = .month
} else if lastTx.weekOfMonth != components.weekOfMonth {
xIndex += isFirst ? 1 : 2
+ marker = .week
// } else if lastItem.weekday != components.weekday {
// index += 2
} else if lastTx.day != components.day {
xIndex += 1
+ marker = .day
}
// advance to next index
xIndex += 1
@@ -281,7 +305,7 @@ extension OIMtransactions {
if balance > maxBalance {
maxBalance = balance
}
- return HistoryItem(distance: xIndex, balance: balance, talerTX: talerTransaction)
+ return HistoryItem(distance: xIndex, marker: marker, balance: balance, talerTX: talerTransaction)
}
for talerTransaction in history {
diff --git a/TalerWallet1/Views/OIM/RiverHistoryView.swift b/TalerWallet1/Views/OIM/RiverHistoryView.swift
@@ -67,40 +67,54 @@ struct RiverHistoryView: View {
// let _ = logger.log("RiverHistoryView \(width.pTwo)")
ZStack(alignment: .top) {
- ScrollViewReader { scrollProxy in
- OptimalSize(.horizontal) { // keep it small if we have only a few tx
- ScrollView(.horizontal) {
- if count > 0 {
- HStack(spacing: 0) {
- ForEach(-maxXValue...0, id: \.self) { xVal in
- RiverTileView(historyItem: historyItem(for: xVal)) {
- selectTX(xVal)
+ HStack(spacing: 0) {
+ VStack {
+ Image("Request")
+ .resizable()
+ .scaledToFit()
+ .frame(width: OIMbuttonSize, height: OIMbuttonSize)
+ .padding(.bottom, 30)
+ Image("SendMoney")
+ .resizable()
+ .scaledToFit()
+ .frame(width: OIMbuttonSize, height: OIMbuttonSize)
+ .padding(.vertical, 30)
+ }
+ ScrollViewReader { scrollProxy in
+ OptimalSize(.horizontal) { // keep it small if we have only a few tx
+ ScrollView(.horizontal) {
+ if count > 0 {
+ HStack(spacing: 0) {
+ ForEach(-maxXValue...0, id: \.self) { xVal in
+ RiverTileView(historyItem: historyItem(for: xVal)) {
+ selectTX(xVal)
+ }
}
- }
- }.id(riverID)
+ }.id(riverID)
+ }
}
- }
- //.border(.blue)
- .scrollBounceBehavior(.basedOnSize, axes: .horizontal) // don't bounce if it's small
- .task(id: scrollBack) {
- logger.log("Task \(scrollBack)")
- if scrollBack {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- logger.log("Scrolling")
- withAnimation() { // .easeOut(duration: 3.0) doesn't work, always uses standard timing
- scrollProxy.scrollTo(riverID, anchor: .bottomTrailing)
+ //.border(.blue)
+ .scrollBounceBehavior(.basedOnSize, axes: .horizontal) // don't bounce if it's small
+ .task(id: scrollBack) {
+ logger.log("Task \(scrollBack)")
+ if scrollBack {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+ logger.log("Scrolling")
+ withAnimation() { // .easeOut(duration: 3.0) doesn't work, always uses standard timing
+ scrollProxy.scrollTo(riverID, anchor: .bottomTrailing)
+ }
}
}
}
- }
- .onTapGesture(count: 2) {
- withAnimation(.easeOut(duration: 0.6)) {
- dataPointWidth = 100 // reset the scale first
- scrollProxy.scrollTo(riverID, anchor: .bottomTrailing)
+ .onTapGesture(count: 2) {
+ withAnimation(.easeOut(duration: 0.6)) {
+ dataPointWidth = 100 // reset the scale first
+ scrollProxy.scrollTo(riverID, anchor: .bottomTrailing)
+ }
}
}
- }
- } // ScrollViewReader
+ } // ScrollViewReader
+ }
if let selectedTX {
if let item = historyItem(for: selectedTX) {
if let talerTX = item.talerTX {
@@ -136,6 +150,14 @@ struct RiverTileView: View {
else { return 4 }
}
+ func getDate(_ date: Date?) -> (Int, Int) {
+ if let date {
+ let components = Calendar.current.dateComponents([.day, .year, .month], from: date)
+ return (components.day ?? 1, components.month ?? 1)
+ }
+ return(1, 1)
+ }
+
var body: some View {
let txValue = historyItem?.talerTX?.common.amountEffective.value ?? 0
// let width = width(for: txValue)
@@ -144,7 +166,7 @@ struct RiverTileView: View {
let treeSpace = 15.0
let background = VStack(spacing: 0) {
- Color.brown // TODO: add some random trees
+ Color.brown // add some random trees
.overlay(alignment: .topLeading) {
GeometryReader { geo in
let height = geo.size.height
@@ -162,28 +184,59 @@ struct RiverTileView: View {
}
Color.yellow
}
+ let background2 = VStack(spacing: 0) {
+ Color.brown
+ Color.yellow
+ }
// transactions
if let historyItem {
if let talerTX = historyItem.talerTX {
let common = talerTX.common
let amount = common.amountEffective
+ let (dateString, date) = TalerDater.dateString(common.timestamp, true)
+ let (day, month) = getDate(date)
+ let sunImage = Image(systemName: "sun.max.fill")
+ let moonImage = Image(systemName: "moon.fill")
+ let sunText = Text("\(sunImage) \(day)")
+ let moonText = Text("\(moonImage) \(month)")
if common.isIncoming {
let sizeIndex = sizeIn(for: amount.value)
- Image("River-Lake-" + String(sizeIndex))
- .resizable()
- .scaledToFit()
-// .border(.red)
- .onTapGesture { selectTX() }
- .background { background }
+ VStack {
+ sunText
+ moonText
+ Image("River-Lake-" + String(sizeIndex))
+ .resizable()
+ .scaledToFit()
+ .onTapGesture { selectTX() }
+ .background { background }
+ }
} else if common.isOutgoing {
let sizeIndex = sizeOut(for: amount.value)
- Image("River-Pond-" + String(sizeIndex))
- .resizable()
- .scaledToFit()
-// .border(.red)
- .onTapGesture { selectTX() }
- .background { background }
+ VStack {
+ sunText
+ moonText
+ Image("River-Pond-" + String(sizeIndex))
+ .resizable()
+ .scaledToFit()
+ .onTapGesture { selectTX() }
+ .background { background }
+ }
+ }
+ if historyItem.marker != .none {
+ let markerIndex = historyItem.marker.rawValue
+ VStack {
+ Text(" ")
+ Text(" ")
+ Image("River-Mark-" + String(markerIndex))
+ .resizable()
+ .scaledToFit()
+ .background { background2 }
+ .overlay {
+ LinearGradient(colors: [.clear, .black, .clear], startPoint: .leading, endPoint: .trailing)
+ .opacity(0.5)
+ }
+ }
}
} else {
let _ = print("no talerTX")