Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 17 additions & 21 deletions Sources/BloomCore/Presentation/HomeScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public enum HomeScope: String, Hashable, Sendable, CaseIterable, Codable {
case needsYou
/// An agent is mid turn right now.
case running
/// Still has a worktree on disk. This is what the old "Hide archived" switch was for, kept as
/// a scope rather than as a switch of its own.
/// Still has a worktree on disk, which the strip calls "Active". This is what the old "Hide
/// archived" switch was for, kept as a scope rather than as a switch of its own.
case live
/// Archived: readable, restorable, with nothing left on disk.
case archived
Expand All @@ -34,24 +34,21 @@ public enum HomeScope: String, Hashable, Sendable, CaseIterable, Codable {

/// The chips on offer, in the order they are drawn.
///
/// **Browsing, there are two: `all` and `archived`.** There were five, and the three that went
/// (`live`, `needsYou`, `running`) were each a true fact about the list drawn as a control.
/// The owner asked for them to go, and the reason is visible in the strip they made: five
/// chips across the top of the first screen he sees, of which he pressed one. A filter nobody
/// reaches for is a row of words to read past.
/// **Browsing, there are three: `all`, `live` and `archived`.** There were five, and `needsYou`
/// and `running` went because each was a true fact about the list drawn as a control nobody
/// pressed. `live` came back, as "Active", because with the archive growing past the live work
/// the only way to see what can still be acted on was to scroll past it.
///
/// What is lost is real and worth naming rather than pretending away: **there is now no way to
/// ask "which of these is waiting on me" from this strip.** The list still answers it, by the
/// glyph on each row and by the order, and the sidebar answers it too. If that turns out not
/// to be enough, `needsYou` is the one to bring back, because it is the only one of the three
/// that asks something the list does not already show at a glance.
/// What is still lost is real: **there is no way to ask "which of these is waiting on me" from
/// this strip.** The list answers it by the glyph on each row and by the order, and the sidebar
/// answers it too. If that is not enough, `needsYou` is the one to bring back.
///
/// Searching, `all` still leads and the two kind chips stay, because there the chips split an
/// answer rather than narrowing a list nobody asked to narrow.
public static func offered(searching: Bool) -> [HomeScope] {
searching
? [.all, .workspaces, .transcripts, .archived]
: [.all, .archived]
: [.all, .live, .archived]
}

/// What the strip is set to when nothing has been asked of it.
Expand Down Expand Up @@ -79,7 +76,7 @@ public enum HomeScope: String, Hashable, Sendable, CaseIterable, Codable {
case .all: searching ? "Everything" : "All"
case .needsYou: "Needs you"
case .running: "Running"
case .live: "Live"
case .live: "Active"
case .archived: "Archived"
case .workspaces: "Workspaces"
case .transcripts: "Transcripts"
Expand Down Expand Up @@ -217,14 +214,13 @@ public struct HomeScopeCounts: Sendable, Equatable {
///
/// The chip stays on the strip either way. Dropping it would reflow the row every time an
/// agent started or stopped, which is movement under the pointer for no gain.
/// **Only the two chips whose number is a size, and not the three whose number is a state.**
/// Live, Needs you and Running each carried one too, and five numbers across one strip is a row
/// of figures to read rather than a set of filters to press. The two that keep theirs are the
/// ones where the number is the point: All says how much there is, and Archived says how much
/// of it is behind you. Live is answered by the list underneath it, and the whole argument
/// below about a nought being worth nothing applies twice over to a three.
///
/// **Only the chips whose number is a size, and not the two whose number is a state.** Needs
/// you and Running each carried one too, and five numbers across one strip is a row of figures
/// to read rather than a set of filters to press. All, Active and Archived keep theirs because
/// together they say how much there is and how it splits.
public func badge(of scope: HomeScope, searching: Bool) -> Int? {
guard scope == .all || scope == .archived else { return nil }
guard scope == .all || scope == .live || scope == .archived else { return nil }
let value = count(of: scope, searching: searching)
return value == 0 ? nil : value
}
Expand Down
20 changes: 11 additions & 9 deletions Tests/BloomCoreTests/HomeScopeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,12 @@ struct HomeScopeTests {
/// The default leads, because a strip whose first chip is one nobody wants selected reads as a
/// strip you have to correct. Its two subsets follow it, then the other half of the machine,
/// then the widest net.
@Test("Live leads the browsing chips and All closes them")
func liveLeadsTheStrip() {
// Two, not five. See `offered`: the three that went were each a true fact drawn as a
// control nobody pressed, and `needsYou` is the one to bring back if it is missed.
#expect(HomeScope.offered(searching: false) == [.all, .archived])
@Test("the browsing chips are All, Active and Archived, in that order")
func activeSitsBetweenAllAndArchived() {
// Three, not five. See `offered`: `needsYou` and `running` were each a true fact drawn as
// a control nobody pressed, and `needsYou` is the one to bring back if it is missed.
#expect(HomeScope.offered(searching: false) == [.all, .live, .archived])
#expect(HomeScope.live.label(searching: false) == "Active")
#expect(HomeScope.offered(searching: true).first == .all)
}

Expand Down Expand Up @@ -188,15 +189,16 @@ struct HomeScopeTests {
var counts = HomeScopeCounts()
counts.live = 3
counts.archived = 17
// Only the two chips whose number is a size. Live's three is a state, and the list under
// the strip already says it.
// Only the chips whose number is a size. Needs you and Running are states, and the list
// under the strip already says them.
#expect(counts.badge(of: .archived, searching: false) == 17)
#expect(counts.badge(of: .all, searching: false) == 20)
#expect(counts.badge(of: .live, searching: false) == nil)
#expect(counts.badge(of: .live, searching: false) == 3)
#expect(counts.badge(of: .needsYou, searching: false) == nil)
#expect(counts.badge(of: .running, searching: false) == nil)
// And the two that do keep a number still drop it at nought.
// And the three that do keep a number still drop it at nought.
#expect(HomeScopeCounts().badge(of: .all, searching: false) == nil)
#expect(HomeScopeCounts().badge(of: .live, searching: false) == nil)
#expect(HomeScopeCounts().badge(of: .archived, searching: false) == nil)
}

Expand Down
Loading