feat: v2
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Заголовок пары
|
||||
|
||||
/// Иконка монеты + «BTC/USDT» + знак Rapira справа.
|
||||
struct PairHeader: View {
|
||||
let thumb: SymbolThumb
|
||||
let icon: Data?
|
||||
let iconSize: CGFloat
|
||||
let titleSize: CGFloat
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: iconSize * 0.3) {
|
||||
CoinIconView(currency: thumb.quoteCurrency, data: icon, size: iconSize)
|
||||
|
||||
HStack(spacing: 1) {
|
||||
Text(thumb.quoteCurrency)
|
||||
.foregroundStyle(
|
||||
LinearGradient(
|
||||
colors: [.white, .white.opacity(0.85)],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
)
|
||||
Text("/\(thumb.baseCurrency)")
|
||||
.foregroundStyle(.white.opacity(0.5))
|
||||
}
|
||||
.font(.system(size: titleSize, weight: .bold))
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.6)
|
||||
|
||||
Spacer(minLength: 4)
|
||||
|
||||
RapiraMark(size: iconSize * 0.52)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Цена
|
||||
|
||||
/// Крупная цена с приглушённым символом валюты: «70 324,00 USDT».
|
||||
struct PriceLabel: View {
|
||||
let thumb: SymbolThumb
|
||||
let size: CGFloat
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .firstTextBaseline, spacing: size * 0.16) {
|
||||
Text(thumb.priceFormatted)
|
||||
.font(.system(size: size, weight: .bold))
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(
|
||||
LinearGradient(
|
||||
colors: [.white, .white.opacity(0.7)],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
|
||||
Text(thumb.baseSymbol)
|
||||
.font(.system(size: size * 0.42, weight: .semibold))
|
||||
.foregroundStyle(.white.opacity(0.5))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Изменение за 24ч
|
||||
|
||||
/// «+1 676,00 USDT · 2.34%» одной зелёной/красной строкой, без подложки.
|
||||
struct StatsLine: View {
|
||||
let thumb: SymbolThumb
|
||||
let fontSize: CGFloat
|
||||
var showAbsolute = true
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: fontSize * 0.4) {
|
||||
if showAbsolute {
|
||||
Text(thumb.changeFormatted)
|
||||
Text("·")
|
||||
.foregroundStyle(RapiraPalette.stat(thumb.isPositive).opacity(0.45))
|
||||
Text(thumb.changePercentPlain)
|
||||
} else {
|
||||
Text(thumb.changePercent)
|
||||
}
|
||||
}
|
||||
.font(.system(size: fontSize, weight: .semibold))
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(RapiraPalette.stat(thumb.isPositive))
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.7)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Время обновления
|
||||
|
||||
/// Подпись «27 октября 17:10» под парой — как в макете.
|
||||
struct UpdatedAt: View {
|
||||
let date: Date
|
||||
let fontSize: CGFloat
|
||||
var withDate = true
|
||||
|
||||
var body: some View {
|
||||
Text(MarketFormatting.updated(date, withDate: withDate))
|
||||
.font(.system(size: fontSize, weight: .medium))
|
||||
.foregroundStyle(.white.opacity(0.5))
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Пустое состояние
|
||||
|
||||
struct EmptyState: View {
|
||||
enum Reason {
|
||||
/// Ни одна выбранная пара не найдена в данных.
|
||||
case noSelection
|
||||
/// Ни сети, ни кэша.
|
||||
case noData
|
||||
}
|
||||
|
||||
let reason: Reason
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 8) {
|
||||
RapiraMark(size: 26)
|
||||
Text(message)
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(.white.opacity(0.45))
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
|
||||
private var message: String {
|
||||
switch reason {
|
||||
case .noSelection: "Выберите пары\nв приложении"
|
||||
case .noData: "Нет данных.\nПроверьте соединение"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user