diff --git a/CHANGELOG.md b/CHANGELOG.md index d52619b8..71ded5ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). # Upcoming +### ✅ Added +- Colors and images for voice recording view [#704](https://github.com/GetStream/stream-chat-swiftui/pull/704) + - `ColorPalette.voiceMessageCurrentUserBackground` and `ColorPalette.voiceMessageOtherUserBackground` + - `ColorPalette.voiceMessageCurrentUserRecordingBackground` and `ColorPalette.voiceMessageOtherUserRecordingBackground` + - `ColorPalette.staticWhiteBackground` + - `Images.pauseFilled` + ### 🐞 Fixed - Use bright color for typing indicator animation in dark mode [#702](https://github.com/GetStream/stream-chat-swiftui/pull/702) +### 🔄 Changed +- `VoiceRecordingContainerView`: adjust layout, update background colors and corner radii, use configurable text colors and assets [#704](https://github.com/GetStream/stream-chat-swiftui/pull/704) + # [4.69.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.69.0) _December 18, 2024_ diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift index 185d5543..e38726c5 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift @@ -29,6 +29,7 @@ struct AddedVoiceRecordingsView: View { let recording = addedVoiceRecordings[i] VoiceRecordingView( handler: voiceRecordingHandler, + textColor: textColor(currentUser: true), addedVoiceRecording: recording, index: i ) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift index 8dc2b2f6..8b3e7619 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift @@ -39,7 +39,7 @@ public struct VoiceRecordingContainerView: View { } public var body: some View { - VStack { + VStack(spacing: 0) { VStack { if let quotedMessage = utils.messageCachingUtils.quotedMessage(for: message) { factory.makeQuotedMessageView( @@ -49,24 +49,26 @@ public struct VoiceRecordingContainerView: View { scrolledId: $scrolledId ) } - - ForEach(message.voiceRecordingAttachments, id: \.self) { attachment in - VoiceRecordingView( - handler: handler, - addedVoiceRecording: AddedVoiceRecording( - url: attachment.payload.voiceRecordingURL, - duration: attachment.payload.duration ?? 0, - waveform: attachment.payload.waveformData ?? [] - ), - index: index(for: attachment) - ) + VStack(spacing: 2) { + ForEach(message.voiceRecordingAttachments, id: \.self) { attachment in + VoiceRecordingView( + handler: handler, + textColor: textColor(for: message), + addedVoiceRecording: AddedVoiceRecording( + url: attachment.payload.voiceRecordingURL, + duration: attachment.payload.duration ?? 0, + waveform: attachment.payload.waveformData ?? [] + ), + index: index(for: attachment) + ) + .padding(.all, 8) + .background(Color(recordingItemBackgroundColor)) + .roundWithBorder(cornerRadius: 14) + } } } - .padding(.all, 8) - .background(Color(colors.background8)) - .cornerRadius(16) if !message.text.isEmpty { - AttachmentTextView(message: message) + AttachmentTextView(message: message, injectedBackgroundColor: bubbleBackgroundColor) .frame(maxWidth: .infinity) } } @@ -94,11 +96,28 @@ public struct VoiceRecordingContainerView: View { } .modifier( factory.makeMessageViewModifier( - for: MessageModifierInfo(message: message, isFirst: isFirst) + for: MessageModifierInfo( + message: message, + isFirst: isFirst, + injectedBackgroundColor: bubbleBackgroundColor, + cornerRadius: 16 + ) ) ) } + private var bubbleBackgroundColor: UIColor { + message.isSentByCurrentUser ? + colors.voiceMessageCurrentUserBackground : + colors.voiceMessageOtherUserBackground + } + + private var recordingItemBackgroundColor: UIColor { + message.isSentByCurrentUser ? + colors.voiceMessageCurrentUserRecordingBackground : + colors.voiceMessageOtherUserRecordingBackground + } + private func index(for attachment: ChatMessageVoiceRecordingAttachment) -> Int { message.voiceRecordingAttachments.firstIndex(of: attachment) ?? 0 } @@ -114,6 +133,7 @@ struct VoiceRecordingView: View { @State var rate: AudioPlaybackRate = .normal @ObservedObject var handler: VoiceRecordingHandler + let textColor: Color let addedVoiceRecording: AddedVoiceRecording let index: Int @@ -135,10 +155,17 @@ struct VoiceRecordingView: View { Button(action: { handlePlayTap() }, label: { - Image(systemName: isPlaying ? "pause.fill" : "play.fill") - .padding(.all, 8) + Image(uiImage: isPlaying ? images.pauseFilled : images.playFilled) + .frame(width: 36, height: 36) .foregroundColor(.primary) - .modifier(ShadowViewModifier(firstRadius: 2, firstY: 4)) + .modifier( + ShadowViewModifier( + backgroundColor: colors.staticWhiteBackground, + cornerRadius: 18, + firstRadius: 2, + firstY: 4 + ) + ) }) .opacity(loading ? 0 : 1) .overlay(loading ? ProgressView() : nil) @@ -152,6 +179,7 @@ struct VoiceRecordingView: View { ) .bold() .lineLimit(1) + .foregroundColor(textColor) HStack { RecordingDurationView( @@ -199,7 +227,7 @@ struct VoiceRecordingView: View { Image(uiImage: images.fileAac) .resizable() .aspectRatio(contentMode: .fit) - .frame(height: 36) + .frame(height: 40) } } .onReceive(handler.$context, perform: { value in diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift index 553fe025..b7600ac8 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift @@ -110,9 +110,11 @@ public struct AttachmentTextView: View { @Injected(\.fonts) private var fonts var message: ChatMessage + let injectedBackgroundColor: UIColor? - public init(message: ChatMessage) { + public init(message: ChatMessage, injectedBackgroundColor: UIColor? = nil) { self.message = message + self.injectedBackgroundColor = injectedBackgroundColor } public var body: some View { @@ -127,6 +129,9 @@ public struct AttachmentTextView: View { } private var backgroundColor: UIColor { + if let injectedBackgroundColor { + return injectedBackgroundColor + } var colors = colors if message.isSentByCurrentUser { if message.type == .ephemeral { diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift index 0b0513a9..9f127ff8 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift @@ -199,4 +199,9 @@ extension View { return Color(colors.messageOtherUserTextColor) } } + + func textColor(currentUser: Bool) -> Color { + @Injected(\.colors) var colors + return currentUser ? Color(colors.messageCurrentUserTextColor) : Color(colors.messageOtherUserTextColor) + } } diff --git a/Sources/StreamChatSwiftUI/ColorPalette.swift b/Sources/StreamChatSwiftUI/ColorPalette.swift index cd540a36..7de8fb0a 100644 --- a/Sources/StreamChatSwiftUI/ColorPalette.swift +++ b/Sources/StreamChatSwiftUI/ColorPalette.swift @@ -50,6 +50,7 @@ public struct ColorPalette { public var highlightedAccentBackground: UIColor = .streamAccentBlue public var highlightedAccentBackground1: UIColor = .streamBlueAlice public var pinnedBackground: UIColor = .streamHighlight + public var staticWhiteBackground: UIColor = .streamWhiteStatic // MARK: - Borders and shadows @@ -79,6 +80,10 @@ public struct ColorPalette { public lazy var reactionCurrentUserColor: UIColor? = UIColor(tintColor) public lazy var reactionOtherUserColor: UIColor? = textLowEmphasis public lazy var selectedReactionBackgroundColor: UIColor? = nil + public var voiceMessageCurrentUserBackground: UIColor = .streamInnerBorder + public var voiceMessageOtherUserBackground: UIColor = .streamBarsBackground + public var voiceMessageCurrentUserRecordingBackground: UIColor = .streamBarsBackground + public var voiceMessageOtherUserRecordingBackground: UIColor = .streamBarsBackground // MARK: - Composer @@ -114,6 +119,7 @@ private extension UIColor { static let streamInnerBorder = mode(0xdbdde1, 0x272a30) static let streamHighlight = mode(0xfbf4dd, 0x333024) static let streamDisabled = mode(0xb4b7bb, 0x4c525c) + static let streamBarsBackground = mode(0xffffff, 0x17191c) // Currently we are not using the correct shadow color from figma's color palette. This is to avoid // an issue with snapshots inconsistency between Intel vs M1. We can't use shadows with transparency. diff --git a/Sources/StreamChatSwiftUI/Images.swift b/Sources/StreamChatSwiftUI/Images.swift index eb236ed8..e34bc504 100644 --- a/Sources/StreamChatSwiftUI/Images.swift +++ b/Sources/StreamChatSwiftUI/Images.swift @@ -237,6 +237,7 @@ public class Images { public var play: UIImage = loadImageSafely(with: "play") public var playFilled: UIImage = UIImage(systemName: "play.fill")! public var pause: UIImage = loadImageSafely(with: "pause") + public var pauseFilled: UIImage = loadImageSafely(with: "pause.fill") public var checkmarkFilled: UIImage = UIImage(systemName: "checkmark.circle.fill")! diff --git a/Sources/StreamChatSwiftUI/Utils/Modifiers.swift b/Sources/StreamChatSwiftUI/Utils/Modifiers.swift index 49172578..9796bfe9 100644 --- a/Sources/StreamChatSwiftUI/Utils/Modifiers.swift +++ b/Sources/StreamChatSwiftUI/Utils/Modifiers.swift @@ -8,12 +8,13 @@ import SwiftUI struct ShadowViewModifier: ViewModifier { @Injected(\.colors) private var colors + var backgroundColor: UIColor = .systemBackground var cornerRadius: CGFloat = 16 var firstRadius: CGFloat = 10 var firstY: CGFloat = 12 func body(content: Content) -> some View { - content.background(Color(UIColor.systemBackground)) + content.background(Color(backgroundColor)) .cornerRadius(cornerRadius) .modifier(ShadowModifier(firstRadius: firstRadius, firstY: firstY)) .overlay( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift index 8e6eeec9..c2bb39f0 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift @@ -200,23 +200,28 @@ class ChatChannelTestHelpers { return fileAttachments } + static func voiceRecordingAttachments(count: Int) -> [AnyChatMessageAttachment] { + (0..