mycode/myApp/Expiranner/IOS/Theme.swift
songyc macbook 9902d44848 feat(expiranner): rebuild as store-based expiry photo checker
- 매장 선택 → 연/월 → 월 캘린더(날짜별 제품 사진 썸네일) → 날짜 상세 플로우로 전면 재작성
- 스캔 플로우: 촬영 → 재촬영/사용 → 그 달 날짜만 선택 → 저장 후 카메라 자동 복귀 (손전등 지원)
- 날짜 상세 다중 선택 삭제 (전체 선택/해제 + 일괄 삭제 확인)
- 다크 전용 민트 테마, SwiftData 모델(Store ↔ ProductRecord, 원본+썸네일 분리 저장)
- 밝은 민트 앱 아이콘(SVG 원본 포함) + 런치 스크린/인앱 스플래시
- CLAUDE.md 새 구조 기준으로 재작성

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:53:14 +09:00

136 lines
4.5 KiB
Swift

import SwiftUI
import UIKit
// MARK: - ( )
extension Color {
init(hex: UInt32) {
self.init(
.sRGB,
red: Double((hex >> 16) & 0xFF) / 255,
green: Double((hex >> 8) & 0xFF) / 255,
blue: Double(hex & 0xFF) / 255
)
}
}
enum Theme {
static let bg = Color(hex: 0x0B0E13)
static let surface = Color(hex: 0x161B25)
static let surfaceHi = Color(hex: 0x202836)
static let stroke = Color.white.opacity(0.07)
static let accent = Color(hex: 0x3BE39F)
static let accentSoft = Color(hex: 0x3BE39F).opacity(0.14)
static let onAccent = Color(hex: 0x07281B)
static let danger = Color(hex: 0xFF7A7A)
static let warn = Color(hex: 0xFFC94D)
static let sunday = Color(hex: 0xFF8A80)
static let saturday = Color(hex: 0x7EB6FF)
static let textPrimary = Color(hex: 0xF3F6FA)
static let textSecondary = Color(hex: 0x8D99AD)
static let accentGradient = LinearGradient(
colors: [Color(hex: 0x5CF0B6), Color(hex: 0x1FC98B)],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
// MARK: -
struct CardBackground: ViewModifier {
var cornerRadius: CGFloat = 18
func body(content: Content) -> some View {
content
.background(
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.fill(Theme.surface)
.overlay(
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.strokeBorder(Theme.stroke, lineWidth: 1)
)
)
}
}
extension View {
func cardStyle(cornerRadius: CGFloat = 18) -> some View {
modifier(CardBackground(cornerRadius: cornerRadius))
}
}
// MARK: -
enum Haptics {
static func success() { UINotificationFeedbackGenerator().notificationOccurred(.success) }
static func warning() { UINotificationFeedbackGenerator().notificationOccurred(.warning) }
static func tap() { UIImpactFeedbackGenerator(style: .light).impactOccurred() }
static func shutter() { UIImpactFeedbackGenerator(style: .medium).impactOccurred() }
}
// MARK: -
enum KoreanCalendar {
static let calendar: Calendar = {
var c = Calendar(identifier: .gregorian)
c.locale = Locale(identifier: "ko_KR")
return c
}()
static let weekdaySymbols = ["", "", "", "", "", "", ""]
/// . nil, 1....
static func gridDays(year: Int, month: Int) -> [Int?] {
let comps = DateComponents(year: year, month: month, day: 1)
guard let first = calendar.date(from: comps),
let range = calendar.range(of: .day, in: .month, for: first) else { return [] }
let firstWeekday = calendar.component(.weekday, from: first)
let leading = (firstWeekday - calendar.firstWeekday + 7) % 7
return Array(repeating: nil, count: leading) + range.map { $0 }
}
static func date(year: Int, month: Int, day: Int) -> Date? {
calendar.date(from: DateComponents(year: year, month: month, day: day))
}
static func isToday(year: Int, month: Int, day: Int) -> Bool {
let t = calendar.dateComponents([.year, .month, .day], from: .now)
return t.year == year && t.month == month && t.day == day
}
/// ( )
static func daysFromToday(to date: Date) -> Int {
let today = calendar.startOfDay(for: .now)
let target = calendar.startOfDay(for: date)
return calendar.dateComponents([.day], from: today, to: target).day ?? 0
}
static func weekdayColor(columnIndex: Int) -> Color {
switch columnIndex {
case 0: return Theme.sunday
case 6: return Theme.saturday
default: return Theme.textSecondary
}
}
}
// MARK: -
extension UIImage {
func downscaled(maxDimension: CGFloat) -> UIImage {
let longest = max(size.width, size.height)
guard longest > maxDimension, longest > 0 else { return self }
let ratio = maxDimension / longest
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
let format = UIGraphicsImageRendererFormat.default()
format.scale = 1
return UIGraphicsImageRenderer(size: newSize, format: format).image { _ in
draw(in: CGRect(origin: .zero, size: newSize))
}
}
}