diff --git a/MacTorn-1.2.5.zip b/MacTorn-v1.3.zip
similarity index 78%
rename from MacTorn-1.2.5.zip
rename to MacTorn-v1.3.zip
index 07979bd..4ede03b 100644
Binary files a/MacTorn-1.2.5.zip and b/MacTorn-v1.3.zip differ
diff --git a/MacTorn/MacTorn/Info.plist b/MacTorn/MacTorn/Info.plist
index f3d9d29..3132ec9 100644
--- a/MacTorn/MacTorn/Info.plist
+++ b/MacTorn/MacTorn/Info.plist
@@ -17,8 +17,8 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.2.5
+ 1.3
CFBundleVersion
- 1.2.5
+ 1.3
diff --git a/MacTorn/MacTorn/Views/StatusView.swift b/MacTorn/MacTorn/Views/StatusView.swift
index d43c5e9..9697e3b 100644
--- a/MacTorn/MacTorn/Views/StatusView.swift
+++ b/MacTorn/MacTorn/Views/StatusView.swift
@@ -195,15 +195,21 @@ struct StatusView: View {
private func cooldownsSection(_ cooldowns: Cooldowns) -> some View {
VStack(alignment: .leading, spacing: 8) {
Divider()
-
+
Text("Cooldowns")
.font(.caption.bold())
.foregroundColor(.secondary)
-
+
HStack(spacing: 16) {
- CooldownItem(label: "Drug", seconds: cooldowns.drug, icon: "pills.fill")
- CooldownItem(label: "Medical", seconds: cooldowns.medical, icon: "cross.case.fill")
- CooldownItem(label: "Booster", seconds: cooldowns.booster, icon: "arrow.up.circle.fill")
+ if let fetchTime = appState.lastUpdated {
+ LiveCooldownItem(label: "Drug", originalSeconds: cooldowns.drug, fetchTime: fetchTime, icon: "pills.fill")
+ LiveCooldownItem(label: "Medical", originalSeconds: cooldowns.medical, fetchTime: fetchTime, icon: "cross.case.fill")
+ LiveCooldownItem(label: "Booster", originalSeconds: cooldowns.booster, fetchTime: fetchTime, icon: "arrow.up.circle.fill")
+ } else {
+ CooldownItem(label: "Drug", seconds: cooldowns.drug, icon: "pills.fill")
+ CooldownItem(label: "Medical", seconds: cooldowns.medical, icon: "cross.case.fill")
+ CooldownItem(label: "Booster", seconds: cooldowns.booster, icon: "arrow.up.circle.fill")
+ }
}
}
}
@@ -260,13 +266,13 @@ struct CooldownItem: View {
let label: String
let seconds: Int
let icon: String
-
+
var body: some View {
VStack(spacing: 2) {
Image(systemName: icon)
.font(.caption)
.foregroundColor(seconds > 0 ? .orange : .green)
-
+
Text(formattedTime)
.font(.caption2.monospacedDigit())
.foregroundColor(seconds > 0 ? .primary : .green)
@@ -274,7 +280,7 @@ struct CooldownItem: View {
}
.frame(maxWidth: .infinity)
}
-
+
private var formattedTime: String {
if seconds <= 0 { return "Ready" }
let hours = seconds / 3600
@@ -286,3 +292,41 @@ struct CooldownItem: View {
return String(format: "%d:%02d", minutes, secs)
}
}
+
+// MARK: - Live Cooldown Item
+struct LiveCooldownItem: View {
+ let label: String
+ let originalSeconds: Int
+ let fetchTime: Date
+ let icon: String
+
+ var body: some View {
+ TimelineView(.periodic(from: fetchTime, by: 1.0)) { context in
+ let elapsed = Int(context.date.timeIntervalSince(fetchTime))
+ let remaining = max(0, originalSeconds - elapsed)
+
+ VStack(spacing: 2) {
+ Image(systemName: icon)
+ .font(.caption)
+ .foregroundColor(remaining > 0 ? .orange : .green)
+
+ Text(formattedTime(remaining))
+ .font(.caption2.monospacedDigit())
+ .foregroundColor(remaining > 0 ? .primary : .green)
+ .fontWeight(remaining <= 0 ? .bold : .regular)
+ }
+ .frame(maxWidth: .infinity)
+ }
+ }
+
+ private func formattedTime(_ seconds: Int) -> String {
+ if seconds <= 0 { return "Ready" }
+ let hours = seconds / 3600
+ let minutes = (seconds % 3600) / 60
+ let secs = seconds % 60
+ if hours > 0 {
+ return String(format: "%d:%02d:%02d", hours, minutes, secs)
+ }
+ return String(format: "%d:%02d", minutes, secs)
+ }
+}