mycode/myApp/HaruDanim/Widgets/WidgetTheme.swift
songyc macbook 9bf617f3e5 feat(widgets): 위젯 테마 옵션 추가 — 앱 테마 일치/라이트·다크 고정/리퀴드 글라스 (CLAUDE.md §8.1)
- 홈 위젯 5종(행동 실행/목표 진행률/다짐 진행률/다짐 현황/통계) 설정에
  '위젯 테마' 옵션 추가
- 앱 테마와 일치: 앱의 라이트/다크 설정을 따름 (테마 키를 App Group으로 이관해
  위젯이 읽을 수 있게 함)
- 라이트/다크 고정: 컬러 스킴 강제 + 해당 모드 팔레트
- 리퀴드 글라스: 반투명 머티리얼 배경 + 표면 셀도 머티리얼로 변형해
  유리 질감 위에서 가독성 유지
- DEBUG 미리보기가 테마를 재현하도록 개선 (-widgetTheme light|dark|glass,
  글라스는 그라데이션 배경 위에 렌더링)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
2026-07-10 09:14:31 +09:00

95 lines
2.8 KiB
Swift

//
// WidgetTheme.swift
// Haru_DanimWidgets
//
// (CLAUDE.md §8.1)
// 1. 2. / 3. ( )
//
import AppIntents
import SwiftUI
import WidgetKit
enum WidgetThemeOption: String, AppEnum {
case matchApp
case light
case dark
case glass
static let typeDisplayRepresentation = TypeDisplayRepresentation(name: "위젯 테마")
static let caseDisplayRepresentations: [WidgetThemeOption: DisplayRepresentation] = [
.matchApp: "앱 테마와 일치",
.light: "라이트 고정",
.dark: "다크 고정",
.glass: "리퀴드 글라스",
]
/// . .
var forcedScheme: ColorScheme? {
switch self {
case .light:
return .light
case .dark:
return .dark
case .matchApp:
let raw = AppGroup.defaults.string(forKey: SettingsKeys.theme)
?? UserDefaults.standard.string(forKey: SettingsKeys.theme) ?? "light"
return raw == "dark" ? .dark : .light
case .glass:
return nil
}
}
}
// MARK: - : ( )
private struct WidgetGlassKey: EnvironmentKey {
static let defaultValue = false
}
extension EnvironmentValues {
var widgetGlass: Bool {
get { self[WidgetGlassKey.self] }
set { self[WidgetGlassKey.self] = newValue }
}
}
// MARK: -
struct WidgetThemeModifier: ViewModifier {
let theme: WidgetThemeOption
func body(content: Content) -> some View {
switch theme {
case .glass:
// :
content
.environment(\.widgetGlass, true)
.containerBackground(for: .widget) {
Rectangle().fill(.ultraThinMaterial)
}
case .light, .dark, .matchApp:
content
.environment(\.colorScheme, theme.forcedScheme ?? .light)
.containerBackground(AppTheme.background, for: .widget)
}
}
}
extension View {
/// ( + )
func widgetTheme(_ theme: WidgetThemeOption) -> some View {
modifier(WidgetThemeModifier(theme: theme))
}
}
/// : ,
struct WidgetCellBackground: View {
@Environment(\.widgetGlass) private var glass
var body: some View {
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(glass ? AnyShapeStyle(.thinMaterial) : AnyShapeStyle(AppTheme.surface))
}
}