Compare commits
	
		
			2 Commits
		
	
	
		
			266742e15d
			...
			67125b230f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 67125b230f | |||
| 44f7336c8d | 
@ -1526,6 +1526,9 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "Поиск отменён." : {
 | 
					    "Поиск отменён." : {
 | 
				
			||||||
      "comment" : "Search cancelled"
 | 
					      "comment" : "Search cancelled"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Поиск стикеров" : {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Пока что у вас нет чатов" : {
 | 
					    "Пока что у вас нет чатов" : {
 | 
				
			||||||
      "localizations" : {
 | 
					      "localizations" : {
 | 
				
			||||||
@ -2095,6 +2098,9 @@
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Стикеры" : {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Тема: %@" : {
 | 
					    "Тема: %@" : {
 | 
				
			||||||
      "comment" : "feedback: success category",
 | 
					      "comment" : "feedback: success category",
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,8 @@ struct PrivateChatView: View {
 | 
				
			|||||||
    @StateObject private var viewModel: PrivateChatViewModel
 | 
					    @StateObject private var viewModel: PrivateChatViewModel
 | 
				
			||||||
    @State private var hasPositionedToBottom: Bool = false
 | 
					    @State private var hasPositionedToBottom: Bool = false
 | 
				
			||||||
    @State private var draftText: String = ""
 | 
					    @State private var draftText: String = ""
 | 
				
			||||||
 | 
					    @State private var inputTab: ComposerTab = .chat
 | 
				
			||||||
 | 
					    @State private var isVideoPreferred: Bool = false
 | 
				
			||||||
    @FocusState private var isComposerFocused: Bool
 | 
					    @FocusState private var isComposerFocused: Bool
 | 
				
			||||||
    @EnvironmentObject private var messageCenter: IncomingMessageCenter
 | 
					    @EnvironmentObject private var messageCenter: IncomingMessageCenter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -206,28 +208,50 @@ struct PrivateChatView: View {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var composer: some View {
 | 
					    private var composer: some View {
 | 
				
			||||||
        VStack(spacing: 0) {
 | 
					        VStack(spacing: 10) {
 | 
				
			||||||
            Divider()
 | 
					            HStack(alignment: .bottom, spacing: 12) {
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
            HStack(alignment: .center, spacing: 12) {
 | 
					                Button(action: {  }) { // переключатель на стикеры
 | 
				
			||||||
                TextField(NSLocalizedString("Сообщение", comment: ""), text: $draftText, axis: .vertical)
 | 
					                    Image(systemName: "paperclip")
 | 
				
			||||||
                    .lineLimit(1...4)
 | 
					 | 
				
			||||||
                    .focused($isComposerFocused)
 | 
					 | 
				
			||||||
                    .submitLabel(.send)
 | 
					 | 
				
			||||||
                    .disabled(viewModel.isSending || currentUserId == nil)
 | 
					 | 
				
			||||||
                    .onSubmit { sendCurrentMessage() }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Button(action: sendCurrentMessage) {
 | 
					 | 
				
			||||||
                    Image(systemName: viewModel.isSending ? "hourglass" : "paperplane.fill")
 | 
					 | 
				
			||||||
                        .font(.system(size: 18, weight: .semibold))
 | 
					                        .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)
 | 
					        .background(.ultraThinMaterial)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -235,6 +259,51 @@ struct PrivateChatView: View {
 | 
				
			|||||||
        draftText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || viewModel.isSending || currentUserId == nil
 | 
					        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() {
 | 
					    private func sendCurrentMessage() {
 | 
				
			||||||
        let text = draftText.trimmingCharacters(in: .whitespacesAndNewlines)
 | 
					        let text = draftText.trimmingCharacters(in: .whitespacesAndNewlines)
 | 
				
			||||||
        guard !text.isEmpty else { return }
 | 
					        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 = {
 | 
					    private static let timeFormatter: DateFormatter = {
 | 
				
			||||||
        let formatter = DateFormatter()
 | 
					        let formatter = DateFormatter()
 | 
				
			||||||
        formatter.dateStyle = .none
 | 
					        formatter.dateStyle = .none
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user