Initial commit: EzTimer iOS app with widget extension

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 22:10:34 -05:00
commit 99e7e79347
73 changed files with 2447 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
//
// EzTimerWidgetLiveActivity.swift
// EzTimerWidget
//
// Created by Jared Evans on 12/17/25.
//
import ActivityKit
import WidgetKit
import SwiftUI
struct EzTimerWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerAttributes.self) { context in
// Lock Screen/Banner UI
VStack(alignment: .leading) {
HStack {
Image(systemName: "timer")
.foregroundColor(.red)
Text("VizTimer")
.font(.headline)
.foregroundColor(.white)
}
HStack {
// This counts down automatically relative to the target date
if context.state.isFinished {
Text("Done at \(context.state.endTime, style: .time)")
.font(.system(size: 40, weight: .bold)) // Slightly smaller to fit time
.foregroundColor(.white)
} else {
Text(timerInterval: Date()...context.state.endTime, countsDown: true)
.font(.system(size: 48, weight: .bold))
.monospacedDigit()
.foregroundColor(.white)
}
Spacer()
if !context.state.message.isEmpty {
Text(context.state.message)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.trailing)
.lineLimit(2)
}
}
}
.padding()
.activityBackgroundTint(Color.black.opacity(0.8))
.activitySystemActionForegroundColor(Color.red)
} dynamicIsland: { context in
DynamicIsland {
// Expanded State
DynamicIslandExpandedRegion(.leading) {
Image(systemName: "timer")
.foregroundColor(.red)
}
DynamicIslandExpandedRegion(.trailing) {
if context.state.isFinished {
Text("Done at \(context.state.endTime, style: .time)")
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.red)
} else {
Text(timerInterval: Date()...context.state.endTime, countsDown: true)
.monospacedDigit()
.font(.title2)
}
}
DynamicIslandExpandedRegion(.bottom) {
if !context.state.message.isEmpty {
Text(context.state.message)
.font(.caption)
.foregroundColor(.white)
.lineLimit(1)
.truncationMode(.tail)
.padding(.top, 4)
} else {
Text("Time Remaining")
.font(.caption)
.foregroundColor(.gray)
}
}
} compactLeading: {
Image(systemName: "timer")
.foregroundColor(.red)
} compactTrailing: {
if context.state.isFinished {
Text("End")
.fontWeight(.bold)
.frame(minWidth: 40)
} else {
Text(timerInterval: Date()...context.state.endTime, countsDown: true)
.monospacedDigit()
.frame(minWidth: 40)
}
} minimal: {
Image(systemName: "timer")
.foregroundColor(.red)
}
.widgetURL(URL(string: "viztimer://open"))
.keylineTint(Color.red)
}
}
}