mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 23:24:32 +00:00
Final Fix: Working with Animation
This commit is contained in:
parent
357335d35e
commit
2ece36fe09
6 changed files with 158 additions and 74 deletions
|
|
@ -16,56 +16,76 @@ struct PrivacyLiveActivity: View {
|
|||
@State private var gestureProgress: CGFloat = 0
|
||||
@State private var isExpanded: Bool = false
|
||||
|
||||
// Calculate if both camera and mic are active
|
||||
private var bothIndicatorsActive: Bool {
|
||||
privacyManager.indicatorLayout.showsCameraIndicator &&
|
||||
privacyManager.indicatorLayout.showsMicrophoneIndicator
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
// Left side - Recording pulsator (if recording is active)
|
||||
// Left side - Recording pulsator OR microphone (if both indicators active without recording)
|
||||
Color.clear
|
||||
.background {
|
||||
if recordingManager.isRecording && isExpanded {
|
||||
if isExpanded {
|
||||
HStack {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 6)
|
||||
.fill(Color.red.opacity(0.15))
|
||||
|
||||
Circle()
|
||||
.fill(Color.red)
|
||||
.frame(width: 10, height: 10)
|
||||
.modifier(PulsingModifier())
|
||||
if recordingManager.isRecording {
|
||||
// Recording pulsator
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 6)
|
||||
.fill(Color.red.opacity(0.15))
|
||||
|
||||
Circle()
|
||||
.fill(Color.red)
|
||||
.frame(width: 10, height: 10)
|
||||
.modifier(PulsingModifier())
|
||||
}
|
||||
.frame(width: vm.effectiveClosedNotchHeight - 12, height: vm.effectiveClosedNotchHeight - 12)
|
||||
} else if bothIndicatorsActive {
|
||||
// Microphone on left when both active and no recording
|
||||
PrivacyIcon(type: .microphone)
|
||||
}
|
||||
.frame(width: vm.effectiveClosedNotchHeight - 12, height: vm.effectiveClosedNotchHeight - 12)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
.frame(width: recordingManager.isRecording && isExpanded ? max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12) + gestureProgress / 2) : 0, height: vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12))
|
||||
.frame(width: isExpanded && (recordingManager.isRecording || bothIndicatorsActive) ? max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12) + gestureProgress / 2 + 20) : 0, height: vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12))
|
||||
|
||||
// Center - Black fill
|
||||
Rectangle()
|
||||
.fill(.black)
|
||||
.frame(width: vm.closedNotchSize.width + (isHovering ? 8 : 0))
|
||||
|
||||
// Right side - Privacy indicators (camera and/or microphone)
|
||||
// Right side - Privacy indicators
|
||||
Color.clear
|
||||
.background {
|
||||
if isExpanded {
|
||||
HStack(spacing: 8) {
|
||||
// Microphone indicator (shows first if both active)
|
||||
if privacyManager.indicatorLayout.showsMicrophoneIndicator {
|
||||
PrivacyIcon(type: .microphone)
|
||||
.transition(.scale.combined(with: .opacity))
|
||||
}
|
||||
HStack(spacing: 4) {
|
||||
// When both active without recording: only camera on right (mic is on left)
|
||||
// When recording + both: show both on right
|
||||
// When only one active: show that one
|
||||
|
||||
// Camera indicator
|
||||
if privacyManager.indicatorLayout.showsCameraIndicator {
|
||||
if bothIndicatorsActive && recordingManager.isRecording {
|
||||
// Both indicators on right when recording
|
||||
PrivacyIcon(type: .microphone)
|
||||
PrivacyIcon(type: .camera)
|
||||
.transition(.scale.combined(with: .opacity))
|
||||
} else if bothIndicatorsActive {
|
||||
// Only camera on right when both active (mic is on left)
|
||||
PrivacyIcon(type: .camera)
|
||||
} else {
|
||||
// Single indicator
|
||||
if privacyManager.indicatorLayout.showsMicrophoneIndicator {
|
||||
PrivacyIcon(type: .microphone)
|
||||
}
|
||||
if privacyManager.indicatorLayout.showsCameraIndicator {
|
||||
PrivacyIcon(type: .camera)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.trailing, 8)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .trailing)
|
||||
}
|
||||
}
|
||||
.frame(width: isExpanded ? max(0, vm.effectiveClosedNotchHeight + 30 + gestureProgress / 2) : 0, height: vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12))
|
||||
.frame(width: isExpanded ? max(0, vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12) + gestureProgress / 2 + 20) : 0, height: vm.effectiveClosedNotchHeight - (isHovering ? 0 : 12))
|
||||
}
|
||||
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0))
|
||||
.onAppear {
|
||||
|
|
@ -92,40 +112,23 @@ struct PrivacyIcon: View {
|
|||
let type: PrivacyIndicatorType
|
||||
@State private var isPulsing = false
|
||||
|
||||
// Color based on type: camera = #26CC41, mic = #FF9402
|
||||
private var iconColor: Color {
|
||||
type == .camera ? Color(red: 0.152, green: 0.804, blue: 0.256) : Color(red: 1.000, green: 0.584, blue: 0.010)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Glow effect
|
||||
Circle()
|
||||
.fill(
|
||||
RadialGradient(
|
||||
colors: [
|
||||
Color.orange.opacity(0.4),
|
||||
Color.orange.opacity(0.2),
|
||||
Color.clear
|
||||
],
|
||||
center: .center,
|
||||
startRadius: 0,
|
||||
endRadius: 10
|
||||
)
|
||||
)
|
||||
.frame(width: 20, height: 20)
|
||||
.opacity(isPulsing ? 0.8 : 0.5)
|
||||
|
||||
// Icon background
|
||||
Circle()
|
||||
.fill(Color.orange.opacity(0.2))
|
||||
.frame(width: 16, height: 16)
|
||||
|
||||
// Icon
|
||||
Image(systemName: type.icon)
|
||||
.font(.system(size: 8, weight: .semibold))
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
.frame(width: 20, height: 20)
|
||||
.onAppear {
|
||||
withAnimation(.easeInOut(duration: 1.5).repeatForever(autoreverses: true)) {
|
||||
isPulsing = true
|
||||
// Simple icon without blur/glow effects
|
||||
Image(systemName: type.icon)
|
||||
.font(.system(size: 13, weight: .semibold))
|
||||
.foregroundColor(iconColor)
|
||||
.frame(width: 24, height: 24)
|
||||
.scaleEffect(isPulsing ? 1.1 : 1.0)
|
||||
.opacity(isPulsing ? 1.0 : 0.85)
|
||||
.onAppear {
|
||||
withAnimation(.easeInOut(duration: 1.5).repeatForever(autoreverses: true)) {
|
||||
isPulsing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue