From fc214ed696e3e682a79b8bc10cc730ac5601eac1 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Wed, 13 Aug 2025 02:49:21 +0300 Subject: [PATCH] left bar --- Shared/Components/TopBarView.swift | 22 +++++ Shared/Views/Tab/MainView.swift | 135 ++++++++++------------------ Shared/Views/Tab/SideMenuView.swift | 116 ++++++++++++++++++++++++ yobble.xcodeproj/project.pbxproj | 4 + 4 files changed, 189 insertions(+), 88 deletions(-) create mode 100644 Shared/Views/Tab/SideMenuView.swift diff --git a/Shared/Components/TopBarView.swift b/Shared/Components/TopBarView.swift index b46c540..160a3e2 100644 --- a/Shared/Components/TopBarView.swift +++ b/Shared/Components/TopBarView.swift @@ -9,6 +9,9 @@ struct TopBarView: View { var accounts: [String] var viewModel: LoginViewModel + // Привязка для управления боковым меню + @Binding var isSideMenuPresented: Bool + var isHomeTab: Bool { return title == "Home" } @@ -20,6 +23,19 @@ struct TopBarView: View { var body: some View { VStack(spacing: 0) { HStack { + // Кнопка "Гамбургер" для открытия меню + Button(action: { + withAnimation { + isSideMenuPresented.toggle() + } + }) { + Image(systemName: "line.horizontal.3") + .imageScale(.large) + .foregroundColor(.primary) + } + +// Spacer() + if isHomeTab{ Text("Yobble") .font(.largeTitle) @@ -70,3 +86,9 @@ struct TopBarView: View { .background(Color(UIColor.systemBackground)) } } + +struct TopBarView_Previews: PreviewProvider { + static var previews: some View { + /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/ + } +} diff --git a/Shared/Views/Tab/MainView.swift b/Shared/Views/Tab/MainView.swift index 4e3f89c..658b303 100644 --- a/Shared/Views/Tab/MainView.swift +++ b/Shared/Views/Tab/MainView.swift @@ -1,10 +1,3 @@ -// -// MainView.swift -// VolnahubApp -// -// Created by cheykrym on 09/06/2025. -// - import SwiftUI struct MainView: View { @@ -17,109 +10,75 @@ struct MainView: View { @State private var accounts = ["@user1", "@user2", "@user3"] @State private var sheetType: ProfileTab.SheetType? = nil - // Состояния для скрытия TopBar - @State private var topBarVisible = true - @State private var lastScrollY: CGFloat = 0 - + // Состояние для бокового меню + @State private var isSideMenuPresented = false + 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" + case 0: return "Home" + case 1: return "Search" + case 2: return "Chats" + case 3: return "Profile" + default: return "Home" } } var body: some View { NavigationView { - VStack(spacing: 0) { - if topBarVisible { + ZStack { + // Основной контент + VStack(spacing: 0) { TopBarView( title: tabTitle, selectedAccount: $selectedAccount, sheetType: $sheetType, accounts: accounts, - viewModel: viewModel + viewModel: viewModel, + isSideMenuPresented: $isSideMenuPresented ) - .transition(AnyTransition.move(edge: .top).combined(with: .opacity)) - } - - ZStack { - switch selectedTab { - case 0: -// HomeTab(onScroll: handleScroll) - NewHomeTab(viewModel: newHomeTabViewModel) - case 1: - SearchTab() // SearchTab не имеет скролла, поэтому onScroll не нужен - case 2: - ChatsTab() // ChatsTab тоже - case 3: - ProfileTab( - viewModel: viewModel, - sheetType: $sheetType, - selectedAccount: $selectedAccount, - accounts: $accounts, - onScroll: handleScroll - ) - default: - HomeTab(onScroll: handleScroll) + + ZStack { + switch selectedTab { + case 0: NewHomeTab(viewModel: newHomeTabViewModel) + case 1: SearchTab() + case 2: ChatsTab() + case 3: ProfileTab(viewModel: viewModel, sheetType: $sheetType, selectedAccount: $selectedAccount, accounts: $accounts, onScroll: { _ in }) + default: NewHomeTab(viewModel: newHomeTabViewModel) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + + CustomTabBar(selectedTab: $selectedTab) { + print("Create button tapped") } } - .frame(maxWidth: .infinity, maxHeight: .infinity) - - if topBarVisible { - CustomTabBar(selectedTab: $selectedTab) { - print("Create button tapped") + .ignoresSafeArea(edges: .bottom) + .navigationBarHidden(true) + .sheet(item: $sheetType) { type in + // ... sheet presentation logic } + // Затемнение фона при открытом меню + .background(isSideMenuPresented ? Color.black.opacity(0.4) : Color.clear) + .onTapGesture { + if isSideMenuPresented { + withAnimation { + isSideMenuPresented = false + } + } } - } - .ignoresSafeArea(edges: .bottom) - .navigationBarHidden(true) - .sheet(item: $sheetType) { type in - switch type { - case .accountShare: - AccountShareSheet( - isPresented: Binding( - get: { sheetType != nil }, - set: { if !$0 { sheetType = nil } } - ), - selectedAccount: $selectedAccount, - accounts: accounts - ) + + // Боковое меню + if isSideMenuPresented { + SideMenuView(isPresented: $isSideMenuPresented) + .frame(width: UIScreen.main.bounds.width * 0.8) + .offset(x: isSideMenuPresented ? 0 : -UIScreen.main.bounds.width) + .transition(.move(edge: .leading)) + .zIndex(1) // Убедимся, что меню поверх всего } } } .navigationViewStyle(StackNavigationViewStyle()) } - - private func handleScroll(offset: CGPoint) { - let currentY = offset.y - - // Показываем бар, если скроллим вверх или дошли до верха -// if currentY < lastScrollY || currentY <= 0 { -// if !topBarVisible { -// withAnimation(.default) { -// topBarVisible = true -// } -// } -// } -// // Скрываем, если скроллим вниз и отступили от верха -// else if currentY > lastScrollY && currentY > 50 { -// if topBarVisible { -// withAnimation(.default) { -// topBarVisible = false -// } -// } -// } - - lastScrollY = currentY - } } struct MainView_Previews: PreviewProvider { diff --git a/Shared/Views/Tab/SideMenuView.swift b/Shared/Views/Tab/SideMenuView.swift new file mode 100644 index 0000000..178e123 --- /dev/null +++ b/Shared/Views/Tab/SideMenuView.swift @@ -0,0 +1,116 @@ +import SwiftUI + +struct SideMenuView: View { + @Binding var isPresented: Bool + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + // Header + VStack(alignment: .leading) { + Image(systemName: "person.circle.fill") + .resizable() + .frame(width: 60, height: 60) + .foregroundColor(.gray) + Text("Your Name") + .font(.title2).bold() + Text("@yourusername") + .font(.subheadline) + .foregroundColor(.secondary) + } + .padding(20) + + // Menu Items + ScrollView { + VStack(alignment: .leading, spacing: 20) { + // Section 1 + VStack(alignment: .leading, spacing: 15) { + SideMenuButton(icon: "person.2.fill", title: "People You May Like", action: {}) + SideMenuButton(icon: "star.fill", title: "Fun Fest", action: {}) + SideMenuButton(icon: "lightbulb.fill", title: "Creator Center", action: {}) + } + + Divider() + + // Section 2 + VStack(alignment: .leading, spacing: 15) { + Text("CATEGORY").font(.caption).foregroundColor(.secondary) + SideMenuButton(icon: "doc.text", title: "Drafts", action: {}) + SideMenuButton(icon: "bubble.left", title: "My Comments", action: {}) + SideMenuButton(icon: "clock", title: "History", action: {}) + SideMenuButton(icon: "arrow.down.circle", title: "My Downloads", action: {}) + } + + Divider() + + // Section 3 + VStack(alignment: .leading, spacing: 15) { + Text("SERVICES").font(.caption).foregroundColor(.secondary) + SideMenuButton(icon: "shippingbox", title: "Orders", action: {}) + SideMenuButton(icon: "cart", title: "Cart", action: {}) + SideMenuButton(icon: "wallet.pass", title: "Wallet", action: {}) + } + + Divider() + + // Section 4 + VStack(alignment: .leading, spacing: 15) { + SideMenuButton(icon: "square.grid.2x2", title: "Applets", action: {}) + } + } + .padding() + } + + Spacer() + + // Footer + HStack(spacing: 20) { + Spacer() + SideMenuFooterButton(icon: "qrcode.viewfinder", title: "Scan", action: {}) + SideMenuFooterButton(icon: "questionmark.circle", title: "Help Center", action: {}) + SideMenuFooterButton(icon: "gear", title: "Settings", action: {}) + Spacer() + } + .padding() + } + .background(Color(UIColor.systemBackground)) + } +} + +// Helper Views for buttons +struct SideMenuButton: View { + let icon: String + let title: String + let action: () -> Void + + var body: some View { + Button(action: action) { + HStack(spacing: 15) { + Image(systemName: icon) + .font(.title3) + .frame(width: 30) + Text(title) + .font(.headline) + } + .foregroundColor(.primary) + .padding(.vertical, 8) + } + } +} + +struct SideMenuFooterButton: View { + let icon: String + let title: String + let action: () -> Void + + var body: some View { + Button(action: action) { + VStack { + Image(systemName: icon) + .font(.title2) + Text(title) + .font(.caption) + } + .foregroundColor(.primary) + } + } +} \ No newline at end of file diff --git a/yobble.xcodeproj/project.pbxproj b/yobble.xcodeproj/project.pbxproj index 4276ba9..01cec54 100644 --- a/yobble.xcodeproj/project.pbxproj +++ b/yobble.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 1A9B01602E4BF9C000887E0B /* placeholderPhoto.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B015E2E4BF9C000887E0B /* placeholderPhoto.jpg */; }; 1A9B01662E4BFA3600887E0B /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B01652E4BFA3600887E0B /* Media.xcassets */; }; 1A9B016E2E4BFB9000887E0B /* NewHomeTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */; }; + 1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B017B2E4C087F00887E0B /* SideMenuView.swift */; }; 1AB4F8CD2E22E341002B6E40 /* AccountShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */; }; 1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */; }; 1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */; }; @@ -88,6 +89,7 @@ 1A9B015E2E4BF9C000887E0B /* placeholderPhoto.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = placeholderPhoto.jpg; path = ../../../../Volumes/Untitled/xcode/volnahub/Shared/Media/placeholderPhoto.jpg; sourceTree = DEVELOPER_DIR; }; 1A9B01652E4BFA3600887E0B /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; 1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewHomeTabViewModel.swift; sourceTree = ""; }; + 1A9B017B2E4C087F00887E0B /* SideMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = ""; }; 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountShareSheet.swift; sourceTree = ""; }; 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersView.swift; sourceTree = ""; }; 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = ""; }; @@ -288,6 +290,7 @@ 1AEE5EA92E21A4FC00A3DCA3 /* Tab */ = { isa = PBXGroup; children = ( + 1A9B017B2E4C087F00887E0B /* SideMenuView.swift */, 1A6FB9542E32D2B200E89EBE /* CustomTabBar.swift */, 1A7940B52DF77F21002569DA /* MainView.swift */, 1A9B014A2E4BF3CD00887E0B /* NewHomeTab.swift */, @@ -423,6 +426,7 @@ 1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */, 1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */, 1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */, + 1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */, 1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */, 1ACE61092E22F57100B37AC5 /* AppPreferencesView.swift in Sources */, 1ACE61052E22F56800B37AC5 /* SecuritySettingsView.swift in Sources */,