fix(widget): resolve invisible content bug by applying proper containerBackground and dynamic contrast for transparent/tinted themes
On a tinted/transparent (or iOS 18 accented) home screen, the Action Run widget turned into a solid white block with invisible content, while the other widgets rendered fine. Cause: only the Action Run cell paints an opaque tag-color background (WidgetTintedCellBackground) with hardcoded .foregroundStyle(.white) text on top. In any non-.fullColor rendering mode the system re-interprets that opaque fill toward white and the white text disappears — classic white-on-white. The other widgets already use the adaptive AppTheme.surface plus semantic .primary/.secondary text, which is why they were unaffected. Fix, confined to ActionRunCellView: - Read @Environment(\.widgetRenderingMode). In .fullColor keep the tag-color fill + white text (unchanged). In accented/vibrant, drop the opaque fill to a faint translucent tint and render content with the semantic .primary color so the system's tint keeps a clear foreground/background contrast. - No hardcoded .white survives on the tinted path; the container background is still owned by widgetAppTheme()'s .containerBackground(for: .widget) (clear in non-fullColor so the system glass shows through), so this composes safely with iOS 18 home-screen customization. The Live Activity's white-on-tint icon (HaruDanimWidgets) is intentionally left as-is — Live Activities always render full color and aren't subject to home-screen widgetRenderingMode. Verified in the in-app widget preview with a new DEBUG affordance (-widgetRenderMode accented|vibrant, added to WidgetPreviewScreen): forcing accented mode, the Action Run cells now show legible dark icons/labels/values on a faint tint instead of blank white. Build succeeds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
This commit is contained in:
parent
dc9434a241
commit
dd95dcd28f
@ -168,6 +168,16 @@ struct WidgetPreviewScreen: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// -widgetRenderMode accented|vibrant → 색조/투명 홈 화면 렌더링 모드를 강제해
|
||||
/// white-on-white 대비 문제를 앱 안에서 검증 (기본은 실제와 동일한 fullColor)
|
||||
private var forcedRenderingMode: WidgetRenderingMode {
|
||||
switch UserDefaults.standard.string(forKey: "widgetRenderMode") {
|
||||
case "accented": return .accented
|
||||
case "vibrant": return .vibrant
|
||||
default: return .fullColor
|
||||
}
|
||||
}
|
||||
|
||||
private func widgetBox(_ family: WidgetFamily, @ViewBuilder content: () -> some View) -> some View {
|
||||
let size: CGSize = switch family {
|
||||
case .systemMedium: CGSize(width: 338, height: 158)
|
||||
@ -181,6 +191,7 @@ struct WidgetPreviewScreen: View {
|
||||
.frame(width: size.width, height: size.height)
|
||||
.background(AppTheme.background)
|
||||
.environment(\.colorScheme, WidgetAppearance.appScheme)
|
||||
.environment(\.widgetRenderingMode, forcedRenderingMode)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 22, style: .continuous))
|
||||
.shadow(color: .black.opacity(0.08), radius: 6, y: 2)
|
||||
}
|
||||
|
||||
@ -76,12 +76,17 @@ struct ActionRunProvider: AppIntentTimelineProvider {
|
||||
// MARK: - 뷰
|
||||
|
||||
struct ActionRunCellView: View {
|
||||
/// 홈 화면 렌더링 모드. .fullColor가 아니면(색조/투명/리퀴드 글라스, iOS 18 accented·vibrant)
|
||||
/// 시스템이 색을 재해석하므로 흰색 하드코딩이 배경째 흰색으로 묻히는 white-on-white가 난다.
|
||||
@Environment(\.widgetRenderingMode) private var renderingMode
|
||||
let cell: ActionCellSnapshot
|
||||
let periodLabel: String
|
||||
var compact = false
|
||||
/// 셀 하나가 위젯 전체를 차지할 때 (소형) — 위젯 모서리에 맞춰 여백 없이 채움
|
||||
var fullBleed = false
|
||||
|
||||
private var isFullColor: Bool { renderingMode == .fullColor }
|
||||
|
||||
var body: some View {
|
||||
Button(intent: RunActionIntent(actionID: cell.id.uuidString)) {
|
||||
VStack(alignment: .leading, spacing: compact ? 2 : 4) {
|
||||
@ -113,10 +118,11 @@ struct ActionRunCellView: View {
|
||||
.opacity(0.85)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.foregroundStyle(.white)
|
||||
// 풀컬러: 꼬리표 색 배경 위 흰 글씨. 색조/투명 모드: 시맨틱 컬러로 그려 시스템 틴트가 대비를 유지.
|
||||
.foregroundStyle(isFullColor ? AnyShapeStyle(.white) : AnyShapeStyle(.primary))
|
||||
.padding(fullBleed ? 14 : (compact ? 8 : 12))
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||
.background(WidgetTintedCellBackground(color: cell.color, fullBleed: fullBleed))
|
||||
.background(cellBackground)
|
||||
.overlay {
|
||||
if cell.isRunning {
|
||||
if fullBleed {
|
||||
@ -131,6 +137,15 @@ struct ActionRunCellView: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
/// 셀 배경: 풀컬러에선 꼬리표 색을 그대로, 색조/투명 모드에선 옅은 반투명으로 깔아
|
||||
/// (불투명 색은 흰색 계열로 재해석돼 콘텐츠를 덮음) 시맨틱 콘텐츠가 위에서 대비를 이루게 한다.
|
||||
@ViewBuilder private var cellBackground: some View {
|
||||
WidgetTintedCellBackground(
|
||||
color: isFullColor ? cell.color : cell.color.opacity(0.2),
|
||||
fullBleed: fullBleed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct ActionRunWidgetView: View {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user