CasinoGames/TOOLTIP_REFACTORING.md

247 lines
6.7 KiB
Markdown

# Tooltip System Refactoring
## Overview
The tooltip management system has been refactored from game-specific implementations to a generic, reusable system in CasinoKit.
## Problem
The original implementation had several issues:
- **Verbose**: Each game had duplicate `TooltipConfig` structs and complex state management
- **Not scalable**: Adding new tooltips required significant boilerplate
- **Repetitive logic**: Similar code duplicated across Blackjack and Baccarat
- **Difficult to maintain**: Changes required updates in multiple places
## Solution
Created a centralized `TooltipManager` class in CasinoKit that:
- Manages tooltip state generically
- Automatically handles dismiss tracking
- Ensures only one tooltip shows at a time
- Integrates seamlessly with `OnboardingState`
## New Components
### 1. `TooltipConfig` (CasinoKit)
A simple struct defining tooltip properties:
```swift
public struct TooltipConfig: Equatable {
public let key: String
public let message: String
public let icon: String
public let position: ContextualTooltip.TooltipPosition
}
```
### 2. `TooltipManager` (CasinoKit)
An `@Observable` class that manages tooltip lifecycle:
```swift
@Observable
@MainActor
public final class TooltipManager {
private let onboarding: OnboardingState
public var currentTooltip: TooltipConfig?
public func show(
key: String,
message: String,
icon: String = "lightbulb.fill",
position: ContextualTooltip.TooltipPosition = .bottom,
delay: TimeInterval = 1.0
)
public func dismiss()
}
```
**Key Features:**
- Automatic dismiss tracking via `didSet` on `currentTooltip`
- Delayed presentation with cancellation if hint already shown
- Respects `OnboardingState.shouldShowHint()` checks
- Single source of truth for current tooltip
### 3. `dynamicTooltip` View Modifier (CasinoKit)
A convenient view modifier that displays tooltips:
```swift
public extension View {
func dynamicTooltip(_ manager: TooltipManager) -> some View
}
```
## Usage in Games
### Before (Verbose)
```swift
// State variables for each tooltip
@State private var showBettingHint = false
@State private var showDealHint = false
@State private var showActionsHint = false
// Separate struct definition
private struct TooltipConfig {
let key: String
let message: String
let icon: String
let position: ContextualTooltip.TooltipPosition
}
// Complex state with tracking
@State private var currentTooltip: TooltipConfig? {
didSet {
if let oldValue = oldValue, oldValue.key != currentTooltip?.key {
state.onboarding.markHintShown(oldValue.key)
}
}
}
// Generic helper with lots of parameters
private func showTooltip(key: String, message: String, icon: String, position: ContextualTooltip.TooltipPosition, delay: TimeInterval) {
Task { @MainActor in
try? await Task.sleep(for: .seconds(delay))
guard state.onboarding.shouldShowHint(key) else { return }
withAnimation(.spring(duration: Design.Animation.springDuration)) {
currentTooltip = TooltipConfig(key: key, message: message, icon: icon, position: position)
}
}
}
// Complex overlay in view body
.overlay {
if let tooltip = currentTooltip {
VStack {
// ... positioning logic
ContextualTooltip(
message: tooltip.message,
icon: tooltip.icon,
position: tooltip.position,
onDismiss: {
state.onboarding.markHintShown(tooltip.key)
withAnimation(.spring(duration: Design.Animation.springDuration)) {
currentTooltip = nil
}
}
)
// ... more positioning
}
}
}
```
### After (Clean)
```swift
// Single state variable
@State private var tooltipManager: TooltipManager?
// Initialize in onAppear
.onAppear {
tooltipManager = TooltipManager(onboarding: state.onboarding)
}
// Simple show calls
private func showBettingHint() {
tooltipManager?.show(
key: "bettingZone",
message: "Select a chip and tap here to bet",
icon: "hand.tap.fill",
position: .bottom,
delay: 1.0
)
}
// One-line view modifier
.dynamicTooltip(tooltipManager ?? TooltipManager(onboarding: state.onboarding))
```
## Benefits
1. **Reduced code**: ~70 lines of boilerplate eliminated per game
2. **Better scalability**: Adding new tooltips is now trivial
3. **Single source of truth**: All tooltip logic in CasinoKit
4. **Easier maintenance**: Changes only need to be made in one place
5. **Reusable**: Any new game can use `TooltipManager` with minimal setup
## Files Changed
### CasinoKit
- **Created**: `Sources/CasinoKit/Models/TooltipManager.swift`
- **Updated**: `Sources/CasinoKit/Exports.swift` (added TooltipManager export)
- **Updated**: `README.md` (added TooltipManager documentation)
### Blackjack
- **Updated**: `Views/Game/GameTableView.swift`
- Removed local `TooltipConfig` struct
- Removed `currentTooltip` @State with didSet
- Removed generic `showTooltip()` helper
- Added `@State private var tooltipManager: TooltipManager?`
- Simplified tooltip show methods
- Replaced complex overlay with `.dynamicTooltip()` modifier
### Baccarat
- **Updated**: `Views/Game/GameTableView.swift`
- Same changes as Blackjack
## Migration Guide
To use `TooltipManager` in a new game:
1. **Add state variable:**
```swift
@State private var tooltipManager: TooltipManager?
```
2. **Initialize in onAppear:**
```swift
.onAppear {
tooltipManager = TooltipManager(onboarding: gameState.onboarding)
}
```
3. **Apply view modifier:**
```swift
.dynamicTooltip(tooltipManager ?? TooltipManager(onboarding: gameState.onboarding))
```
4. **Show tooltips:**
```swift
tooltipManager?.show(
key: "uniqueKey",
message: "Your hint text",
icon: "lightbulb.fill",
position: .bottom,
delay: 1.0
)
```
## Testing
Both Blackjack and Baccarat have been built and tested successfully with the new system.
```bash
# Blackjack
xcodebuild -workspace CasinoGames.xcworkspace -scheme Blackjack \
-configuration Debug -destination 'platform=iOS Simulator,id=...' build
# ✅ BUILD SUCCEEDED
# Baccarat
xcodebuild -workspace CasinoGames.xcworkspace -scheme Baccarat \
-configuration Debug -destination 'platform=iOS Simulator,id=...' build
# ✅ BUILD SUCCEEDED
```
## Future Enhancements
Potential improvements:
- **Tooltip queue**: Allow queueing multiple tooltips
- **Positioning hints**: Auto-detect best position based on screen space
- **Animation customization**: Per-tooltip animation styles
- **Analytics**: Track which tooltips are most helpful