mycode/myApp/HaruDanim/Widgets/WidgetTheme.swift
songyc macbook f7ddd42260 refactor(widget): complete widget architecture overhaul for reliable interactions and removed bloated configurations
- 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.
2026-07-11 22:41:54 +09:00

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)
}
}
}