// // LemonLimeWidgetLiveActivity.swift // LemonLimeWidget // // Created by 송예찬 on 6/18/26. // import ActivityKit import WidgetKit import SwiftUI private let timerEndDate = Date.distantFuture struct LemonLimeWidgetLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: TimerActivityAttributes.self) { context in // MARK: Lock Screen / Banner HStack(spacing: 14) { Image(systemName: "timer") .font(.title2.weight(.semibold)) .foregroundStyle(.yellow) VStack(alignment: .leading, spacing: 3) { Text(context.attributes.taskName) .font(.subheadline.weight(.semibold)) .foregroundStyle(.white) .lineLimit(1) Text(timerInterval: context.state.startDate...timerEndDate, countsDown: false) .font(.caption.monospacedDigit()) .foregroundStyle(.yellow) } Spacer() Text(context.attributes.taskIcon) .font(.largeTitle) } .padding(.horizontal, 16) .padding(.vertical, 12) .activityBackgroundTint(Color(red: 0.08, green: 0.30, blue: 0.08)) .activitySystemActionForegroundColor(.yellow) } dynamicIsland: { context in DynamicIsland { // MARK: Expanded – top row DynamicIslandExpandedRegion(.leading) { Label { Text(context.attributes.taskName) .font(.caption.weight(.semibold)) .lineLimit(1) } icon: { Text(context.attributes.taskIcon) .font(.caption) } .foregroundStyle(.green) } DynamicIslandExpandedRegion(.trailing) { Image(systemName: "circle.fill") .font(.caption) .foregroundStyle(.green) .padding(.trailing, 4) } // MARK: Expanded – center (large timer) DynamicIslandExpandedRegion(.bottom) { Text(timerInterval: context.state.startDate...timerEndDate, countsDown: false) .font(.system(size: 44, weight: .bold, design: .monospaced)) .foregroundStyle(.yellow) .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 4) } } compactLeading: { Image(systemName: "timer") .foregroundStyle(.green) .font(.caption.weight(.semibold)) } compactTrailing: { Text(timerInterval: context.state.startDate...timerEndDate, countsDown: false) .monospacedDigit() .font(.caption2.weight(.medium)) .foregroundStyle(.yellow) .frame(maxWidth: 52) } minimal: { ZStack { Circle() .fill(LinearGradient( colors: [.green, Color(red: 0.8, green: 0.9, blue: 0.0)], startPoint: .topLeading, endPoint: .bottomTrailing )) Text(context.attributes.taskIcon) .font(.system(size: 11)) } } .keylineTint(.green) } } } // MARK: - Previews extension TimerActivityAttributes { fileprivate static var preview: TimerActivityAttributes { TimerActivityAttributes(taskName: "운동하기", taskIcon: "🏃") } } extension TimerActivityAttributes.ContentState { fileprivate static var running: TimerActivityAttributes.ContentState { TimerActivityAttributes.ContentState( startDate: Date().addingTimeInterval(-125), elapsedSeconds: 125 ) } } #Preview("Notification", as: .content, using: TimerActivityAttributes.preview) { LemonLimeWidgetLiveActivity() } contentStates: { TimerActivityAttributes.ContentState.running }