244 lines
8.5 KiB
Swift
244 lines
8.5 KiB
Swift
import SwiftUI
|
||
|
||
struct TopBarView: View {
|
||
var title: String
|
||
|
||
let isMessengerModeEnabled: Bool
|
||
// Состояния для ProfileTab
|
||
@Binding var selectedAccount: String
|
||
// @Binding var sheetType: ProfileTab.SheetType?
|
||
var accounts: [String]
|
||
// var viewModel: LoginViewModel
|
||
@ObservedObject var viewModel: LoginViewModel
|
||
@Binding var isSettingsPresented: Bool
|
||
|
||
// Привязка для управления боковым меню
|
||
@Binding var isSideMenuPresented: Bool
|
||
@Binding var chatSearchRevealProgress: CGFloat
|
||
@Binding var chatSearchText: String
|
||
|
||
var isHomeTab: Bool {
|
||
return title == "Home"
|
||
}
|
||
|
||
var isChatsTab: Bool {
|
||
return title == "Chats"
|
||
}
|
||
|
||
var isProfileTab: Bool {
|
||
return title == "Profile"
|
||
}
|
||
|
||
private var statusMessage: String? {
|
||
if viewModel.chatLoadingState == .loading {
|
||
return NSLocalizedString("Загрузка чатов", comment: "")
|
||
}
|
||
if viewModel.socketState == .connecting {
|
||
return NSLocalizedString("Подключение", comment: "")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
var body: some View {
|
||
VStack(spacing: 0) {
|
||
HStack {
|
||
|
||
if !isMessengerModeEnabled{
|
||
// Кнопка "Гамбургер" для открытия меню
|
||
Button(action: {
|
||
withAnimation {
|
||
isSideMenuPresented.toggle()
|
||
}
|
||
}) {
|
||
Image(systemName: "line.horizontal.3")
|
||
.imageScale(.large)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
// Spacer()
|
||
|
||
if let statusMessage {
|
||
connectionStatusView(message: statusMessage)
|
||
Spacer()
|
||
} else if isHomeTab{
|
||
Text("Yobble")
|
||
.font(.largeTitle)
|
||
.fontWeight(.bold)
|
||
Spacer()
|
||
} else if isProfileTab {
|
||
Spacer()
|
||
Button(action: { }) {
|
||
HStack(spacing: 4) {
|
||
Text("@\(viewModel.username)")
|
||
.font(.headline)
|
||
.foregroundColor(.primary)
|
||
Image(systemName: "chevron.down")
|
||
.font(.subheadline)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
Spacer()
|
||
} else {
|
||
Text(title)
|
||
.font(.largeTitle)
|
||
.fontWeight(.bold)
|
||
Spacer()
|
||
}
|
||
|
||
if isHomeTab{
|
||
HStack(spacing: 20) {
|
||
// Кнопка поиска
|
||
Button(action: {
|
||
// пока ничего не делаем
|
||
}) {
|
||
Image(systemName: "magnifyingglass")
|
||
.imageScale(.large)
|
||
.foregroundColor(.primary)
|
||
}
|
||
// Кнопка уведомлений
|
||
Button(action: {
|
||
// пока ничего не делаем
|
||
}) {
|
||
Image(systemName: "bell")
|
||
.imageScale(.large)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
} else if isProfileTab {
|
||
NavigationLink(isActive: $isSettingsPresented) {
|
||
SettingsView(viewModel: viewModel)
|
||
} label: {
|
||
Image(systemName: "wrench")
|
||
.imageScale(.large)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
|
||
// else if isChatsTab {
|
||
// Button(action: {
|
||
// NotificationCenter.default.post(name: .debugRefreshChats, object: nil)
|
||
// }) {
|
||
// Text(NSLocalizedString("DEBUG UPDATE", comment: ""))
|
||
// .foregroundColor(.primary)
|
||
// }
|
||
// }
|
||
}
|
||
.padding()
|
||
.frame(height: 50) // Стандартная высота для нав. бара
|
||
|
||
if isChatsTab {
|
||
revealableSearchBar
|
||
}
|
||
|
||
Divider()
|
||
}
|
||
.background(Color(UIColor.systemBackground))
|
||
.onChange(of: isChatsTab) { isChats in
|
||
let hasSearchText = !chatSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||
if !isChats {
|
||
guard !hasSearchText else { return }
|
||
withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
|
||
chatSearchRevealProgress = 0
|
||
}
|
||
} else if hasSearchText {
|
||
withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
|
||
chatSearchRevealProgress = 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private extension TopBarView {
|
||
func connectionStatusView(message: String) -> some View {
|
||
HStack(spacing: 8) {
|
||
ProgressView()
|
||
.progressViewStyle(.circular)
|
||
Text(message)
|
||
.font(.headline)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
|
||
private var normalizedRevealProgress: CGFloat {
|
||
guard isChatsTab else { return 0 }
|
||
return max(0, min(chatSearchRevealProgress, 1))
|
||
}
|
||
|
||
private var revealableSearchBar: some View {
|
||
let progress = normalizedRevealProgress
|
||
return VStack(spacing: 0) {
|
||
searchBar
|
||
.padding(.horizontal)
|
||
.padding(.bottom, searchBarBottomSpacing)
|
||
.opacity(progress)
|
||
}
|
||
.frame(height: searchBarRevealHeight * progress, alignment: .top)
|
||
.clipped()
|
||
.allowsHitTesting(progress > 0.9)
|
||
.accessibilityHidden(progress < 0.9)
|
||
}
|
||
|
||
private var searchBarRevealHeight: CGFloat { searchBarBaseHeight + searchBarBottomSpacing }
|
||
|
||
// 36 min height + 6 * 2 vertical padding inside searchBar
|
||
private var searchBarBaseHeight: CGFloat { 48 }
|
||
|
||
private var searchBarBottomSpacing: CGFloat { 0 }
|
||
|
||
var searchBar: some View {
|
||
HStack(spacing: 8) {
|
||
Image(systemName: "magnifyingglass")
|
||
.foregroundColor(.secondary)
|
||
TextField(NSLocalizedString("Поиск", comment: ""), text: $chatSearchText)
|
||
.textFieldStyle(.plain)
|
||
.textInputAutocapitalization(.never)
|
||
.autocorrectionDisabled()
|
||
if !chatSearchText.isEmpty {
|
||
Button(action: { chatSearchText = "" }) {
|
||
Image(systemName: "xmark.circle.fill")
|
||
.foregroundColor(.secondary)
|
||
}
|
||
.buttonStyle(.plain)
|
||
}
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.vertical, 6)
|
||
.frame(minHeight: 36)
|
||
.background(
|
||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||
.fill(Color(UIColor.secondarySystemBackground))
|
||
)
|
||
}
|
||
}
|
||
|
||
struct TopBarView_Previews: PreviewProvider {
|
||
struct Wrapper: View {
|
||
@State private var selectedAccount = "@user"
|
||
@State private var isSideMenuPresented = false
|
||
@State private var revealProgress: CGFloat = 1
|
||
@StateObject private var viewModel = LoginViewModel()
|
||
@State private var searchText: String = ""
|
||
@State private var isSettingsPresented = false
|
||
|
||
var body: some View {
|
||
TopBarView(
|
||
title: "Chats",
|
||
isMessengerModeEnabled: false,
|
||
selectedAccount: $selectedAccount,
|
||
accounts: [selectedAccount],
|
||
viewModel: viewModel,
|
||
isSettingsPresented: $isSettingsPresented,
|
||
isSideMenuPresented: $isSideMenuPresented,
|
||
chatSearchRevealProgress: $revealProgress,
|
||
chatSearchText: $searchText,
|
||
)
|
||
}
|
||
}
|
||
|
||
static var previews: some View {
|
||
Wrapper()
|
||
.environmentObject(ThemeManager())
|
||
}
|
||
}
|