Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Examples/.build
# Local-only project notes / planning artifacts (not committed)
docs/
.remember/
.superpowers/

# SPM
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

# Graphify
graphify-out/
26 changes: 9 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Organizing rule: **one platform = one place.** Everything outside `UIKit/` and `

| Path | Role |
|------|------|
| `Core/ScreenUtil.swift` | Singleton engine (`ScreenUtil.shared`), `configure`, `scale`/`fastScale`, `.w/.h/.sp/.r/.sw/.sh/.fast*` |
| `Core/ScreenUtil.swift` | Singleton engine (`ScreenUtil.shared`), `configure`, `scale`/`fastScale`, `.w/.h/.sp/.r/.sw/.sh` |
| `Core/ScreenUtilConfiguration.swift` | Config struct + device presets (`iPhone13Pro`, `iPadPro11`, …) |
| `Core/ScaleType.swift` | Protocols (`ScreenScalable`, `ScreenUtilConfigurable`, `ScreenDimensionProvider`) + `ScaleType` |
| `Core/ScalingLimits.swift` | `ScalingLimits` (`.default`/`.strict`/`.relaxed`) |
Expand All @@ -22,45 +22,37 @@ Organizing rule: **one platform = one place.** Everything outside `UIKit/` and `
| `Metrics/ScreenDimensions.swift` | Platform dimensions snapshot (UIKit-gated reader) |
| `Metrics/SafeAreaInsets.swift` | Platform safe-area snapshot (UIKit-gated reader) |
| `Metrics/DeviceType.swift` | Device/platform classification |
| `Scaling/Numeric+Scaling.swift` | `Int/Float/Double/CGFloat` `.w/.h/.sp/.r/.sw/.sh/.fast*` |
| `Scaling/Numeric+Scaling.swift` | `Int/Float/Double/CGFloat` `.w/.h/.sp/.r/.sw/.sh` |
| `Scaling/CGGeometry+Scaling.swift` | `CGSize/CGPoint/CGRect` scaling (cross-platform) |
| `Scaling/FastScale.swift` | `FastScale` capture-once struct for hot loops + `withFastScale` |
| `Scaling/BatchScaling.swift` | `batch*` methods + `BatchScaler` for bulk scaling |
| `Scaling/BatchScaling.swift` | `BatchScaler` / `withBatchScaler` for bulk scaling |
| `UIKit/UIFont+Scaling.swift` | `UIFont` scaled helpers (`#if canImport(UIKit)`) |
| `UIKit/UIView+Scaling.swift` | `UIView` constraint/styling + `NSLayoutConstraint.updateConstant` |
| `UIKit/UIEdgeInsets+Scaling.swift` | `UIEdgeInsets.scaled(...)` |
| `SwiftUI/View+Responsive.swift` | `View` modifiers, `Font.scaledSystem/scaledCustom`, `EnvironmentValues.screenUtil` |
| `SwiftUI/ScaledValue.swift` | `@ScaledValue`, `@ScreenPercentage` property wrappers |
| `Debug/ScreenUtilDebug.swift` | Debug logging, benchmarking, validation, overlay |
| `SwiftUI/Environment+ScreenUtil.swift` | `EnvironmentValues.screenUtil` (injects `.shared`) |
| `Debug/ScreenUtilDebug.swift` | `enum` namespace: debug logging, benchmarking, overlay |

## Public Contract (must not break)

Anything not reachable from this set is a removal/merge candidate.

- `ScreenUtil.shared` + `configure(with:)` — singleton, configured once at launch.
- Numeric scaling: `.w .h .sp .r .sw .sh` and fast variants `.fastW .fastH .fastSp`.
- Numeric scaling: `.w .h .sp .r .sw .sh`.
- `ScreenUtilConfiguration` (+ presets) and `ScalingLimits`.
- `FastScale` / `withFastScale`, `BatchScaler` / `withBatchScaler` / `batch*`.
- SwiftUI: `responsiveFrame/responsivePadding/responsiveCornerRadius`, `Font.scaledSystem`, `@ScaledValue`, `@ScreenPercentage`.
- `FastScale` / `withFastScale`, `BatchScaler` / `withBatchScaler`.
- SwiftUI: `EnvironmentValues.screenUtil`.
- UIKit: `UIFont.systemFont(…, scaled:)`, `UIView` helpers, `UIEdgeInsets.scaled`.

## Review Checklist (when editing)

- Keep **zero dependencies** — `Package.swift` `dependencies: []` stays empty.
- **One platform = one place**: UIKit code only under `UIKit/` (or `#if canImport(UIKit)` blocks); SwiftUI only under `SwiftUI/`. Never bare `import UIKit` in cross-platform files — breaks macOS.
- Builds under `-strict-concurrency=complete` — no new concurrency warnings.
- `ScreenUtil` is `@unchecked Sendable`. New shared state must be `Sendable` / atomic.
- `ScreenUtil` is compiler-verified `Sendable` (atomic `Snapshot`; no `@unchecked`). New shared state must be `Sendable` / atomic.
- Bulk APIs accept `[T: Numeric]` — route through `cgFloatValue(_:)` so `CGFloat`/`Int64`/etc don't silently scale to zero.
- Removing code: confirm it's not reachable from the Public Contract and not referenced in `Tests/` or `Examples/`.
- Verify with `swift build` **and** `swift test` on macOS (catches the platform-isolation regressions).

## Known Issues (not yet addressed)

- **Data race**: `_scaleWidth/_scaleHeight/_scaleText` are plain `var` read without synchronization (only `@unchecked Sendable` hides it). TSan would flag. A proper fix needs atomic reads.
- **Stale on rotation**: caches invalidate on orientation change, but scale factors only recompute on `configure()`/`refreshMetrics()`. No observer re-derives `_scale*` after rotation.
- **`fastW` ≈ `.w`**: measured ~1.1× faster, not the README's "6×". For real hot loops use `FastScale` (capture-once).
- **README drift**: README documents APIs that don't exist (`.ssp`, `adaptiveFont`, `isIPad`, `pixelRatio`, `orientation`, `bottomSafeArea`, `prewarmCaches`, `ResponsiveGrid`, `fontResolver`, `debugMode`). Reconcile before publishing.

## Build & Test

```bash
Expand Down
28 changes: 10 additions & 18 deletions Examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,15 @@ Complete SwiftUI implementation examples including:

#### Basic SwiftUI Views
- **BasicSwiftUIView**: Core SwiftUI usage patterns
- `.scaledSystem()` font modifier
- `.responsivePadding()` and `.responsiveCornerRadius()` modifiers
- `.font(.system(size: 16.sp))` — scale the size with `.sp` inside native font APIs
- `.frame(width: 200.w, height: 50.h)` / `.padding(.horizontal, 20.w)` — scale inside native modifiers
- Grid layouts with responsive spacing
- Screen metrics display

#### Advanced SwiftUI Features
- **PropertyWrappersDemo**: Property wrapper usage
- `@ScaledValue` for automatic value scaling
- `@ScreenPercentage` for percentage-based sizing
- `@ResponsiveFont` for adaptive typography

- **ViewModifiersDemo**: Custom view modifiers
- `.responsiveFrame()` modifier
- `.responsivePadding()` modifier
- **ViewModifiersDemo**: Scaling values inside native SwiftUI modifiers
- `.frame(width: 200.w, height: 100.h)`
- `.clipShape(RoundedRectangle(cornerRadius: 12.r, style: .continuous))`
- Animated scaling examples

#### Custom Components
Expand All @@ -65,7 +60,7 @@ label.font = .systemFont(ofSize: 16.sp)
view.layer.cornerRadius = 8.r

// SwiftUI
Text("Hello").font(.scaledSystem(size: 16))
Text("Hello").font(.system(size: 16.sp))
Rectangle().frame(width: 100.w, height: 50.h)
```

Expand All @@ -86,8 +81,8 @@ ScreenUtil.shared.configure(with: config)
### 3. Batch Operations
```swift
let values = [10, 20, 30, 40, 50]
let scaledWidths = ScreenUtil.shared.batchWidths(values)
let scaledHeights = ScreenUtil.shared.batchHeights(values)
let scaledWidths = ScreenUtil.shared.batchScaler.widths(values)
let scaledHeights = ScreenUtil.shared.batchScaler.heights(values)
```

### 4. Fast Scaling
Expand All @@ -108,13 +103,10 @@ print("Device: \(ScreenUtil.shared.deviceType)")
### 6. Debug Tools
```swift
// Print current configuration
ScreenUtil.shared.debug.printCurrentConfiguration()
ScreenUtilDebug.printCurrentConfiguration()

// Run performance benchmark
ScreenUtil.shared.debug.benchmarkScalingOperations()

// Generate test report
let report = ScreenUtil.shared.debug.generateTestReport()
ScreenUtilDebug.benchmarkScalingOperations()
```

## Usage Instructions
Expand Down
Loading
Loading