From c5906f42b7c328f1c5b79ae07d4f45afcfa2b209 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Thu, 14 Aug 2025 03:59:41 +0300 Subject: [PATCH] switcher theme in BM --- Shared/Services/ThemeManager.swift | 53 +++++++++++++++++++++++++++++ Shared/Views/Tab/SideMenuView.swift | 48 +++++++++++++++++++++----- Shared/yobbleApp.swift | 25 +++++--------- yobble.xcodeproj/project.pbxproj | 4 +++ 4 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 Shared/Services/ThemeManager.swift diff --git a/Shared/Services/ThemeManager.swift b/Shared/Services/ThemeManager.swift new file mode 100644 index 0000000..1152117 --- /dev/null +++ b/Shared/Services/ThemeManager.swift @@ -0,0 +1,53 @@ +import SwiftUI + +// Enum to represent the three theme options +enum Theme: String, CaseIterable { + case system = "System" + case light = "Light" + case dark = "Dark" + + var colorScheme: ColorScheme? { + switch self { + case .system: + return nil + case .light: + return .light + case .dark: + return .dark + } + } +} + +// Observable class to manage the theme state +class ThemeManager: ObservableObject { + @AppStorage("selectedTheme") private var selectedThemeValue: String = Theme.system.rawValue + + @Published var theme: Theme + + init() { + // Read directly from UserDefaults to avoid using self before initialization is complete. + let storedThemeValue = UserDefaults.standard.string(forKey: "selectedTheme") ?? "" + self.theme = Theme(rawValue: storedThemeValue) ?? .system + } + + func setTheme(_ theme: Theme) { + self.theme = theme + selectedThemeValue = theme.rawValue + } + + // This will be called from the button + func toggleTheme(from currentSystemScheme: ColorScheme) { + let newTheme: Theme + + switch theme { + case .system: + // If system is active, toggle to the opposite of the current system theme + newTheme = currentSystemScheme == .dark ? .light : .dark + case .light: + newTheme = .dark + case .dark: + newTheme = .light + } + setTheme(newTheme) + } +} diff --git a/Shared/Views/Tab/SideMenuView.swift b/Shared/Views/Tab/SideMenuView.swift index 79a3f46..5fedf25 100644 --- a/Shared/Views/Tab/SideMenuView.swift +++ b/Shared/Views/Tab/SideMenuView.swift @@ -62,6 +62,8 @@ struct SideMenuFooterButton: View { // --- MAIN VIEW --- struct SideMenuView: View { + @EnvironmentObject var themeManager: ThemeManager + @Environment(\.colorScheme) var colorScheme @Binding var isPresented: Bool @State private var isAccountListExpanded = false @@ -77,22 +79,50 @@ struct SideMenuView: View { Account(name: "Test User", username: "@test", isCurrent: false), Account(name: "Creative Profile", username: "@creative", isCurrent: false) ] + + private var themeToggleButton: some View { + Button(action: { + themeManager.toggleTheme(from: colorScheme) + }) { + Image(systemName: iconName) + .font(.title2) + .foregroundColor(.primary) + } + } + + private var iconName: String { + let effectiveScheme: ColorScheme + switch themeManager.theme { + case .system: + effectiveScheme = colorScheme + case .light: + effectiveScheme = .light + case .dark: + effectiveScheme = .dark + } + + return effectiveScheme == .dark ? "moon.fill" : "sun.max.fill" + } var body: some View { VStack(alignment: .leading, spacing: 0) { ScrollView { VStack(alignment: .leading, spacing: 0) { // Parent VStack - // --- Header - Button(action: { }) { - Image(systemName: "person.circle.fill") - .resizable() - .frame(width: 60, height: 60) - .foregroundColor(.gray) - .padding(.horizontal, 20) - .padding(.top, topPadding) - .padding(.bottom, 10) + // --- Header --- + HStack { + Button(action: { }) { + Image(systemName: "person.circle.fill") + .resizable() + .frame(width: 60, height: 60) + .foregroundColor(.gray) + } + Spacer() + themeToggleButton } + .padding(.horizontal, 20) + .padding(.top, topPadding) + .padding(.bottom, 10) // --- Header Button --- Button(action: { diff --git a/Shared/yobbleApp.swift b/Shared/yobbleApp.swift index 4e27251..4f52e4f 100644 --- a/Shared/yobbleApp.swift +++ b/Shared/yobbleApp.swift @@ -7,31 +7,24 @@ import SwiftUI -//@AppStorage("isLoggedIn") var isLoggedIn: Bool = false -//@AppStorage("isDarkMode") private var isDarkMode: Bool = false -//@AppStorage("currentUser") var currentUser: String = "" - @main struct volnahubApp: App { - @AppStorage("isDarkMode") private var isDarkMode: Bool = true + @StateObject private var themeManager = ThemeManager() @StateObject private var viewModel = LoginViewModel() var body: some Scene { WindowGroup { - ZStack { - Color(isDarkMode ? .black : .white) // ✅ Фон в зависимости от темы - - if viewModel.isLoading{ + Group { + if viewModel.isLoading { SplashScreenView() - }else{ - if viewModel.isLoggedIn { - MainView(viewModel: viewModel) - } else { - LoginView(viewModel: viewModel) - } + } else if viewModel.isLoggedIn { + MainView(viewModel: viewModel) + } else { + LoginView(viewModel: viewModel) } } - .preferredColorScheme(isDarkMode ? .dark : .light) + .environmentObject(themeManager) + .preferredColorScheme(themeManager.theme.colorScheme) } } } diff --git a/yobble.xcodeproj/project.pbxproj b/yobble.xcodeproj/project.pbxproj index 01cec54..bcd5ad1 100644 --- a/yobble.xcodeproj/project.pbxproj +++ b/yobble.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 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 */; }; + 1A9E4FB32E4D6A67002249D6 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9E4FB22E4D6A67002249D6 /* ThemeManager.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 */; }; @@ -90,6 +91,7 @@ 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 = ""; }; + 1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeManager.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 = ""; }; @@ -227,6 +229,7 @@ 1A7940E52DF7B341002569DA /* Services */ = { isa = PBXGroup; children = ( + 1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */, 1A7940E12DF7B1C5002569DA /* KeychainService.swift */, ); path = Services; @@ -450,6 +453,7 @@ 1A7940E22DF7B1C5002569DA /* KeychainService.swift in Sources */, 1A7940A62DF77DF5002569DA /* User.swift in Sources */, 1A7940A22DF77DE9002569DA /* AuthService.swift in Sources */, + 1A9E4FB32E4D6A67002249D6 /* ThemeManager.swift in Sources */, 1AEE5EB32E21A85800A3DCA3 /* SearchTab.swift in Sources */, 1ACE61152E22FE2000B37AC5 /* PostDetailView.swift in Sources */, 1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */,