easy-codex 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,10 +51,10 @@ macOS 14+ 安装后运行:
51
51
  easy-codex overlay
52
52
  ```
53
53
 
54
- 独立 AppKit 浮窗在 Codex 位于前台时显示,切到其他应用、最小化或关闭 Codex 窗口后隐藏。默认位于 Codex 窗口右下角上方;拖动可校准位置,偏移量保存在本机。它按窗口边界跟随,不自动识别头像;侧栏布局变化后可再次拖动。首版跟随最前面的一个 Codex 普通窗口。
54
+ 独立 AppKit 浮窗在 Codex 位于前台时显示,切到其他应用、最小化或关闭 Codex 窗口后隐藏。默认位于 Codex 窗口左下角头像上方;拖动可校准位置,偏移量保存在本机。它按窗口边界跟随,不自动识别头像;侧栏布局变化后可再次拖动。首版跟随最前面的一个 Codex 普通窗口。
55
55
 
56
56
  - 圆环长度表示剩余百分比:大于 50% 绿色,20%–50% 橙色,低于 20% 红色。
57
- - 浮窗为小尺寸(16×16),背景透明,无底板和阴影。圆环只显示百分比,无数据时显示 `—`,不显示窗口时长或状态文字;时长与状态见悬停提示和菜单。
57
+ - 浮窗为头像大小(32×32),背景透明,无底板和阴影。圆环只显示百分比,无数据时显示 `—`,不显示窗口时长或状态文字;时长与状态见悬停提示和菜单。
58
58
  - 未知或过期数据为灰色;失败后的过期说明见悬停提示。已到重置时间时也先标为过期,等待重新查询,不擅自恢复满额。
59
59
  - 浮窗可见时每 60 秒刷新,查询不会重叠;回到前台且距离上次查询超过 60 秒会刷新。
60
60
  - 默认优先 codex 额度桶,显示其中剩余比例最低的窗口;右键可切换其他窗口,不把各窗口相加。
@@ -46,8 +46,8 @@ func appKitRect(_ rect: CGRect, primaryHeight: CGFloat) -> CGRect {
46
46
  CGRect(x: rect.minX, y: primaryHeight - rect.maxY, width: rect.width, height: rect.height)
47
47
  }
48
48
  func ringOrigin(in rect: CGRect, inset: CGPoint) -> CGPoint {
49
- CGPoint(x: max(rect.minX, min(rect.maxX - 16, rect.maxX - 16 - inset.x)),
50
- y: max(rect.minY, min(rect.maxY - 16, rect.minY + inset.y)))
49
+ CGPoint(x: max(rect.minX, min(rect.maxX - 32, rect.minX + inset.x)),
50
+ y: max(rect.minY, min(rect.maxY - 32, rect.minY + inset.y)))
51
51
  }
52
52
 
53
53
  @MainActor
@@ -81,28 +81,28 @@ final class RingView: NSView {
81
81
 
82
82
  override func draw(_ dirtyRect: NSRect) {
83
83
  let center = CGPoint(x: bounds.midX, y: bounds.midY)
84
- let track = NSBezierPath(ovalIn: CGRect(x: center.x - 7, y: center.y - 7, width: 14, height: 14))
85
- track.lineWidth = 1
84
+ let track = NSBezierPath(ovalIn: CGRect(x: center.x - 14, y: center.y - 14, width: 28, height: 28))
85
+ track.lineWidth = 2
86
86
  NSColor.labelColor.withAlphaComponent(0.12).setStroke()
87
87
  track.stroke()
88
88
  let state = RingState.resolve(remaining, stale: stale)
89
89
  if let remaining, remaining > 0, !stale {
90
90
  let arc = NSBezierPath()
91
- arc.lineWidth = 1
91
+ arc.lineWidth = 2
92
92
  arc.lineCapStyle = .round
93
- arc.appendArc(withCenter: center, radius: 7, startAngle: 90,
93
+ arc.appendArc(withCenter: center, radius: 14, startAngle: 90,
94
94
  endAngle: 90 - CGFloat(min(100, max(0, remaining))) * 3.6, clockwise: true)
95
95
  state.color.setStroke()
96
96
  arc.stroke()
97
97
  }
98
98
  let text = remaining.map { "\(Int($0.rounded()))%" } ?? "—"
99
- drawText(text, y: 5, font: .monospacedDigitSystemFont(ofSize: 4.5, weight: .semibold), color: state.color)
99
+ drawText(text, y: 10, font: .monospacedDigitSystemFont(ofSize: 9, weight: .semibold), color: state.color)
100
100
  }
101
101
  private func drawText(_ text: String, y: CGFloat, font: NSFont, color: NSColor) {
102
102
  let style = NSMutableParagraphStyle()
103
103
  style.alignment = .center
104
104
  style.lineBreakMode = .byTruncatingTail
105
- (text as NSString).draw(in: CGRect(x: 1, y: y, width: bounds.width - 2, height: 6),
105
+ (text as NSString).draw(in: CGRect(x: 2, y: y, width: bounds.width - 4, height: 12),
106
106
  withAttributes: [.font: font, .foregroundColor: color, .paragraphStyle: style])
107
107
  }
108
108
  override func mouseDown(with event: NSEvent) {
@@ -127,9 +127,9 @@ final class RingView: NSView {
127
127
 
128
128
  @MainActor
129
129
  final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
130
- let panel = NSPanel(contentRect: CGRect(x: 0, y: 0, width: 16, height: 16),
130
+ let panel = NSPanel(contentRect: CGRect(x: 0, y: 0, width: 32, height: 32),
131
131
  styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: false)
132
- let ring = RingView(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
132
+ let ring = RingView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
133
133
  var status: NSStatusItem?
134
134
  var timer: Timer?
135
135
  var query: Process?
@@ -150,8 +150,8 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
150
150
  node = args[1]; script = args[2]; searchPath = args[3]
151
151
  codexHome = args.count > 4 ? args[4] : ""
152
152
  let prefs = UserDefaults.standard
153
- if prefs.object(forKey: "rightInset") != nil {
154
- inset = CGPoint(x: prefs.double(forKey: "rightInset"), y: prefs.double(forKey: "bottomInset"))
153
+ if prefs.object(forKey: "leftInset") != nil {
154
+ inset = CGPoint(x: prefs.double(forKey: "leftInset"), y: prefs.double(forKey: "bottomInset"))
155
155
  }
156
156
  selectedID = prefs.string(forKey: "selectedWindow")
157
157
  panel.isOpaque = false
@@ -165,8 +165,8 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
165
165
  ring.refresh = { [weak self] in self?.refresh() }
166
166
  ring.moved = { [weak self] point in
167
167
  guard let self, let rect = self.lastRect else { return }
168
- self.inset = CGPoint(x: rect.maxX - point.x - 16, y: point.y - rect.minY)
169
- prefs.set(self.inset.x, forKey: "rightInset")
168
+ self.inset = CGPoint(x: point.x - rect.minX, y: point.y - rect.minY)
169
+ prefs.set(self.inset.x, forKey: "leftInset")
170
170
  prefs.set(self.inset.y, forKey: "bottomInset")
171
171
  }
172
172
  ring.setAccessibilityElement(true)
@@ -275,7 +275,7 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
275
275
  }
276
276
  @objc func resetPosition() {
277
277
  inset = CGPoint(x: 10, y: 74)
278
- UserDefaults.standard.removeObject(forKey: "rightInset")
278
+ UserDefaults.standard.removeObject(forKey: "leftInset")
279
279
  UserDefaults.standard.removeObject(forKey: "bottomInset")
280
280
  tick()
281
281
  }
@@ -299,8 +299,9 @@ struct Main {
299
299
  assert(RingState.resolve(99, stale: true) == .unknown)
300
300
  assert(appKitRect(CGRect(x: -900, y: 100, width: 800, height: 600), primaryHeight: 900).origin == CGPoint(x: -900, y: 200))
301
301
  let bounds = CGRect(x: 100, y: 100, width: 800, height: 600)
302
- assert(ringOrigin(in: bounds, inset: CGPoint(x: 10, y: 74)) == CGPoint(x: 874, y: 174))
303
- assert(ringOrigin(in: bounds, inset: CGPoint(x: -100, y: -100)) == CGPoint(x: 884, y: 100))
302
+ assert(ringOrigin(in: bounds, inset: CGPoint(x: 10, y: 74)) == CGPoint(x: 110, y: 174))
303
+ assert(ringOrigin(in: bounds, inset: CGPoint(x: -100, y: -100)) == CGPoint(x: 100, y: 100))
304
+ assert(ringOrigin(in: bounds, inset: CGPoint(x: 9999, y: 9999)) == CGPoint(x: 868, y: 668))
304
305
  print("Swift 圆环颜色与窗口坐标检查通过")
305
306
  return
306
307
  }
@@ -318,7 +319,7 @@ struct Main {
318
319
  NSGraphicsContext.saveGraphicsState()
319
320
  let transform = AffineTransform(translationByX: CGFloat(index * 84 + 4), byY: 8)
320
321
  (transform as NSAffineTransform).concat()
321
- let view = RingView(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
322
+ let view = RingView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
322
323
  view.remaining = value < 0 ? nil : value; view.stale = value < 0
323
324
  view.caption = value < 0 ? "额度未知" : "7天"
324
325
  view.draw(view.bounds)
@@ -5,7 +5,7 @@
5
5
  <key>CFBundleIdentifier</key><string>com.unionschool.easy-codex.overlay</string>
6
6
  <key>CFBundleName</key><string>Easy Codex Overlay</string>
7
7
  <key>CFBundlePackageType</key><string>APPL</string>
8
- <key>CFBundleShortVersionString</key><string>0.1.1</string>
8
+ <key>CFBundleShortVersionString</key><string>0.1.3</string>
9
9
  <key>LSMinimumSystemVersion</key><string>14.0</string>
10
10
  <key>LSUIElement</key><true/>
11
11
  <key>NSHighResolutionCapable</key><true/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easy-codex",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Display remaining Codex account usage limits",
5
5
  "type": "module",
6
6
  "bin": {