├── Users
├── Supporting Files
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ └── Info.plist
├── Business Logic
│ ├── Models
│ │ ├── Users.swift
│ │ └── User.swift
│ ├── Endpoints
│ │ ├── Endpoint+Users.swift
│ │ └── Endpoint+URL.swift
│ └── Services
│ │ ├── UserPictureService.swift
│ │ └── UsersService.swift
├── Core
│ └── Networking
│ │ ├── NetworkError.swift
│ │ ├── Endpoint.swift
│ │ └── Networker.swift
├── App
│ └── UsersApp.swift
└── Presentation
│ ├── More Info
│ ├── MoreInfoViewModel.swift
│ ├── MoreInfoConfigurator.swift
│ └── MoreInfoView.swift
│ ├── Users
│ ├── UsersRouter.swift
│ ├── UsersConfigurator.swift
│ ├── UsersView.swift
│ └── UsersViewModel.swift
│ └── User Detail
│ ├── UserDetailRouter.swift
│ ├── UserDetailConfigurator.swift
│ ├── UserDetailViewModel.swift
│ └── UserDetailView.swift
└── Users.xcodeproj
├── project.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── xcuserdata
└── zafar.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── project.pbxproj
/Users/Supporting Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Users/Supporting Files/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Users.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Users/Business Logic/Models/Users.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Users.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Users: Codable {
11 | let data: [User]
12 | }
13 |
--------------------------------------------------------------------------------
/Users/Core/Networking/NetworkError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkError.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | enum NetworkError: Error {
11 | case invalidURL
12 | }
13 |
--------------------------------------------------------------------------------
/Users/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Users/Core/Networking/Endpoint.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Endpoint.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Endpoint {
11 | var path: String
12 | var queryItems: [URLQueryItem] = []
13 | }
14 |
--------------------------------------------------------------------------------
/Users.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Users/App/UsersApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersApp.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct UsersApp: App {
12 |
13 | var body: some Scene {
14 | WindowGroup {
15 | UsersConfigurator.configureUsersView()
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Users/Presentation/More Info/MoreInfoViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MoreInfoViewModel.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | final class MoreInfoViewModel {
11 |
12 | let user: User
13 |
14 | init(user: User) {
15 | self.user = user
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Users/Presentation/Users/UsersRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersRouter.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | final class UsersRouter {
11 |
12 | public static func destinationForTappedUser(user: User) -> some View {
13 | return UserDetailConfigurator.configureUserDetailView(with: user)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Users/Presentation/User Detail/UserDetailRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailRouter.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | final class UserDetailRouter {
11 |
12 | public static func destinationForMoreInfoAction(user: User) -> some View {
13 | return MoreInfoConfigurator.configureMoreInfoView(with: user)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Users/Presentation/More Info/MoreInfoConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MoreInfoConfigurator.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | final class MoreInfoConfigurator {
11 |
12 | static func configureMoreInfoView(with user: User) -> MoreInfoView {
13 | let viewModel = MoreInfoViewModel(user: user)
14 | return MoreInfoView(viewModel: viewModel)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Users.xcodeproj/xcuserdata/zafar.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Users.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Users/Presentation/Users/UsersConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersConfigurator.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | final class UsersConfigurator {
11 |
12 | public static func configureUsersView(
13 | with viewModel: UsersViewModel = UsersViewModel()
14 | ) -> UsersView {
15 |
16 | let usersView = UsersView(viewModel: viewModel)
17 | return usersView
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Users/Presentation/User Detail/UserDetailConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailConfigurator.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | final class UserDetailConfigurator {
11 |
12 | public static func configureUserDetailView(
13 | with user: User)
14 | -> UserDetailView {
15 |
16 | let userDetailView = UserDetailView(
17 | viewModel: UserDetailViewModel(user: user)
18 | )
19 | return userDetailView
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Users/Business Logic/Endpoints/Endpoint+Users.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Endpoint+Users.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Endpoint {
11 |
12 | static var users: Self {
13 | return Endpoint(path: "/user")
14 | }
15 |
16 | static func users(count: Int) -> Self {
17 | return Endpoint(path: "/user", queryItems: [
18 | URLQueryItem(name: "limit", value: "\(count)")
19 | ])
20 | }
21 |
22 | static func user(id: String) -> Self {
23 | return Endpoint(path: "/user/\(id)")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Users/Business Logic/Endpoints/Endpoint+URL.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Endpoint+URL.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Endpoint {
11 | var url: URL {
12 | var components = URLComponents()
13 | components.scheme = "https"
14 | components.host = "dummyapi.io"
15 | components.path = "/data/v1" + path
16 | components.queryItems = queryItems
17 |
18 | guard let url = components.url else {
19 | preconditionFailure("Invalid URL components: \(components)")
20 | }
21 |
22 | return url
23 | }
24 |
25 | var headers: [String: Any] {
26 | return [
27 | "app-id": "YOUR APP ID HERE"
28 | ]
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Users/Business Logic/Models/User.swift:
--------------------------------------------------------------------------------
1 | //
2 | // User.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 |
10 | struct User: Codable, Identifiable {
11 | let id: String?
12 | let title: String?
13 | let firstName: String
14 | let lastName: String
15 | let email: String?
16 | let dateOfBirth: String?
17 | let registerDate: String?
18 | let phone: String?
19 | let picture: String?
20 | }
21 |
22 | extension User {
23 | static func fake() -> Self {
24 | return User(id: "123",
25 | title: "Test",
26 | firstName: "First Name",
27 | lastName: "Last Name",
28 | email: "test@gmail.com",
29 | dateOfBirth: "1/1/1990",
30 | registerDate: "1/1/2020",
31 | phone: "+123456",
32 | picture: nil)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Users/Presentation/Users/UsersView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersView.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct UsersView: View {
11 |
12 | @ObservedObject var viewModel: UsersViewModel
13 |
14 | var body: some View {
15 | NavigationView {
16 | List(viewModel.users.data) { user in
17 |
18 | NavigationLink(
19 | destination: UsersRouter.destinationForTappedUser(
20 | user: user)
21 | ) {
22 | Text(user.firstName)
23 | }
24 |
25 | }.navigationTitle("Users")
26 | }.onAppear(perform: {
27 | viewModel.onAppear()
28 | })
29 | }
30 | }
31 |
32 | struct UsersView_Previews: PreviewProvider {
33 | static var previews: some View {
34 | UsersView(viewModel: UsersViewModel())
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Users/Presentation/More Info/MoreInfoView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MoreInfoView.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct MoreInfoView: View {
11 |
12 | let viewModel: MoreInfoViewModel
13 |
14 | var body: some View {
15 | VStack(alignment: .leading, spacing: 20) {
16 | Text("ID: \(viewModel.user.id ?? "N/A")")
17 | Text("Full Name: \(viewModel.user.firstName) \(viewModel.user.lastName)")
18 | Text("Email: \(viewModel.user.email ?? "N/A")")
19 | Text("Registration Date: \(viewModel.user.registerDate ?? "N/A")")
20 | Text("Phone: \(viewModel.user.phone ?? "N/A")")
21 | }
22 | }
23 | }
24 |
25 | struct MoreInfoView_Previews: PreviewProvider {
26 | static var previews: some View {
27 | MoreInfoView(
28 | viewModel: MoreInfoViewModel(
29 | user: User.fake()
30 | )
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Users/Business Logic/Services/UserPictureService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserPictureService.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | protocol UserPictureServiceProtocol: AnyObject {
12 | var networker: NetworkerProtocol { get }
13 |
14 | func getUserAvatarData(urlString: String) -> AnyPublisher
15 | }
16 |
17 | final class UserPictureService: UserPictureServiceProtocol {
18 | let networker: NetworkerProtocol
19 |
20 | init(networker: NetworkerProtocol = Networker()) {
21 | self.networker = networker
22 | }
23 |
24 | enum UserPictureError: Error {
25 | case dataInvalid
26 | }
27 |
28 | func getUserAvatarData(urlString: String) -> AnyPublisher {
29 | guard let url = URL(string: urlString) else {
30 | return Fail(error: NetworkError.invalidURL).eraseToAnyPublisher()
31 | }
32 |
33 | return networker.getData(url: url, headers: [:])
34 | .mapError { _ in UserPictureError.dataInvalid }
35 | .eraseToAnyPublisher()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Users/Presentation/Users/UsersViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersViewModel.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class UsersViewModel: ObservableObject {
12 | @Published public var users: Users = Users(data: [])
13 |
14 | private var usersService: UsersServiceProtocol
15 | private var cancellables = Set()
16 |
17 | init(users: Users = Users(data: []),
18 | usersService: UsersServiceProtocol = UsersService()) {
19 |
20 | self.users = users
21 | self.usersService = usersService
22 | }
23 |
24 | public func onAppear() {
25 | self.getUsers(count: 40)
26 | }
27 |
28 | private func getUsers(count: Int) {
29 | usersService.getUsers(count: count)
30 | .receive(on: DispatchQueue.main)
31 | .sink { completion in
32 | switch completion {
33 | case .failure(let error):
34 | print(error)
35 | case .finished: break
36 | }
37 | } receiveValue: { [weak self] users in
38 | self?.users = users
39 | }
40 | .store(in: &cancellables)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Users/Presentation/User Detail/UserDetailViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailViewModel.swift
3 | // Users
4 | //
5 | // Created by Zafar on 29/06/21.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | class UserDetailViewModel: ObservableObject {
12 | @Published public var avatar: UIImage = UIImage()
13 |
14 | public let user: User
15 |
16 | private var userPictureService: UserPictureServiceProtocol
17 | private var cancellables = Set()
18 |
19 | init(user: User,
20 | userPictureService: UserPictureServiceProtocol = UserPictureService()) {
21 |
22 | self.user = user
23 | self.userPictureService = userPictureService
24 | }
25 |
26 | public func onAppear() {
27 | getAvatarData()
28 | }
29 |
30 | private func getAvatarData() {
31 | guard let pictureUrlString = user.picture else {
32 | print("URL doesn't exist")
33 | return
34 | }
35 |
36 | userPictureService.getUserAvatarData(urlString: pictureUrlString)
37 | .receive(on: DispatchQueue.main)
38 | .sink { completion in
39 | switch completion {
40 | case .failure(let error): print(error)
41 | case .finished: break
42 | }
43 | } receiveValue: { [weak self] data in
44 | guard let image = UIImage(data: data) else { return }
45 | self?.avatar = image
46 | }
47 | .store(in: &cancellables)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Users/Business Logic/Services/UsersService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UsersService.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | protocol UsersServiceProtocol: AnyObject {
12 | var networker: NetworkerProtocol { get }
13 |
14 | func getUsers() -> AnyPublisher
15 | func getUsers(count: Int) -> AnyPublisher
16 | func getUser(id: String) -> AnyPublisher
17 | }
18 |
19 | final class UsersService: UsersServiceProtocol {
20 |
21 | let networker: NetworkerProtocol
22 |
23 | init(networker: NetworkerProtocol = Networker()) {
24 | self.networker = networker
25 | }
26 |
27 | func getUsers() -> AnyPublisher {
28 | let endpoint = Endpoint.users
29 |
30 | return networker.get(type: Users.self,
31 | url: endpoint.url,
32 | headers: endpoint.headers)
33 | }
34 |
35 | func getUsers(count: Int) -> AnyPublisher {
36 | let endpoint = Endpoint.users(count: count)
37 |
38 | return networker.get(type: Users.self,
39 | url: endpoint.url,
40 | headers: endpoint.headers)
41 | }
42 |
43 | func getUser(id: String) -> AnyPublisher {
44 | let endpoint = Endpoint.user(id: id)
45 |
46 | return networker.get(type: User.self,
47 | url: endpoint.url,
48 | headers: endpoint.headers)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Users/Core/Networking/Networker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Networker.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | protocol NetworkerProtocol: AnyObject {
12 | typealias Headers = [String: Any]
13 |
14 | func get(type: T.Type,
15 | url: URL,
16 | headers: Headers) -> AnyPublisher where T: Decodable
17 |
18 | func getData(url: URL, headers: Headers) -> AnyPublisher
19 | }
20 |
21 | final class Networker: NetworkerProtocol {
22 |
23 | func get(type: T.Type,
24 | url: URL,
25 | headers: Headers) -> AnyPublisher where T : Decodable {
26 |
27 | var urlRequest = URLRequest(url: url)
28 |
29 | headers.forEach { key, value in
30 | if let value = value as? String {
31 | urlRequest.setValue(value, forHTTPHeaderField: key)
32 | }
33 | }
34 |
35 | return URLSession.shared.dataTaskPublisher(for: urlRequest)
36 | .map(\.data)
37 | .decode(type: T.self, decoder: JSONDecoder())
38 | .eraseToAnyPublisher()
39 | }
40 |
41 | func getData(url: URL, headers: Headers) -> AnyPublisher {
42 |
43 | var urlRequest = URLRequest(url: url)
44 |
45 | headers.forEach { key, value in
46 | if let value = value as? String {
47 | urlRequest.setValue(value, forHTTPHeaderField: key)
48 | }
49 | }
50 |
51 | return URLSession.shared.dataTaskPublisher(for: urlRequest)
52 | .map(\.data)
53 | .eraseToAnyPublisher()
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Users/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Users/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Users/Presentation/User Detail/UserDetailView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDetailView.swift
3 | // Users
4 | //
5 | // Created by Zafar on 28/06/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct UserDetailView: View {
11 | @ObservedObject var viewModel: UserDetailViewModel
12 |
13 | let screenWidth = UIScreen.main.bounds.width
14 |
15 | @State private var showingModalSheet = false
16 |
17 | var body: some View {
18 | VStack {
19 | Image(uiImage: viewModel.avatar)
20 | .resizable()
21 | .aspectRatio(contentMode: .fit)
22 | .frame(width: screenWidth * 0.2,
23 | height: screenWidth * 0.2,
24 | alignment: .center)
25 | .clipShape(Circle())
26 | .shadow(radius: 10)
27 | .overlay(Circle().stroke(Color.blue, lineWidth: 3))
28 | .padding()
29 |
30 | HStack {
31 | Text(viewModel.user.firstName)
32 | Text(viewModel.user.lastName)
33 | }
34 | Button(action: {
35 | showingModalSheet.toggle()
36 | }) {
37 | Text("Get more info")
38 | .padding()
39 | .frame(width: screenWidth * 0.6)
40 | .foregroundColor(Color.white)
41 | .background(Color.blue)
42 | .cornerRadius(16)
43 | }
44 | .sheet(isPresented: $showingModalSheet, content: {
45 | UserDetailRouter.destinationForMoreInfoAction(user: viewModel.user)
46 | })
47 | .padding(.top, 20)
48 | Spacer()
49 | }
50 | .navigationTitle(viewModel.user.firstName)
51 | .onAppear(perform: {
52 | self.viewModel.onAppear()
53 | })
54 | }
55 | }
56 |
57 | struct UserDetailView_Previews: PreviewProvider {
58 | static var previews: some View {
59 | UserDetailView(
60 | viewModel: UserDetailViewModel(
61 | user: User.fake()
62 | )
63 | )
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/Users.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1C1A22A2268B7C4F000F03C6 /* UsersConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A22A1268B7C4F000F03C6 /* UsersConfigurator.swift */; };
11 | 1C1A22A4268B7E19000F03C6 /* UserDetailConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A22A3268B7E19000F03C6 /* UserDetailConfigurator.swift */; };
12 | 1C1A22A9268B7F6F000F03C6 /* MoreInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A22A8268B7F6F000F03C6 /* MoreInfoView.swift */; };
13 | 1C1A22AB268B814D000F03C6 /* MoreInfoConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A22AA268B814D000F03C6 /* MoreInfoConfigurator.swift */; };
14 | 1C1A22AD268B82D8000F03C6 /* MoreInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A22AC268B82D8000F03C6 /* MoreInfoViewModel.swift */; };
15 | 1C755659268A262800BB684A /* UsersApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755658268A262800BB684A /* UsersApp.swift */; };
16 | 1C75565B268A262800BB684A /* UsersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C75565A268A262800BB684A /* UsersView.swift */; };
17 | 1C75565D268A262A00BB684A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C75565C268A262A00BB684A /* Assets.xcassets */; };
18 | 1C755660268A262A00BB684A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C75565F268A262A00BB684A /* Preview Assets.xcassets */; };
19 | 1C755668268A26B400BB684A /* UsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755667268A26B400BB684A /* UsersViewModel.swift */; };
20 | 1C75566A268A29CE00BB684A /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755669268A29CE00BB684A /* User.swift */; };
21 | 1C755673268A2D5700BB684A /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755672268A2D5700BB684A /* Endpoint.swift */; };
22 | 1C755675268A2DE900BB684A /* Endpoint+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755674268A2DE900BB684A /* Endpoint+URL.swift */; };
23 | 1C755677268A330300BB684A /* Endpoint+Users.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755676268A330300BB684A /* Endpoint+Users.swift */; };
24 | 1C755679268A346600BB684A /* Networker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755678268A346600BB684A /* Networker.swift */; };
25 | 1C75567B268A364A00BB684A /* UsersService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C75567A268A364A00BB684A /* UsersService.swift */; };
26 | 1C75567D268A3C2F00BB684A /* Users.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C75567C268A3C2F00BB684A /* Users.swift */; };
27 | 1C755681268A3FDF00BB684A /* UserDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755680268A3FDF00BB684A /* UserDetailView.swift */; };
28 | 1C755683268A557400BB684A /* UserDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755682268A557400BB684A /* UserDetailViewModel.swift */; };
29 | 1C755685268A563F00BB684A /* UserPictureService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755684268A563F00BB684A /* UserPictureService.swift */; };
30 | 1C755687268A5A8600BB684A /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755686268A5A8600BB684A /* NetworkError.swift */; };
31 | 1C755689268A608600BB684A /* UserDetailRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C755688268A608600BB684A /* UserDetailRouter.swift */; };
32 | 1C75568B268A61C200BB684A /* UsersRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C75568A268A61C200BB684A /* UsersRouter.swift */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXFileReference section */
36 | 1C1A22A1268B7C4F000F03C6 /* UsersConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersConfigurator.swift; sourceTree = ""; };
37 | 1C1A22A3268B7E19000F03C6 /* UserDetailConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailConfigurator.swift; sourceTree = ""; };
38 | 1C1A22A8268B7F6F000F03C6 /* MoreInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreInfoView.swift; sourceTree = ""; };
39 | 1C1A22AA268B814D000F03C6 /* MoreInfoConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreInfoConfigurator.swift; sourceTree = ""; };
40 | 1C1A22AC268B82D8000F03C6 /* MoreInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreInfoViewModel.swift; sourceTree = ""; };
41 | 1C755655268A262800BB684A /* Users.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Users.app; sourceTree = BUILT_PRODUCTS_DIR; };
42 | 1C755658268A262800BB684A /* UsersApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersApp.swift; sourceTree = ""; };
43 | 1C75565A268A262800BB684A /* UsersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersView.swift; sourceTree = ""; };
44 | 1C75565C268A262A00BB684A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
45 | 1C75565F268A262A00BB684A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
46 | 1C755661268A262A00BB684A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | 1C755667268A26B400BB684A /* UsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersViewModel.swift; sourceTree = ""; };
48 | 1C755669268A29CE00BB684A /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; };
49 | 1C755672268A2D5700BB684A /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; };
50 | 1C755674268A2DE900BB684A /* Endpoint+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Endpoint+URL.swift"; sourceTree = ""; };
51 | 1C755676268A330300BB684A /* Endpoint+Users.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Endpoint+Users.swift"; sourceTree = ""; };
52 | 1C755678268A346600BB684A /* Networker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networker.swift; sourceTree = ""; };
53 | 1C75567A268A364A00BB684A /* UsersService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersService.swift; sourceTree = ""; };
54 | 1C75567C268A3C2F00BB684A /* Users.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Users.swift; sourceTree = ""; };
55 | 1C755680268A3FDF00BB684A /* UserDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailView.swift; sourceTree = ""; };
56 | 1C755682268A557400BB684A /* UserDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailViewModel.swift; sourceTree = ""; };
57 | 1C755684268A563F00BB684A /* UserPictureService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPictureService.swift; sourceTree = ""; };
58 | 1C755686268A5A8600BB684A /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; };
59 | 1C755688268A608600BB684A /* UserDetailRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailRouter.swift; sourceTree = ""; };
60 | 1C75568A268A61C200BB684A /* UsersRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersRouter.swift; sourceTree = ""; };
61 | /* End PBXFileReference section */
62 |
63 | /* Begin PBXFrameworksBuildPhase section */
64 | 1C755652268A262800BB684A /* Frameworks */ = {
65 | isa = PBXFrameworksBuildPhase;
66 | buildActionMask = 2147483647;
67 | files = (
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | /* End PBXFrameworksBuildPhase section */
72 |
73 | /* Begin PBXGroup section */
74 | 1C1A22A5268B7F52000F03C6 /* More Info */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 1C1A22AA268B814D000F03C6 /* MoreInfoConfigurator.swift */,
78 | 1C1A22A8268B7F6F000F03C6 /* MoreInfoView.swift */,
79 | 1C1A22AC268B82D8000F03C6 /* MoreInfoViewModel.swift */,
80 | );
81 | path = "More Info";
82 | sourceTree = "";
83 | };
84 | 1C1A22AE268BA25E000F03C6 /* Services */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 1C75567A268A364A00BB684A /* UsersService.swift */,
88 | 1C755684268A563F00BB684A /* UserPictureService.swift */,
89 | );
90 | path = Services;
91 | sourceTree = "";
92 | };
93 | 1C1A22AF268BA759000F03C6 /* Endpoints */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 1C755674268A2DE900BB684A /* Endpoint+URL.swift */,
97 | 1C755676268A330300BB684A /* Endpoint+Users.swift */,
98 | );
99 | path = Endpoints;
100 | sourceTree = "";
101 | };
102 | 1C75564C268A262800BB684A = {
103 | isa = PBXGroup;
104 | children = (
105 | 1C755657268A262800BB684A /* Users */,
106 | 1C755656268A262800BB684A /* Products */,
107 | );
108 | sourceTree = "";
109 | };
110 | 1C755656268A262800BB684A /* Products */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 1C755655268A262800BB684A /* Users.app */,
114 | );
115 | name = Products;
116 | sourceTree = "";
117 | };
118 | 1C755657268A262800BB684A /* Users */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 1C75566B268A2CD200BB684A /* App */,
122 | 1C75566C268A2CD700BB684A /* Presentation */,
123 | 1C75566D268A2CE900BB684A /* Business Logic */,
124 | 1C75566E268A2D0700BB684A /* Core */,
125 | 1C755671268A2D2E00BB684A /* Supporting Files */,
126 | );
127 | path = Users;
128 | sourceTree = "";
129 | };
130 | 1C75565E268A262A00BB684A /* Preview Content */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 1C75565F268A262A00BB684A /* Preview Assets.xcassets */,
134 | );
135 | path = "Preview Content";
136 | sourceTree = "";
137 | };
138 | 1C75566B268A2CD200BB684A /* App */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 1C755658268A262800BB684A /* UsersApp.swift */,
142 | );
143 | path = App;
144 | sourceTree = "";
145 | };
146 | 1C75566C268A2CD700BB684A /* Presentation */ = {
147 | isa = PBXGroup;
148 | children = (
149 | 1C75567E268A3FCD00BB684A /* Users */,
150 | 1C75567F268A3FD100BB684A /* User Detail */,
151 | 1C1A22A5268B7F52000F03C6 /* More Info */,
152 | );
153 | path = Presentation;
154 | sourceTree = "";
155 | };
156 | 1C75566D268A2CE900BB684A /* Business Logic */ = {
157 | isa = PBXGroup;
158 | children = (
159 | 1C1A22AE268BA25E000F03C6 /* Services */,
160 | 1C75566F268A2D0F00BB684A /* Models */,
161 | 1C1A22AF268BA759000F03C6 /* Endpoints */,
162 | );
163 | path = "Business Logic";
164 | sourceTree = "";
165 | };
166 | 1C75566E268A2D0700BB684A /* Core */ = {
167 | isa = PBXGroup;
168 | children = (
169 | 1C755670268A2D1A00BB684A /* Networking */,
170 | );
171 | path = Core;
172 | sourceTree = "";
173 | };
174 | 1C75566F268A2D0F00BB684A /* Models */ = {
175 | isa = PBXGroup;
176 | children = (
177 | 1C75567C268A3C2F00BB684A /* Users.swift */,
178 | 1C755669268A29CE00BB684A /* User.swift */,
179 | );
180 | path = Models;
181 | sourceTree = "";
182 | };
183 | 1C755670268A2D1A00BB684A /* Networking */ = {
184 | isa = PBXGroup;
185 | children = (
186 | 1C755672268A2D5700BB684A /* Endpoint.swift */,
187 | 1C755678268A346600BB684A /* Networker.swift */,
188 | 1C755686268A5A8600BB684A /* NetworkError.swift */,
189 | );
190 | path = Networking;
191 | sourceTree = "";
192 | };
193 | 1C755671268A2D2E00BB684A /* Supporting Files */ = {
194 | isa = PBXGroup;
195 | children = (
196 | 1C75565C268A262A00BB684A /* Assets.xcassets */,
197 | 1C755661268A262A00BB684A /* Info.plist */,
198 | 1C75565E268A262A00BB684A /* Preview Content */,
199 | );
200 | path = "Supporting Files";
201 | sourceTree = "";
202 | };
203 | 1C75567E268A3FCD00BB684A /* Users */ = {
204 | isa = PBXGroup;
205 | children = (
206 | 1C1A22A1268B7C4F000F03C6 /* UsersConfigurator.swift */,
207 | 1C75568A268A61C200BB684A /* UsersRouter.swift */,
208 | 1C75565A268A262800BB684A /* UsersView.swift */,
209 | 1C755667268A26B400BB684A /* UsersViewModel.swift */,
210 | );
211 | path = Users;
212 | sourceTree = "";
213 | };
214 | 1C75567F268A3FD100BB684A /* User Detail */ = {
215 | isa = PBXGroup;
216 | children = (
217 | 1C1A22A3268B7E19000F03C6 /* UserDetailConfigurator.swift */,
218 | 1C755688268A608600BB684A /* UserDetailRouter.swift */,
219 | 1C755680268A3FDF00BB684A /* UserDetailView.swift */,
220 | 1C755682268A557400BB684A /* UserDetailViewModel.swift */,
221 | );
222 | path = "User Detail";
223 | sourceTree = "";
224 | };
225 | /* End PBXGroup section */
226 |
227 | /* Begin PBXNativeTarget section */
228 | 1C755654268A262800BB684A /* Users */ = {
229 | isa = PBXNativeTarget;
230 | buildConfigurationList = 1C755664268A262A00BB684A /* Build configuration list for PBXNativeTarget "Users" */;
231 | buildPhases = (
232 | 1C755651268A262800BB684A /* Sources */,
233 | 1C755652268A262800BB684A /* Frameworks */,
234 | 1C755653268A262800BB684A /* Resources */,
235 | );
236 | buildRules = (
237 | );
238 | dependencies = (
239 | );
240 | name = Users;
241 | productName = Users;
242 | productReference = 1C755655268A262800BB684A /* Users.app */;
243 | productType = "com.apple.product-type.application";
244 | };
245 | /* End PBXNativeTarget section */
246 |
247 | /* Begin PBXProject section */
248 | 1C75564D268A262800BB684A /* Project object */ = {
249 | isa = PBXProject;
250 | attributes = {
251 | LastSwiftUpdateCheck = 1250;
252 | LastUpgradeCheck = 1250;
253 | TargetAttributes = {
254 | 1C755654268A262800BB684A = {
255 | CreatedOnToolsVersion = 12.5;
256 | };
257 | };
258 | };
259 | buildConfigurationList = 1C755650268A262800BB684A /* Build configuration list for PBXProject "Users" */;
260 | compatibilityVersion = "Xcode 9.3";
261 | developmentRegion = en;
262 | hasScannedForEncodings = 0;
263 | knownRegions = (
264 | en,
265 | Base,
266 | );
267 | mainGroup = 1C75564C268A262800BB684A;
268 | productRefGroup = 1C755656268A262800BB684A /* Products */;
269 | projectDirPath = "";
270 | projectRoot = "";
271 | targets = (
272 | 1C755654268A262800BB684A /* Users */,
273 | );
274 | };
275 | /* End PBXProject section */
276 |
277 | /* Begin PBXResourcesBuildPhase section */
278 | 1C755653268A262800BB684A /* Resources */ = {
279 | isa = PBXResourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 1C755660268A262A00BB684A /* Preview Assets.xcassets in Resources */,
283 | 1C75565D268A262A00BB684A /* Assets.xcassets in Resources */,
284 | );
285 | runOnlyForDeploymentPostprocessing = 0;
286 | };
287 | /* End PBXResourcesBuildPhase section */
288 |
289 | /* Begin PBXSourcesBuildPhase section */
290 | 1C755651268A262800BB684A /* Sources */ = {
291 | isa = PBXSourcesBuildPhase;
292 | buildActionMask = 2147483647;
293 | files = (
294 | 1C75566A268A29CE00BB684A /* User.swift in Sources */,
295 | 1C755687268A5A8600BB684A /* NetworkError.swift in Sources */,
296 | 1C75565B268A262800BB684A /* UsersView.swift in Sources */,
297 | 1C1A22A9268B7F6F000F03C6 /* MoreInfoView.swift in Sources */,
298 | 1C75567D268A3C2F00BB684A /* Users.swift in Sources */,
299 | 1C755668268A26B400BB684A /* UsersViewModel.swift in Sources */,
300 | 1C75567B268A364A00BB684A /* UsersService.swift in Sources */,
301 | 1C755679268A346600BB684A /* Networker.swift in Sources */,
302 | 1C755683268A557400BB684A /* UserDetailViewModel.swift in Sources */,
303 | 1C1A22A2268B7C4F000F03C6 /* UsersConfigurator.swift in Sources */,
304 | 1C755677268A330300BB684A /* Endpoint+Users.swift in Sources */,
305 | 1C1A22AD268B82D8000F03C6 /* MoreInfoViewModel.swift in Sources */,
306 | 1C755659268A262800BB684A /* UsersApp.swift in Sources */,
307 | 1C755685268A563F00BB684A /* UserPictureService.swift in Sources */,
308 | 1C1A22A4268B7E19000F03C6 /* UserDetailConfigurator.swift in Sources */,
309 | 1C755675268A2DE900BB684A /* Endpoint+URL.swift in Sources */,
310 | 1C755689268A608600BB684A /* UserDetailRouter.swift in Sources */,
311 | 1C755673268A2D5700BB684A /* Endpoint.swift in Sources */,
312 | 1C755681268A3FDF00BB684A /* UserDetailView.swift in Sources */,
313 | 1C75568B268A61C200BB684A /* UsersRouter.swift in Sources */,
314 | 1C1A22AB268B814D000F03C6 /* MoreInfoConfigurator.swift in Sources */,
315 | );
316 | runOnlyForDeploymentPostprocessing = 0;
317 | };
318 | /* End PBXSourcesBuildPhase section */
319 |
320 | /* Begin XCBuildConfiguration section */
321 | 1C755662268A262A00BB684A /* Debug */ = {
322 | isa = XCBuildConfiguration;
323 | buildSettings = {
324 | ALWAYS_SEARCH_USER_PATHS = NO;
325 | CLANG_ANALYZER_NONNULL = YES;
326 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
328 | CLANG_CXX_LIBRARY = "libc++";
329 | CLANG_ENABLE_MODULES = YES;
330 | CLANG_ENABLE_OBJC_ARC = YES;
331 | CLANG_ENABLE_OBJC_WEAK = YES;
332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
333 | CLANG_WARN_BOOL_CONVERSION = YES;
334 | CLANG_WARN_COMMA = YES;
335 | CLANG_WARN_CONSTANT_CONVERSION = YES;
336 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
338 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
339 | CLANG_WARN_EMPTY_BODY = YES;
340 | CLANG_WARN_ENUM_CONVERSION = YES;
341 | CLANG_WARN_INFINITE_RECURSION = YES;
342 | CLANG_WARN_INT_CONVERSION = YES;
343 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
344 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
345 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
347 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
349 | CLANG_WARN_STRICT_PROTOTYPES = YES;
350 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
351 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
352 | CLANG_WARN_UNREACHABLE_CODE = YES;
353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
354 | COPY_PHASE_STRIP = NO;
355 | DEBUG_INFORMATION_FORMAT = dwarf;
356 | ENABLE_STRICT_OBJC_MSGSEND = YES;
357 | ENABLE_TESTABILITY = YES;
358 | GCC_C_LANGUAGE_STANDARD = gnu11;
359 | GCC_DYNAMIC_NO_PIC = NO;
360 | GCC_NO_COMMON_BLOCKS = YES;
361 | GCC_OPTIMIZATION_LEVEL = 0;
362 | GCC_PREPROCESSOR_DEFINITIONS = (
363 | "DEBUG=1",
364 | "$(inherited)",
365 | );
366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
368 | GCC_WARN_UNDECLARED_SELECTOR = YES;
369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
370 | GCC_WARN_UNUSED_FUNCTION = YES;
371 | GCC_WARN_UNUSED_VARIABLE = YES;
372 | INFOPLIST_FILE = "";
373 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
374 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
375 | MTL_FAST_MATH = YES;
376 | ONLY_ACTIVE_ARCH = YES;
377 | SDKROOT = iphoneos;
378 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
379 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
380 | };
381 | name = Debug;
382 | };
383 | 1C755663268A262A00BB684A /* Release */ = {
384 | isa = XCBuildConfiguration;
385 | buildSettings = {
386 | ALWAYS_SEARCH_USER_PATHS = NO;
387 | CLANG_ANALYZER_NONNULL = YES;
388 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
389 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
390 | CLANG_CXX_LIBRARY = "libc++";
391 | CLANG_ENABLE_MODULES = YES;
392 | CLANG_ENABLE_OBJC_ARC = YES;
393 | CLANG_ENABLE_OBJC_WEAK = YES;
394 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
395 | CLANG_WARN_BOOL_CONVERSION = YES;
396 | CLANG_WARN_COMMA = YES;
397 | CLANG_WARN_CONSTANT_CONVERSION = YES;
398 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
399 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
400 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
401 | CLANG_WARN_EMPTY_BODY = YES;
402 | CLANG_WARN_ENUM_CONVERSION = YES;
403 | CLANG_WARN_INFINITE_RECURSION = YES;
404 | CLANG_WARN_INT_CONVERSION = YES;
405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
409 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
411 | CLANG_WARN_STRICT_PROTOTYPES = YES;
412 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
413 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
414 | CLANG_WARN_UNREACHABLE_CODE = YES;
415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
416 | COPY_PHASE_STRIP = NO;
417 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
418 | ENABLE_NS_ASSERTIONS = NO;
419 | ENABLE_STRICT_OBJC_MSGSEND = YES;
420 | GCC_C_LANGUAGE_STANDARD = gnu11;
421 | GCC_NO_COMMON_BLOCKS = YES;
422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
424 | GCC_WARN_UNDECLARED_SELECTOR = YES;
425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
426 | GCC_WARN_UNUSED_FUNCTION = YES;
427 | GCC_WARN_UNUSED_VARIABLE = YES;
428 | INFOPLIST_FILE = "";
429 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
430 | MTL_ENABLE_DEBUG_INFO = NO;
431 | MTL_FAST_MATH = YES;
432 | SDKROOT = iphoneos;
433 | SWIFT_COMPILATION_MODE = wholemodule;
434 | SWIFT_OPTIMIZATION_LEVEL = "-O";
435 | VALIDATE_PRODUCT = YES;
436 | };
437 | name = Release;
438 | };
439 | 1C755665268A262A00BB684A /* Debug */ = {
440 | isa = XCBuildConfiguration;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
444 | CODE_SIGN_STYLE = Automatic;
445 | DEVELOPMENT_ASSET_PATHS = "\"Users/Supporting Files/Preview Content\"";
446 | DEVELOPMENT_TEAM = MJWVGRX9VD;
447 | ENABLE_PREVIEWS = YES;
448 | INFOPLIST_FILE = "Users/Supporting Files/Info.plist";
449 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
450 | LD_RUNPATH_SEARCH_PATHS = (
451 | "$(inherited)",
452 | "@executable_path/Frameworks",
453 | );
454 | PRODUCT_BUNDLE_IDENTIFIER = com.zafar.Users;
455 | PRODUCT_NAME = "$(TARGET_NAME)";
456 | SWIFT_VERSION = 5.0;
457 | TARGETED_DEVICE_FAMILY = "1,2";
458 | };
459 | name = Debug;
460 | };
461 | 1C755666268A262A00BB684A /* Release */ = {
462 | isa = XCBuildConfiguration;
463 | buildSettings = {
464 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
465 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
466 | CODE_SIGN_STYLE = Automatic;
467 | DEVELOPMENT_ASSET_PATHS = "\"Users/Supporting Files/Preview Content\"";
468 | DEVELOPMENT_TEAM = MJWVGRX9VD;
469 | ENABLE_PREVIEWS = YES;
470 | INFOPLIST_FILE = "Users/Supporting Files/Info.plist";
471 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
472 | LD_RUNPATH_SEARCH_PATHS = (
473 | "$(inherited)",
474 | "@executable_path/Frameworks",
475 | );
476 | PRODUCT_BUNDLE_IDENTIFIER = com.zafar.Users;
477 | PRODUCT_NAME = "$(TARGET_NAME)";
478 | SWIFT_VERSION = 5.0;
479 | TARGETED_DEVICE_FAMILY = "1,2";
480 | };
481 | name = Release;
482 | };
483 | /* End XCBuildConfiguration section */
484 |
485 | /* Begin XCConfigurationList section */
486 | 1C755650268A262800BB684A /* Build configuration list for PBXProject "Users" */ = {
487 | isa = XCConfigurationList;
488 | buildConfigurations = (
489 | 1C755662268A262A00BB684A /* Debug */,
490 | 1C755663268A262A00BB684A /* Release */,
491 | );
492 | defaultConfigurationIsVisible = 0;
493 | defaultConfigurationName = Release;
494 | };
495 | 1C755664268A262A00BB684A /* Build configuration list for PBXNativeTarget "Users" */ = {
496 | isa = XCConfigurationList;
497 | buildConfigurations = (
498 | 1C755665268A262A00BB684A /* Debug */,
499 | 1C755666268A262A00BB684A /* Release */,
500 | );
501 | defaultConfigurationIsVisible = 0;
502 | defaultConfigurationName = Release;
503 | };
504 | /* End XCConfigurationList section */
505 | };
506 | rootObject = 1C75564D268A262800BB684A /* Project object */;
507 | }
508 |
--------------------------------------------------------------------------------