Files
mobile-ios/Rosetta/Features/Calls/MinimizedCallBar.swift

89 lines
3.0 KiB
Swift

import SwiftUI
// MARK: - Minimized Call Bar (Telegram-style)
/// Telegram-style call status bar that sits at the very top of the screen,
/// extending into the safe area (status bar region). Content is centered
/// in the bottom 24pt of the bar. Tapping ANYWHERE on the gradient
/// (including the status bar area) expands back to full-screen.
struct MinimizedCallBar: View {
@ObservedObject var callManager: CallManager
private var state: CallUiState {
callManager.uiState
}
private var durationText: String {
let duration = max(state.durationSec, 0)
let minutes = duration / 60
let seconds = duration % 60
return String(format: "%d:%02d", minutes, seconds)
}
// Telegram colors: green=speaking, blue=muted/active, gray=connecting
private var gradientColors: [Color] {
switch state.phase {
case .active:
if state.isMuted {
// Blue gradient (muted)
return [Color(hex: 0x007FFF), Color(hex: 0x00AFFE)]
} else {
// Green gradient (speaking)
return [Color(hex: 0x33C659), Color(hex: 0x00A0B9)]
}
case .incoming:
return [Color(hex: 0x33C659), Color(hex: 0x00A0B9)]
case .outgoing, .keyExchange, .webRtcExchange:
// Gray (connecting)
return [Color(hex: 0xB6B6BB), Color(hex: 0xB6B6BB)]
case .ended:
return [Color(hex: 0xEF436C), Color(hex: 0xC0508D)]
case .idle:
return [Color(hex: 0x007FFF), Color(hex: 0x00AFFE)]
}
}
private var statusText: String {
switch state.phase {
case .active: return durationText
case .incoming: return "Tap to Answer"
case .outgoing: return "Ringing..."
case .keyExchange, .webRtcExchange: return "Connecting..."
case .ended: return "Ended"
case .idle: return ""
}
}
var body: some View {
// Content stays BELOW Dynamic Island. Only gradient extends behind it.
HStack(spacing: 5) {
Image(systemName: "phone.fill")
.font(.system(size: 12, weight: .bold))
Text(state.displayName)
.font(.system(size: 13, weight: .semibold))
.lineLimit(1)
Text(statusText)
.font(.system(size: 13, weight: .regular).monospacedDigit())
}
.foregroundStyle(.white)
.frame(height: 28)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.onTapGesture {
callManager.expandCall()
}
// Block swipe gestures bar responds to taps only.
.highPriorityGesture(DragGesture())
.background(
LinearGradient(
colors: gradientColors,
startPoint: .leading,
endPoint: .trailing
)
.ignoresSafeArea(edges: .top) // Only gradient extends behind Dynamic Island
)
}
}