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:
songyc macbook 2026-07-12 23:35:09 +09:00
parent dc9434a241
commit dd95dcd28f
2 changed files with 28 additions and 2 deletions

View File

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

View File

@ -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 {