From 1f32d3766e8904f9f5afd2e57a1295aa97ca1330 Mon Sep 17 00:00:00 2001 From: Piotr Stachyra Date: Thu, 12 Nov 2026 11:21:08 +0100 Subject: [PATCH] fix: preserve tags when restoring a profile --- Bitkit/Managers/PubkyProfileManager.swift | 5 +++ Bitkit/Views/Profile/CreateProfileView.swift | 1 + BitkitTests/PubkyProfileManagerTests.swift | 44 ++++++++++++++++++++ changelog.d/next/1303.fixed.md | 1 + 4 files changed, 51 insertions(+) create mode 100644 changelog.d/next/1303.fixed.md diff --git a/Bitkit/Managers/PubkyProfileManager.swift b/Bitkit/Managers/PubkyProfileManager.swift index 2bfc42129..3511330b2 100644 --- a/Bitkit/Managers/PubkyProfileManager.swift +++ b/Bitkit/Managers/PubkyProfileManager.swift @@ -485,6 +485,7 @@ class PubkyProfileManager: ObservableObject { tags: [String] = [], existingImageUrl: String? = nil, baseRevision: String? = nil, + baseTagsUnread: Bool = false, avatarImage: UIImage? = nil, loadStoredSecretKey: () async throws -> String? = { await Task.detached { PubkyProfileManager.activeSecretKeyHex() }.value @@ -501,6 +502,7 @@ class PubkyProfileManager: ObservableObject { tags: tags, existingImageUrl: existingImageUrl, baseRevision: baseRevision, + baseTagsUnread: baseTagsUnread, avatarImage: avatarImage ) return @@ -536,6 +538,7 @@ class PubkyProfileManager: ObservableObject { tags: tags, existingImageUrl: existingImageUrl, baseRevision: baseRevision, + baseTagsUnread: baseTagsUnread, avatarImage: avatarImage ) }, @@ -755,6 +758,7 @@ class PubkyProfileManager: ObservableObject { tags: [String], existingImageUrl: String?, baseRevision: String?, + baseTagsUnread: Bool, avatarImage: UIImage? ) async throws { var avatarUri: String? @@ -771,6 +775,7 @@ class PubkyProfileManager: ObservableObject { links: links, tags: tags, baseRevision: baseRevision, + baseTagsUnread: baseTagsUnread, expectedIdentity: publicKey ) if tagsNotSavedAt != nil { diff --git a/Bitkit/Views/Profile/CreateProfileView.swift b/Bitkit/Views/Profile/CreateProfileView.swift index 63ec3a939..0b0167d1a 100644 --- a/Bitkit/Views/Profile/CreateProfileView.swift +++ b/Bitkit/Views/Profile/CreateProfileView.swift @@ -234,6 +234,7 @@ struct CreateProfileView: View { tags: existingProfile?.tags ?? [], existingImageUrl: existingProfile?.imageUrl, baseRevision: existingProfile?.revision, + baseTagsUnread: existingProfile?.tagsUnread ?? false, avatarImage: avatarImage ) navigation.navigate(.payContacts) diff --git a/BitkitTests/PubkyProfileManagerTests.swift b/BitkitTests/PubkyProfileManagerTests.swift index 0d7481a08..e3bf6d7f0 100644 --- a/BitkitTests/PubkyProfileManagerTests.swift +++ b/BitkitTests/PubkyProfileManagerTests.swift @@ -1313,6 +1313,50 @@ final class PubkyProfileManagerTests: XCTestCase { } } + @MainActor + func testCreateIdentityPreservesUnreadTagsFromTheRestoreFormAfterRefresh() async throws { + try await withRestoredProfileDefaults { + UserDefaults.standard.set(true, forKey: "pubky_profile_setup_pending") + var unread = makeProfile(publicKey: ringKeyA, name: "Alice") + unread.revision = "restored-revision" + unread.tagsUnread = true + let stub = RemoteProfileStub(profiles: [ringKeyA: unread]) + let publications = ProfilePublications() + let manager = PubkyProfileManager( + remoteProfileResolver: { try await stub.resolve($0) }, + profilePublisher: { try await publications.publish($0, expectedIdentity: $1) } + ) + manager.publicKey = ringKeyA + await manager.loadProfile() + let restored = try XCTUnwrap(manager.profile) + XCTAssertTrue(restored.tagsUnread) + XCTAssertTrue(restored.tags.isEmpty) + + let refreshed = unread.withTags(["friend", "work"]) + var readable = refreshed + readable.tagsUnread = false + await stub.setProfile(readable, for: ringKeyA) + await manager.loadProfile() + XCTAssertEqual(manager.profile?.tags, ["friend", "work"]) + XCTAssertEqual(manager.profile?.tagsUnread, false) + + try await manager.createIdentity( + name: "Renamed", + bio: restored.bio, + links: restored.links, + tags: restored.tags, + baseRevision: restored.revision, + baseTagsUnread: restored.tagsUnread + ) + + let published = await publications.published + let profile = try XCTUnwrap(published.first) + XCTAssertEqual(published.count, 1) + XCTAssertEqual(profile.baseRevision, "restored-revision") + XCTAssertTrue(profile.baseTagsUnread, "The store must preserve the tags the restore form could not show") + } + } + @MainActor func testSignupDoesNotRestoreProfileStateAfterWalletReset() async throws { snapshotAppDefaultsDomain() diff --git a/changelog.d/next/1303.fixed.md b/changelog.d/next/1303.fixed.md new file mode 100644 index 000000000..40d4cf098 --- /dev/null +++ b/changelog.d/next/1303.fixed.md @@ -0,0 +1 @@ +Restoring a Pubky profile preserves its saved tags when the profile initially loads without them.