Skip to content

Commit

Permalink
feat: pre-login mobile app exploration (#139)
Browse files Browse the repository at this point in the history
* feat: pre-login mobile app exploration

* fix: generated mock files again to fix the broken tests

* refactor: file formatting

* fix: fix broken code after GitHub resolve conflicts

* chore: making feature configureable via config

* refactor: remove empty method that was wrote for implementing analytics in future

* fix: fixup after rebasing with develop

* refactor: address feedback

* refactor: address review feedback

* fix: getting the ci_script changes

* refactor: address review feedback

* refactor: delete old config file
  • Loading branch information
saeedbashir authored Dec 2, 2023
1 parent 375f99b commit ec53c4c
Show file tree
Hide file tree
Showing 28 changed files with 706 additions and 48 deletions.
20 changes: 20 additions & 0 deletions Authorization/Authorization.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0770DE7028D0C0E7006D8A5D /* Strings.swift */; };
5FB79D2802949372CDAF08D6 /* Pods_App_Authorization_AuthorizationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FAE9B7FD61FF88C9C4FE1E8 /* Pods_App_Authorization_AuthorizationTests.framework */; };
DE843D6BB1B9DDA398494890 /* Pods_App_Authorization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47BCFB7C19382EECF15131B6 /* Pods_App_Authorization.framework */; };
E03261642AE64676002CA7EB /* StartupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03261632AE64676002CA7EB /* StartupViewModel.swift */; };
E03261662AE64AF4002CA7EB /* StartupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03261652AE64AF4002CA7EB /* StartupView.swift */; };
E03261682AE9F156002CA7EB /* LogistrationBottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03261672AE9F156002CA7EB /* LogistrationBottomView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -75,6 +78,9 @@
96C85172770225EB81A6D2DA /* Pods-App-Authorization.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.releasedev.xcconfig"; sourceTree = "<group>"; };
9BF6A1004A955E24527FCF0F /* Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.releaseprod.xcconfig"; sourceTree = "<group>"; };
A99D45203C981893C104053A /* Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig"; sourceTree = "<group>"; };
E03261632AE64676002CA7EB /* StartupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupViewModel.swift; sourceTree = "<group>"; };
E03261652AE64AF4002CA7EB /* StartupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartupView.swift; sourceTree = "<group>"; };
E03261672AE9F156002CA7EB /* LogistrationBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogistrationBottomView.swift; sourceTree = "<group>"; };
E78971D8E6ED2116BBF9FD66 /* Pods-App-Authorization.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.release.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.release.xcconfig"; sourceTree = "<group>"; };
F52826C68AEA1CF4769389EA /* Pods-App-Authorization.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.releasestage.xcconfig"; sourceTree = "<group>"; };
F5802BBA113276950ABCD9B3 /* Pods-App-Authorization.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.releaseprod.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -139,6 +145,7 @@
071009CC28D1E24000344290 /* Presentation */ = {
isa = PBXGroup;
children = (
E03261622AE6464A002CA7EB /* Startup */,
020C31BD290AADA700D6DEA2 /* Base */,
071009C528D1D9FA00344290 /* Login */,
07169462296D93E000E3DED6 /* Registration */,
Expand Down Expand Up @@ -258,6 +265,16 @@
path = ../Pods;
sourceTree = "<group>";
};
E03261622AE6464A002CA7EB /* Startup */ = {
isa = PBXGroup;
children = (
E03261632AE64676002CA7EB /* StartupViewModel.swift */,
E03261652AE64AF4002CA7EB /* StartupView.swift */,
E03261672AE9F156002CA7EB /* LogistrationBottomView.swift */,
);
path = Startup;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -471,11 +488,14 @@
0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */,
025F40E229D360E20064C183 /* ResetPasswordViewModel.swift in Sources */,
02066B462906D72F00F4307E /* SignUpViewModel.swift in Sources */,
E03261642AE64676002CA7EB /* StartupViewModel.swift in Sources */,
02A2ACDB2A4B016100FBBBBB /* AuthorizationAnalytics.swift in Sources */,
E03261682AE9F156002CA7EB /* LogistrationBottomView.swift in Sources */,
025F40E029D1E2FC0064C183 /* ResetPasswordView.swift in Sources */,
020C31CB290BF49900D6DEA2 /* FieldsView.swift in Sources */,
0770DE4E28D0A677006D8A5D /* SignInView.swift in Sources */,
02F3BFE5292533720051930C /* AuthorizationRouter.swift in Sources */,
E03261662AE64AF4002CA7EB /* StartupView.swift in Sources */,
071009C728D1DA4F00344290 /* SignInViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
36 changes: 25 additions & 11 deletions Authorization/Authorization/Presentation/Login/SignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import SwiftUI
import Core
import Swinject

public struct SignInView: View {

Expand All @@ -29,6 +30,19 @@ public struct SignInView: View {
.resizable()
.edgesIgnoringSafeArea(.top)
}.frame(maxWidth: .infinity, maxHeight: 200)
if viewModel.config.features.startupScreenEnabled {
VStack {
Button(action: { viewModel.router.back() }, label: {
CoreAssets.arrowLeft.swiftUIImage.renderingMode(.template)
.backButtonStyle(color: .white)
})
.foregroundColor(Theme.Colors.styledButtonText)
.padding(.leading, isHorizontal ? 48 : 0)
.padding(.top, 11)

}.frame(maxWidth: .infinity, alignment: .topLeading)
.padding(.top, isHorizontal ? 20 : 0)
}

VStack(alignment: .center) {
CoreAssets.appLogo.swiftUIImage
Expand Down Expand Up @@ -83,21 +97,23 @@ public struct SignInView: View {
.stroke(lineWidth: 1)
.fill(Theme.Colors.textInputStroke)
)

HStack {
Button(AuthLocalization.SignIn.registerBtn) {
viewModel.trackSignUpClicked()
viewModel.router.showRegisterScreen()
}.foregroundColor(Theme.Colors.accentColor)

Spacer()

if !viewModel.config.features.startupScreenEnabled {
Button(AuthLocalization.SignIn.registerBtn) {
viewModel.trackSignUpClicked()
viewModel.router.showRegisterScreen()
}.foregroundColor(Theme.Colors.accentColor)

Spacer()
}

Button(AuthLocalization.SignIn.forgotPassBtn) {
viewModel.trackForgotPasswordClicked()
viewModel.router.showForgotPasswordScreen()
}.foregroundColor(Theme.Colors.accentColor)
.padding(.top, 0)
}
.padding(.top, 10)

if viewModel.isShowProgress {
HStack(alignment: .center) {
ProgressBar(size: 40, lineWidth: 8)
Expand Down Expand Up @@ -153,8 +169,6 @@ public struct SignInView: View {
}
}
.hideNavigationBar()
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
.ignoresSafeArea(.all, edges: .horizontal)
.background(Theme.Colors.background.ignoresSafeArea(.all))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class SignInViewModel: ObservableObject {
}

let router: AuthorizationRouter
private let config: ConfigProtocol
let config: ConfigProtocol
private let interactor: AuthInteractorProtocol
private let analytics: AuthorizationAnalytics
private let validator: Validator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// LogistrationBottomView.swift
// Authorization
//
// Created by SaeedBashir on 10/26/23.
//

import Foundation
import SwiftUI
import Core

public struct LogistrationBottomView: View {
@ObservedObject
private var viewModel: StartupViewModel

@Environment(\.isHorizontal) private var isHorizontal

public init(viewModel: StartupViewModel) {
self.viewModel = viewModel
}

public var body: some View {
VStack(alignment: .leading) {
HStack(spacing: 24) {
StyledButton(AuthLocalization.SignIn.registerBtn) {
viewModel.router.showRegisterScreen()
viewModel.tracksignUpClicked()
}
.frame(maxWidth: .infinity)

StyledButton(
AuthLocalization.SignIn.logInTitle,
action: { viewModel.router.showLoginScreen() },
color: .white,
textColor: Theme.Colors.accentColor,
borderColor: Theme.Colors.textInputStroke
)
.frame(width: 100)
}
.padding(.horizontal, isHorizontal ? 0 : 0)
}
.padding(.horizontal, isHorizontal ? 10 : 24)
}
}

struct LogistrationBottomView_Previews: PreviewProvider {
static var previews: some View {
let vm = StartupViewModel(
interactor: AuthInteractor.mock,
router: AuthorizationRouterMock(),
analytics: AuthorizationAnalyticsMock()
)
LogistrationBottomView(viewModel: vm)
.preferredColorScheme(.light)
.previewDisplayName("StartupView Light")
.loadFonts()

LogistrationBottomView(viewModel: vm)
.preferredColorScheme(.dark)
.previewDisplayName("StartupView Dark")
.loadFonts()
}
}
124 changes: 124 additions & 0 deletions Authorization/Authorization/Presentation/Startup/StartupView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//
// StartupView.swift
// Authorization
//
// Created by SaeedBashir on 10/23/23.
//

import Foundation
import SwiftUI
import Core

public struct StartupView: View {

@State private var searchQuery: String = ""

@Environment(\.isHorizontal) private var isHorizontal

@ObservedObject
private var viewModel: StartupViewModel

public init(viewModel: StartupViewModel) {
self.viewModel = viewModel
}

public var body: some View {
ZStack(alignment: .top) {
VStack(alignment: .leading) {
CoreAssets.appLogo.swiftUIImage
.resizable()
.frame(maxWidth: 189, maxHeight: 54)
.padding(.top, isHorizontal ? 20 : 40)
.padding(.bottom, isHorizontal ? 0 : 20)
.padding(.horizontal, isHorizontal ? 10 : 24)
.colorMultiply(Theme.Colors.accentColor)

VStack {
VStack(alignment: .leading) {
Text(AuthLocalization.Startup.infoMessage)
.font(Theme.Fonts.titleLarge)
.foregroundColor(Theme.Colors.textPrimary)
.padding(.bottom, isHorizontal ? 10 : 20 )

Text(AuthLocalization.Startup.searchTitle)
.font(Theme.Fonts.bodyLarge)
.bold()
.foregroundColor(Theme.Colors.textPrimary)
.padding(.top, isHorizontal ? 0 : 24)

HStack(spacing: 11) {
Image(systemName: "magnifyingglass")
.padding(.leading, 16)
.padding(.top, 1)
TextField(AuthLocalization.Startup.searchPlaceholder, text: $searchQuery, onCommit: {
if searchQuery.isEmpty { return }
viewModel.router.showDiscoveryScreen(searchQuery: searchQuery, fromStartupScreen: true)
})
.autocapitalization(.none)
.autocorrectionDisabled()
.frame(minHeight: 50)
.submitLabel(.search)

}.overlay(
Theme.Shapes.textInputShape
.stroke(lineWidth: 1)
.fill(Theme.Colors.textInputStroke)
)
.background(
Theme.Shapes.textInputShape
.fill(Theme.Colors.textInputBackground)
)

Button {
viewModel.router.showDiscoveryScreen(searchQuery: searchQuery, fromStartupScreen: true)
} label: {
Text(AuthLocalization.Startup.exploreAllCourses)
.underline()
.foregroundColor(Theme.Colors.accentColor)
.font(Theme.Fonts.bodyLarge)
}
.padding(.top, isHorizontal ? 0 : 5)
Spacer()
}
.padding(.horizontal, isHorizontal ? 10 : 24)

LogistrationBottomView(viewModel: viewModel)
}
.padding(.top, 10)
.padding(.bottom, 2)
}
.onDisappear {
searchQuery = ""
}
}
.hideNavigationBar()
.padding(.all, isHorizontal ? 1 : 0)
.background(Theme.Colors.background.ignoresSafeArea(.all))
.ignoresSafeArea(.keyboard, edges: .bottom)
.onTapGesture {
UIApplication.shared.endEditing()
}
}
}

#if DEBUG
struct StartupView_Previews: PreviewProvider {
static var previews: some View {
let vm = StartupViewModel(
interactor: AuthInteractor.mock,
router: AuthorizationRouterMock(),
analytics: AuthorizationAnalyticsMock()
)

StartupView(viewModel: vm)
.preferredColorScheme(.light)
.previewDisplayName("StartupView Light")
.loadFonts()

StartupView(viewModel: vm)
.preferredColorScheme(.dark)
.previewDisplayName("StartupView Dark")
.loadFonts()
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// StartupViewModel.swift
// Authorization
//
// Created by SaeedBashir on 10/23/23.
//

import Foundation
import Core

public class StartupViewModel: ObservableObject {
let router: AuthorizationRouter
private let interactor: AuthInteractorProtocol
private let analytics: AuthorizationAnalytics
@Published var searchQuery: String?

public init(
interactor: AuthInteractorProtocol,
router: AuthorizationRouter,
analytics: AuthorizationAnalytics
) {
self.interactor = interactor
self.router = router
self.analytics = analytics
}

func tracksignUpClicked() {
analytics.signUpClicked()
}
}
10 changes: 10 additions & 0 deletions Authorization/Authorization/SwiftGen/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ public enum AuthLocalization {
/// Sign up
public static let title = AuthLocalization.tr("Localizable", "SIGN_UP.TITLE", fallback: "Sign up")
}
public enum Startup {
/// Explore all courses
public static let exploreAllCourses = AuthLocalization.tr("Localizable", "STARTUP.EXPLORE_ALL_COURSES", fallback: "Explore all courses")
/// Courses and programs from the world's best universities in your pocket.
public static let infoMessage = AuthLocalization.tr("Localizable", "STARTUP.INFO_MESSAGE", fallback: "Courses and programs from the world's best universities in your pocket.")
/// Search our 3000+ courses
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?")
}
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
Expand Down
5 changes: 5 additions & 0 deletions Authorization/Authorization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@
"FORGOT.REQUEST" = "Reset password";
"FORGOT.CHECK_TITLE" = "Check your email";
"FORGOT.CHECK_Description" = "We have sent a password recover instructions to your email ";

"STARTUP.INFO_MESSAGE" = "Courses and programs from the world's best universities in your pocket.";
"STARTUP.SEARCH_TITLE" = "What do you want to learn?";
"STARTUP.SEARCH_PLACEHOLDER" = "Search our 3000+ courses";
"STARTUP.EXPLORE_ALL_COURSES" = "Explore all courses";
5 changes: 5 additions & 0 deletions Authorization/Authorization/uk.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@
"FORGOT.REQUEST" = "Відновити пароль";
"FORGOT.CHECK_TITLE" = "Перевірте свою електронну пошту";
"FORGOT.CHECK_Description" = "Ми надіслали інструкції щодо відновлення пароля на вашу електронну пошту ";

"STARTUP.INFO_MESSAGE" = "Courses and programs from the world's best universities in your pocket.";
"STARTUP.SEARCH_TITLE" = "What do you want to learn?";
"STARTUP.SEARCH_PLACEHOLDER" = "Search our 3000+ courses";
"STARTUP.EXPLORE_ALL_COURSES" = "Explore all courses";
Loading

0 comments on commit ec53c4c

Please sign in to comment.