From 694ab3ce3f94ff65088cee27153d3b2105230f5c Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Tue, 13 Feb 2024 01:16:13 +0100 Subject: [PATCH] Updated sample app --- .../WireKitSample.xcodeproj/project.pbxproj | 8 +- .../xcshareddata/swiftpm/Package.resolved | 16 --- .../TodoList/TodoListViewModel.swift | 125 ++++++------------ .../TodoList/TodoListViewModelTests.swift | 31 ++--- 4 files changed, 59 insertions(+), 121 deletions(-) delete mode 100644 docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj b/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj index fcbbcf0..c6471bd 100644 --- a/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj +++ b/docs/ExampleApp/WireKitSample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -52,6 +52,7 @@ D6E759AA29FD0B4000E058E3 /* URLProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLProtocolMock.swift; sourceTree = ""; }; D6E759AC29FD14BB00E058E3 /* todoItems.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = todoItems.json; sourceTree = ""; }; D6E759B129FD156000E058E3 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; + D6F8AC372B7AEBAD009F9E3F /* WireKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = WireKit; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -76,6 +77,7 @@ D68B254B257DD2550019B48A = { isa = PBXGroup; children = ( + D6F8AC372B7AEBAD009F9E3F /* WireKit */, D68B2556257DD2550019B48A /* WireKitSample */, D6E759A129FD0A0D00E058E3 /* WireKitSampleTests */, D68B2555257DD2550019B48A /* Products */, @@ -413,7 +415,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"WireKitSample/Preview Content\""; - DEVELOPMENT_TEAM = JM9222EF99; + DEVELOPMENT_TEAM = 83QBHAG7HD; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = WireKitSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -435,7 +437,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"WireKitSample/Preview Content\""; - DEVELOPMENT_TEAM = JM9222EF99; + DEVELOPMENT_TEAM = 83QBHAG7HD; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = WireKitSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; diff --git a/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index c199d84..0000000 --- a/docs/ExampleApp/WireKitSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "WireKit", - "repositoryURL": "git@github.com:afterxleep/WireKit.git", - "state": { - "branch": null, - "revision": "f9eecd8b1e84fa2d1616b00743d47200a84d69bf", - "version": "1.0.0" - } - } - ] - }, - "version": 1 -} diff --git a/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift b/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift index f8c447b..6903306 100644 --- a/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift +++ b/docs/ExampleApp/WireKitSample/TodoList/TodoListViewModel.swift @@ -7,7 +7,6 @@ import Foundation import WireKit -import Combine import SwiftUI class TodoListViewModel: ObservableObject { @@ -18,7 +17,6 @@ class TodoListViewModel: ObservableObject { @Published var loadingMessage = "Loading Data..." let apiClient: WKAPIClient - private var cancellables = [AnyCancellable]() private enum Constants { static let apiURL = "https://jsonplaceholder.typicode.com" @@ -28,97 +26,62 @@ class TodoListViewModel: ObservableObject { init(apiClient: WKAPIClient) { self.apiClient = apiClient - loadData() + Task { + await loadData() + } } - private func loadData() { - - // Perform a request from the TodoAPI - // You can pass parameters and other data here. - apiClient.dispatch(TodoAPI.FindAll()) - - // Since we are displaying results in the UI, receive on Main Thread - .receive(on: DispatchQueue.main) - - // Observe for Returned values - .sink( - receiveCompletion: { result in - - // Hide our loader on completion - self.isLoading = false - - // Act on when we get a result or failure - switch result { - case .failure(let error): - // Handle API response errors here (WKNetworkRequestError) - print("Error loading data: \(error)") - default: break - } - }, - receiveValue: { value in - - // Populate the observable property in the UI - self.todoItems = value - }) - - // Store the cancellable in a set (to hold a ref) - .store(in: &cancellables) + private func loadData() async { + isLoading = true + do { + let todos: [Todo] = try await apiClient.dispatch(TodoAPI.FindAll()) + DispatchQueue.main.async { + self.todoItems = todos + self.isLoading = false + } + } catch { + DispatchQueue.main.async { + print("Error loading data: \(error)") + self.isLoading = false + } + } } - // Quick helper method to set color and icon for each todo func todoImage(todoItem: Todo) -> (name: String, color: Color) { todoItem.completed ? (name: Constants.completedImage, color: .green) : (name: Constants.defaultImage, color: .red) } func delete(at offsets: IndexSet) { - for o in offsets { - guard let id = todoItems[o].id else { return } - todoItems.remove(at: o) - apiClient.dispatch(TodoAPI.Delete(id)) - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { result in - switch result { - case .failure(let error): - print("Error deleting data: \(error)") - default: - print("Item Deleted Correctly") - // You could reload the list from the server here - // We're not doing it as this is a Mock API - //self.loadData() - break - } - }, - receiveValue: { value in - print("Response: \(value)") - // The received value is empty - }) - .store(in: &cancellables) + Task { + for index in offsets { + guard let id = todoItems[index].id else { continue } + do { + let _: Empty = try await apiClient.dispatch(TodoAPI.Delete(id)) + DispatchQueue.main.async { + self.todoItems.remove(at: index) + } + } catch { + DispatchQueue.main.async { + print("Error deleting data: \(error)") + } + } + } } } func add(todo: Todo) { - apiClient.dispatch(TodoAPI.Add(todo)) - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { result in - switch result { - case .failure(let error): - print("Error adding data: \(error)") - default: - print("Item Added Correctly") - // You could reload the list from the server here - // We're not doing it as this is a Mock API - //self.loadData() - break - } - }, - receiveValue: { value in - print("Response: \(value)") - // The received value is empty - }) - .store(in: &cancellables) - + Task { + do { + let _: Todo = try await apiClient.dispatch(TodoAPI.Add(todo)) + DispatchQueue.main.async { + self.todoItems.append(todo) + print("Item Added Correctly") + } + } catch { + DispatchQueue.main.async { + print("Error adding data: \(error)") + } + } + } } - } diff --git a/docs/ExampleApp/WireKitSampleTests/TodoList/TodoListViewModelTests.swift b/docs/ExampleApp/WireKitSampleTests/TodoList/TodoListViewModelTests.swift index 36ff986..7945418 100644 --- a/docs/ExampleApp/WireKitSampleTests/TodoList/TodoListViewModelTests.swift +++ b/docs/ExampleApp/WireKitSampleTests/TodoList/TodoListViewModelTests.swift @@ -7,16 +7,11 @@ import Foundation import XCTest -import Combine -import WireKit @testable import WireKitSample class TodoListViewModelTests: XCTestCase { - private var todoItemsCancellable: AnyCancellable? - - func testListModelWorks() { - + func testListModelWorks() async { // Note that we're using non SSL urls here as URLProtocol does let url = URL(string: "https://jsonplaceholder.typicode.com/todos") @@ -26,6 +21,7 @@ class TodoListViewModelTests: XCTestCase { URLProtocolMock.testURLs = [url: jsonData] } catch { XCTFail("Error loading JSON data: \(error)") + return } // Use the Mock @@ -37,25 +33,18 @@ class TodoListViewModelTests: XCTestCase { // Initialize the APIClient and pass along a custom dispatcher let baseURL = "https://jsonplaceholder.typicode.com" - - // Then let dispatcher = WKNetworkDispatcher(urlSession: session) let apiClient = WKAPIClient(baseURL: baseURL, networkDispatcher: dispatcher) - let expectation = XCTestExpectation(description: "Wait for the response") let model = TodoListViewModel(apiClient: apiClient) - todoItemsCancellable = model.$todoItems - .dropFirst() // To skip the initial (empty) value - .sink { todoItems in - XCTAssertGreaterThan(todoItems.count, 0, "Todo items should be loaded") - expectation.fulfill() - } - wait(for: [expectation], timeout: 1) - } - deinit { - todoItemsCancellable?.cancel() + // Wait for the model to load data + let expectation = XCTestExpectation(description: "Wait for the response") + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + XCTAssertGreaterThan(model.todoItems.count, 0, "Todo items should be loaded") + expectation.fulfill() + } + + wait(for: [expectation], timeout: 2) } - } -