Compare commits

...

2 Commits

Author SHA1 Message Date
67125b230f new chat view 2025-10-22 04:43:38 +03:00
44f7336c8d пупупу 2025-10-22 03:59:48 +03:00
2 changed files with 119 additions and 18 deletions

View File

@ -1526,6 +1526,9 @@
},
"Поиск отменён." : {
"comment" : "Search cancelled"
},
"Поиск стикеров" : {
},
"Пока что у вас нет чатов" : {
"localizations" : {
@ -2095,6 +2098,9 @@
}
}
}
},
"Стикеры" : {
},
"Тема: %@" : {
"comment" : "feedback: success category",

View File

@ -7,6 +7,8 @@ struct PrivateChatView: View {
@StateObject private var viewModel: PrivateChatViewModel
@State private var hasPositionedToBottom: Bool = false
@State private var draftText: String = ""
@State private var inputTab: ComposerTab = .chat
@State private var isVideoPreferred: Bool = false
@FocusState private var isComposerFocused: Bool
@EnvironmentObject private var messageCenter: IncomingMessageCenter
@ -206,28 +208,50 @@ struct PrivateChatView: View {
}
private var composer: some View {
VStack(spacing: 0) {
Divider()
VStack(spacing: 10) {
HStack(alignment: .bottom, spacing: 12) {
HStack(alignment: .center, spacing: 12) {
TextField(NSLocalizedString("Сообщение", comment: ""), text: $draftText, axis: .vertical)
.lineLimit(1...4)
.focused($isComposerFocused)
.submitLabel(.send)
.disabled(viewModel.isSending || currentUserId == nil)
.onSubmit { sendCurrentMessage() }
Button(action: sendCurrentMessage) {
Image(systemName: viewModel.isSending ? "hourglass" : "paperplane.fill")
Button(action: { }) { // переключатель на стикеры
Image(systemName: "paperclip")
.font(.system(size: 18, weight: .semibold))
.frame(width: 40, height: 40)
.foregroundColor(.secondary)
}
HStack(alignment: .center, spacing: 8) {
TextField(inputTab.placeholder, text: $draftText, axis: .vertical)
.lineLimit(1...4)
.focused($isComposerFocused)
.submitLabel(.send)
.disabled(viewModel.isSending || currentUserId == nil)
.onSubmit { sendCurrentMessage() }
Button(action: { }) { // переключатель на стикеры
Image(systemName: "face.smiling")
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.secondary)
}
}
.padding(.vertical, 10)
.padding(.horizontal, 12)
.background(Color(.secondarySystemBackground))
.clipShape(RoundedRectangle(cornerRadius: 18, style: .continuous))
if !isSendAvailable {
Button(action: { isVideoPreferred.toggle() }) {
Image(systemName: isVideoPreferred ? "video.fill" : "mic.fill")
.font(.system(size: 18, weight: .semibold))
.frame(width: 40, height: 40)
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
} else {
sendButton
}
.disabled(isSendDisabled)
.buttonStyle(.plain)
}
.padding(.vertical, 10)
.padding(.horizontal, 16)
.background(.clear)
}
.padding(.horizontal, 16)
.padding(.top, 10)
.padding(.bottom, 8)
.background(.ultraThinMaterial)
}
@ -235,6 +259,51 @@ struct PrivateChatView: View {
draftText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || viewModel.isSending || currentUserId == nil
}
private var isSendAvailable: Bool {
!draftText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && currentUserId != nil
}
private var sendButton: some View {
Button(action: sendCurrentMessage) {
Image(systemName: viewModel.isSending ? "hourglass" : "paperplane.fill")
.font(.system(size: 18, weight: .semibold))
.foregroundColor(.white)
.frame(width: 40, height: 40)
.background(Color.accentColor)
.clipShape(Circle())
}
.disabled(isSendDisabled)
.buttonStyle(.plain)
}
// private func composerToolbarButton(systemName: String, action: @escaping () -> Void) -> some View {
// Button(action: action) {
// Image(systemName: systemName)
// .font(.system(size: 16, weight: .medium))
// }
private func composerModeButton(_ tab: ComposerTab) -> some View {
Button(action: { inputTab = tab }) {
Text(tab.title)
.font(.caption)
.fontWeight(inputTab == tab ? .semibold : .regular)
.padding(.vertical, 8)
.padding(.horizontal, 14)
.background(
Group {
if inputTab == tab {
Color.accentColor.opacity(0.15)
} else {
Color(.secondarySystemBackground)
}
}
)
.foregroundColor(inputTab == tab ? .accentColor : .primary)
.clipShape(Capsule())
}
.buttonStyle(.plain)
}
private func sendCurrentMessage() {
let text = draftText.trimmingCharacters(in: .whitespacesAndNewlines)
guard !text.isEmpty else { return }
@ -247,6 +316,32 @@ struct PrivateChatView: View {
}
}
private enum ComposerTab: String {
case chat
case stickers
var title: String {
switch self {
case .chat: return NSLocalizedString("Чат", comment: "")
case .stickers: return NSLocalizedString("Стикеры", comment: "")
}
}
var iconName: String {
switch self {
case .chat: return "text.bubble"
case .stickers: return "face.smiling"
}
}
var placeholder: String {
switch self {
case .chat: return NSLocalizedString("Сообщение", comment: "")
case .stickers: return NSLocalizedString("Поиск стикеров", comment: "")
}
}
}
private static let timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .none