Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d76c7496bb | ||
|
|
45a3925f65 | ||
|
|
113e91583d | ||
|
|
c60fb93e1a | ||
|
|
b16c24cb44 | ||
|
|
89a79c6f13 | ||
|
|
aa529835f7 | ||
|
|
b5c3cc6379 | ||
|
|
c8adaf1baf | ||
|
|
3e99e1417e | ||
|
|
e41d3d0c0f | ||
|
|
1078951c43 | ||
|
|
ed6a5e1b51 | ||
|
|
8701fb1326 | ||
|
|
247b5fc202 | ||
|
|
255de797f8 | ||
|
|
0046c53283 |
@@ -60,6 +60,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
.sink { [weak self] _ in self?.updateStatusItem() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
updateManager.$updateAvailable
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.updateStatusItem() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Refresh timer
|
||||
scheduleTimer(interval: usageViewModel.refreshInterval)
|
||||
|
||||
@@ -166,7 +171,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
let sdStr = sd.map { "\(Int($0.usedPercent.rounded()))%" } ?? "—"
|
||||
button.image = nil
|
||||
button.attributedTitle = NSAttributedString(string: "")
|
||||
button.title = "◔ \(fhStr) \(sdStr)"
|
||||
let updatePrefix = updateManager.updateAvailable ? "↑ Update " : "◔ "
|
||||
button.title = "\(updatePrefix)\(fhStr) \(sdStr)"
|
||||
button.font = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium)
|
||||
} else if updateManager.updateAvailable {
|
||||
button.image = nil
|
||||
button.attributedTitle = NSAttributedString(string: "")
|
||||
button.title = "↑ Update"
|
||||
button.font = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium)
|
||||
} else {
|
||||
button.title = ""
|
||||
@@ -199,6 +210,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
@objc func showPopover() {
|
||||
guard let button = statusItem?.button, let popover else { return }
|
||||
if !popover.isShown {
|
||||
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
|
||||
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
@@ -209,6 +221,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
if popover.isShown {
|
||||
popover.performClose(nil)
|
||||
} else {
|
||||
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
|
||||
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,9 @@ struct ContentView: View {
|
||||
}
|
||||
.frame(width: 480)
|
||||
.animation(.easeInOut(duration: 0.2), value: showSettings)
|
||||
.onReceive(NotificationCenter.default.publisher(for: .popoverWillOpen)) { _ in
|
||||
showSettings = false
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .openUpdateSheet)) { _ in
|
||||
showSettings = false
|
||||
showUpdateSheet = true
|
||||
@@ -977,6 +980,36 @@ struct UpdateSuccessBanner: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Markdown notes renderer
|
||||
|
||||
struct ReleaseNotesText: View {
|
||||
let text: String
|
||||
var font: Font = .system(size: 12)
|
||||
|
||||
var body: some View {
|
||||
let processed = text
|
||||
.split(separator: "\n", omittingEmptySubsequences: false)
|
||||
.map { line -> String in
|
||||
let s = String(line)
|
||||
if s.hasPrefix("### ") { return "**\(s.dropFirst(4))**" }
|
||||
if s.hasPrefix("## ") { return "**\(s.dropFirst(3))**" }
|
||||
if s.hasPrefix("# ") { return "**\(s.dropFirst(2))**" }
|
||||
if s.hasPrefix("- ") { return "• \(s.dropFirst(2))" }
|
||||
return s
|
||||
}
|
||||
.joined(separator: "\n")
|
||||
|
||||
if let attr = try? AttributedString(markdown: processed,
|
||||
options: .init(interpretedSyntax: .inlineOnlyPreservingWhitespace)) {
|
||||
Text(attr).font(font).foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
} else {
|
||||
Text(text).font(font).foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Update Banner
|
||||
|
||||
struct UpdateBanner: View {
|
||||
@@ -992,22 +1025,13 @@ struct UpdateBanner: View {
|
||||
Text("Update available — v\(updater.latestVersion)")
|
||||
.font(.system(size: 12, weight: .semibold))
|
||||
if !updater.releaseNotes.isEmpty {
|
||||
Text(updater.releaseNotes)
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
ReleaseNotesText(text: updater.releaseNotes, font: .system(size: 11))
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
Button("Update") { showSheet = true }
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.small)
|
||||
Button { updater.updateAvailable = false } label: {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 10, weight: .medium))
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
@@ -1061,9 +1085,7 @@ struct UpdateSheet: View {
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
if !updater.releaseNotes.isEmpty {
|
||||
Text(updater.releaseNotes)
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.secondary)
|
||||
ReleaseNotesText(text: updater.releaseNotes)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.6</string>
|
||||
<string>1.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>25</string>
|
||||
<string>33</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>13.0</string>
|
||||
<key>LSUIElement</key>
|
||||
|
||||
@@ -14,7 +14,7 @@ class UpdateNotificationWindowController: NSWindowController {
|
||||
|
||||
// Called when a new update is detected while running
|
||||
static func showUpdate(version: String, notes: String, near statusItem: NSStatusItem?) {
|
||||
showWindow(version: version, subtitle: notes.isEmpty ? "Tap to update now." : notes, near: statusItem, isUpdate: true)
|
||||
showWindow(version: version, subtitle: "Tap to view release notes & update now!", near: statusItem, isUpdate: true)
|
||||
}
|
||||
|
||||
static func showLimitWarning(windowName: String, percent: Int, near statusItem: NSStatusItem?) {
|
||||
|
||||
@@ -307,6 +307,7 @@ extension Notification.Name {
|
||||
static let refreshIntervalChanged = Notification.Name("refreshIntervalChanged")
|
||||
static let closePopover = Notification.Name("closePopover")
|
||||
static let showPopover = Notification.Name("showPopover")
|
||||
static let popoverWillOpen = Notification.Name("popoverWillOpen")
|
||||
static let updateDetected = Notification.Name("updateDetected")
|
||||
static let limitWarning = Notification.Name("limitWarning")
|
||||
static let limitReset = Notification.Name("limitReset")
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
[](https://www.apple.com/macos/)
|
||||
[](https://swift.org)
|
||||
[](https://github.com/superdooper86/claudechecker/releases)
|
||||
[](https://github.com/superdooper86/claudechecker/releases)
|
||||
[](LICENSE)
|
||||
|
||||
</div>
|
||||
|
||||
+15
-3
@@ -1,4 +1,16 @@
|
||||
## What's new in v1.0.6
|
||||
## What's new in v1.1.0
|
||||
|
||||
### Improved update notification
|
||||
The update notification now reads **"Tap to view release notes & update now!"** — making it clear you can read what's changed before installing.
|
||||
### Clickable notifications
|
||||
Tapping a limit warning or reset notification opens the main window. Tapping an update notification opens the update sheet directly — no need to manually click the menubar icon.
|
||||
|
||||
### Update indicator in menubar
|
||||
When an update is available, the menubar shows **↑ Update** alongside your usage percentages so you know at a glance without opening the app.
|
||||
|
||||
### Release notes render correctly
|
||||
The update banner and update sheet now render markdown formatting — headers, **bold text**, and bullet points display properly.
|
||||
|
||||
### Update notification improved
|
||||
The update popup now reads **"Tap to view release notes & update now!"** making it clear you can read what changed before installing.
|
||||
|
||||
### Main window always opens on click
|
||||
Closing the app while Settings was open would cause the next click to reopen straight to Settings. The app now always returns to the main window.
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.5",
|
||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.0.5/ClaudeChecker.zip",
|
||||
"notes": "## What's new in v1.0.5\n\n### Release notes now render correctly\nThe update sheet and in-app banner now render markdown formatting in release notes — headers, bold text, and bullet points all display correctly instead of showing raw `##` and `**` characters.\n\nThe update notification popup no longer shows the full release notes text; it shows a concise \"Tap to update now.\" prompt instead, keeping it compact."
|
||||
"version": "1.0.12",
|
||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.0.12/ClaudeChecker.zip",
|
||||
"notes": "## What's new in v1.0.12\n\n### Update indicator in menubar\nWhen an update is available, the menubar now shows **↑ Update** alongside your usage percentages — so you can see there's an update without opening the app."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user