From b641198bee91b93f92cbe63f745342a0ca86db04 Mon Sep 17 00:00:00 2001 From: robonen Date: Fri, 14 Aug 2026 21:19:32 +0700 Subject: [PATCH] feat: update Sparkline and Widget components for improved layout and visuals --- crypto/Sparkline.swift | 28 +++++++++++++++---- crypto/WidgetCards.swift | 18 +++++++++--- crypto/WidgetComponents.swift | 8 ++++-- crypto/WidgetViews.swift | 8 +++--- .../xcshareddata/WorkspaceSettings.xcsettings | 5 ++++ .../WorkspaceSettings.xcsettings | 16 +++++++++++ .../xcschemes/xcschememanagement.plist | 2 +- 7 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 rapira-market-widget.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 rapira-market-widget.xcodeproj/project.xcworkspace/xcuserdata/robonen.xcuserdatad/WorkspaceSettings.xcsettings diff --git a/crypto/Sparkline.swift b/crypto/Sparkline.swift index e99281a..31201e5 100644 --- a/crypto/Sparkline.swift +++ b/crypto/Sparkline.swift @@ -46,6 +46,9 @@ struct Sparkline: View { var areaOpacity: Double = 0.25 /// Отступ справа в диаметрах точки: линия обрывается, не доходя до края. var trailingRoom: CGFloat = 1.4 + /// В карточке-герое график уходит под края виджета и левая кромка заливки + /// не видна. Отдельно стоящий график гасит её, иначе получается срез. + var isFullBleed: Bool = true /// Больше точек глазом уже не различить, а форма тяжелеет. private static let maxPoints = 96 @@ -66,12 +69,7 @@ struct Sparkline: View { startPoint: .top, endPoint: .bottom ) ) - .mask( - LinearGradient( - colors: [.white, .white.opacity(0.25)], - startPoint: .leading, endPoint: .trailing - ) - ) + .mask(areaMask) // Гало точки лежит под линией, ядро — над ней. if showPulse, let last = points.last { @@ -104,6 +102,24 @@ struct Sparkline: View { } } + /// Горизонтальная маска заливки: свечение сосредоточено слева, как в макете. + private var areaMask: LinearGradient { + LinearGradient( + gradient: Gradient(stops: isFullBleed + ? [ + .init(color: .white, location: 0), + .init(color: .white.opacity(0.25), location: 1), + ] + : [ + .init(color: .white.opacity(0), location: 0), + .init(color: .white, location: 0.3), + .init(color: .white.opacity(0.3), location: 1), + ]), + startPoint: .leading, + endPoint: .trailing + ) + } + // MARK: - Геометрия private func points(in size: CGSize) -> [CGPoint] { diff --git a/crypto/WidgetCards.swift b/crypto/WidgetCards.swift index 0a1c21c..8f92529 100644 --- a/crypto/WidgetCards.swift +++ b/crypto/WidgetCards.swift @@ -47,7 +47,7 @@ struct HeroCard: View { values: quote.series, positive: thumb.isPositive, lineWidth: 2, - pulseSize: iconSize * 0.52 + pulseSize: chartHeight * 0.26 ) } else { // Нет истории — держим ритм макета ровной линией. @@ -76,7 +76,14 @@ struct CryptoRow: View { let compact: Bool private var thumb: SymbolThumb { quote.thumb } - private var iconSize: CGFloat { compact ? 24 : 26 } + private var iconSize: CGFloat { compact ? 21 : 23 } + + /// График занимает почти весь зазор между названием и ценой: на узком + /// поле линия выглядит сплюснутой, поэтому тянем её вширь. + /// В большом виджете строк больше — там график ниже. + private var chartSize: CGSize { + compact ? CGSize(width: 92, height: 28) : CGSize(width: 88, height: 26) + } var body: some View { HStack(spacing: 8) { @@ -91,6 +98,8 @@ struct CryptoRow: View { } .font(.system(size: compact ? 12 : 13, weight: .bold)) .lineLimit(1) + // Длинные тикеры вроде MATIC/USDT сжимаются, а не обрезаются. + .minimumScaleFactor(0.8) Text(thumb.quoteCurrencyName) .font(.system(size: compact ? 9 : 10, weight: .medium)) @@ -107,9 +116,10 @@ struct CryptoRow: View { lineWidth: 1.5, pulseSize: 7, areaOpacity: 0.16, - trailingRoom: 0.6 + trailingRoom: 0.6, + isFullBleed: false ) - .frame(width: compact ? 46 : 56, height: 22) + .frame(width: chartSize.width, height: chartSize.height) } VStack(alignment: .trailing, spacing: 2) { diff --git a/crypto/WidgetComponents.swift b/crypto/WidgetComponents.swift index 8f9d16b..c65cfa1 100644 --- a/crypto/WidgetComponents.swift +++ b/crypto/WidgetComponents.swift @@ -9,8 +9,12 @@ struct PairHeader: View { let iconSize: CGFloat let titleSize: CGFloat + /// Знак и отступы привязаны к кеглю заголовка, а не к иконке: размер + /// иконки подбирается отдельно и не должен тянуть за собой логотип. + private var markSize: CGFloat { titleSize * 1.05 } + var body: some View { - HStack(spacing: iconSize * 0.3) { + HStack(spacing: titleSize * 0.55) { CoinIconView(currency: thumb.quoteCurrency, data: icon, size: iconSize) HStack(spacing: 1) { @@ -30,7 +34,7 @@ struct PairHeader: View { Spacer(minLength: 4) - RapiraMark(size: iconSize * 0.52) + RapiraMark(size: markSize) } } } diff --git a/crypto/WidgetViews.swift b/crypto/WidgetViews.swift index 4fa9563..af02ae0 100644 --- a/crypto/WidgetViews.swift +++ b/crypto/WidgetViews.swift @@ -16,10 +16,10 @@ struct SmallWidgetView: View { quote: hero, updatedAt: entry.date, horizontalPadding: padding, - iconSize: 24, + iconSize: 20, titleSize: 13, priceSize: 21, - chartHeight: 38, + chartHeight: 40, showFullDate: false, showAbsolute: false ) @@ -98,10 +98,10 @@ struct LargeWidgetView: View { quote: hero, updatedAt: entry.date, horizontalPadding: padding, - iconSize: 36, + iconSize: 28, titleSize: 19, priceSize: 32, - chartHeight: 72 + chartHeight: 70 ) if !rest.isEmpty { diff --git a/rapira-market-widget.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/rapira-market-widget.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/rapira-market-widget.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/rapira-market-widget.xcodeproj/project.xcworkspace/xcuserdata/robonen.xcuserdatad/WorkspaceSettings.xcsettings b/rapira-market-widget.xcodeproj/project.xcworkspace/xcuserdata/robonen.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..723a561 --- /dev/null +++ b/rapira-market-widget.xcodeproj/project.xcworkspace/xcuserdata/robonen.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,16 @@ + + + + + BuildLocationStyle + UseAppPreferences + CompilationCachingSetting + Default + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/rapira-market-widget.xcodeproj/xcuserdata/robonen.xcuserdatad/xcschemes/xcschememanagement.plist b/rapira-market-widget.xcodeproj/xcuserdata/robonen.xcuserdatad/xcschemes/xcschememanagement.plist index 5f36630..49b9324 100644 --- a/rapira-market-widget.xcodeproj/xcuserdata/robonen.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/rapira-market-widget.xcodeproj/xcuserdata/robonen.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ cryptoExtension.xcscheme_^#shared#^_ orderHint - 1 + 0 rapira-market-widget.xcscheme_^#shared#^_