- IntentStore now recreates the ModelContainer on demand in the widget extension (IntentStore.refresh()), called before every AppIntent perform() and every provider's makeEntry(). Fixes stale/blank widget buttons and double-toggle bugs caused by the extension process reading an old in-memory snapshot after CloudKit remote changes. - Replaced the fixed 15/30-minute polling Timeline policy (which burns WidgetKit's daily reload budget across 6 widget kinds) with WidgetRefresh.timeline: idle widgets wait until the next logical-day boundary since value changes are already pushed via reloadAllTimelines, while widgets showing a live ratio (a currently running quest/goal) get pre-computed future entries so progress rings and bars keep advancing without extra reloads. - Removed the per-widget "위젯 테마" (match app / light / dark / liquid glass) configuration option from all 5 home-screen widgets. It duplicated the same enum five times, and the liquid-glass variant's custom background/scheme override fought the system's own vibrant/tinted rendering in tinted Home Screens, which was part of the "블랙 화면"/렌더링 오류 reports. Widgets now simply follow the app's own theme setting (WidgetAppearance.appScheme), which is what "앱 테마와 일치" already defaulted to. - Added shared gallery/placeholder sample data (ActionCellSnapshot, QuestCellSnapshot, GoalSnapshot, StatsChart sample points) so the widget gallery and redacted placeholders show a realistic shape instead of an empty/blank card. - Unified empty-state UI via WidgetEmptyView across all 5 widgets. Scope: Widgets/*, Shared/HaruDanimIntents.swift (widget-facing IntentStore only), IOS/Views/WidgetPreviewScreen.swift (DEBUG preview tool). No changes to app core data models, sync, or view logic.
85 lines
3.0 KiB
Swift
85 lines
3.0 KiB
Swift
//
|
|
// WidgetTheme.swift
|
|
// Haru_DanimWidgets
|
|
//
|
|
// 위젯 외형 (CLAUDE.md §8.1)
|
|
// - 위젯은 항상 앱 설정의 테마(라이트/다크)를 따른다. 위젯별 테마 설정 옵션은
|
|
// 강제 컬러 스킴 재정의가 렌더링 버그를 유발해 제거했다 (설정도 단순해짐).
|
|
// - 홈 화면이 틴트/클리어(리퀴드 글라스) 모드일 때는 시스템이 배경을 자체 유리로
|
|
// 대체하고 색을 재해석하므로, 배경만 비우고 시스템 렌더링에 맡긴다.
|
|
//
|
|
|
|
import SwiftUI
|
|
import WidgetKit
|
|
|
|
enum WidgetAppearance {
|
|
/// 앱 설정의 테마 ("light" | "dark") → 위젯에 그대로 적용할 컬러 스킴
|
|
static var appScheme: ColorScheme {
|
|
let raw = AppGroup.defaults.string(forKey: SettingsKeys.theme)
|
|
?? UserDefaults.standard.string(forKey: SettingsKeys.theme) ?? "light"
|
|
return raw == "dark" ? .dark : .light
|
|
}
|
|
}
|
|
|
|
// MARK: - 테마 적용 모디파이어
|
|
|
|
struct WidgetThemeModifier: ViewModifier {
|
|
@Environment(\.widgetRenderingMode) private var renderingMode
|
|
|
|
func body(content: Content) -> some View {
|
|
if renderingMode != .fullColor {
|
|
// 틴트/클리어(리퀴드 글라스) 홈 화면: 커스텀 배경·강제 스킴을 얹으면
|
|
// 시스템 유리 위에서 텍스트가 묻힌다 → 시스템 기본(바이브런트) 렌더링에 맡긴다
|
|
content
|
|
.containerBackground(for: .widget) { Color.clear }
|
|
} else {
|
|
let scheme = WidgetAppearance.appScheme
|
|
content
|
|
.environment(\.colorScheme, scheme)
|
|
.containerBackground(for: .widget) {
|
|
// containerBackground는 시스템이 위젯 자체 환경(시스템 모드)으로 그리므로
|
|
// 콘텐츠에 적용한 스킴을 배경에도 직접 지정해야 앱 테마가 실제로 적용된다
|
|
AppTheme.background
|
|
.environment(\.colorScheme, scheme)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
/// 위젯 루트에 앱 테마 적용 (컬러 스킴 + 배경)
|
|
func widgetAppTheme() -> some View {
|
|
modifier(WidgetThemeModifier())
|
|
}
|
|
}
|
|
|
|
// MARK: - 셀 배경
|
|
|
|
/// 셀 카드 배경 (표면색).
|
|
/// fullBleed = 셀 하나가 위젯 전체를 차지할 때 위젯 모서리(ContainerRelativeShape)에 맞춤
|
|
struct WidgetCellBackground: View {
|
|
var fullBleed = false
|
|
|
|
var body: some View {
|
|
if fullBleed {
|
|
ContainerRelativeShape().fill(AppTheme.surface)
|
|
} else {
|
|
RoundedRectangle(cornerRadius: 14, style: .continuous).fill(AppTheme.surface)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 행동 실행 셀처럼 꼬리표 색이 배경인 셀
|
|
struct WidgetTintedCellBackground: View {
|
|
let color: Color
|
|
var fullBleed = false
|
|
|
|
var body: some View {
|
|
if fullBleed {
|
|
ContainerRelativeShape().fill(color)
|
|
} else {
|
|
RoundedRectangle(cornerRadius: 14, style: .continuous).fill(color)
|
|
}
|
|
}
|
|
}
|