| 1721 | } |
| 1722 | |
| 1723 | struct CompactNotchWaveformView: View { |
| 1724 | let audioPublisher: AnyPublisher<CGFloat, Never> |
| 1725 | let color: Color |
| 1726 | |
| 1727 | @StateObject private var data: AudioVisualizationData |
| 1728 | @ObservedObject private var contentState = NotchContentState.shared |
| 1729 | @State private var barHeights: [CGFloat] = Array(repeating: 3, count: 8) |
| 1730 | |
| 1731 | private let barCount = 8 |
| 1732 | private let barWidth: CGFloat = 2.5 |
| 1733 | private let barSpacing: CGFloat = 2 |
| 1734 | private let minHeight: CGFloat = 3 |
| 1735 | private let maxHeight: CGFloat = 15 |
| 1736 | private let noiseThreshold: CGFloat = 0.05 |
| 1737 | private let processingFlatHeight: CGFloat = 3 |
| 1738 | |
| 1739 | init(audioPublisher: AnyPublisher<CGFloat, Never>, color: Color) { |
| 1740 | self.audioPublisher = audioPublisher |
| 1741 | self.color = color |
| 1742 | _data = StateObject(wrappedValue: AudioVisualizationData(audioLevelPublisher: audioPublisher)) |
| 1743 | } |
| 1744 | |
| 1745 | var body: some View { |
| 1746 | ZStack { |
| 1747 | self.barsView(using: { index in |
| 1748 | self.displayHeight(for: index) |
| 1749 | }) |
| 1750 | .foregroundStyle(self.color.opacity(self.contentState.isProcessing ? 0.16 : 1.0)) |
| 1751 | |
| 1752 | if self.contentState.isProcessing { |
| 1753 | CompositorShimmerSweep(duration: 1.05, peakOpacity: 0.9) |
| 1754 | .mask { |
| 1755 | self.barsView(using: { index in |
| 1756 | self.displayHeight(for: index) |
| 1757 | }) |
| 1758 | } |
| 1759 | .shadow(color: .white.opacity(0.28), radius: 2.5, x: 0, y: 0) |
| 1760 | } |
| 1761 | } |
| 1762 | .onChange(of: self.data.audioLevel) { _, level in |
| 1763 | if !self.contentState.isProcessing { |
| 1764 | self.updateBars(level: level) |
| 1765 | } |
| 1766 | } |
| 1767 | .onChange(of: self.contentState.isProcessing) { _, processing in |
| 1768 | if processing { |
| 1769 | self.resetBarsToBaseline(animated: false) |
| 1770 | } else { |
| 1771 | self.updateBars(level: self.data.audioLevel) |
| 1772 | } |
| 1773 | } |
| 1774 | .onAppear { |
| 1775 | if self.contentState.isProcessing { |
| 1776 | self.resetBarsToBaseline(animated: false) |
| 1777 | } else { |
| 1778 | self.updateBars(level: self.data.audioLevel) |
| 1779 | } |
| 1780 | } |
no test coverage detected