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

Fix: #94,#97,#99 #95

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PackageDescription

let package = Package(
name: "Chat",
defaultLocalization: "en",
platforms: [
.iOS(.v16)
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct AttachmentCell: View {
} else {
content
.overlay {
Text("Unknown")
Text("Unknown", bundle: .module)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ struct AttachmentsEditor<InputViewContent: View>: View {
seleсtedMedias = []
inputViewModel.showPicker = false
} label: {
Text("Cancel")
Text("Cancel", bundle: .module)
.foregroundColor(.white.opacity(0.7))
}

Spacer()
}

HStack {
Text("Recents")
Text("Recents", bundle: .module)
Image(systemName: "chevron.down")
.rotationEffect(Angle(radians: showingAlbums ? .pi : 0))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct AttachmentsPage: View {
.frame(minWidth: 100, minHeight: 100)
.frame(maxHeight: 200)
.overlay {
Text("Unknown")
Text("Unknown", bundle: .module)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ExyteChat/ChatView/ChatView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public struct ChatView<MessageContent: View, InputViewContent: View, MenuAction:
HStack {
Spacer()
Image("waiting", bundle: .current)
Text("Waiting for network")
Text("Waiting for network", bundle: .module)
Spacer()
}
.padding(.top, 6)
Expand Down
3 changes: 3 additions & 0 deletions Sources/ExyteChat/ChatView/ChatViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import Foundation
import Combine
import UIKit

final class ChatViewModel: ObservableObject {

Expand Down Expand Up @@ -43,6 +44,8 @@ final class ChatViewModel: ObservableObject {
@MainActor
func messageMenuActionInternal(message: Message, action: DefaultMessageMenuAction) {
switch action {
case .copy:
UIPasteboard.general.string = message.text
case .reply:
inputViewModel?.attachments.replyMessage = message.toReplyMessage()
globalFocusState?.focus = .uuid(inputFieldId)
Expand Down
10 changes: 6 additions & 4 deletions Sources/ExyteChat/ChatView/InputView/InputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ struct InputView: View {
.foregroundColor(theme.colors.myMessage)
.frame(width: 2)
VStack(alignment: .leading) {
Text("Reply to \(message.user.name)")
Text(String(localized: "Reply to \(message.user.name)", bundle: .module))
.font(.caption2)
.foregroundColor(theme.colors.buttonBackground)
if !message.text.isEmpty {
Expand Down Expand Up @@ -428,7 +428,7 @@ struct InputView: View {
} label: {
HStack {
theme.images.recordAudio.cancelRecord
Text("Cancel")
Text("Cancel", bundle: .module)
.font(.footnote)
.foregroundColor(theme.colors.textLightContext)
}
Expand All @@ -440,7 +440,7 @@ struct InputView: View {
var recordingInProgress: some View {
HStack {
Spacer()
Text("Recording...")
Text("Recording...", bundle: .module)
.font(.footnote)
.foregroundColor(theme.colors.textLightContext)
Spacer()
Expand Down Expand Up @@ -503,7 +503,9 @@ struct InputView: View {
}
.frame(width: 20)

RecordWaveformPlaying(samples: samples, progress: recordingPlayer.progress, color: theme.colors.textLightContext, addExtraDots: true)
RecordWaveformPlaying(samples: samples, progress: recordingPlayer.progress, color: theme.colors.textLightContext, addExtraDots: true) { progress in
recordingPlayer.seek(with: viewModel.attachments.recording!, to: progress)
}
}
.padding(.horizontal, 8)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ExyteChat/ChatView/InputView/TextInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct TextInputView: View {
TextField("", text: $text, axis: .vertical)
.customFocus($globalFocusState.focus, equals: .uuid(inputFieldId))
.placeholder(when: text.isEmpty) {
Text(style.placeholder)
Text(LocalizedStringKey(style.placeholder), bundle: .module)
.foregroundColor(theme.colors.buttonBackground)
}
.foregroundColor(style == .message ? theme.colors.textLightContext : theme.colors.textDarkContext)
Expand Down
20 changes: 13 additions & 7 deletions Sources/ExyteChat/ChatView/MessageView/MessageMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ public protocol MessageMenuAction: Equatable, CaseIterable {

public enum DefaultMessageMenuAction: MessageMenuAction {

case copy
case reply
case edit(saveClosure: (String)->Void)

public func title() -> String {
switch self {
case .copy:
"Copy"
case .reply:
"Reply"
case .edit:
Expand All @@ -30,6 +33,8 @@ public enum DefaultMessageMenuAction: MessageMenuAction {

public func icon() -> Image {
switch self {
case .copy:
Image(systemName: "doc.on.doc")
case .reply:
Image(.reply)
case .edit:
Expand All @@ -38,17 +43,18 @@ public enum DefaultMessageMenuAction: MessageMenuAction {
}

public static func == (lhs: DefaultMessageMenuAction, rhs: DefaultMessageMenuAction) -> Bool {
if case .reply = lhs, case .reply = rhs {
switch (lhs, rhs) {
case (.copy, .copy),
(.reply, .reply),
(.edit(_), .edit(_)):
return true
default:
return false
}
if case .edit(_) = lhs, case .edit(_) = rhs {
return true
}
return false
}

public static var allCases: [DefaultMessageMenuAction] = [
.reply, .edit(saveClosure: {_ in})
.copy, .reply, .edit(saveClosure: {_ in})
]
}

Expand Down Expand Up @@ -95,7 +101,7 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
.opacity(0.5)
.cornerRadius(12)
HStack {
Text(title)
Text(LocalizedStringKey(title), bundle: .module)
.foregroundColor(theme.colors.textLightContext)
Spacer()
icon
Expand Down
94 changes: 68 additions & 26 deletions Sources/ExyteChat/ChatView/Recording/RecordWaveform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ struct RecordWaveformWithButtons: View {

@StateObject var recordPlayer = RecordingPlayer()

// 160 is screen left-padding/right-padding and playButton's width.
// ensure that the view does not exceed the screen, need to subtract
// TODO: do not hardcode this value
static let viewPadding: CGFloat = 160

var recording: Recording

var colorButton: Color
Expand Down Expand Up @@ -42,31 +47,52 @@ struct RecordWaveformWithButtons: View {
}

VStack(alignment: .leading, spacing: 5) {
RecordWaveformPlaying(samples: recording.waveformSamples, progress: recordPlayer.progress, color: colorWaveform, addExtraDots: false)
RecordWaveformPlaying(samples: recording.waveformSamples, progress: recordPlayer.progress, color: colorWaveform, addExtraDots: false) { progress in
recordPlayer.seek(with: recording, to: progress)
}
Text(DateFormatter.timeString(duration))
.font(.caption2)
.monospacedDigit()
.foregroundColor(colorWaveform)
}
}
.onDisappear {
recordPlayer.pause()
}
}
}

struct RecordWaveformPlaying: View {

var samples: [CGFloat] // 0...1
var progress: CGFloat
var color: Color
var addExtraDots: Bool

var maxLength: CGFloat {
max((RecordWaveform.spacing + RecordWaveform.width) * CGFloat(samples.count) - RecordWaveform.spacing, 0)
var maxLength: CGFloat = 0.0

let progressChangeHandler: (CGFloat) -> Void

@State private var offset: CGSize = .zero

private var adjustedSamples: [CGFloat] = []

init(samples: [CGFloat],
progress: CGFloat,
color: Color,
addExtraDots: Bool,
progressChangeHandler: @escaping (CGFloat) -> Void) {
self.samples = samples
self.progress = progress
self.color = color
self.addExtraDots = addExtraDots
self.progressChangeHandler = progressChangeHandler
self.adjustedSamples = adjustedSamples(UIScreen.main.bounds.width)
self.maxLength = max((RecordWaveform.spacing + RecordWaveform.width) * CGFloat(self.adjustedSamples.count) - RecordWaveform.spacing, 0)
}

var body: some View {
GeometryReader { g in
ZStack {
let adjusted = adjustedSamples(g.size.width)
let adjusted = addExtraDots ? adjustedSamples(g.size.width) : adjustedSamples
RecordWaveform(samples: adjusted, addExtraDots: addExtraDots)
.foregroundColor(color.opacity(0.4))
RecordWaveform(samples: adjusted, addExtraDots: addExtraDots)
Expand All @@ -77,36 +103,52 @@ struct RecordWaveformPlaying: View {
}
}
.frame(height: RecordWaveform.maxSampleHeight)

}
.frame(height: RecordWaveform.maxSampleHeight)
.applyIf(!addExtraDots) {
$0.frame(width: maxLength)
}
.frame(maxWidth: addExtraDots ? .infinity : maxLength)
.fixedSize(horizontal: !addExtraDots, vertical: true)
.gesture(addDragGesture)
}

func adjustedSamples(_ width: CGFloat) -> [CGFloat] {
let maxWidth = addExtraDots ? width : UIScreen.main.bounds.width
let maxSamples = Int(maxWidth / (RecordWaveform.width + RecordWaveform.spacing))

var adjusted = samples
var temp = [CGFloat]()
while adjusted.count > maxSamples {
var i = 0
while i < adjusted.count {
if i == adjusted.count - 1 {
temp.append(adjusted[i])
break
private var addDragGesture: some Gesture {
DragGesture()
.onChanged { value in
offset = value.translation
}
.onEnded { _ in
let currentPosition = maxLength * progress
// multiply by 0.5 so that the sliding will not be too sensitive
var newPosition: CGFloat = currentPosition + offset.width * 0.5
if offset.width > 0 {
newPosition = min(newPosition, maxLength)
}else{
newPosition = max(newPosition, 0)
}

temp.append((adjusted[i] + adjusted[i+1])/2)
i+=2
let newProgress = newPosition / maxLength
progressChangeHandler(newProgress)
}
adjusted = temp
temp = []
}

func adjustedSamples(_ maxWidth: CGFloat) -> [CGFloat] {
let maxSamples = Int((maxWidth - RecordWaveformWithButtons.viewPadding) / (RecordWaveform.width + RecordWaveform.spacing))
let temp = samples

if temp.count <= maxSamples {
return temp
}

// use ceil to ensure that the adjusted.count will not be greater than maxSamples
let ratio = Int(ceil( Double(temp.count) / Double(maxSamples) ))
let adjusted = stride(from: 0, to: temp.count, by: ratio).map {
temp[$0]
}

return adjusted

}
}

Expand All @@ -126,9 +168,9 @@ struct RecordWaveform: View {
Capsule()
.frame(width: RecordWaveform.width, height: RecordWaveform.maxSampleHeight * CGFloat(s))
}

if addExtraDots {
ForEach(samples.count..<Int(g.size.width / (RecordWaveform.width + RecordWaveform.spacing)), id: \.self) { _ in
let maxSampleCounts = Int((g.size.width) / (RecordWaveform.width + RecordWaveform.spacing))
if addExtraDots && samples.count < maxSampleCounts {
ForEach(samples.count..<maxSampleCounts, id: \.self) { _ in
Capsule()
.viewSize(RecordWaveform.width)
}
Expand Down
Loading