137 lines
5.7 KiB
Swift
137 lines
5.7 KiB
Swift
import SwiftUI
|
||
|
||
struct MainView: View {
|
||
@ObservedObject var viewModel: LoginViewModel
|
||
@State private var selectedTab: Int = 0
|
||
// @StateObject private var newHomeTabViewModel = NewHomeTabViewModel()
|
||
|
||
// Состояния для TopBarView
|
||
@State private var selectedAccount = "@user1"
|
||
@State private var accounts = ["@user1", "@user2", "@user3"]
|
||
// @State private var sheetType: ProfileTab.SheetType? = nil
|
||
|
||
// Состояния для бокового меню
|
||
@State private var isSideMenuPresented = false
|
||
@State private var menuOffset: CGFloat = 0
|
||
|
||
private var tabTitle: String {
|
||
switch selectedTab {
|
||
case 0: return "Home"
|
||
case 1: return "Search"
|
||
case 2: return "Chats"
|
||
case 3: return "Profile"
|
||
default: return "Home"
|
||
}
|
||
}
|
||
|
||
private var menuWidth: CGFloat {
|
||
UIScreen.main.bounds.width * 0.8
|
||
}
|
||
|
||
var body: some View {
|
||
NavigationView {
|
||
ZStack(alignment: .leading) { // Выравниваем ZStack по левому краю
|
||
// Основной контент
|
||
VStack(spacing: 0) {
|
||
TopBarView(
|
||
title: tabTitle,
|
||
selectedAccount: $selectedAccount,
|
||
accounts: accounts,
|
||
viewModel: viewModel,
|
||
isSideMenuPresented: $isSideMenuPresented
|
||
)
|
||
|
||
ZStack {
|
||
NewHomeTab()
|
||
.opacity(selectedTab == 0 ? 1 : 0)
|
||
|
||
SearchTab()
|
||
.opacity(selectedTab == 1 ? 1 : 0)
|
||
|
||
ChatsTab()
|
||
.opacity(selectedTab == 2 ? 1 : 0)
|
||
|
||
ProfileTab()
|
||
.opacity(selectedTab == 3 ? 1 : 0)
|
||
}
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
|
||
CustomTabBar(selectedTab: $selectedTab) {
|
||
print("Create button tapped")
|
||
}
|
||
}
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity) // Убедимся, что основной контент занимает все пространство
|
||
.ignoresSafeArea(edges: .bottom)
|
||
.navigationBarHidden(true)
|
||
// .sheet(item: $sheetType) { type in
|
||
// // ... sheet presentation logic
|
||
// }
|
||
|
||
// Затемнение и закрытие по тапу
|
||
Color.black
|
||
.opacity(Double(menuOffset / menuWidth) * 0.4)
|
||
.ignoresSafeArea()
|
||
.onTapGesture {
|
||
withAnimation(.easeInOut) {
|
||
isSideMenuPresented = false
|
||
}
|
||
}
|
||
.allowsHitTesting(menuOffset > 0)
|
||
|
||
// Боковое меню
|
||
SideMenuView(isPresented: $isSideMenuPresented)
|
||
.frame(width: menuWidth)
|
||
.offset(x: -menuWidth + menuOffset) // Новая логика смещения
|
||
.ignoresSafeArea(edges: .vertical)
|
||
}
|
||
.gesture(
|
||
DragGesture()
|
||
.onChanged { gesture in
|
||
if !isSideMenuPresented && gesture.startLocation.x > 60 { return }
|
||
|
||
let translation = gesture.translation.width
|
||
|
||
// Определяем базовое смещение в зависимости от того, открыто меню или нет
|
||
let baseOffset = isSideMenuPresented ? menuWidth : 0
|
||
|
||
// Новое смещение — это база плюс текущий свайп
|
||
let newOffset = baseOffset + translation
|
||
|
||
// Жестко ограничиваем итоговое смещение между 0 и шириной меню
|
||
self.menuOffset = max(0, min(menuWidth, newOffset))
|
||
}
|
||
.onEnded { gesture in
|
||
if !isSideMenuPresented && gesture.startLocation.x > 60 { return }
|
||
|
||
let threshold = menuWidth * 0.4
|
||
|
||
withAnimation(.easeInOut) {
|
||
if self.menuOffset > threshold {
|
||
isSideMenuPresented = true
|
||
} else {
|
||
isSideMenuPresented = false
|
||
}
|
||
// Устанавливаем финальное смещение после анимации
|
||
self.menuOffset = isSideMenuPresented ? menuWidth : 0
|
||
}
|
||
}
|
||
)
|
||
}
|
||
.navigationViewStyle(StackNavigationViewStyle())
|
||
.onChange(of: isSideMenuPresented) { presented in
|
||
// Плавная анимация при нажатии на кнопку, а не только при жесте
|
||
withAnimation(.easeInOut) {
|
||
menuOffset = presented ? menuWidth : 0
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
struct MainView_Previews: PreviewProvider {
|
||
static var previews: some View {
|
||
let mockViewModel = LoginViewModel()
|
||
MainView(viewModel: mockViewModel)
|
||
.environmentObject(ThemeManager())
|
||
}
|
||
}
|