Skip to content
Merged
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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
build:
name: Build and analyse
runs-on: macos-latest
runs-on: macos-26

strategy:
matrix:
Expand Down
4 changes: 4 additions & 0 deletions Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,10 @@
}
}
},
"Version: %@" : {
"comment" : "A label showing the current version of the app.",
"isCommentAutoGenerated" : true
},
"welcome.subtitle" : {
"localizations" : {
"de" : {
Expand Down
26 changes: 22 additions & 4 deletions PReek/ViewModel/PullRequestsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ class PullRequestsViewModel: ObservableObject {
updatePullRequestIndexMap()
}

deinit {
timer?.invalidate()
timer = nil
cancellables.removeAll()
}

@Published private(set) var lastUpdated: Date? = nil
@Published private(set) var isRefreshing = false
@Published var error: Error? = nil
Expand Down Expand Up @@ -64,6 +70,8 @@ class PullRequestsViewModel: ObservableObject {
private let setFocusTrigger = PassthroughSubject<SetFocusType, Never>()
private var pullRequestIndexMap: [String: Int] = [:]

private let maxCacheSize = 500

private func updatePullRequestIndexMap() {
pullRequestIndexMap = Dictionary(
pullRequests.enumerated().map { index, pr in (pr.id, index) },
Expand Down Expand Up @@ -166,8 +174,8 @@ class PullRequestsViewModel: ObservableObject {
if timer != nil {
return
}
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in
self.triggerUpdatePullRequests()
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in
self?.triggerUpdatePullRequests()
}
}

Expand Down Expand Up @@ -332,10 +340,20 @@ class PullRequestsViewModel: ObservableObject {
let daysToDeduct = (ConfigService.deleteAfterWeeks * 7) + 1
let deleteFrom = Calendar.current.date(byAdding: .day, value: daysToDeduct * -1, to: Date())!

let filteredPullRequestMap = pullRequestMap.filter { _, pullRequest in
var filteredPullRequestMap = pullRequestMap.filter { _, pullRequest in
pullRequest.lastUpdated > deleteFrom || (ConfigService.deleteOnlyClosed && !pullRequest.isClosed)
}

// Enforce maximum cache size to prevent unbounded memory growth
if filteredPullRequestMap.count > maxCacheSize {
let sortedPRs = filteredPullRequestMap.values.sorted { $0.lastUpdated > $1.lastUpdated }
let keysToKeep = Set(sortedPRs.prefix(maxCacheSize).map { $0.id })
filteredPullRequestMap = filteredPullRequestMap.filter { keysToKeep.contains($0.key) }
// swiftformat:disable redundantSelf
logger.info("Limiting cache to \(self.maxCacheSize) most recent pull requests")
// swiftformat:enable redundantSelf
}

let filteredPullRequestReadMap = pullRequestReadMap.filter { pullRequestId, _ in
filteredPullRequestMap.index(forKey: pullRequestId) != nil
}
Expand All @@ -345,7 +363,7 @@ class PullRequestsViewModel: ObservableObject {
logger.info("Removing \(self.pullRequestMap.count - filteredPullRequestMap.count) pull requests")
logger.info("Removing \(self.pullRequestReadMap.count - filteredPullRequestReadMap.count) pull requests read info")
// swiftformat:enable redundantSelf
await MainActor.run {
await MainActor.run { [filteredPullRequestMap, filteredPullRequestReadMap] in
self.pullRequestMap = filteredPullRequestMap
self.pullRequestReadMap = filteredPullRequestReadMap
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct PullRequestHeaderView: View, Equatable {
ResourceIcon(image: .check)
.frame(width: 13)
.foregroundColor(.success)
.padding(.top, 1)
}
.help(usersToString(pullRequest.approvalFrom))
}
Expand All @@ -115,7 +116,7 @@ struct PullRequestHeaderView: View, Equatable {
ResourceIcon(image: .fileDiff)
.frame(width: 12)
.foregroundColor(.failure)
.padding(.top, 1)
.padding(.top, 2)
}
.help(usersToString(pullRequest.changesRequestedFrom))
}
Expand Down
32 changes: 20 additions & 12 deletions PReek/Views/Settings/SettingsScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import SwiftUI
import CodeScanner
#endif

func getAppVersion() -> String {
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
return appVersion
}
return "Unknown"
}

struct SettingsScreen: View {
@ObservedObject var configViewModel: ConfigViewModel

Expand Down Expand Up @@ -32,20 +39,21 @@ struct SettingsScreen: View {
}
}
.importSheet(configViewModel: configViewModel, isPresented: $showImportSheet)
#endif
#if os(macOS)
.safeAreaInset(edge: .bottom, spacing: 0) {
HStack {
Button("Quit App", action: { NSApplication.shared.terminate(nil) })
NavigationLink(value: Screen.share) {
Text("Share")
#elseif os(macOS)
.safeAreaInset(edge: .bottom, spacing: 0) {
HStack {
Button("Quit App", action: { NSApplication.shared.terminate(nil) })
NavigationLink(value: Screen.share) {
Text("Share")
}
Spacer()
Text("Version: \(getAppVersion())")
.foregroundStyle(.secondary)
}
Spacer()
.padding(.horizontal, 20)
.padding(.vertical, 10)
.background(.windowBackground)
}
.padding(.horizontal, 20)
.padding(.vertical, 10)
.background(.windowBackground)
}
#endif
}

Expand Down
3 changes: 0 additions & 3 deletions build-dmg.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/bin/bash

# Exit on error
set -e

# Configuration
SCHEME_NAME="PReek"
PROJECT_PATH="PReek.xcodeproj"
Expand Down