Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust layout and colors of the voice recording view #704

Merged
merged 7 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ 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.voiceMessageControlBackground`
- `Images.pauseFilled`

### 🐞 Fixed
- Use bright color for typing indicator animation in dark mode [#702](https://github.com/GetStream/stream-chat-swiftui/pull/702)
- Refresh quoted message preview when the quoted message is deleted [#705](https://github.com/GetStream/stream-chat-swiftui/pull/705)

### 🔄 Changed
- Support theming and update layout of `VoiceRecordingContainerView` [#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_

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct AddedVoiceRecordingsView: View {
let recording = addedVoiceRecordings[i]
VoiceRecordingView(
handler: voiceRecordingHandler,
textColor: textColor(currentUser: true),
addedVoiceRecording: recording,
index: i
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public struct VoiceRecordingContainerView<Factory: ViewFactory>: View {
}

public var body: some View {
VStack {
VStack(spacing: 0) {
VStack {
if let quotedMessage = utils.messageCachingUtils.quotedMessage(for: message) {
factory.makeQuotedMessageView(
Expand All @@ -49,24 +49,26 @@ public struct VoiceRecordingContainerView<Factory: ViewFactory>: 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)
}
}
Expand Down Expand Up @@ -94,11 +96,28 @@ public struct VoiceRecordingContainerView<Factory: ViewFactory>: 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
}
Expand All @@ -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

Expand All @@ -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.voiceMessageControlBackground,
cornerRadius: 18,
firstRadius: 2,
firstY: 4
)
)
})
.opacity(loading ? 0 : 1)
.overlay(loading ? ProgressView() : nil)
Expand All @@ -152,6 +179,7 @@ struct VoiceRecordingView: View {
)
.bold()
.lineLimit(1)
.foregroundColor(textColor)

HStack {
RecordingDurationView(
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,9 @@ extension View {
return Color(colors.messageOtherUserTextColor)
}
}

func textColor(currentUser: Bool) -> Color {
@Injected(\.colors) var colors
return currentUser ? Color(colors.messageCurrentUserTextColor) : Color(colors.messageOtherUserTextColor)
}
}
6 changes: 6 additions & 0 deletions Sources/StreamChatSwiftUI/ColorPalette.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ 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
public var voiceMessageControlBackground: UIColor = .streamWhiteStatic

// MARK: - Composer

Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions Sources/StreamChatSwiftUI/Images.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")!

Expand Down
3 changes: 2 additions & 1 deletion Sources/StreamChatSwiftUI/Utils/Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,23 +200,28 @@ class ChatChannelTestHelpers {
return fileAttachments
}

static func voiceRecordingAttachments(count: Int) -> [AnyChatMessageAttachment] {
(0..<count).map { index in
let title = index == 0 ? "Recording" : "Recording-\(index)"
let payload = VoiceRecordingAttachmentPayload(
title: title,
voiceRecordingRemoteURL: .localYodaImage,
file: try! .init(url: .localYodaImage),
duration: Double(index) + 5.0,
waveformData: [0, 0.1, 0.5, 1],
extraData: nil
)
return ChatMessageVoiceRecordingAttachment(
id: .unique,
type: .voiceRecording,
payload: payload,
downloadingState: nil,
uploadingState: nil
).asAnyAttachment
}
}

static var voiceRecordingAttachments: [AnyChatMessageAttachment] {
let payload = VoiceRecordingAttachmentPayload(
title: "Recording",
voiceRecordingRemoteURL: .localYodaImage,
file: try! .init(url: .localYodaImage),
duration: 5,
waveformData: [0, 0.1, 0.5, 1],
extraData: nil
)
let attachment = ChatMessageVoiceRecordingAttachment(
id: .unique,
type: .voiceRecording,
payload: payload,
downloadingState: nil,
uploadingState: nil
).asAnyAttachment

return [attachment]
voiceRecordingAttachments(count: 1)
}
}
Loading
Loading