From f6fb5b7a83e4e494e8d818f8d74c5d36d3c2c9ce Mon Sep 17 00:00:00 2001 From: Marcin Czachursk Date: Thu, 6 Apr 2023 13:19:55 +0200 Subject: [PATCH] #12 Add bottom right/left menu items --- ...plicationSettings+CoreDataProperties.swift | 1 + CoreData/ApplicationSettingsHandler.swift | 6 + .../Vernissage.xcdatamodeld/.xccurrentversion | 2 +- .../Vernissage-007.xcdatamodel/contents | 94 ++++++++ Localization/en.lproj/Localizable.strings | 4 + Localization/eu.lproj/Localizable.strings | 4 + Localization/pl.lproj/Localizable.strings | 4 + Models/MenuPosition.swift | 13 ++ Vernissage.xcodeproj/project.pbxproj | 30 ++- .../EnvironmentObjects/ApplicationState.swift | 3 + Vernissage/VernissageApp.swift | 4 + Vernissage/ViewModifiers/NavigationMenu.swift | 74 ++++++ Vernissage/Views/MainView.swift | 220 +++++++++--------- .../Subviews/GeneralSectionView.swift | 20 ++ 14 files changed, 365 insertions(+), 114 deletions(-) create mode 100644 CoreData/Vernissage.xcdatamodeld/Vernissage-007.xcdatamodel/contents create mode 100644 Models/MenuPosition.swift create mode 100644 Vernissage/ViewModifiers/NavigationMenu.swift diff --git a/CoreData/ApplicationSettings+CoreDataProperties.swift b/CoreData/ApplicationSettings+CoreDataProperties.swift index 3713f50..4263b4a 100644 --- a/CoreData/ApplicationSettings+CoreDataProperties.swift +++ b/CoreData/ApplicationSettings+CoreDataProperties.swift @@ -28,6 +28,7 @@ extension ApplicationSettings { @NSManaged public var showSensitive: Bool @NSManaged public var showPhotoDescription: Bool + @NSManaged public var menuPosition: Int32 } extension ApplicationSettings: Identifiable { diff --git a/CoreData/ApplicationSettingsHandler.swift b/CoreData/ApplicationSettingsHandler.swift index 6e43340..f302c8c 100644 --- a/CoreData/ApplicationSettingsHandler.swift +++ b/CoreData/ApplicationSettingsHandler.swift @@ -107,6 +107,12 @@ class ApplicationSettingsHandler { CoreDataHandler.shared.save() } + func set(menuPosition: MenuPosition) { + let defaultSettings = self.get() + defaultSettings.menuPosition = Int32(menuPosition.rawValue) + CoreDataHandler.shared.save() + } + private func createApplicationSettingsEntity(viewContext: NSManagedObjectContext? = nil) -> ApplicationSettings { let context = viewContext ?? CoreDataHandler.shared.container.viewContext return ApplicationSettings(context: context) diff --git a/CoreData/Vernissage.xcdatamodeld/.xccurrentversion b/CoreData/Vernissage.xcdatamodeld/.xccurrentversion index c9463e5..caec0e4 100644 --- a/CoreData/Vernissage.xcdatamodeld/.xccurrentversion +++ b/CoreData/Vernissage.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Vernissage-006.xcdatamodel + Vernissage-007.xcdatamodel diff --git a/CoreData/Vernissage.xcdatamodeld/Vernissage-007.xcdatamodel/contents b/CoreData/Vernissage.xcdatamodeld/Vernissage-007.xcdatamodel/contents new file mode 100644 index 0000000..2fbe9f3 --- /dev/null +++ b/CoreData/Vernissage.xcdatamodeld/Vernissage-007.xcdatamodel/contents @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Localization/en.lproj/Localizable.strings b/Localization/en.lproj/Localizable.strings index af4a9ee..5775a4e 100644 --- a/Localization/en.lproj/Localizable.strings +++ b/Localization/en.lproj/Localizable.strings @@ -204,6 +204,10 @@ "settings.title.sourceCode" = "Source code"; "settings.title.rate" = "Rate Vernissage"; "settings.title.socials" = "Socials"; +"settings.title.menuPosition" = "Menu position"; +"settings.title.topMenu" = "Navigation bar"; +"settings.title.bottomRightMenu" = "Bottom right"; +"settings.title.bottomLeftMenu" = "Bottom left"; // Mark: Signin view. "signin.navigationBar.title" = "Sign in to Pixelfed"; diff --git a/Localization/eu.lproj/Localizable.strings b/Localization/eu.lproj/Localizable.strings index d61663a..6aa069a 100644 --- a/Localization/eu.lproj/Localizable.strings +++ b/Localization/eu.lproj/Localizable.strings @@ -204,6 +204,10 @@ "settings.title.sourceCode" = "Iturburu kodea"; "settings.title.rate" = "Rate Vernissage"; "settings.title.socials" = "Socials"; +"settings.title.menuPosition" = "Menu position"; +"settings.title.topMenu" = "Navigation bar"; +"settings.title.bottomRightMenu" = "Bottom right"; +"settings.title.bottomLeftMenu" = "Bottom left"; // Mark: Signin view. "signin.navigationBar.title" = "Hasi saioa Pixelfed-en"; diff --git a/Localization/pl.lproj/Localizable.strings b/Localization/pl.lproj/Localizable.strings index 1439855..244e6b2 100644 --- a/Localization/pl.lproj/Localizable.strings +++ b/Localization/pl.lproj/Localizable.strings @@ -204,6 +204,10 @@ "settings.title.sourceCode" = "Kod źródłowy"; "settings.title.rate" = "Oceń Vernissage"; "settings.title.socials" = "Społeczności"; +"settings.title.menuPosition" = "Pozycja menu"; +"settings.title.topMenu" = "Panel tytułowy"; +"settings.title.bottomRightMenu" = "Dolny prawy"; +"settings.title.bottomLeftMenu" = "Dolny lewy"; // Mark: Signin view. "signin.navigationBar.title" = "Zaloguj się do Pixelfed"; diff --git a/Models/MenuPosition.swift b/Models/MenuPosition.swift new file mode 100644 index 0000000..26445cf --- /dev/null +++ b/Models/MenuPosition.swift @@ -0,0 +1,13 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation + +public enum MenuPosition: Int { + case top = 1 + case bottomRight = 2 + case bottomLeft = 3 +} diff --git a/Vernissage.xcodeproj/project.pbxproj b/Vernissage.xcodeproj/project.pbxproj index 81643b9..7c80233 100644 --- a/Vernissage.xcodeproj/project.pbxproj +++ b/Vernissage.xcodeproj/project.pbxproj @@ -146,6 +146,9 @@ F88FAD2B295F43B8009B20C9 /* AccountData+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */; }; F88FAD2D295F4AD7009B20C9 /* ApplicationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD2C295F4AD7009B20C9 /* ApplicationState.swift */; }; F88FAD32295F5029009B20C9 /* RemoteFileService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88FAD31295F5029009B20C9 /* RemoteFileService.swift */; }; + F8911A1729DE914D00770F44 /* NavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1629DE914D00770F44 /* NavigationMenu.swift */; }; + F8911A1A29DEA0F500770F44 /* MenuPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1929DEA0F500770F44 /* MenuPosition.swift */; }; + F8911A1B29DEA0F500770F44 /* MenuPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8911A1929DEA0F500770F44 /* MenuPosition.swift */; }; F891E7CE29C35BF50022C449 /* ImageRowItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F891E7CD29C35BF50022C449 /* ImageRowItem.swift */; }; F891E7D029C368750022C449 /* ImageRowItemAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F891E7CF29C368750022C449 /* ImageRowItemAsync.swift */; }; F897978829681B9C00B22335 /* UserAvatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897978729681B9C00B22335 /* UserAvatar.swift */; }; @@ -369,6 +372,9 @@ F88FAD29295F43B8009B20C9 /* AccountData+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountData+CoreDataProperties.swift"; sourceTree = ""; }; F88FAD2C295F4AD7009B20C9 /* ApplicationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationState.swift; sourceTree = ""; }; F88FAD31295F5029009B20C9 /* RemoteFileService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteFileService.swift; sourceTree = ""; }; + F8911A1629DE914D00770F44 /* NavigationMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenu.swift; sourceTree = ""; }; + F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-007.xcdatamodel"; sourceTree = ""; }; + F8911A1929DEA0F500770F44 /* MenuPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPosition.swift; sourceTree = ""; }; F891E7CD29C35BF50022C449 /* ImageRowItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRowItem.swift; sourceTree = ""; }; F891E7CF29C368750022C449 /* ImageRowItemAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRowItemAsync.swift; sourceTree = ""; }; F897978729681B9C00B22335 /* UserAvatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAvatar.swift; sourceTree = ""; }; @@ -692,6 +698,7 @@ F86167C7297FE781004D1F67 /* AvatarShape.swift */, F89D6C3E29716E41001DA3D4 /* Theme.swift */, F87AEB932986C51B00434FB6 /* AppConstants.swift */, + F8911A1929DEA0F500770F44 /* MenuPosition.swift */, ); path = Models; sourceTree = ""; @@ -937,6 +944,7 @@ F8C5E56129892CC300ADF6A7 /* FirstAppear.swift */, F8CAE63D29B8902D001E0372 /* ClearButton.swift */, F8E9391E29C0BCFA002BB3B8 /* ImageContextMenu.swift */, + F8911A1629DE914D00770F44 /* NavigationMenu.swift */, ); path = ViewModifiers; sourceTree = ""; @@ -1140,6 +1148,7 @@ F864F77D29BB9A4600B13921 /* AttachmentData+CoreDataClass.swift in Sources */, F864F7A629BBA01D00B13921 /* CoreDataError.swift in Sources */, F864F77E29BB9A4900B13921 /* AttachmentData+CoreDataProperties.swift in Sources */, + F8911A1B29DEA0F500770F44 /* MenuPosition.swift in Sources */, F864F78229BB9A6500B13921 /* StatusData+CoreDataClass.swift in Sources */, F864F78329BB9A6800B13921 /* StatusData+CoreDataProperties.swift in Sources */, F864F78429BB9A6E00B13921 /* ApplicationSettings+CoreDataClass.swift in Sources */, @@ -1187,6 +1196,7 @@ F8864CF129ACFFB80020C534 /* View+Keyboard.swift in Sources */, F88FAD21295F3944009B20C9 /* HomeFeedView.swift in Sources */, F8FA991E299FAB92007AB130 /* PhotoEditorView.swift in Sources */, + F8911A1729DE914D00770F44 /* NavigationMenu.swift in Sources */, F88C2475295C37BB0006098B /* CoreDataHandler.swift in Sources */, F87AEB972986D16D00434FB6 /* AuthorisationError.swift in Sources */, F8742FC429990AFB00E9642B /* ClientError.swift in Sources */, @@ -1254,6 +1264,7 @@ F89A46DE296EABA20062125F /* StatusPlaceholderView.swift in Sources */, F88C2482295C3A4F0006098B /* StatusView.swift in Sources */, F866F6A329604161002E8F88 /* AccountDataHandler.swift in Sources */, + F8911A1A29DEA0F500770F44 /* MenuPosition.swift in Sources */, F8996DEB2971D29D0043EEC6 /* View+Transition.swift in Sources */, F876418B298AC1B80057D362 /* NoDataView.swift in Sources */, F8E9392129C0DA7E002BB3B8 /* LazyImageState+ImageResponse.swift in Sources */, @@ -1361,7 +1372,7 @@ CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 94; + CURRENT_PROJECT_VERSION = 95; DEVELOPMENT_TEAM = B2U9FEKYP8; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VernissageWidget/Info.plist; @@ -1372,7 +1383,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1389,7 +1400,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = VernissageWidget/VernissageWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 94; + CURRENT_PROJECT_VERSION = 95; DEVELOPMENT_TEAM = B2U9FEKYP8; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = VernissageWidget/Info.plist; @@ -1400,7 +1411,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1537,7 +1548,7 @@ CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 94; + CURRENT_PROJECT_VERSION = 95; DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\""; DEVELOPMENT_TEAM = B2U9FEKYP8; ENABLE_PREVIEWS = YES; @@ -1554,7 +1565,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1577,7 +1588,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 94; + CURRENT_PROJECT_VERSION = 95; DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\""; DEVELOPMENT_TEAM = B2U9FEKYP8; ENABLE_PREVIEWS = YES; @@ -1594,7 +1605,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -1731,6 +1742,7 @@ F88C2476295C37BB0006098B /* Vernissage.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */, F8EF371429C624DA00669F45 /* Vernissage-006.xcdatamodel */, F8CAE64129B8F1AF001E0372 /* Vernissage-005.xcdatamodel */, F8B05ACC29B48DD000857221 /* Vernissage-004.xcdatamodel */, @@ -1739,7 +1751,7 @@ F8C937A929882CA90004D782 /* Vernissage-001.xcdatamodel */, F88C2477295C37BB0006098B /* Vernissage.xcdatamodel */, ); - currentVersion = F8EF371429C624DA00669F45 /* Vernissage-006.xcdatamodel */; + currentVersion = F8911A1829DE9E5500770F44 /* Vernissage-007.xcdatamodel */; path = Vernissage.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Vernissage/EnvironmentObjects/ApplicationState.swift b/Vernissage/EnvironmentObjects/ApplicationState.swift index da4d9c4..6f90209 100644 --- a/Vernissage/EnvironmentObjects/ApplicationState.swift +++ b/Vernissage/EnvironmentObjects/ApplicationState.swift @@ -85,6 +85,9 @@ public class ApplicationState: ObservableObject { /// Updated user profile. @Published var updatedProfile: Account? + /// Information which menu should be shown (top or bottom). + @Published var menuPosition = MenuPosition.top + public func changeApplicationState(accountModel: AccountModel, instance: Instance?, lastSeenStatusId: String?) { self.account = accountModel self.lastSeenStatusId = lastSeenStatusId diff --git a/Vernissage/VernissageApp.swift b/Vernissage/VernissageApp.swift index 75cbbd9..4d49681 100644 --- a/Vernissage/VernissageApp.swift +++ b/Vernissage/VernissageApp.swift @@ -169,6 +169,10 @@ struct VernissageApp: App { self.applicationState.showSensitive = defaultSettings.showSensitive self.applicationState.showPhotoDescription = defaultSettings.showPhotoDescription + if let menuPosition = MenuPosition(rawValue: Int(defaultSettings.menuPosition)) { + self.applicationState.menuPosition = menuPosition + } + self.applicationState.hapticTabSelectionEnabled = defaultSettings.hapticTabSelectionEnabled self.applicationState.hapticRefreshEnabled = defaultSettings.hapticRefreshEnabled self.applicationState.hapticButtonPressEnabled = defaultSettings.hapticButtonPressEnabled diff --git a/Vernissage/ViewModifiers/NavigationMenu.swift b/Vernissage/ViewModifiers/NavigationMenu.swift new file mode 100644 index 0000000..3b73e0b --- /dev/null +++ b/Vernissage/ViewModifiers/NavigationMenu.swift @@ -0,0 +1,74 @@ +// +// https://mczachurski.dev +// Copyright © 2023 Marcin Czachurski and the repository contributors. +// Licensed under the Apache License 2.0. +// + +import Foundation +import SwiftUI + +public extension View { + func navigationMenu(menuPosition: Binding, + @ViewBuilder menuItems: @escaping () -> MenuItems) -> some View where MenuItems: View { + modifier(NavigationMenu(menuPosition: menuPosition, menuItems: menuItems)) + } +} + +private struct NavigationMenu: ViewModifier where MenuItems: View { + + private let menuItems: () -> MenuItems + + @Binding var menuPosition: MenuPosition + + init(menuPosition: Binding, @ViewBuilder menuItems: @escaping () -> MenuItems) { + self.menuItems = menuItems + self._menuPosition = menuPosition + } + + func body(content: Content) -> some View { + if self.menuPosition == .top { + content + } else { + ZStack { + content + + VStack(alignment: .trailing) { + Spacer() + HStack { + if self.menuPosition == .bottomRight { + Spacer() + + self.menuContent() + .padding(.trailing, 20) + } + + if self.menuPosition == .bottomLeft { + self.menuContent() + .padding(.leading, 20) + + Spacer() + } + } + } + } + } + } + + @ViewBuilder + private func menuContent() -> some View { + Menu { + self.menuItems() + } label: { + + Image(systemName: "line.3.horizontal.circle") + .resizable() + .foregroundColor(.mainTextColor.opacity(0.8)) + .shadow(radius: 5) + .padding(8) + .frame(width: 44, height: 44) + .background(.ultraThinMaterial) + .clipShape(Circle()) + + } + } +} diff --git a/Vernissage/Views/MainView.swift b/Vernissage/Views/MainView.swift index 060dd2c..2412349 100644 --- a/Vernissage/Views/MainView.swift +++ b/Vernissage/Views/MainView.swift @@ -32,21 +32,28 @@ struct MainView: View { var body: some View { self.getMainView() - .navigationTitle(navBarTitle) - .navigationBarTitleDisplayMode(.inline) - .toolbar { - self.getLeadingToolbar() - self.getPrincipalToolbar() - self.getTrailingToolbar() - } - .onChange(of: tipsStore.status) { status in - if status == .successful { - withAnimation(.spring()) { - self.routerPath.presentedOverlay = .successPayment - self.tipsStore.reset() + .navigationMenu(menuPosition: $applicationState.menuPosition) { + self.navigationMenuContent() + } + .navigationTitle(navBarTitle) + .navigationBarTitleDisplayMode(.inline) + .toolbar { + self.getLeadingToolbar() + + if self.applicationState.menuPosition == .top { + self.getPrincipalToolbar() + } + + self.getTrailingToolbar() + } + .onChange(of: tipsStore.status) { status in + if status == .successful { + withAnimation(.spring()) { + self.routerPath.presentedOverlay = .successPayment + self.tipsStore.reset() + } } } - } } @ViewBuilder @@ -92,97 +99,7 @@ struct MainView: View { private func getPrincipalToolbar() -> some ToolbarContent { ToolbarItem(placement: .principal) { Menu { - Button { - self.switchView(to: .home) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .home)) - Image(systemName: "house") - } - } - - Button { - self.switchView(to: .local) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .local)) - Image(systemName: "building") - } - } - - Button { - self.switchView(to: .federated) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .federated)) - Image(systemName: "globe.europe.africa") - } - } - - Button { - self.switchView(to: .search) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .search)) - Image(systemName: "magnifyingglass") - } - } - - Divider() - - Menu { - Button { - self.switchView(to: .trendingPhotos) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .trendingPhotos)) - Image(systemName: "photo.stack") - } - } - - Button { - self.switchView(to: .trendingTags) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .trendingTags)) - Image(systemName: "tag") - } - } - - Button { - self.switchView(to: .trendingAccounts) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .trendingAccounts)) - Image(systemName: "person.3") - } - } - } label: { - HStack { - Text("mainview.tab.trending", comment: "Trending menu section") - Image(systemName: "chart.line.uptrend.xyaxis") - } - } - - Divider() - - Button { - self.switchView(to: .profile) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .profile)) - Image(systemName: "person.crop.circle") - } - } - - Button { - self.switchView(to: .notifications) - } label: { - HStack { - Text(self.getViewTitle(viewMode: .notifications)) - Image(systemName: "bell.badge") - } - } + self.navigationMenuContent() } label: { HStack { Text(navBarTitle, comment: "Navbar title") @@ -244,6 +161,101 @@ struct MainView: View { } } + @ViewBuilder + private func navigationMenuContent() -> some View { + Button { + self.switchView(to: .home) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .home)) + Image(systemName: "house") + } + } + + Button { + self.switchView(to: .local) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .local)) + Image(systemName: "building") + } + } + + Button { + self.switchView(to: .federated) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .federated)) + Image(systemName: "globe.europe.africa") + } + } + + Button { + self.switchView(to: .search) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .search)) + Image(systemName: "magnifyingglass") + } + } + + Divider() + + Menu { + Button { + self.switchView(to: .trendingPhotos) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .trendingPhotos)) + Image(systemName: "photo.stack") + } + } + + Button { + self.switchView(to: .trendingTags) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .trendingTags)) + Image(systemName: "tag") + } + } + + Button { + self.switchView(to: .trendingAccounts) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .trendingAccounts)) + Image(systemName: "person.3") + } + } + } label: { + HStack { + Text("mainview.tab.trending", comment: "Trending menu section") + Image(systemName: "chart.line.uptrend.xyaxis") + } + } + + Divider() + + Button { + self.switchView(to: .profile) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .profile)) + Image(systemName: "person.crop.circle") + } + } + + Button { + self.switchView(to: .notifications) + } label: { + HStack { + Text(self.getViewTitle(viewMode: .notifications)) + Image(systemName: "bell.badge") + } + } + } + @ViewBuilder private func getAvatarImage(avatarUrl: URL?, avatarData: Data?) -> some View { if let avatarData, diff --git a/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift b/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift index aa7dfa4..e962294 100644 --- a/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift +++ b/Vernissage/Views/SettingsView/Subviews/GeneralSectionView.swift @@ -29,6 +29,12 @@ struct GeneralSectionView: View { (Theme.dark, "settings.title.dark") ] + private let menuPositions: [(menuPosition: MenuPosition, name: LocalizedStringKey)] = [ + (MenuPosition.top, "settings.title.topMenu"), + (MenuPosition.bottomRight, "settings.title.bottomRightMenu"), + (MenuPosition.bottomLeft, "settings.title.bottomLeftMenu") + ] + var body: some View { Section("settings.title.general") { @@ -64,6 +70,20 @@ struct GeneralSectionView: View { self.applicationState.theme = theme ApplicationSettingsHandler.shared.set(theme: theme) } + + // Menu position. + Picker(selection: $applicationState.menuPosition) { + ForEach(self.menuPositions, id: \.menuPosition) { item in + Text(item.name, comment: "Menu positions") + .tag(item.menuPosition) + } + } label: { + Text("settings.title.menuPosition", comment: "Menu position") + } + .onChange(of: self.applicationState.menuPosition) { menuPosition in + self.applicationState.menuPosition = menuPosition + ApplicationSettingsHandler.shared.set(menuPosition: menuPosition) + } } } }