Skip to content

Instantly share code, notes, and snippets.

@alperen23230
Last active July 10, 2020 22:46
Show Gist options
  • Save alperen23230/224eac8153690b0c4b1e6fa408580482 to your computer and use it in GitHub Desktop.
Save alperen23230/224eac8153690b0c4b1e6fa408580482 to your computer and use it in GitHub Desktop.
SwiftUI and Combine Codes
import Foundation
import Combine
enum ErrorType {
case badRequest, authError, outdatedError, undefined
}
struct APIError: Error {
let statusCode: Int
var errorDescription: ErrorType {
switch statusCode {
case 401...500:
return .authError
case 501...599:
return .badRequest
case 600:
return .outdatedError
default:
return .undefined
}
}
}
struct APIService {
func fetchWithURLRequest<T: Decodable>(_ urlRequest: URLRequest) -> AnyPublisher<T, Error> {
URLSession.shared.dataTaskPublisher(for: urlRequest)
.mapError({ $0 as Error })
.flatMap({ result -> AnyPublisher<T, Error> in
guard let urlResponse = result.response as? HTTPURLResponse, (200...299).contains(urlResponse.statusCode) else {
return Just(result.response)
.tryMap({ response in
if let urlResponse = response as? HTTPURLResponse {
let apiError = APIError(statusCode: urlResponse.statusCode)
throw apiError
} else {
throw APIError(statusCode: 0)
}
}).eraseToAnyPublisher()
}
return Just(result.data).decode(type: T.self, decoder: JSONDecoder()).eraseToAnyPublisher()
})
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
//
// AppView.swift
// StalkForTwitter
//
// Created by Alperen Ünal on 4.06.2020.
// Copyright © 2020 Alperen Ünal. All rights reserved.
//
import SwiftUI
struct AppView: View {
init() {
UITabBar.appearance().barTintColor = UIColor(named: "BackgroundBlue")
}
var body: some View {
TabView {
InspectedView().tabItem {
Image(systemName: "eye")
Text("Inspected")
}.tag(0)
ProfileView().tabItem {
Image(systemName: "house")
Text("Profile")
}.tag(1)
MoreView().tabItem {
Image(systemName: "ellipsis")
Text("More")
}.tag(2)
}
.accentColor(.white)
}
}
struct AppView_Previews: PreviewProvider {
static var previews: some View {
AppView()
}
}
import SwiftUI
import PopupView
enum ContainedView {
case splash, auth, app
}
struct RootView: View {
@ObservedObject var rootVM = RootViewModel()
var body: some View {
ZStack {
containedView()
.transition(.slide)
}
.onAppear {
NotificationCenter.default.addObserver(forName: NSNotification.Name("signOut"), object: nil, queue: .main) { (_) in
self.rootVM.containedView = .auth
}
self.rootVM.checkIsAuth()
}
.popup(isPresented: $rootVM.protectedError, type: .`default`, closeOnTap: false) {
PopUpView(title: "Oops!", imageName: "protected_account", description: "To use this app, you must be having public account") {
self.rootVM.protectedError = false
self.rootVM.containedView = .auth
}
}
}
func containedView() -> AnyView {
switch rootVM.containedView {
case .splash: return AnyView(SplashView().id("splash"))
case .auth: return AnyView(AuthView().environmentObject(TwitterService()).id("auth"))
case .app: return AnyView(AppView().id("app"))
}
}
struct RootView_Previews: PreviewProvider {
static var previews: some View {
RootView()
}
}
}
import SwiftUI
import FirebaseAuth
import Combine
import KeychainSwift
class RootViewModel: ObservableObject {
@Published var containedView: ContainedView = .splash
@Published var protectedError = false
var isError = false
var cancellables = Set<AnyCancellable>()
let apiService = APIService()
let keychain = KeychainSwift()
func checkIsAuth() {
if Auth.auth().currentUser == nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
self.containedView = .auth
}
}
} else {
self.getUserInfo()
}
}
func getUserInfo() {
let userID = keychain.get("userId") ?? ""
Route.sharedInstance.urlComponent.path = Route.Path.getUserInfo.rawValue
Route.sharedInstance.urlComponent.queryItems = [
URLQueryItem(name: "user_id", value: userID)
]
var urlRequest = URLRequest(url: Route.sharedInstance.urlComponent.url!)
urlRequest.addValue("Bearer \(BEARER_TOKEN)", forHTTPHeaderField: "authorization")
let publisher: AnyPublisher<User, Error> = apiService.fetchWithURLRequest(urlRequest)
publisher.sink(receiveCompletion: { (completion) in
if case .failure(let error) = completion,
let _ = error as? APIError {
self.containedView = .auth
}
}) { (user) in
CurrentUser.addCurrentUser(user: user)
withAnimation {
if !user.protected {
if !self.isError {
self.containedView = .app
} else {
self.containedView = .auth
}
} else {
self.protectedError = true
}
}
}
.store(in: &cancellables)
}
}
import SwiftUI
import FirebaseAuth
import Combine
import KeychainSwift
class RootViewModel: ObservableObject {
@Published var containedView: ContainedView = .splash
@Published var protectedError = false
var isError = false
var cancellables = Set<AnyCancellable>()
let apiService = APIService()
let keychain = KeychainSwift()
func checkIsAuth() {
if Auth.auth().currentUser == nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
self.containedView = .auth
}
}
} else {
self.getUserInfo()
}
}
func getUserInfo() {
let userID = keychain.get("userId") ?? ""
Route.sharedInstance.urlComponent.path = Route.Path.getUserInfo.rawValue
Route.sharedInstance.urlComponent.queryItems = [
URLQueryItem(name: "user_id", value: userID)
]
var urlRequest = URLRequest(url: Route.sharedInstance.urlComponent.url!)
urlRequest.addValue("Bearer \(BEARER_TOKEN)", forHTTPHeaderField: "authorization")
let publisher: AnyPublisher<User, Error> = apiService.fetchWithURLRequest(urlRequest)
publisher.sink(receiveCompletion: { (completion) in
if case .failure(let error) = completion,
let _ = error as? APIError {
self.containedView = .auth
}
}) { (user) in
CurrentUser.addCurrentUser(user: user)
withAnimation {
if !user.protected {
if !self.isError {
self.containedView = .app
} else {
self.containedView = .auth
}
} else {
self.protectedError = true
}
}
}
.store(in: &cancellables)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment