Skip to content
Open
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
2 changes: 1 addition & 1 deletion RepoBariOS/Sources/App/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ final class AppModel {
}

private func mergeHydrated(_ detailed: [Repository], into repos: [Repository]) -> [Repository] {
let lookup = Dictionary(uniqueKeysWithValues: detailed.map { ($0.fullName, $0) })
let lookup = Dictionary(detailed.map { ($0.fullName, $0) }, uniquingKeysWith: { _, latest in latest })
return repos.map { lookup[$0.fullName] ?? $0 }
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/RepoBar/App/AppState+Refresh.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ extension AppState {
}

private func mergeHydrated(_ detailed: [Repository], into repos: [Repository]) -> [Repository] {
let lookup = Dictionary(uniqueKeysWithValues: detailed.map { ($0.fullName, $0) })
let lookup = Dictionary(detailed.map { ($0.fullName, $0) }, uniquingKeysWith: { _, latest in latest })
return repos.map { lookup[$0.fullName] ?? $0 }
}

Expand All @@ -282,7 +282,7 @@ extension AppState {
let models = repos.map { repo in
RepositoryDisplayModel(repo: repo, localStatus: localIndex.status(for: repo), now: now)
}
let index = Dictionary(uniqueKeysWithValues: models.map { ($0.title.lowercased(), $0) })
let index = Dictionary(models.map { ($0.title.lowercased(), $0) }, uniquingKeysWith: { _, latest in latest })
await MainActor.run {
self.session.menuDisplayIndex = index
}
Expand Down Expand Up @@ -320,7 +320,7 @@ extension AppState {
now: capturedAt
)
}
self.session.menuDisplayIndex = Dictionary(uniqueKeysWithValues: models.map { ($0.title.lowercased(), $0) })
self.session.menuDisplayIndex = Dictionary(models.map { ($0.title.lowercased(), $0) }, uniquingKeysWith: { _, latest in latest })
}
}
}
Expand Down
14 changes: 10 additions & 4 deletions Sources/RepoBar/StatusBar/StatusBarMenuBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,20 +180,26 @@ final class StatusBarMenuBuilder {
.padding(.vertical, MenuStyle.sectionVerticalPadding)
return [self.viewItem(for: emptyState, enabled: false)]
}
var items: [NSMenuItem] = []
// Deduplicate repos by id to prevent adding the same cached menu item twice
// (which would crash with "Item to be inserted into menu already is in another menu")
var usedRepoKeys: Set<String> = []
for (index, repo) in repos.enumerated() {
let uniqueRepos = repos.filter { repo in
if usedRepoKeys.contains(repo.id) { return false }
usedRepoKeys.insert(repo.id)
return true
}
var items: [NSMenuItem] = []
for (index, repo) in uniqueRepos.enumerated() {
let isPinned = settings.repoList.pinnedRepositories.contains {
$0.trimmingCharacters(in: .whitespacesAndNewlines)
.caseInsensitiveCompare(repo.title) == .orderedSame
}
let item = self.repoMenuItem(for: repo, isPinned: isPinned)
item.representedObject = repo.title
items.append(item)
if index < repos.count - 1 {
if index < uniqueRepos.count - 1 {
items.append(self.repoCardSeparator())
}
usedRepoKeys.insert(repo.id)
}
self.repoMenuItemCache = self.repoMenuItemCache.filter { usedRepoKeys.contains($0.key) }
self.repoSubmenuCache = self.repoSubmenuCache.filter { usedRepoKeys.contains($0.key) }
Expand Down