Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Add long tap and menu for custom navbar #389

Merged
merged 8 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Authorization/Authorization/Presentation/Login/SignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ public struct SignInView: View {
}.frame(maxWidth: .infinity, maxHeight: 200)
if viewModel.config.features.startupScreenEnabled {
VStack {
Button(action: { viewModel.router.back() }, label: {
CoreAssets.arrowLeft.swiftUIImage.renderingMode(.template)
.backButtonStyle(color: Theme.Colors.loginNavigationText)
})
.foregroundColor(Theme.Colors.styledButtonText)
BackNavigationButton(
color: Theme.Colors.loginNavigationText,
action: {
viewModel.router.back()
}
)
.backViewStyle()
.padding(.leading, isHorizontal ? 48 : 0)
.padding(.top, 11)
.accessibilityIdentifier("back_button")

}.frame(maxWidth: .infinity, alignment: .topLeading)
.padding(.top, isHorizontal ? 20 : 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ public struct SignUpView: View {
.accessibilityIdentifier("register_text")
}
VStack {
Button(action: { viewModel.router.back() }, label: {
CoreAssets.arrowLeft.swiftUIImage.renderingMode(.template)
.backButtonStyle(color: Theme.Colors.loginNavigationText)
})
.foregroundColor(Theme.Colors.styledButtonText)
BackNavigationButton(
color: Theme.Colors.loginNavigationText,
action: {
viewModel.router.back()
}
)
.backViewStyle()
.padding(.leading, isHorizontal ? 48 : 0)
.accessibilityIdentifier("back_button")

}.frame(minWidth: 0,
maxWidth: .infinity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public struct StartupView: View {
}
.frameLimit()
}
.navigationTitle(AuthLocalization.Startup.title)
.hideNavigationBar()
.padding(.all, isHorizontal ? 1 : 0)
.background(Theme.Colors.background.ignoresSafeArea(.all))
Expand Down
2 changes: 2 additions & 0 deletions Authorization/Authorization/SwiftGen/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public enum AuthLocalization {
public static let searchPlaceholder = AuthLocalization.tr("Localizable", "STARTUP.SEARCH_PLACEHOLDER", fallback: "Search our 3000+ courses")
/// What do you want to learn?
public static let searchTitle = AuthLocalization.tr("Localizable", "STARTUP.SEARCH_TITLE", fallback: "What do you want to learn?")
/// Start
public static let title = AuthLocalization.tr("Localizable", "STARTUP.TITLE", fallback: "Start")
}
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
Expand Down
1 change: 1 addition & 0 deletions Authorization/Authorization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ accordance with the [Privacy Policy.](%@)";
"STARTUP.SEARCH_TITLE" = "What do you want to learn?";
"STARTUP.SEARCH_PLACEHOLDER" = "Search our 3000+ courses";
"STARTUP.EXPLORE_ALL_COURSES" = "Explore all courses";
"STARTUP.TITLE" = "Start";
1 change: 1 addition & 0 deletions Authorization/Authorization/uk.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ accordance with the [Privacy Policy.](%@)";
"STARTUP.SEARCH_TITLE" = "What do you want to learn?";
"STARTUP.SEARCH_PLACEHOLDER" = "Search our 3000+ courses";
"STARTUP.EXPLORE_ALL_COURSES" = "Explore all courses";
"STARTUP.TITLE" = "Start";
8 changes: 8 additions & 0 deletions Core/Core.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
06619EAD2B90918B001FAADE /* ReadabilityInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06619EAC2B90918B001FAADE /* ReadabilityInjection.swift */; };
06619EAF2B973B25001FAADE /* AccessibilityInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06619EAE2B973B25001FAADE /* AccessibilityInjection.swift */; };
06BEEA0E2B6A55C500D25A97 /* ColorInversionInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06BEEA0D2B6A55C500D25A97 /* ColorInversionInjection.swift */; };
06DEA4A32BBD66A700110D20 /* BackNavigationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06DEA4A22BBD66A700110D20 /* BackNavigationButton.swift */; };
06DEA4A52BBD66D700110D20 /* BackNavigationButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06DEA4A42BBD66D700110D20 /* BackNavigationButtonViewModel.swift */; };
070019A528F6F17900D5FC78 /* Data_Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = 070019A428F6F17900D5FC78 /* Data_Media.swift */; };
070019AC28F6FD0100D5FC78 /* CourseDetailBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 070019AB28F6FD0100D5FC78 /* CourseDetailBlock.swift */; };
070019AE28F701B200D5FC78 /* Certificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 070019AD28F701B200D5FC78 /* Certificate.swift */; };
Expand Down Expand Up @@ -275,6 +277,8 @@
06619EAC2B90918B001FAADE /* ReadabilityInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadabilityInjection.swift; sourceTree = "<group>"; };
06619EAE2B973B25001FAADE /* AccessibilityInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityInjection.swift; sourceTree = "<group>"; };
06BEEA0D2B6A55C500D25A97 /* ColorInversionInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorInversionInjection.swift; sourceTree = "<group>"; };
06DEA4A22BBD66A700110D20 /* BackNavigationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackNavigationButton.swift; sourceTree = "<group>"; };
06DEA4A42BBD66D700110D20 /* BackNavigationButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackNavigationButtonViewModel.swift; sourceTree = "<group>"; };
070019A428F6F17900D5FC78 /* Data_Media.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data_Media.swift; sourceTree = "<group>"; };
070019AB28F6FD0100D5FC78 /* CourseDetailBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDetailBlock.swift; sourceTree = "<group>"; };
070019AD28F701B200D5FC78 /* Certificate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Certificate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -725,6 +729,8 @@
BA8FA6672AD59A5700EA029A /* SocialAuthButton.swift */,
02E93F862AEBAED4006C4750 /* AppReview */,
BA981BCF2B91ED50005707C2 /* FullScreenProgressView.swift */,
06DEA4A22BBD66A700110D20 /* BackNavigationButton.swift */,
06DEA4A42BBD66D700110D20 /* BackNavigationButtonViewModel.swift */,
);
path = Base;
sourceTree = "<group>";
Expand Down Expand Up @@ -1062,6 +1068,7 @@
06619EAF2B973B25001FAADE /* AccessibilityInjection.swift in Sources */,
BAFB99822B0E2354007D09F9 /* FacebookConfig.swift in Sources */,
027BD3B32909475900392132 /* Publishers+KeyboardState.swift in Sources */,
06DEA4A32BBD66A700110D20 /* BackNavigationButton.swift in Sources */,
0727877D28D25212002E9142 /* ProgressBar.swift in Sources */,
BA981BD02B91ED50005707C2 /* FullScreenProgressView.swift in Sources */,
0236961F28F9A2F600EEF206 /* AuthEndpoint.swift in Sources */,
Expand Down Expand Up @@ -1142,6 +1149,7 @@
072787B628D37A0E002E9142 /* Validator.swift in Sources */,
0236961D28F9A2D200EEF206 /* Data_AuthResponse.swift in Sources */,
A5F4E7B52B61544A00ACD166 /* BrazeConfig.swift in Sources */,
06DEA4A52BBD66D700110D20 /* BackNavigationButtonViewModel.swift in Sources */,
02AFCC182AEFDB24000360F0 /* ThirdPartyMailClient.swift in Sources */,
0233D5712AF13EC800BAC8BD /* SelectMailClientView.swift in Sources */,
BAFB99842B0E282E007D09F9 /* MicrosoftConfig.swift in Sources */,
Expand Down
11 changes: 8 additions & 3 deletions Core/Core/Extensions/ViewExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@ public extension View {
func onFirstAppear(_ action: @escaping () -> Void) -> some View {
modifier(FirstAppear(action: action))
}

func backViewStyle(topPadding: CGFloat = -10) -> some View {
return self
.frame(height: 24)
.padding(.horizontal, 8)
.offset(y: topPadding)
}
}

public extension View {
Expand Down Expand Up @@ -300,10 +307,8 @@ public extension Image {
.renderingMode(.template)
.resizable()
.scaledToFit()
.frame(height: 24)
.padding(.horizontal, 8)
.offset(y: topPadding)
.foregroundColor(color)
.backViewStyle(topPadding: topPadding)
}
}

Expand Down
93 changes: 93 additions & 0 deletions Core/Core/View/Base/BackNavigationButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//
// BackNavigationButton.swift
// Core
//
// Created by Vadim Kuznetsov on 3.04.24.
//

import SwiftUI
import Theme

class BackButton: UIButton {
override func menuAttachmentPoint(for configuration: UIContextMenuConfiguration) -> CGPoint {
return .zero
}
}

public struct BackNavigationButtonRepresentable: UIViewRepresentable {
@ObservedObject var viewModel: BackNavigationButtonViewModel
var action: (() -> Void)?
var color: Color

init(action: (() -> Void)? = nil, color: Color, viewModel: BackNavigationButtonViewModel) {
self.viewModel = viewModel
self.action = action
self.color = color
}

public func makeUIView(context: Context) -> UIButton {
let button = BackButton(type: .custom)
let image = CoreAssets.arrowLeft.image.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.tintColor = UIColor(color)
button.contentHorizontalAlignment = .leading
button.addTarget(context.coordinator, action: #selector(Coordinator.buttonAction), for: .touchUpInside)
button.accessibilityIdentifier = "back_button"
return button
}

public func updateUIView(_ button: UIButton, context: Context) {
var actions: [UIAction] = []
for item in viewModel.items {
let action = UIAction(title: item.title) {[weak viewModel] _ in
viewModel?.navigateTo(item: item)
}
actions.append(action)
}
button.menu = UIMenu(title: "", children: actions)
}

public func makeCoordinator() -> Coordinator {
Coordinator(action: action)
}

public class Coordinator: NSObject {
var action: (() -> Void)?
init(action: (() -> Void)?) {
self.action = action
}

@objc func buttonAction() {
action?()
}
}
}

public struct BackNavigationButton: View {
@StateObject var viewModel = BackNavigationButtonViewModel()
private let color: Color
private let action: (() -> Void)?

public init(
color: Color = Theme.Colors.accentXColor,
action: (() -> Void)? = nil
) {
self.color = color
self.action = action
}

public var body: some View {
BackNavigationButtonRepresentable(action: action, color: color, viewModel: viewModel)
.onAppear {
viewModel.loadItems()
}

}
}
#if DEBUG
struct BackNavigationButton_Previews: PreviewProvider {
static var previews: some View {
BackNavigationButton()
}
}
#endif
41 changes: 41 additions & 0 deletions Core/Core/View/Base/BackNavigationButtonViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// BackNavigationButtonViewModel.swift
// Core
//
// Created by Vadim Kuznetsov on 3.04.24.
//

import Swinject
import UIKit

public protocol BackNavigationProtocol {
func getBackMenuItems() -> [BackNavigationMenuItem]
func navigateTo(item: BackNavigationMenuItem)
}

public struct BackNavigationMenuItem: Identifiable {
public var id: Int
public var title: String

public init(id: Int, title: String) {
self.id = id
self.title = title
}
}

class BackNavigationButtonViewModel: ObservableObject {
private let helper: BackNavigationProtocol
@Published var items: [BackNavigationMenuItem] = []

init() {
self.helper = Container.shared.resolve(BackNavigationProtocol.self)!
}

func loadItems() {
self.items = helper.getBackMenuItems()
}

func navigateTo(item: BackNavigationMenuItem) {
helper.navigateTo(item: item)
}
}
22 changes: 8 additions & 14 deletions Core/Core/View/Base/NavigationBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,14 @@ public struct NavigationBar: View {
}
.padding(.horizontal, 24)
if leftButton {
VStack {
Button(action: {
leftButtonAction?()
}, label: {
CoreAssets.arrowLeft.swiftUIImage
.backButtonStyle(color: leftButtonColor)
.padding(8)
})
.foregroundColor(Theme.Colors.styledButtonText)
.accessibilityIdentifier("back_button")

}.frame(minWidth: 0,
maxWidth: .infinity,
alignment: .topLeading)
VStack {
BackNavigationButton(color: leftButtonColor, action: leftButtonAction)
.padding(8)
.backViewStyle()
}
.frame(minWidth: 0,
maxWidth: .infinity,
alignment: .topLeading)

}
if rightButtonType != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public struct SearchView: View {
viewModel.searchText = ""
}
.background(Theme.Colors.background.ignoresSafeArea())
.addTapToEndEditing(isForced: true)
.avoidKeyboard(dismissKeyboardByTap: true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,19 @@ public struct ResponsesView: View {
}
.ignoresSafeArea(.all, edges: .horizontal)
.navigationBarHidden(false)
.navigationBarBackButtonHidden(false)
.navigationBarBackButtonHidden(true)
.navigationTitle(title)
.toolbar {
ToolbarItem(
placement: .navigationBarLeading,
content: {
BackNavigationButton(color: Theme.Colors.accentColor) {
viewModel.router.back()
}
.offset(x: -8, y: -1.5)
}
)
}
.edgesIgnoringSafeArea(.bottom)
.background(
Theme.Colors.background
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,19 @@ public struct ThreadView: View {
}
.ignoresSafeArea(.all, edges: .horizontal)
.navigationBarHidden(false)
.navigationBarBackButtonHidden(false)
.navigationBarBackButtonHidden(true)
.navigationTitle(title)
.toolbar {
ToolbarItem(
placement: .navigationBarLeading,
content: {
BackNavigationButton(color: Theme.Colors.accentColor) {
viewModel.router.back()
}
.offset(x: -8, y: -1.5)
}
)
}
.onFirstAppear {
Task {
await viewModel.getPosts(thread: thread, page: 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,18 @@ public struct DiscussionSearchTopicsView: View {
}
}
}
.background(Theme.Colors.background.ignoresSafeArea())
.avoidKeyboard(dismissKeyboardByTap: true)
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
.navigationTitle(DiscussionLocalization.search)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
withAnimation(.easeIn(duration: 0.3)) {
animated = true
}
}
}
.background(Theme.Colors.background.ignoresSafeArea())
.addTapToEndEditing(isForced: true)
}
}

Expand Down
4 changes: 4 additions & 0 deletions OpenEdX/DI/ScreenAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,10 @@ class ScreenAssembly: Assembly {
config: r.resolve(ConfigProtocol.self)!
)
}

container.register(BackNavigationProtocol.self) { r in
r.resolve(Router.self)!
}
}
}
// swiftlint:enable function_body_length type_body_length
Loading
Loading