71 lines
2.5 KiB
Swift
71 lines
2.5 KiB
Swift
|
import Foundation
|
||
|
import SwiftUI
|
||
|
|
||
|
struct ConversationMessageRow: View {
|
||
|
@EnvironmentObject var store: AppStore
|
||
|
|
||
|
let message: Message
|
||
|
@State private var offset: CGSize = .zero
|
||
|
|
||
|
var body: some View {
|
||
|
VStack(spacing: 0) {
|
||
|
HStack(spacing: 0) {
|
||
|
if isOutgoing() {
|
||
|
Spacer()
|
||
|
MessageAttr(message: message)
|
||
|
.padding(.trailing, 4)
|
||
|
}
|
||
|
ConversationMessageContainer(message: message, isOutgoing: isOutgoing())
|
||
|
.background(isOutgoing() ? Color.Material.greenDark100 : Color.Main.white)
|
||
|
.clipShape(ConversationMessageBubble(isOutgoing: isOutgoing()))
|
||
|
if !isOutgoing() {
|
||
|
MessageAttr(message: message)
|
||
|
.padding(.leading, 4)
|
||
|
Spacer()
|
||
|
}
|
||
|
}
|
||
|
.padding(.vertical, 10)
|
||
|
.padding(.horizontal, 16)
|
||
|
.background(Color.clearTappable)
|
||
|
.offset(offset)
|
||
|
.gesture(
|
||
|
DragGesture(minimumDistance: 20, coordinateSpace: .local)
|
||
|
.onEnded { value in
|
||
|
withAnimation(.easeOut(duration: 0.1)) {
|
||
|
if value.translation.width < 0 {
|
||
|
offset = CGSize(width: -50, height: 0)
|
||
|
Vibration.success.vibrate()
|
||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
|
||
|
store.dispatch(.conversationAction(.setReplyText(message.body ?? "")))
|
||
|
withAnimation(.easeOut(duration: 0.1)) {
|
||
|
offset = .zero
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
offset = .zero
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
.sharedListRow()
|
||
|
}
|
||
|
|
||
|
private func isOutgoing() -> Bool {
|
||
|
message.from == store.state.conversationsState.currentChat?.account
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct ConversationMessageBubble: Shape {
|
||
|
let isOutgoing: Bool
|
||
|
|
||
|
func path(in rect: CGRect) -> Path {
|
||
|
let path = UIBezierPath(
|
||
|
roundedRect: rect,
|
||
|
byRoundingCorners: isOutgoing ? [.topLeft, .bottomLeft, .bottomRight] : [.topRight, .bottomLeft, .bottomRight],
|
||
|
cornerRadii: CGSize(width: 8, height: 10)
|
||
|
)
|
||
|
return Path(path.cgPath)
|
||
|
}
|
||
|
}
|