From 9c11d69002d71556fea1e2a938e02d4f4d503ea5 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Fri, 7 Aug 2026 03:06:34 -0500 Subject: Expand App Intents: dialogs, search type, mutating intents (#17) Addresses the three open items on the App Intents ticket: - Check Status / Check Builds now return a spoken/visible dialog alongside their value, so they surface a result in Siri instead of appearing to do nothing. Logic consolidated to always produce a message. - Search Hutch gains a Search Type parameter (user, git/hg repo, mailing list, tracker, build job) threaded through the .search route into Lookup, which pre-selects the type. LookupType now conforms to AppEnum. - Adds mutating intents (not just navigation): Clear Recent Activity and Unpin Resource, backed by RecentActivityStore.clear and a new HomePinStore.removePin. Both act on the active account's storage. Tests cover search-type routing, the blank-query fallback, and pin removal. --- HutchTests/HutchIntentsTests.swift | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'HutchTests/HutchIntentsTests.swift') diff --git a/HutchTests/HutchIntentsTests.swift b/HutchTests/HutchIntentsTests.swift index ddbe973..e201f42 100644 --- a/HutchTests/HutchIntentsTests.swift +++ b/HutchTests/HutchIntentsTests.swift @@ -110,4 +110,37 @@ struct HutchIntentsTests { ActiveAccountContextStore.save("account-a", defaults: defaults) #expect(NeedsAttentionSnapshotStore.load(defaults: defaults)?.failedBuilds == 3) } + + @Test + func searchIntentCarriesQueryAndType() { + let intent = SearchHutchIntent() + intent.query = "~alice/hutch" + intent.searchType = .tracker + #expect(intent.route == .search(query: "~alice/hutch", type: .tracker)) + } + + @Test + func searchIntentWithBlankQueryFallsBackToLookup() { + let intent = SearchHutchIntent() + intent.query = " " + intent.searchType = .user + #expect(intent.route == .lookup) + } + + @Test + func removePinDropsMatchingResource() { + let defaultsName = "HutchIntentsTests-unpin-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: defaultsName)! + defer { defaults.removePersistentDomain(forName: defaultsName) } + + let alice = HomePinRecord(kind: .user, value: "~alice", title: "~alice", subtitle: "User", ownerUsername: "~alice", service: nil) + let bob = HomePinRecord(kind: .user, value: "~bob", title: "~bob", subtitle: "User", ownerUsername: "~bob", service: nil) + HomePinStore.togglePin(alice, for: "~me", defaults: defaults) + HomePinStore.togglePin(bob, for: "~me", defaults: defaults) + + HomePinStore.removePin(id: alice.id, for: "~me", defaults: defaults) + + let remaining = HomePinStore.loadPins(for: "~me", defaults: defaults) + #expect(remaining.map(\.id) == [bob.id]) + } } -- cgit v1.2.3