Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c3cc6379 | ||
|
|
c8adaf1baf | ||
|
|
3e99e1417e | ||
|
|
e41d3d0c0f | ||
|
|
1078951c43 | ||
|
|
ed6a5e1b51 | ||
|
|
8701fb1326 | ||
|
|
247b5fc202 | ||
|
|
255de797f8 | ||
|
|
0046c53283 | ||
|
|
8d222d63f0 | ||
|
|
5720370649 | ||
|
|
0843730ae1 | ||
|
|
9c030fcdd5 | ||
|
|
dd68ff39d6 | ||
|
|
b76bdf3bc1 | ||
|
|
c31950fd76 | ||
|
|
4e6ae21825 | ||
|
|
c0bf2e4873 | ||
|
|
081d4804ab |
@@ -50,13 +50,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Update version.json
|
- name: Update version.json
|
||||||
run: |
|
run: |
|
||||||
cat > version.json << JSON
|
notes=$(cat RELEASE_NOTES.md 2>/dev/null || echo "Release ${{ steps.version.outputs.version }}")
|
||||||
{
|
jq -n \
|
||||||
"version": "${{ steps.version.outputs.version }}",
|
--arg version "${{ steps.version.outputs.version }}" \
|
||||||
"url": "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/ClaudeChecker.zip",
|
--arg url "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/ClaudeChecker.zip" \
|
||||||
"notes": "$(cat RELEASE_NOTES.md 2>/dev/null || echo 'Release ${{ steps.version.outputs.version }}')"
|
--arg notes "$notes" \
|
||||||
}
|
'{version: $version, url: $url, notes: $notes}' > version.json
|
||||||
JSON
|
|
||||||
|
|
||||||
- name: Update Homebrew cask
|
- name: Update Homebrew cask
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
@objc func showPopover() {
|
@objc func showPopover() {
|
||||||
guard let button = statusItem?.button, let popover else { return }
|
guard let button = statusItem?.button, let popover else { return }
|
||||||
if !popover.isShown {
|
if !popover.isShown {
|
||||||
|
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
|
||||||
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
}
|
}
|
||||||
@@ -209,6 +210,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
if popover.isShown {
|
if popover.isShown {
|
||||||
popover.performClose(nil)
|
popover.performClose(nil)
|
||||||
} else {
|
} else {
|
||||||
|
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
|
||||||
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,13 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.frame(width: 480)
|
.frame(width: 480)
|
||||||
.animation(.easeInOut(duration: 0.2), value: showSettings)
|
.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
|
||||||
|
}
|
||||||
.sheet(isPresented: $showLogin) {
|
.sheet(isPresented: $showLogin) {
|
||||||
LoginSheetView(isPresented: $showLogin) {
|
LoginSheetView(isPresented: $showLogin) {
|
||||||
Task { await vm.refresh() }
|
Task { await vm.refresh() }
|
||||||
@@ -973,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
|
// MARK: - Update Banner
|
||||||
|
|
||||||
struct UpdateBanner: View {
|
struct UpdateBanner: View {
|
||||||
@@ -988,10 +1025,7 @@ struct UpdateBanner: View {
|
|||||||
Text("Update available — v\(updater.latestVersion)")
|
Text("Update available — v\(updater.latestVersion)")
|
||||||
.font(.system(size: 12, weight: .semibold))
|
.font(.system(size: 12, weight: .semibold))
|
||||||
if !updater.releaseNotes.isEmpty {
|
if !updater.releaseNotes.isEmpty {
|
||||||
Text(updater.releaseNotes)
|
ReleaseNotesText(text: updater.releaseNotes, font: .system(size: 11))
|
||||||
.font(.system(size: 11))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -1057,9 +1091,7 @@ struct UpdateSheet: View {
|
|||||||
.foregroundColor(.blue)
|
.foregroundColor(.blue)
|
||||||
}
|
}
|
||||||
if !updater.releaseNotes.isEmpty {
|
if !updater.releaseNotes.isEmpty {
|
||||||
Text(updater.releaseNotes)
|
ReleaseNotesText(text: updater.releaseNotes)
|
||||||
.font(.system(size: 12))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0.2</string>
|
<string>1.0.10</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>21</string>
|
<string>30</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>13.0</string>
|
<string>13.0</string>
|
||||||
<key>LSUIElement</key>
|
<key>LSUIElement</key>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class UpdateNotificationWindowController: NSWindowController {
|
|||||||
|
|
||||||
// Called when a new update is detected while running
|
// Called when a new update is detected while running
|
||||||
static func showUpdate(version: String, notes: String, near statusItem: NSStatusItem?) {
|
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?) {
|
static func showLimitWarning(windowName: String, percent: Int, near statusItem: NSStatusItem?) {
|
||||||
@@ -39,7 +39,12 @@ class UpdateNotificationWindowController: NSWindowController {
|
|||||||
sharedLimit?.close()
|
sharedLimit?.close()
|
||||||
let content = UpdateNotificationView(
|
let content = UpdateNotificationView(
|
||||||
version: "", subtitle: subtitle, isUpdate: false,
|
version: "", subtitle: subtitle, isUpdate: false,
|
||||||
titleText: title, badgeIcon: badgeIcon, badgeColor: badgeColor
|
titleText: title, badgeIcon: badgeIcon, badgeColor: badgeColor,
|
||||||
|
onTap: {
|
||||||
|
sharedLimit?.close()
|
||||||
|
sharedLimit = nil
|
||||||
|
NotificationCenter.default.post(name: .showPopover, object: nil)
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
sharedLimit?.close()
|
sharedLimit?.close()
|
||||||
sharedLimit = nil
|
sharedLimit = nil
|
||||||
@@ -53,7 +58,16 @@ class UpdateNotificationWindowController: NSWindowController {
|
|||||||
|
|
||||||
private static func showWindow(version: String, subtitle: String, near statusItem: NSStatusItem?, isUpdate: Bool) {
|
private static func showWindow(version: String, subtitle: String, near statusItem: NSStatusItem?, isUpdate: Bool) {
|
||||||
shared?.close()
|
shared?.close()
|
||||||
let content = UpdateNotificationView(version: version, subtitle: subtitle, isUpdate: isUpdate) {
|
let content = UpdateNotificationView(version: version, subtitle: subtitle, isUpdate: isUpdate,
|
||||||
|
onTap: {
|
||||||
|
shared?.close()
|
||||||
|
shared = nil
|
||||||
|
NotificationCenter.default.post(name: .showPopover, object: nil)
|
||||||
|
if isUpdate {
|
||||||
|
NotificationCenter.default.post(name: .openUpdateSheet, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
shared?.close()
|
shared?.close()
|
||||||
shared = nil
|
shared = nil
|
||||||
}
|
}
|
||||||
@@ -129,6 +143,7 @@ struct UpdateNotificationView: View {
|
|||||||
var titleText: String? = nil
|
var titleText: String? = nil
|
||||||
var badgeIcon: String? = nil
|
var badgeIcon: String? = nil
|
||||||
var badgeColor: Color? = nil
|
var badgeColor: Color? = nil
|
||||||
|
var onTap: (() -> Void)? = nil
|
||||||
let onDismiss: () -> Void
|
let onDismiss: () -> Void
|
||||||
|
|
||||||
private var effectiveTitle: String {
|
private var effectiveTitle: String {
|
||||||
@@ -142,6 +157,8 @@ struct UpdateNotificationView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
ZStack(alignment: .topTrailing) {
|
||||||
|
Button(action: { onTap?() }) {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
Image(nsImage: NSImage(named: "AppIcon") ?? NSImage())
|
Image(nsImage: NSImage(named: "AppIcon") ?? NSImage())
|
||||||
@@ -159,13 +176,21 @@ struct UpdateNotificationView: View {
|
|||||||
VStack(alignment: .leading, spacing: 3) {
|
VStack(alignment: .leading, spacing: 3) {
|
||||||
Text(effectiveTitle)
|
Text(effectiveTitle)
|
||||||
.font(.system(size: 13, weight: .semibold))
|
.font(.system(size: 13, weight: .semibold))
|
||||||
|
.foregroundColor(.primary)
|
||||||
Text(subtitle)
|
Text(subtitle)
|
||||||
.font(.system(size: 11))
|
.font(.system(size: 11))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: 24)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 14)
|
||||||
|
.padding(.vertical, 14)
|
||||||
|
.frame(width: 340, alignment: .leading)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
|
||||||
Button(action: onDismiss) {
|
Button(action: onDismiss) {
|
||||||
Image(systemName: "xmark")
|
Image(systemName: "xmark")
|
||||||
@@ -173,10 +198,8 @@ struct UpdateNotificationView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
.padding(14)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 14)
|
|
||||||
.padding(.vertical, 14)
|
|
||||||
.frame(width: 340, alignment: .leading)
|
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 13)
|
RoundedRectangle(cornerRadius: 13)
|
||||||
.fill(Color(nsColor: .windowBackgroundColor))
|
.fill(Color(nsColor: .windowBackgroundColor))
|
||||||
|
|||||||
@@ -307,7 +307,9 @@ extension Notification.Name {
|
|||||||
static let refreshIntervalChanged = Notification.Name("refreshIntervalChanged")
|
static let refreshIntervalChanged = Notification.Name("refreshIntervalChanged")
|
||||||
static let closePopover = Notification.Name("closePopover")
|
static let closePopover = Notification.Name("closePopover")
|
||||||
static let showPopover = Notification.Name("showPopover")
|
static let showPopover = Notification.Name("showPopover")
|
||||||
|
static let popoverWillOpen = Notification.Name("popoverWillOpen")
|
||||||
static let updateDetected = Notification.Name("updateDetected")
|
static let updateDetected = Notification.Name("updateDetected")
|
||||||
static let limitWarning = Notification.Name("limitWarning")
|
static let limitWarning = Notification.Name("limitWarning")
|
||||||
static let limitReset = Notification.Name("limitReset")
|
static let limitReset = Notification.Name("limitReset")
|
||||||
|
static let openUpdateSheet = Notification.Name("openUpdateSheet")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
[](https://www.apple.com/macos/)
|
[](https://www.apple.com/macos/)
|
||||||
[](https://swift.org)
|
[](https://swift.org)
|
||||||
[](https://github.com/superdooper86/claudechecker/releases)
|
[](https://github.com/superdooper86/claudechecker/releases)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
## What's new in v1.0.10
|
||||||
|
|
||||||
|
### 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 when reopened.
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.0.1/ClaudeChecker.zip",
|
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.0/ClaudeChecker.zip",
|
||||||
"notes": "Update banner can now be dismissed. Fixes update state not clearing correctly."
|
"notes": "## What's new in v1.1.0\n\n### Main window always opens on click\nClosing 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 when reopened."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user