// // Copyright 2023, 2024 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. // import SwiftUI struct VoiceMessageButton: View { @ScaledMetric private var buttonSize: CGFloat enum State { case loading case playing case paused } enum Size { case small case medium } let state: State let action: () -> Void init(state: State, size: Size, action: @escaping () -> Void) { switch size { case .small: _buttonSize = .init(wrappedValue: 30) case .medium: _buttonSize = .init(wrappedValue: 36) } self.state = state self.action = action } var body: some View { Button(action: action) { buttonLabel .frame(width: buttonSize, height: buttonSize) } .animation(nil, value: state) .buttonStyle(VoiceMessageButtonStyle()) .disabled(state == .loading) .accessibilityLabel(accessibilityLabel) } @ViewBuilder private var buttonLabel: some View { switch state { case .loading: ProgressView() case .playing, .paused: let imageAsset = state == .playing ? Asset.Images.mediaPause : Asset.Images.mediaPlay let offset: CGFloat = state == .playing ? 0 : 2 Image(asset: imageAsset) .resizable() .scaledToFit() .scaledFrame(width: 12, height: 14) .offset(x: offset) } } private var accessibilityLabel: String { switch state { case .loading: return "" case .playing: return L10n.a11yPause case .paused: return L10n.a11yPlay } } } private struct VoiceMessageButtonStyle: ButtonStyle { @Environment(\.isEnabled) var isEnabled: Bool func makeBody(configuration: Configuration) -> some View { configuration.label .foregroundColor(isEnabled ? .compound.textSecondary.opacity(configuration.isPressed ? 0.6 : 1) : .compound.iconDisabled) .background( Circle() .foregroundColor(configuration.isPressed ? .compound.bgSubtlePrimary : .compound.bgCanvasDefault) ) } } extension VoiceMessageButton.State { init(_ state: AudioPlayerPlaybackState) { switch state { case .loading: self = .loading case .playing: self = .playing case .stopped, .error, .readyToPlay: self = .paused } } } struct VoiceMessageButton_Previews: PreviewProvider, TestablePreview { static var previews: some View { VStack(spacing: 8) { HStack(spacing: 8) { VoiceMessageButton(state: .paused, size: .small) { } VoiceMessageButton(state: .paused, size: .medium) { } } HStack(spacing: 8) { VoiceMessageButton(state: .playing, size: .small) { } VoiceMessageButton(state: .playing, size: .medium) { } } } .padding() .background(Color.gray) } }