feat(app): add flow diagnostics and refine interface
Improve failure recovery visibility, strengthen account-session handling, and make the cross-platform interface more consistent.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// MonthlyUsageCalendar.swift
|
||||
// OSGKeyboard · HostSupport
|
||||
//
|
||||
// Current-month dictation heat map. Every date remains visible; the accent
|
||||
// Current-month dictation heat map. Every date remains visible; the monochrome
|
||||
// circle's opacity communicates that day's character count relative to the
|
||||
// busiest day in the same month.
|
||||
|
||||
@@ -158,21 +158,21 @@ public struct MonthlyUsageCalendar: View {
|
||||
let isToday = calendar.isDateInToday(point.date)
|
||||
let isFuture = calendar.startOfDay(for: point.date) > calendar.startOfDay(for: Date())
|
||||
let opacity = fillOpacity(for: point.value, isFuture: isFuture)
|
||||
let usesLightText = opacity >= 0.48
|
||||
let usesContrastingText = opacity >= 0.48
|
||||
|
||||
return Text(day.formatted())
|
||||
.font(.system(size: compact ? 12 : 13, weight: isToday ? .semibold : .medium, design: .rounded))
|
||||
.foregroundStyle(
|
||||
isFuture
|
||||
? palette.textTertiary.opacity(0.45)
|
||||
: (usesLightText ? palette.textOnAccent : palette.textPrimary)
|
||||
: (usesContrastingText ? palette.background : palette.textPrimary)
|
||||
)
|
||||
.frame(width: cellDiameter, height: cellDiameter)
|
||||
.background(palette.accent.opacity(opacity), in: Circle())
|
||||
.background(palette.textPrimary.opacity(opacity), in: Circle())
|
||||
.overlay {
|
||||
if isToday {
|
||||
Circle()
|
||||
.stroke(palette.accent, lineWidth: 1.5)
|
||||
.stroke(palette.textPrimary, lineWidth: 1.5)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -188,7 +188,7 @@ public struct MonthlyUsageCalendar: View {
|
||||
private func fillOpacity(for value: Int, isFuture: Bool) -> Double {
|
||||
guard value > 0, !isFuture else { return 0 }
|
||||
let ratio = min(max(Double(value) / Double(maximumValue), 0), 1)
|
||||
return 0.14 + sqrt(ratio) * 0.62
|
||||
return 0.05 + pow(ratio, 1.15) * 0.73
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public struct SupportDeveloperSection: View {
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, Spacing.sm)
|
||||
.foregroundStyle(.white)
|
||||
.foregroundStyle(OSGColor.fixedLightContent)
|
||||
.background(palette.accent, in: RoundedRectangle(cornerRadius: Radius.large, style: .continuous))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
@@ -223,12 +223,12 @@ public struct UsageStatsCluster<Header: View>: View {
|
||||
VStack(spacing: CardLayoutMetrics.compactItemSpacing) {
|
||||
HStack(spacing: CardLayoutMetrics.compactItemSpacing) {
|
||||
compactCell(
|
||||
systemImage: "waveform.badge.microphone",
|
||||
systemImage: "timer",
|
||||
value: UsageStatisticsStore.formatDuration(dictationDurationSeconds, language: language),
|
||||
label: SharedL10n.string("stat.dictationTime", language: language)
|
||||
)
|
||||
compactCell(
|
||||
systemImage: "text.quote",
|
||||
systemImage: "quote.bubble",
|
||||
value: UsageStatisticsStore.formatCount(dictationCharacterCount, language: language),
|
||||
label: SharedL10n.string("stat.words", language: language),
|
||||
action: onOpenHistory
|
||||
@@ -242,7 +242,7 @@ public struct UsageStatsCluster<Header: View>: View {
|
||||
label: SharedL10n.string("stat.translation", language: language)
|
||||
)
|
||||
compactCell(
|
||||
systemImage: "books.vertical",
|
||||
systemImage: "book.pages",
|
||||
value: UsageStatisticsStore.formatCount(dictionaryTermCount, language: language),
|
||||
label: SharedL10n.string("stat.dictionary", language: language),
|
||||
action: onOpenDictionary
|
||||
@@ -292,9 +292,9 @@ public struct UsageStatsCluster<Header: View>: View {
|
||||
return ZStack(alignment: .bottomTrailing) {
|
||||
// Subtle watermark stays fully visible within the card edges.
|
||||
Image(systemName: systemImage)
|
||||
.font(.system(size: 26, weight: .semibold))
|
||||
.foregroundStyle(palette.textPrimary.opacity(0.06))
|
||||
.frame(width: 32, height: 32, alignment: .center)
|
||||
.font(.system(size: 38, weight: .ultraLight))
|
||||
.foregroundStyle(palette.textPrimary.opacity(0.10))
|
||||
.frame(width: 44, height: 44, alignment: .center)
|
||||
.offset(x: Spacing.xs, y: Spacing.xs)
|
||||
|
||||
VStack(alignment: .leading, spacing: Spacing.xxs) {
|
||||
@@ -323,6 +323,7 @@ public struct UsageStatsCluster<Header: View>: View {
|
||||
}
|
||||
}
|
||||
.clipShape(shape)
|
||||
.cardElevation()
|
||||
}
|
||||
|
||||
private var disclosureIndicator: some View {
|
||||
|
||||
Reference in New Issue
Block a user