{"id":21870455,"url":"https://github.com/anscoder/olaapp-task","last_synced_at":"2025-03-21T22:21:08.491Z","repository":{"id":103901813,"uuid":"221291539","full_name":"ANSCoder/OlaApp-Task","owner":"ANSCoder","description":"This is basic example for the car booking app with custom map pin points.","archived":false,"fork":false,"pushed_at":"2020-03-04T12:39:53.000Z","size":106,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-26T16:45:33.611Z","etag":null,"topics":["jsoncoda","mapkit-ios-demo","mvvm","mvvm-architecture","networking","rxswi","rxswift-examples","storyboard","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ANSCoder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-12T19:05:38.000Z","updated_at":"2023-10-16T06:52:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"8bd072c1-aeeb-4632-84ee-83c11ecf4fef","html_url":"https://github.com/ANSCoder/OlaApp-Task","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ANSCoder%2FOlaApp-Task","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ANSCoder%2FOlaApp-Task/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ANSCoder%2FOlaApp-Task/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ANSCoder%2FOlaApp-Task/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ANSCoder","download_url":"https://codeload.github.com/ANSCoder/OlaApp-Task/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244875720,"owners_count":20524703,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jsoncoda","mapkit-ios-demo","mvvm","mvvm-architecture","networking","rxswi","rxswift-examples","storyboard","swift"],"created_at":"2024-11-28T06:11:29.026Z","updated_at":"2025-03-21T22:21:08.485Z","avatar_url":"https://github.com/ANSCoder.png","language":"Swift","readme":"# OlaApp-Task\n[![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg?style=flat)](https://swift.org)\n\nThis repository contains a **OlaApp-Task** based on Web APIs.\nUser can see pre fetch car list and able to see the car inside \nthe mapView with details.\n\nApplication having basic functionality for the Car grouping inside the Map View with custom annotation image.\n\nCar list displaying in the View forms not directly horizontally presented in a short from once user tap on it. \nApp will start to display details about the car. 🚗 \n\n*This is the one pager 📟  application and truly handy in a single page.*\n\n- **Concept of the application** - App will fetch the users current location based on location it will display the \nAvailable rental cars.\nApplication having functionalists for the display Car type like Mini, Luxury, Premium.\nBased on selection use can view the cars details and able to do booking.\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19596311/68887351-d9b36180-073e-11ea-8c46-a0210f15190e.png\" width=\"210\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19596311/68887352-da4bf800-073e-11ea-870e-458764e52eb0.png\" width=\"210\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19596311/68887354-da4bf800-073e-11ea-9eb9-a159078ce705.png\" width=\"210\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19596311/75880290-ff29bf80-5e42-11ea-9018-6c2e15ed54bf.gif\" width=\"210\"\u003e\n\u003c/p\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\n## Features \n\n- [x] Map View  \n- [x] Car Details\n- [x] Car Types\n- [x] Book car\n\n\n## Requirements\n\n- iOS 13.1+\n- Xcode 11.1\n\n### Project Structure\n \n \n    ├─ Common \n      ├─ StoryBoarded\n      ├─ LoadingViewController\n      ├─ ImageProvider\n      ├─ Extensions\n      ├─ ANCustomView\n    ├─ Networking\n    ├─ Home\n      ├─ Remote \n      ├─ Model\n      ├─ ViewModel\n      ├─ View (ViewController, Cell, Annotation View)\n      \n      \n  ## Swift Package Manager\n    \n    - RxSwift\n    \n```swift\n    dependencies: [\n    .package(url: \"https://github.com/ReactiveX/RxSwift.git\", from: \"5.0.0\")\n  ],\n  targets: [\n    .target(name: \"OlaApp-Task\", dependencies: [\"RxSwift\", \"RxCocoa\"])\n  ]\n```\n\n## Architecture\n\n* MVVM [Model View ViewModel]\n\n  This project completely developed in MVVM design patten.\n  \n\n  \n## Image Downloading \u0026 Cache \n  * This class will be responsible for the downloading image asynchronously \u0026 cache.\n\n```swift\nimport UIKit\n\n\nstruct ImageProvider {\n    \n    fileprivate let downloadQueue = DispatchQueue(label: \"Images cache\", qos: DispatchQoS.background)\n    internal var cache = NSCache\u003cNSURL, UIImage\u003e()\n\n    \n    //MARK: - Fetch image from URL and Images cache\n    func loadImages(from url: NSURL, completion: @escaping (_ image: UIImage) -\u003e Void) {\n        downloadQueue.async(execute: { () -\u003e Void in\n            if let image = self.cache.object(forKey: url) {\n                DispatchQueue.main.async {\n                    completion(image)\n                }\n                return\n            }\n            \n            do{\n                let data = try Data(contentsOf: url as URL)\n                if let image = UIImage(data: data) {\n                    DispatchQueue.main.async {\n                        self.cache.setObject(image, forKey: url)\n                        completion(image)\n                    }\n                } else {\n                    print(\"Could not decode image\")\n                }\n            }catch {\n                print(\"Could not load URL: \\(url): \\(error)\")\n            }\n        })\n    }\n}\n\n```\n\n\n## Networking 🚀\n\n   Inside this application networking handling by Endpoint. It is responsible for the creation of URL path.\n   \n```swift\n\nstruct Endpoint {\n    let path: String\n    \n    enum Errors: Error {\n        case invalidURL\n    }\n}\n\n\nextension Endpoint {\n\n    var url: URL? {\n        var components = URLComponents()\n        components.scheme = \"http\"\n        components.host = \"www.mocky.io\"\n        components.path = path\n        return components.url\n    }\n}\n\nextension Endpoint{\n    static func fetchVehicleList() -\u003e Endpoint{\n        return Endpoint(\n            path: \"/v2/5dc3f2c13000003c003477a0\"\n        )\n    }\n}\n\n```\n\n * Networking  wrapper completely written Generic it's capable for handle any kind of response data.\n \n \n ```swift\n typealias Networking = (Endpoint) -\u003e Future\u003cData\u003e\n\nextension URLSession {\n    func request(_ endpoint: Endpoint) -\u003e Future\u003cData\u003e {\n        // Start by constructing a Promise, that will later be\n        // returned as a Future\n        let promise = Promise\u003cData\u003e()\n        \n        // Immediately reject the promise in case the passed\n        // endpoint can't be converted into a valid URL\n        guard let url = endpoint.url else {\n            promise.reject(with: Endpoint.Errors.invalidURL)\n            return promise\n        }\n        \n        let task = dataTask(with: url) { data, _, error in\n            // Reject or resolve the promise, depending on the result\n            if let error = error {\n                promise.reject(with: error)\n            } else {\n                promise.resolve(with: data ?? Data())\n            }\n        }\n        task.resume()\n        \n        return promise\n    }\n}\n ```\n \n \n ## Remote class\n \n    Inside this class created `loadProduct()` function for the specific path it’s could be based on URL request.\n    Return type required to define here `Future\u003cVehicles\u003e`.\n \n ```swift\n struct VehicleLoader {\n    \n    private let networking: Networking\n    \n    init(networking: @escaping Networking = URLSession.shared.request) {\n        self.networking = networking\n    }\n    \n    func loadProduct() -\u003e Future\u003cVehicles\u003e {\n        return networking(.fetchVehicleList()).decoded()\n    }\n}\n ```\n \n \n  * Use of this wrapper inside the project \n  \n  \n```swift \nlet vehicleLoader = VehicleLoader()\nvehicleLoader.loadProduct().observe { result in\n                switch result{\n                case .success(let values):\n                    debugPrint(values)\n                case .failure(let error):\n                    debugPrint(error.localizedDescription)\n                }\n            }\n```\n\n## JSONDecoding\n   Model inside this application are using the `Codable` protocol. \n   Response from Network request in a from of Data decoding by `extension Future`. \n   \n```swift\nfileprivate func newJSONDecoder() -\u003e JSONDecoder {\n    let decoder = JSONDecoder()\n    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {\n        decoder.dateDecodingStrategy = .iso8601\n    }\n    return decoder\n}\n\nextension Future where Value == Data {\n    func decoded\u003cT: Decodable\u003e() -\u003e Future\u003cT\u003e {\n        return transformed{ try newJSONDecoder().decode(T.self, from: $0) }\n    }\n}\n```\n\n## Storyboarded \n    This Protocol basically using for the UIViewController initialization.\n\n```swift \nprotocol Storyboarded {\n    static func instantiate() -\u003e Self\n}\n\nextension Storyboarded where Self: UIViewController {\n    static func instantiate() -\u003e Self {\n        let className = String(describing: self)\n        let storyboard = UIStoryboard(name: \"Main\", bundle: Bundle.main)\n        return storyboard.instantiateViewController(withIdentifier: className) as! Self\n    }\n}\n```\n * Use of it.\n \n```swift\n let mapViewController = MapViewController.instantiate()\n```\n\n\n\n\n##  UI Components \u0026 Apple APIs\n\n- [x] Storyboard \n- [x] Coadable Protocol\n- [x] UICollectionView\n- [x] UIAlertController\n- [x] MKMapView\n- [x] UIStackView\n\n\n## UIViewController Extension \n   This is using for display the Loadingview which works with the `RxBinder` for add and remove form UIViewController.\n\n```swift\nextension UIViewController{\n    \n    func add(_ child: UIViewController) {\n        addChild(child)\n        view.addSubview(child.view)\n        child.didMove(toParent: self)\n    }\n    \n    func remove() {\n        guard parent != nil else {\n            return\n        }\n        \n        willMove(toParent: nil)\n        view.removeFromSuperview()\n        removeFromParent()\n    }\n    \n    public var isAnimating: Binder\u003cBool\u003e {\n        let loadingViewController = LoadingViewController()\n        \n        return Binder(self, binding: {[weak self] (vc, active) in\n            if active {\n                self?.add(loadingViewController)\n            } else {\n                loadingViewController.remove()\n            }\n        })\n    }\n}\n```\n\n\n## 👤 Author\n\n**Anscoder** [(Anand Nimje)](https://twitter.com/anand8402) \n\n\n\n\n    \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanscoder%2Folaapp-task","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanscoder%2Folaapp-task","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanscoder%2Folaapp-task/lists"}