Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7ab0dd9
[feat] created protocol Onboarding presenting
GosutoDev Jun 5, 2024
b6b9885
[feat] created protocl CancellablesContaining
GosutoDev Jun 5, 2024
a20a475
[feat] apply protocol Cancellables to classes
GosutoDev Jun 5, 2024
d5a41f3
[feat] made classes final
GosutoDev Jun 5, 2024
9dc03ed
[feat] apply protocol OnboardingCoordinatorPresenting to MainTabBArCo…
GosutoDev Jun 5, 2024
d60ae89
[feat] change value of isSignedIn to show MainTabBar first
GosutoDev Jun 5, 2024
4947ec3
[feat] made Onboarding sheet instead of fullscreen
GosutoDev Jun 5, 2024
e0caf50
[feat] made button Onboarding Modal working, to show sheet
GosutoDev Jun 5, 2024
3e6b40b
[feat] made button Onboarding working
GosutoDev Jun 5, 2024
b849a31
[style] added marks
GosutoDev Jun 5, 2024
7a15284
[feat] created Endpoint protocol + Convenience
GosutoDev Jun 6, 2024
2ee66a7
[feat] created ImagesRouter
GosutoDev Jun 6, 2024
64414fe
[feat] created API manager
GosutoDev Jun 6, 2024
edfc379
[feat] created JokesRouter
GosutoDev Jun 6, 2024
53b9f3b
[feat] show logger info when requesting api jokes
GosutoDev Jun 6, 2024
92599d8
[style] remove swiftlint warnings
GosutoDev Jun 7, 2024
01f7947
[feat] created HTTPResponseStatusCode
GosutoDev Jun 7, 2024
1af06b7
[feat] added more HTTP Methods
GosutoDev Jun 7, 2024
7c3043c
[feat] created protocol JokeServicing
GosutoDev Jun 8, 2024
3e3040d
[feat] created class Joke Service
GosutoDev Jun 8, 2024
5fcb83d
[feat] try to run the app with the jokes
GosutoDev Jun 8, 2024
f6a1d85
[fix] able to load images
GosutoDev Jun 9, 2024
fc3d6a1
[refactor] rewrite correct naming
GosutoDev Jun 9, 2024
3b86867
[feat] set categoriesCollectionView as lazy
GosutoDev Jun 9, 2024
b2777c5
[style] remove swiftlint warnings
GosutoDev Jun 9, 2024
3381a42
[style] added marks and deleted unused code
GosutoDev Jun 9, 2024
1b5fef7
[style] remove swiftlint warnings
GosutoDev Jun 10, 2024
f0e2b7d
[feat] loading cards if cards stack is below 5
GosutoDev Jun 10, 2024
5a503f9
[style] remove swiftlint warning
GosutoDev Jun 10, 2024
ed240ac
[feat] add OnFirstAppear modifier
GosutoDev Jun 10, 2024
93dafa2
[feat] add typealias Actions
GosutoDev Jun 10, 2024
e63964d
[feat] change onFirstAppear instead onAppear in SwipingView
GosutoDev Jun 10, 2024
6a3d600
[feat] add property jokeID to store joke id from URL
GosutoDev Jun 10, 2024
fd3d403
[style] remove swiftlint warning
GosutoDev Jun 10, 2024
9914448
[style] WRAP LESSON 12
GosutoDev Jun 10, 2024
8430541
[feat] create model Credentials
GosutoDev Jun 10, 2024
4a4265f
[feat] create protocol AuthManaging
GosutoDev Jun 10, 2024
656ba81
[feat] create class Auth Manager
GosutoDev Jun 10, 2024
343d898
[feat] update KeychainService
GosutoDev Jun 10, 2024
11e8eb5
[feat] implement auth signIn in SignInView
GosutoDev Jun 10, 2024
5be12c8
[feat] handle signOut in profile and create Storage Manager
GosutoDev Jun 10, 2024
208977e
[feat] handle writing document in swipingView
GosutoDev Jun 10, 2024
aec8cfc
[feat] read value from firestore and made HEART icon in swipingView
GosutoDev Jun 10, 2024
c8fa6e5
[feat] able to read and rewrite if it liked in homeScreen
GosutoDev Jun 10, 2024
6834226
[style] remove swiftlint warning
GosutoDev Jun 10, 2024
a0531a8
[fix] added deinit to profile and MainTabBar
GosutoDev Jun 11, 2024
bc43873
[feat] able to tap item at homeScreen and direct to Swipe
GosutoDev Jun 12, 2024
1b42dcc
[feat] add scaleToFit for Image
GosutoDev Jun 13, 2024
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
178 changes: 171 additions & 7 deletions App/Course App.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions App/Course App/App/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Combine
import UIKit

final class AppCoordinator: ObservableObject, ViewControllerCoordinator {
final class AppCoordinator: ObservableObject, ViewControllerCoordinator, CancellablesContaining {
// MARK: Private properties
private(set) lazy var rootViewController: UIViewController = {
if isSignedIn {
Expand All @@ -17,9 +17,9 @@ final class AppCoordinator: ObservableObject, ViewControllerCoordinator {
makeSignInFlow().rootViewController
}
}()
private var anyCancellables = Set<AnyCancellable>()

// MARK: Public properties
var cancellables = Set<AnyCancellable>()
var childCoordinators = [Coordinator]()
@Published var isSignedIn = false
}
Expand All @@ -39,7 +39,7 @@ private extension AppCoordinator {
mainTabBarCoordinator.eventPublisher.sink { [weak self] event in
self?.handle(event)
}
.store(in: &anyCancellables)
.store(in: &cancellables)
return mainTabBarCoordinator
}

Expand All @@ -49,22 +49,26 @@ private extension AppCoordinator {
signInCoordinator.eventPublisher.sink { [weak self] event in
self?.handle(event)
}
.store(in: &anyCancellables)
.store(in: &cancellables)
return signInCoordinator
}
}

// MARK: - Setup UI
private extension AppCoordinator {
func setupAppUI() {
UITabBar.appearance().backgroundColor = .brown
UITabBar.appearance().tintColor = .white
UITabBarItem.appearance().setTitleTextAttributes(
[
NSAttributedString.Key.font: TextType.caption.uiFont
],
for: .normal
)
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithDefaultBackground()
tabBarAppearance.backgroundColor = .brown
UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
UITabBar.appearance().standardAppearance = tabBarAppearance

UINavigationBar.appearance().tintColor = .white
}
Expand Down
4 changes: 2 additions & 2 deletions App/Course App/App/BuildConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ struct BuildConfiguration: Decodable {
case jokesBaseURL = "API_JOKES_BASE_URL"
}

let jokesBaseURL: String
let imagesBaseURL: String
let jokesBaseURL: URL
let imagesBaseURL: URL
}

extension BuildConfiguration {
Expand Down
2 changes: 1 addition & 1 deletion App/Course App/App/Course_AppApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import FirebaseCore
import os
import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
final class AppDelegate: NSObject, UIApplicationDelegate {
weak var deeplinkHandler: DeeplinkHandling?

func application(
Expand Down
12 changes: 12 additions & 0 deletions App/Course App/Common/Protocols/CancellablesContaining.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// CancellablesContaining.swift
// Course App
//
// Created by Tomáš Duchoslav on 05.06.2024.
//

import Combine

protocol CancellablesContaining: AnyObject {
var cancellables: Set<AnyCancellable> { get set }
}
8 changes: 8 additions & 0 deletions App/Course App/Common/Services/KeychainService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ final class KeychainService: KeychainServicing {
func storeAuthData(authData: String) throws {
try keychainManager.store(key: KeychainKey.authData.rawValue, value: authData)
}

func fetchAuthData() throws -> String {
try keychainManager.fetch(key: KeychainKey.authData.rawValue)
}

func removeAuthData() throws {
try keychainManager.remove(key: KeychainKey.authData.rawValue)
}
}
11 changes: 11 additions & 0 deletions App/Course App/Common/Types/Action.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// Action.swift
// Course App
//
// Created by Tomáš Duchoslav on 10.06.2024.
//

import Foundation

typealias VoidAction = () -> Void
typealias Action<T> = (T) -> Void
38 changes: 38 additions & 0 deletions App/Course App/DataAPI/DataProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// MockDataProvider.swift
// Course App
//
// Created by Tomáš Duchoslav on 14.05.2024.
//

import UIKit

struct SectionData: Identifiable, Hashable {
let id = UUID()
let title: String
var jokes: [Joke]

init(title: String, jokes: [JokeResponse]) {
self.title = title
self.jokes = jokes.map { Joke(jokeResponse: $0) }
}
}

struct Joke: Identifiable, Hashable {
let id = UUID()
let jokeID: String
let text: String
let categories: [String]
var isLiked: Bool?

init(jokeResponse: JokeResponse, isLiked: Bool? = nil) {
self.jokeID = jokeResponse.id
self.text = jokeResponse.value
self.categories = jokeResponse.categories
self.isLiked = isLiked
}
}

final class DataProvider: ObservableObject {
@Published var data: [SectionData] = []
}
61 changes: 0 additions & 61 deletions App/Course App/DataAPI/MockDataProvider.swift

This file was deleted.

39 changes: 39 additions & 0 deletions App/Course App/Networking/Authentication/FirebaseAuthManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// FirebaseAuthManager.swift
// Course App
//
// Created by Tomáš Duchoslav on 10.06.2024.
//

import FirebaseAuth
import Foundation

final class FirebaseAuthManager: FirebaseAuthManaging {
// MARK: Private properties
private let authService = Auth.auth()
private let keychainService: KeychainServicing = KeychainService(keychainManager: KeychainManager())

// MARK: Functions
func signUp(_ credentials: Credentials) async throws {
let result = try await authService.createUser(withEmail: credentials.email, password: credentials.password)

guard let accessToken = try? await result.user.getIDToken() else {
return
}

try keychainService.storeAuthData(authData: accessToken)
}

func signIn(_ entity: Credentials) async throws {
let result = try await authService.signIn(withEmail: entity.email, password: entity.password)
guard let accessToken = try? await result.user.getIDToken() else {
return
}

try keychainService.storeAuthData(authData: accessToken)
}

func signOut() async throws {
try authService.signOut()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// FirebaseAuthManaging.swift
// Course App
//
// Created by Tomáš Duchoslav on 10.06.2024.
//

import Foundation

protocol FirebaseAuthManaging {
func signUp(_ credentials: Credentials) async throws
func signIn(_ entity: Credentials) async throws
func signOut() async throws
}
46 changes: 46 additions & 0 deletions App/Course App/Networking/Endpoint+Convenience.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Endpoint+Convenience.swift
// Course App
//
// Created by Tomáš Duchoslav on 06.06.2024.
//

import Foundation

extension Endpoint {
var method: HTTPMethod {
.get
}

var headers: [String: String] {
[:]
}

var urlParameters: [String: String] {
[:]
}

func asURLRequest() throws -> URLRequest {
let url = host.appendingPathComponent(path)

guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
throw NetworkingError.invalidUrlComponents
}

if !urlParameters.isEmpty {
urlComponents.queryItems = urlParameters.map { URLQueryItem(name: $0, value: String(describing: $1)) }
}

guard let url = urlComponents.url else {
throw NetworkingError.invalidUrlComponents
}

var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.allHTTPHeaderFields = headers

request.setValue(HTTPHeader.ContentType.json.rawValue, forHTTPHeaderField: HTTPHeader.HeaderField.contentType.rawValue)

return request
}
}
18 changes: 18 additions & 0 deletions App/Course App/Networking/Endpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Endpoint.swift
// Course App
//
// Created by Tomáš Duchoslav on 05.06.2024.
//

import Foundation

protocol Endpoint {
var host: URL { get }
var path: String { get }
var method: HTTPMethod { get }
var headers: [String: String] { get }
var urlParameters: [String: String] { get }

func asURLRequest() throws -> URLRequest
}
20 changes: 20 additions & 0 deletions App/Course App/Networking/Endpoints/ImagesRouter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// ImagesRouter.swift
// Course App
//
// Created by Tomáš Duchoslav on 06.06.2024.
//

import Foundation

enum ImagesRouter: Endpoint {
case size300x200

var host: URL {
BuildConfiguration.default.imagesBaseURL
}

var path: String {
"300/200"
}
}
36 changes: 36 additions & 0 deletions App/Course App/Networking/Endpoints/JokesRouter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// JokesRoutes.swift
// Course App
//
// Created by Tomáš Duchoslav on 06.06.2024.
//

import Foundation

enum JokesRouter: Endpoint {
case getJokeCategories
case getRandomJoke
case getJokeFor(category: String)

var host: URL {
BuildConfiguration.default.jokesBaseURL
}

var path: String {
switch self {
case .getJokeCategories:
"jokes/categories"
case .getRandomJoke, .getJokeFor:
"jokes/random"
}
}

var urlParameters: [String: String] {
switch self {
case let .getJokeFor(category):
["category": category]
default:
[String: String]()
}
}
}
Loading