Skip to content

Commit

Permalink
Support dynamic columns in transaction history table
Browse files Browse the repository at this point in the history
  • Loading branch information
shimastripe committed Sep 29, 2024
1 parent 8b84489 commit e34e4ee
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import AppStoreServerLibrary

public typealias JWSTransactionDecodedPayload = AppStoreServerLibrary.JWSTransactionDecodedPayload

extension JWSTransactionDecodedPayload: @retroactive Identifiable {
public var id: String? {
transactionId
Expand Down
34 changes: 34 additions & 0 deletions Sources/IAPView/Binding+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Binding+.swift
// InAppPurchaseViewer
//
// Created by shimastripe on 2024/09/29.
//

import SwiftUI

extension Binding
where
Value: MutableCollection, Value: RangeReplaceableCollection, Value: Sendable,
Value.Element: Identifiable
{
func filter(_ isIncluded: @Sendable @escaping (Value.Element) -> Bool) -> Binding<
[Value.Element]
> {
Binding<[Value.Element]>(
get: {
wrappedValue.filter(isIncluded)
},
set: { newValue in
newValue.forEach { newItem in
guard let i = wrappedValue.firstIndex(where: { $0.id == newItem.id })
else {
self.wrappedValue.append(newItem)
return
}
self.wrappedValue[i] = newItem
}
}
)
}
}
179 changes: 179 additions & 0 deletions Sources/IAPView/IAPCellDataSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// IAPCellDataSource.swift
// InAppPurchaseViewer
//
// Created by shimastripe on 2024/09/29.
//

import Foundation
import IAPInterface

struct IAPCellDataSource: Sendable, Identifiable {
let keyPath: PartialKeyPath<JWSTransactionDecodedPayload> & Sendable
let name: String
let idealWidth: CGFloat
var isOn: Bool

var id: PartialKeyPath<JWSTransactionDecodedPayload> & Sendable { keyPath }
}

extension IAPCellDataSource {
static let defaultTransactionInfo: [IAPCellDataSource] = [
.init(
keyPath: \JWSTransactionDecodedPayload.purchaseDate,
name: "purchaseDate",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.transactionReason,
name: "transactionReason",
idealWidth: 160,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.price,
name: "price",
idealWidth: 60,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.currency,
name: "currency",
idealWidth: 60,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.originalTransactionId,
name: "originalTransactionId",
idealWidth: 140,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.transactionId,
name: "transactionId",
idealWidth: 140,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.originalPurchaseDate,
name: "originalPurchaseDate",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.expiresDate,
name: "expiresDate",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.offerIdentifier,
name: "offerIdentifier",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.offerType,
name: "offerType",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.offerDiscountType,
name: "offerDiscountType",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.appAccountToken,
name: "appAccountToken",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.bundleId,
name: "bundleId",
idealWidth: 140,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.productId,
name: "productId",
idealWidth: 140,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.subscriptionGroupIdentifier,
name: "subscriptionGroupIdentifier",
idealWidth: 160,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.quantity,
name: "quantity",
idealWidth: 60,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.type,
name: "type",
idealWidth: 180,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.inAppOwnershipType,
name: "inAppOwnershipType",
idealWidth: 160,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.environment,
name: "environment",
idealWidth: 80,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.storefront,
name: "storefront",
idealWidth: 60,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.storefrontId,
name: "storefrontId",
idealWidth: 80,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.webOrderLineItemId,
name: "webOrderLineItemId",
idealWidth: 140,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.revocationReason,
name: "revocationReason",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.revocationDate,
name: "revocationDate",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.isUpgraded,
name: "isUpgraded",
idealWidth: 120,
isOn: true
),
.init(
keyPath: \JWSTransactionDecodedPayload.signedDate,
name: "signedDate",
idealWidth: 120,
isOn: true
),
]
}
16 changes: 16 additions & 0 deletions Sources/IAPView/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@
},
"Download AppleRootCA-G3.cer" : {

},
"Edit" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "編集"
}
}
}
},
"eligibleWinBackOfferIds" : {

Expand Down Expand Up @@ -363,12 +373,18 @@
},
"TransactionID" : {

},
"transactionInfo" : {

},
"transactionReason" : {

},
"type" : {

},
"Unsupported Format" : {

},
"webOrderLineItemId" : {

Expand Down
38 changes: 38 additions & 0 deletions Sources/IAPView/TransactionHistoryInspectorView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// TransactionHistoryInspectorView.swift
// InAppPurchaseViewer
//
// Created by shimastripe on 2024/09/29.
//

import SwiftUI

struct TransactionHistoryInspectorView: View {

@Binding var currentColumns: [IAPCellDataSource]

var body: some View {
List {
Section(header: Text("transactionInfo")) {
ForEach($currentColumns) { $item in
LabeledContent {
Image(systemName: "line.3.horizontal")
} label: {
HStack {
Toggle("", isOn: $item.isOn)
Text(item.name)
}
}
.opacity(item.isOn ? 1 : 0.5)
}
.onDelete(perform: { indexSet in
currentColumns.remove(atOffsets: indexSet)
})
.onMove(perform: { indices, newOffset in
currentColumns.move(fromOffsets: indices, toOffset: newOffset)
})
}
}
.listStyle(.sidebar)
}
}
Loading

0 comments on commit e34e4ee

Please sign in to comment.