gitbay/Issues/IssueFilter.swift

main
gitbay-ios/gitbay/Issues/IssueFilter.swift history · blame · raw

53 lines · 1931 bytes

3 symbols in this file
 1import Foundation
 2
 3/// What `issue list` is narrowed to. Renders itself to the flags the
 4/// command accepts; an empty value sends no flag at all, since
 5/// `--search ""` is a different query from no search.
 6nonisolated struct IssueFilter: Equatable, Sendable {
 7
 8    enum State: String, CaseIterable, Identifiable, Sendable {
 9        case open, closed, all
10        var id: String { rawValue }
11        var label: String { stateLabel(rawValue) }
12    }
13
14    var state: State = .open
15    var search = ""
16    var label: String?
17    var assignee: String?
18    var author: String?
19    /// A milestone title, or the literal "none" for issues without one.
20    var milestone: String?
21
22    func flags() -> [String] {
23        var flags = ["--state", state.rawValue]
24        flags += filterFlag("--search", search)
25        flags += filterFlag("--label", label)
26        flags += filterFlag("--assignee", assignee)
27        flags += filterFlag("--author", author)
28        flags += filterFlag("--milestone", milestone)
29        return flags
30    }
31
32    /// True when anything beyond the state picker is set, which is what
33    /// decides whether the empty state blames the filters.
34    var isNarrowed: Bool { flags().count > 2 }
35
36    var emptyMessage: String {
37        if isNarrowed {
38            return state == .all
39                ? "No issues match these filters."
40                : "No \(state.rawValue) issues match these filters."
41        }
42        return state == .all ? "No issues." : "No \(state.rawValue) issues."
43    }
44}
45
46/// One flag, or nothing when the value is absent or blank. Shared by
47/// both filters, so it is named for what it does rather than taking the
48/// bare name `flag` in the module namespace.
49nonisolated func filterFlag(_ name: String, _ value: String?) -> [String] {
50    guard let value else { return [] }
51    let trimmed = value.trimmingCharacters(in: .whitespaces)
52    return trimmed.isEmpty ? [] : [name, trimmed]
53}