Skip to content

Commit 8cc4b1d

Browse files
committed
Add monthly window label handling
Introduce a monthly window threshold and update AccountCardView to display dynamic window labels (Monthly/Weekly) based on window seconds. Adds helper methods (windowLabel, resetPrefix, awaitingActivationLabel) to centralize label logic and updates UI text, frame sizing, and reset/awaiting-activation messages to use the new labels. This unifies weekly/monthly text handling and ensures correct labeling for longer usage windows.
1 parent 06e2979 commit 8cc4b1d

2 files changed

Lines changed: 36 additions & 8 deletions

File tree

CodexAccounts/Models/CodexAccount.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ struct CodexAccount: Identifiable, Codable, Hashable {
215215

216216
struct AccountUsage: Equatable {
217217
static let weeklyWindowThresholdSeconds = 3 * 24 * 60 * 60
218+
static let monthlyWindowThresholdSeconds = 25 * 24 * 60 * 60
218219

219220
/// Codex usage shown in the primary bar (short window when available, otherwise weekly)
220221
var usedPercent: Double

CodexAccounts/Views/AccountCardView.swift

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,13 @@ struct AccountCardView: View {
216216
Text("\(Int(clampedPercent(usage.remainingPercent)))%")
217217
.font(.system(size: 13, weight: .bold, design: .monospaced))
218218
.foregroundStyle(percentColor(for: usage.remainingPercent))
219-
if usage.isWeeklyPrimary {
220-
Text("Weekly")
219+
if let primaryWindowLabel = windowLabel(for: usage.primaryWindowSeconds) {
220+
Text(primaryWindowLabel)
221221
.font(.system(size: 7.5, weight: .semibold))
222222
.foregroundStyle(Color.white.opacity(0.62))
223223
}
224224
}
225-
.frame(width: usage.isWeeklyPrimary ? 48 : 40, alignment: .trailing)
225+
.frame(width: windowLabel(for: usage.primaryWindowSeconds) == nil ? 40 : 54, alignment: .trailing)
226226
}
227227
.padding(.top, 6)
228228

@@ -279,10 +279,12 @@ struct AccountCardView: View {
279279

280280
@ViewBuilder
281281
private func weeklyUsageRow(weeklyRemaining: Double, weeklyResetAt: Date?) -> some View {
282+
let windowLabel = windowLabel(for: usage?.weeklyWindowSeconds)
283+
let windowPrefix = windowLabel.map { "\($0) " } ?? ""
282284
switch usageDetailMode {
283285
case .compact:
284286
HStack(spacing: 4) {
285-
Text("Weekly \(Int(clampedPercent(weeklyRemaining)))% left")
287+
Text("\(windowPrefix)\(Int(clampedPercent(weeklyRemaining)))% left")
286288
.font(.system(size: 9, weight: .medium))
287289
.foregroundStyle(Color.white.opacity(0.70))
288290
if let weeklyResetAt {
@@ -295,7 +297,7 @@ struct AccountCardView: View {
295297
case .detailed:
296298
VStack(alignment: .leading, spacing: 4) {
297299
HStack(spacing: 6) {
298-
Text("Weekly")
300+
Text(windowLabel ?? "Weekly")
299301
.font(.system(size: 8.5, weight: .bold))
300302
.textCase(.uppercase)
301303
.foregroundStyle(Color.white.opacity(0.60))
@@ -517,18 +519,43 @@ struct AccountCardView: View {
517519

518520
private func resetSummary(for usage: AccountUsage, resetAt: Date) -> String {
519521
if usage.isWeeklyPrimary, usage.weeklyResetIsOverdue(grace: 60) {
520-
return "Weekly awaiting activation"
522+
return awaitingActivationLabel(for: usage.primaryWindowSeconds ?? usage.weeklyWindowSeconds)
521523
}
522-
return "\(usage.isWeeklyPrimary ? "Weekly resets" : "Resets") \(resetAt.resetDescription)"
524+
return "\(resetPrefix(for: usage.primaryWindowSeconds ?? usage.weeklyWindowSeconds)) \(resetAt.resetDescription)"
523525
}
524526

525527
private func weeklyResetDescription(for resetAt: Date) -> String {
526528
if let usage, usage.weeklyResetIsOverdue(grace: 60) {
527-
return "Awaiting activation"
529+
return awaitingActivationLabel(for: usage.weeklyWindowSeconds)
528530
}
529531
return "resets \(resetAt.resetDescription)"
530532
}
531533

534+
private func windowLabel(for windowSeconds: Int?) -> String? {
535+
guard let windowSeconds, windowSeconds > 0 else { return nil }
536+
if windowSeconds >= AccountUsage.monthlyWindowThresholdSeconds {
537+
return "Monthly"
538+
}
539+
if windowSeconds >= AccountUsage.weeklyWindowThresholdSeconds {
540+
return "Weekly"
541+
}
542+
return nil
543+
}
544+
545+
private func resetPrefix(for windowSeconds: Int?) -> String {
546+
if let label = windowLabel(for: windowSeconds) {
547+
return "\(label) resets"
548+
}
549+
return "Resets"
550+
}
551+
552+
private func awaitingActivationLabel(for windowSeconds: Int?) -> String {
553+
if let label = windowLabel(for: windowSeconds) {
554+
return "\(label) awaiting activation"
555+
}
556+
return "Awaiting activation"
557+
}
558+
532559
private var stateIconName: String {
533560
switch status {
534561
case .active: return "checkmark.circle.fill"

0 commit comments

Comments
 (0)