Files
MagicCounter/ios/MagicCounter/Components.swift
2025-12-07 23:58:13 -07:00

132 lines
3.5 KiB
Swift

//
// Components.swift
// MagicCounter
//
// Created by Atridad Lahiji on 2025-12-06.
//
import SwiftUI
/**
* A circular button with an icon, used for game controls.
*/
struct CircleButton: View {
let icon: String
let color: Color
let size: CGFloat
let action: () -> Void
init(icon: String, color: Color, size: CGFloat = 44, action: @escaping () -> Void) {
self.icon = icon
self.color = color
self.size = size
self.action = action
}
var body: some View {
Button(action: action) {
Image(systemName: icon)
.font(size < 40 ? .caption : .title3)
.frame(width: size, height: size)
.background(color.opacity(0.2))
.clipShape(Circle())
.foregroundStyle(color)
}
}
}
/**
* A control for adjusting a large numerical value (like Life).
*/
struct LifeCounterControl: View {
let value: Int
let onDecrease: () -> Void
let onIncrease: () -> Void
var body: some View {
HStack(spacing: 16) {
CircleButton(icon: "minus", color: .red, action: onDecrease)
Text("\(value)")
.font(.system(size: 56, weight: .bold, design: .rounded))
.minimumScaleFactor(0.5)
.lineLimit(1)
.foregroundStyle(.primary)
CircleButton(icon: "plus", color: .green, action: onIncrease)
}
.padding(.horizontal, 16)
}
}
/**
* A smaller control for adjusting secondary values (like Poison).
*/
struct SmallCounterControl: View {
let value: Int
let icon: String
let color: Color
let onDecrease: () -> Void
let onIncrease: () -> Void
var body: some View {
HStack(spacing: 4) {
CircleButton(icon: "minus", color: .gray, size: 24, action: onDecrease)
VStack(spacing: 0) {
Image(systemName: icon)
.font(.caption2)
.foregroundStyle(color)
Text("\(value)")
.font(.title3.bold())
.foregroundStyle(color)
}
.frame(minWidth: 30)
CircleButton(icon: "plus", color: .gray, size: 24, action: onIncrease)
}
.padding(6)
.background(color.opacity(0.1))
.cornerRadius(12)
}
}
/**
* A reusable slider row for settings.
*/
struct SettingSlider: View {
let title: String
let value: Binding<Double>
let range: ClosedRange<Double>
let step: Double
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(title)
Spacer()
Text("\(Int(value.wrappedValue))")
.bold()
}
Slider(value: value, in: range, step: step)
}
}
}
/**
* Helper for haptic feedback.
*/
enum Haptics {
static func play(_ style: UIImpactFeedbackGenerator.FeedbackStyle) {
guard UserDefaults.standard.bool(forKey: "hapticFeedbackEnabled") else { return }
let generator = UIImpactFeedbackGenerator(style: style)
generator.impactOccurred()
}
static func notification(_ type: UINotificationFeedbackGenerator.FeedbackType) {
guard UserDefaults.standard.bool(forKey: "hapticFeedbackEnabled") else { return }
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(type)
}
}