Skip to content

Commit 3d1f2b2

Browse files
committed
fix: show contact names in activity rows
1 parent 220ee6a commit 3d1f2b2

6 files changed

Lines changed: 129 additions & 6 deletions

File tree

Bitkit/Components/Activity/ActivityList.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import SwiftUI
33

44
struct ActivityList: View {
55
@EnvironmentObject var activity: ActivityListViewModel
6+
@EnvironmentObject var contactsManager: ContactsManager
67
@EnvironmentObject var feeEstimatesManager: FeeEstimatesManager
78
@State private var isHorizontalSwipe = false
89

@@ -28,7 +29,11 @@ struct ActivityList: View {
2829

2930
case let .activity(item):
3031
NavigationLink(value: Route.activityDetail(item)) {
31-
ActivityRow(item: item, feeEstimates: feeEstimatesManager.estimates)
32+
ActivityRow(
33+
item: item,
34+
feeEstimates: feeEstimatesManager.estimates,
35+
contact: item.contact(in: contactsManager.contacts)
36+
)
3237
}
3338
.accessibilityIdentifier("Activity-\(index)")
3439
.disabled(isHorizontalSwipe)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import BitkitCore
2+
3+
extension Activity {
4+
func contact(in contacts: [PubkyContact]) -> PubkyContact? {
5+
guard let contactPublicKey else { return nil }
6+
return contacts.first(where: { PubkyPublicKeyFormat.matches($0.publicKey, contactPublicKey) })
7+
}
8+
9+
private var contactPublicKey: String? {
10+
switch self {
11+
case let .lightning(lightning):
12+
return lightning.contact
13+
14+
case let .onchain(onchain):
15+
return onchain.contact
16+
}
17+
}
18+
}

Bitkit/Views/Contacts/ContactActivityView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ struct ContactActivityView: View {
114114
}
115115

116116
private func resolveContactName() {
117-
contactName = contactsManager.contacts.first(where: { $0.publicKey == publicKey })?.profile.name ?? ""
117+
contactName = contactsManager.contacts.first(where: { PubkyPublicKeyFormat.matches($0.publicKey, publicKey) })?.displayName ?? ""
118118
}
119119

120120
private func activityTitle(_ activity: Activity) -> String {

Bitkit/Views/Wallets/Activity/ActivityLatest.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import SwiftUI
44
struct ActivityLatest: View {
55
@EnvironmentObject private var activity: ActivityListViewModel
66
@EnvironmentObject private var app: AppViewModel
7+
@EnvironmentObject private var contactsManager: ContactsManager
78
@EnvironmentObject private var feeEstimatesManager: FeeEstimatesManager
89
@EnvironmentObject private var navigation: NavigationViewModel
910
@EnvironmentObject private var settings: SettingsViewModel
@@ -60,7 +61,11 @@ struct ActivityLatest: View {
6061
LazyVStack(alignment: .leading, spacing: 16) {
6162
ForEach(Array(zip(rows.indices, rows)), id: \.1) { index, item in
6263
NavigationLink(value: Route.activityDetail(item)) {
63-
ActivityRow(item: item, feeEstimates: feeEstimatesManager.estimates)
64+
ActivityRow(
65+
item: item,
66+
feeEstimates: feeEstimatesManager.estimates,
67+
contact: item.contact(in: contactsManager.contacts)
68+
)
6469
}
6570
.accessibilityIdentifier("ActivityShort-\(index)")
6671
}

Bitkit/Views/Wallets/Activity/ActivityRow.swift

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,60 @@ import SwiftUI
44
struct ActivityRow: View {
55
let item: Activity
66
let feeEstimates: FeeRates?
7+
let contact: PubkyContact?
78
let titleOverride: String?
89

9-
init(item: Activity, feeEstimates: FeeRates?, titleOverride: String? = nil) {
10+
init(item: Activity, feeEstimates: FeeRates?, contact: PubkyContact? = nil, titleOverride: String? = nil) {
1011
self.item = item
1112
self.feeEstimates = feeEstimates
13+
self.contact = contact
1214
self.titleOverride = titleOverride
1315
}
1416

17+
private var rowTitleOverride: String? {
18+
if let titleOverride {
19+
return titleOverride
20+
}
21+
22+
return contactTitle
23+
}
24+
25+
private var contactTitle: String? {
26+
guard let contact else { return nil }
27+
28+
let txType: PaymentType
29+
switch item {
30+
case let .lightning(lightning):
31+
guard lightning.status == .succeeded else {
32+
return nil
33+
}
34+
txType = lightning.txType
35+
36+
case let .onchain(onchain):
37+
guard onchain.doesExist,
38+
!onchain.isTransfer,
39+
!(onchain.isBoosted && !onchain.confirmed)
40+
else {
41+
return nil
42+
}
43+
txType = onchain.txType
44+
}
45+
46+
switch txType {
47+
case .sent:
48+
return t("contacts__activity_sent_to", variables: ["name": contact.displayName])
49+
case .received:
50+
return t("contacts__activity_received_from", variables: ["name": contact.displayName])
51+
}
52+
}
53+
1554
var body: some View {
1655
Group {
1756
switch item {
1857
case let .lightning(activity):
19-
ActivityRowLightning(item: activity, titleOverride: titleOverride)
58+
ActivityRowLightning(item: activity, titleOverride: rowTitleOverride)
2059
case let .onchain(activity):
21-
ActivityRowOnchain(item: activity, feeEstimates: feeEstimates, titleOverride: titleOverride)
60+
ActivityRowOnchain(item: activity, feeEstimates: feeEstimates, titleOverride: rowTitleOverride)
2261
}
2362
}
2463
.padding(16)

BitkitTests/ContactsManagerTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@testable import Bitkit
2+
import BitkitCore
23
import XCTest
34

45
@MainActor
@@ -24,6 +25,61 @@ final class ContactsManagerTests: XCTestCase {
2425
XCTAssertFalse(PubkyPublicKeyFormat.matches(prefixedKey, "pubkyinvalid"))
2526
}
2627

28+
func testActivityContactResolvesLightningContactKey() {
29+
let rawKey = "3rsduhcxpw74snwyct86m38c63j3pq8x4ycqikxg64roik8yw5xg"
30+
let contact = makeContact(publicKey: "pubky\(rawKey)")
31+
let activity = Activity.lightning(
32+
LightningActivity(
33+
id: "test-lightning-contact",
34+
txType: .sent,
35+
status: .succeeded,
36+
value: 1000,
37+
fee: 10,
38+
invoice: "lnbc...",
39+
message: "",
40+
timestamp: 0,
41+
preimage: nil,
42+
contact: rawKey,
43+
createdAt: nil,
44+
updatedAt: nil,
45+
seenAt: nil
46+
)
47+
)
48+
49+
XCTAssertEqual(activity.contact(in: [contact])?.publicKey, contact.publicKey)
50+
}
51+
52+
func testActivityContactResolvesBoostingOnchainContactKey() {
53+
let rawKey = "3rsduhcxpw74snwyct86m38c63j3pq8x4ycqikxg64roik8yw5xg"
54+
let contact = makeContact(publicKey: "pubky\(rawKey)")
55+
let activity = Activity.onchain(
56+
OnchainActivity(
57+
id: "test-onchain-boosting-contact",
58+
txType: .sent,
59+
txId: "txid",
60+
value: 1000,
61+
fee: 10,
62+
feeRate: 1,
63+
address: "bcrt1...",
64+
confirmed: false,
65+
timestamp: 0,
66+
isBoosted: true,
67+
boostTxIds: [],
68+
isTransfer: false,
69+
doesExist: true,
70+
confirmTimestamp: nil,
71+
channelId: nil,
72+
transferTxId: nil,
73+
contact: contact.publicKey,
74+
createdAt: nil,
75+
updatedAt: nil,
76+
seenAt: nil
77+
)
78+
)
79+
80+
XCTAssertEqual(activity.contact(in: [contact])?.publicKey, contact.publicKey)
81+
}
82+
2783
func testResolveAddContactValidationReturnsEmptyForBlankInput() {
2884
XCTAssertEqual(resolveAddContactValidation(input: " ", ownPublicKey: nil), .empty)
2985
}

0 commit comments

Comments
 (0)