288 lines
6.3 KiB
Swift
288 lines
6.3 KiB
Swift
//
|
|
// BatteryOverlayView.swift
|
|
// TheNoiseClock
|
|
//
|
|
// Created by Matt Bruce on 9/7/25.
|
|
//
|
|
|
|
import SwiftUI
|
|
import Combine
|
|
|
|
/// Component for displaying battery level overlay
|
|
struct BatteryOverlayView: View {
|
|
|
|
// MARK: - Properties
|
|
let color: Color
|
|
let opacity: Double
|
|
let batteryLevel: Int
|
|
let isCharging: Bool
|
|
|
|
// MARK: - Body
|
|
var body: some View {
|
|
let clamped = ColorUtils.clampOpacity(opacity)
|
|
let batteryIcon = getBatteryIcon()
|
|
let batteryColor = getBatteryColor()
|
|
|
|
HStack(spacing: 4) {
|
|
Image(systemName: batteryIcon)
|
|
.foregroundColor(batteryColor)
|
|
Text("\(batteryLevel)%")
|
|
.foregroundColor(color)
|
|
}
|
|
.opacity(clamped)
|
|
.font(.callout.weight(.semibold))
|
|
}
|
|
|
|
// MARK: - Private Methods
|
|
private func getBatteryIcon() -> String {
|
|
// Show charging icon when charging
|
|
if isCharging {
|
|
return "bolt.circle.fill"
|
|
}
|
|
|
|
// Return battery icon based on level
|
|
switch batteryLevel {
|
|
case 75...100:
|
|
return "battery.100"
|
|
case 50..<75:
|
|
return "battery.75"
|
|
case 25..<50:
|
|
return "battery.50"
|
|
case 10..<25:
|
|
return "battery.25"
|
|
default:
|
|
return "battery.0"
|
|
}
|
|
}
|
|
|
|
private func getBatteryColor() -> Color {
|
|
// Green when charging
|
|
if isCharging {
|
|
return .green
|
|
}
|
|
|
|
// Color based on battery level
|
|
switch batteryLevel {
|
|
case 50...100:
|
|
return .green
|
|
case 20..<50:
|
|
return .yellow
|
|
case 10..<20:
|
|
return .orange
|
|
default:
|
|
return .red
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Previews
|
|
#Preview("Battery Overlay - Full Charge") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 100,
|
|
isCharging: false
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - High Charge") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Medium Charge") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 50,
|
|
isCharging: false
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Low Charge") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 25,
|
|
isCharging: false
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Critical Charge") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 10,
|
|
isCharging: false
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Charging") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 85,
|
|
isCharging: true
|
|
)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Charging States") {
|
|
VStack(spacing: 20) {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: true
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 25,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 25,
|
|
isCharging: true
|
|
)
|
|
}
|
|
.padding()
|
|
.background(Color.black)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Different Colors") {
|
|
VStack(spacing: 20) {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .blue,
|
|
opacity: 1.0,
|
|
batteryLevel: 50,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .green,
|
|
opacity: 1.0,
|
|
batteryLevel: 25,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .red,
|
|
opacity: 1.0,
|
|
batteryLevel: 10,
|
|
isCharging: false
|
|
)
|
|
}
|
|
.padding()
|
|
.background(Color.black)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Different Opacities") {
|
|
VStack(spacing: 20) {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 0.7,
|
|
batteryLevel: 50,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 0.5,
|
|
batteryLevel: 25,
|
|
isCharging: false
|
|
)
|
|
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 0.3,
|
|
batteryLevel: 10,
|
|
isCharging: false
|
|
)
|
|
}
|
|
.padding()
|
|
.background(Color.black)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Dark Background") {
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 1.0,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
.padding()
|
|
.background(Color.black)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Light Background") {
|
|
BatteryOverlayView(
|
|
color: .black,
|
|
opacity: 1.0,
|
|
batteryLevel: 50,
|
|
isCharging: false
|
|
)
|
|
.padding()
|
|
.background(Color.white)
|
|
}
|
|
|
|
#Preview("Battery Overlay - Clock Context") {
|
|
ZStack {
|
|
// Simulate clock background
|
|
Color.black
|
|
.ignoresSafeArea()
|
|
|
|
VStack {
|
|
Spacer()
|
|
|
|
// Simulate clock display
|
|
Text("12:34")
|
|
.font(.system(size: 80, weight: .bold, design: .rounded))
|
|
.foregroundColor(.white)
|
|
|
|
Spacer()
|
|
|
|
// Battery overlay at bottom
|
|
HStack {
|
|
Spacer()
|
|
BatteryOverlayView(
|
|
color: .white,
|
|
opacity: 0.8,
|
|
batteryLevel: 75,
|
|
isCharging: false
|
|
)
|
|
Spacer()
|
|
}
|
|
.padding(.bottom, 50)
|
|
}
|
|
}
|
|
}
|