import CodexBarCoreimport Foundation extension UsageMenuCardView.Model { static func minimaxMetrics(services: [MiniMaxServiceUsage], input: Input) -> [Metric] { let percentStyle: PercentStyle = .used let displayNameCounts = Dictionary(grouping: services.map(\.displayName), by: { $0 }).mapValues(\.count) return services.enumerated().map { index, service in let used = service.usage let displayPercent = min(100, max(0, service.percent)) let usageLabel = if service.isUnlimited { nil as String? } else { String( format: L("minimax_usage_amount_format"), used.formatted(), service.limit.formatted()) } let localizedName = Self.localizedMiniMaxServiceName(service.displayName) let title = if (displayNameCounts[service.displayName] ?? 0) > 1 { "\(localizedName) · \(Self.displayWindowBadge(for: service.windowType))" } else { localizedName } return Metric( id: "minimax-service-\(index)", title: title, percent: displayPercent, percentStyle: percentStyle, statusText: service.isUnlimited ? "∞ Unlimited" : nil, resetText: Self.localizedMiniMaxResetDescription(service.resetDescription), detailText: nil, detailLeftText: usageLabel, detailRightText: nil, pacePercent: nil, paceOnTop: true, warningMarkerPercents: service.isUnlimited ? [] : Self.miniMaxWarningMarkerPercents(service: service, input: input), workdayMarkerPercents: service.isUnlimited ? [] : Self.miniMaxWorkdayMarkerPercents(service: service, input: input), cardStyle: false) } } private static func miniMaxWarningMarkerPercents(service: MiniMaxServiceUsage, input: Input) -> [Double] { switch self.miniMaxQuotaWarningWindow(for: service) { case .session: warningMarkerPercents( thresholds: input.quotaWarningThresholds[.session], showUsed: true) case .weekly: warningMarkerPercents( thresholds: input.quotaWarningThresholds[.weekly], showUsed: true) } } private static func miniMaxWorkdayMarkerPercents(service: MiniMaxServiceUsage, input: Input) -> [Double] { guard self.miniMaxQuotaWarningWindow(for: service) == .weekly else { return [] } return workDayMarkerPercents( workDays: input.workDaysPerWeek, windowMinutes: self.miniMaxWindowMinutes(for: service.windowType)) } private static func miniMaxQuotaWarningWindow(for service: MiniMaxServiceUsage) -> QuotaWarningWindow { service.windowType.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == "weekly" ? .weekly : .session } private static func miniMaxWindowMinutes(for windowType: String) -> Int? { let normalized = windowType.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() if normalized == "weekly" { return 7 * 24 * 60 } if normalized == "today" || normalized == "daily" { return 24 * 60 } if normalized == "5h" { return 5 * 60 } let pieces = normalized.split(separator: " ") guard pieces.count >= 2, let value = Int(pieces[0]) else { return nil } switch pieces[1] { case "hour", "hours", "hr", "hrs": return value * 60 case "minute", "minutes", "min", "mins": return value default: return nil } } private static func displayWindowBadge(for windowType: String) -> String { let trimmed = windowType.trimmingCharacters(in: .whitespacesAndNewlines) let normalized = trimmed.lowercased() if normalized == "weekly" { return L("Weekly") } if normalized == "5 hours" || normalized == "5 hour" || normalized == "5h" { return "5h" } if normalized == "today" { return L("Today") } if normalized == "daily" { return L("Daily") } return trimmed.isEmpty ? windowType : trimmed } private static func localizedMiniMaxResetDescription(_ text: String) -> String { let prefix = "Resets in " guard text.hasPrefix(prefix) else { return text } let rest = String(text.dropFirst(prefix.count)) return L("Resets in %@", rest) } private static func localizedMiniMaxServiceName(_ raw: String) -> String { switch raw { case "Text Generation", "text_generation": L("minimax_service_text_generation") case "Text to Speech", "text_to_speech": L("minimax_service_text_to_speech") case "Music Generation", "music_generation": L("minimax_service_music_generation") case "Image Generation", "image_generation": L("minimax_service_image_generation") case "lyrics_generation": L("minimax_service_lyrics_generation") case "coding-plan-vlm": L("minimax_service_coding_plan_vlm") case "coding-plan-search": L("minimax_service_coding_plan_search") default: raw } }}
import CodexBarCore
import Foundation
extension UsageMenuCardView.Model {
static func minimaxMetrics(services: [MiniMaxServiceUsage], input: Input) -> [Metric] {
let percentStyle: PercentStyle = .used
let displayNameCounts = Dictionary(grouping: services.map(\.displayName), by: { $0 }).mapValues(\.count)
return services.enumerated().map { index, service in
let used = service.usage
let displayPercent = min(100, max(0, service.percent))
let usageLabel = if service.isUnlimited {
nil as String?
} else {
String(
format: L("minimax_usage_amount_format"),
used.formatted(),
service.limit.formatted())
}
let localizedName = Self.localizedMiniMaxServiceName(service.displayName)
let title = if (displayNameCounts[service.displayName] ?? 0) > 1 {
"\(localizedName) · \(Self.displayWindowBadge(for: service.windowType))"
} else {
localizedName
}
return Metric(
id: "minimax-service-\(index)",
title: title,
percent: displayPercent,
percentStyle: percentStyle,
statusText: service.isUnlimited ? "∞ Unlimited" : nil,
resetText: Self.localizedMiniMaxResetDescription(service.resetDescription),
detailText: nil,
detailLeftText: usageLabel,
detailRightText: nil,
pacePercent: nil,
paceOnTop: true,
warningMarkerPercents: service.isUnlimited
? []
: Self.miniMaxWarningMarkerPercents(service: service, input: input),
workdayMarkerPercents: service.isUnlimited
? []
: Self.miniMaxWorkdayMarkerPercents(service: service, input: input),
cardStyle: false)
}
}
private static func miniMaxWarningMarkerPercents(service: MiniMaxServiceUsage, input: Input) -> [Double] {
switch self.miniMaxQuotaWarningWindow(for: service) {
case .session:
warningMarkerPercents(
thresholds: input.quotaWarningThresholds[.session],
showUsed: true)
case .weekly:
warningMarkerPercents(
thresholds: input.quotaWarningThresholds[.weekly],
showUsed: true)
}
}
private static func miniMaxWorkdayMarkerPercents(service: MiniMaxServiceUsage, input: Input) -> [Double] {
guard self.miniMaxQuotaWarningWindow(for: service) == .weekly else { return [] }
return workDayMarkerPercents(
workDays: input.workDaysPerWeek,
windowMinutes: self.miniMaxWindowMinutes(for: service.windowType))
}
private static func miniMaxQuotaWarningWindow(for service: MiniMaxServiceUsage) -> QuotaWarningWindow {
service.windowType.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == "weekly" ? .weekly : .session
}
private static func miniMaxWindowMinutes(for windowType: String) -> Int? {
let normalized = windowType.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if normalized == "weekly" {
return 7 * 24 * 60
}
if normalized == "today" || normalized == "daily" {
return 24 * 60
}
if normalized == "5h" {
return 5 * 60
}
let pieces = normalized.split(separator: " ")
guard pieces.count >= 2, let value = Int(pieces[0]) else { return nil }
switch pieces[1] {
case "hour", "hours", "hr", "hrs":
return value * 60
case "minute", "minutes", "min", "mins":
return value
default:
return nil
}
}
private static func displayWindowBadge(for windowType: String) -> String {
let trimmed = windowType.trimmingCharacters(in: .whitespacesAndNewlines)
let normalized = trimmed.lowercased()
if normalized == "weekly" {
return L("Weekly")
}
if normalized == "5 hours" || normalized == "5 hour" || normalized == "5h" {
return "5h"
}
if normalized == "today" {
return L("Today")
}
if normalized == "daily" {
return L("Daily")
}
return trimmed.isEmpty ? windowType : trimmed
}
private static func localizedMiniMaxResetDescription(_ text: String) -> String {
let prefix = "Resets in "
guard text.hasPrefix(prefix) else { return text }
let rest = String(text.dropFirst(prefix.count))
return L("Resets in %@", rest)
}
private static func localizedMiniMaxServiceName(_ raw: String) -> String {
switch raw {
case "Text Generation", "text_generation":
L("minimax_service_text_generation")
case "Text to Speech", "text_to_speech":
L("minimax_service_text_to_speech")
case "Music Generation", "music_generation":
L("minimax_service_music_generation")
case "Image Generation", "image_generation":
L("minimax_service_image_generation")
case "lyrics_generation":
L("minimax_service_lyrics_generation")
case "coding-plan-vlm":
L("minimax_service_coding_plan_vlm")
case "coding-plan-search":
L("minimax_service_coding_plan_search")
default:
raw
}
}
}