From 36a58874e06b70a79991f65d6cd0dd1178c96762 Mon Sep 17 00:00:00 2001 From: Ben Kreeger Date: Fri, 21 Nov 2025 13:52:04 -0600 Subject: [PATCH] Add first bit of network functionality --- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 {Meow => App}/Assets.xcassets/Contents.json | 0 {Meow => App}/ContentView.swift | 0 {Meow => App}/MeowApp.swift | 0 Meow.xcodeproj/project.pbxproj | 23 +++- .../UserInterfaceState.xcuserstate | Bin 11880 -> 24995 bytes .../xcshareddata/xcschemes/App.xcscheme | 102 ++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 20 +++- Meow/.gitignore | 8 ++ Meow/Package.swift | 27 +++++ Meow/Sources/Meow/FactsResponse.swift | 10 ++ Meow/Sources/Meow/Meow.swift | 43 ++++++++ Meow/Sources/Meow/MeowError.swift | 12 +++ Meow/Tests/MeowTests/MeowTests.swift | 19 ++++ 15 files changed, 259 insertions(+), 5 deletions(-) rename {Meow => App}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {Meow => App}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {Meow => App}/Assets.xcassets/Contents.json (100%) rename {Meow => App}/ContentView.swift (100%) rename {Meow => App}/MeowApp.swift (100%) create mode 100644 Meow.xcodeproj/xcshareddata/xcschemes/App.xcscheme create mode 100644 Meow/.gitignore create mode 100644 Meow/Package.swift create mode 100644 Meow/Sources/Meow/FactsResponse.swift create mode 100644 Meow/Sources/Meow/Meow.swift create mode 100644 Meow/Sources/Meow/MeowError.swift create mode 100644 Meow/Tests/MeowTests/MeowTests.swift diff --git a/Meow/Assets.xcassets/AccentColor.colorset/Contents.json b/App/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from Meow/Assets.xcassets/AccentColor.colorset/Contents.json rename to App/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/Meow/Assets.xcassets/AppIcon.appiconset/Contents.json b/App/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Meow/Assets.xcassets/AppIcon.appiconset/Contents.json rename to App/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Meow/Assets.xcassets/Contents.json b/App/Assets.xcassets/Contents.json similarity index 100% rename from Meow/Assets.xcassets/Contents.json rename to App/Assets.xcassets/Contents.json diff --git a/Meow/ContentView.swift b/App/ContentView.swift similarity index 100% rename from Meow/ContentView.swift rename to App/ContentView.swift diff --git a/Meow/MeowApp.swift b/App/MeowApp.swift similarity index 100% rename from Meow/MeowApp.swift rename to App/MeowApp.swift diff --git a/Meow.xcodeproj/project.pbxproj b/Meow.xcodeproj/project.pbxproj index 99b5784..c85a586 100644 --- a/Meow.xcodeproj/project.pbxproj +++ b/Meow.xcodeproj/project.pbxproj @@ -6,6 +6,10 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + C3A5E8D52ED0C60D002DB10E /* Meow in Frameworks */ = {isa = PBXBuildFile; productRef = C3A5E8D42ED0C60D002DB10E /* Meow */; }; +/* End PBXBuildFile section */ + /* Begin PBXContainerItemProxy section */ C3BB76492ED0C38900D56534 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -24,15 +28,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + C3A5E8D22ED0C5E8002DB10E /* Meow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Meow; sourceTree = ""; }; C3BB763B2ED0C38800D56534 /* Meow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Meow.app; sourceTree = BUILT_PRODUCTS_DIR; }; C3BB76482ED0C38900D56534 /* MeowTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeowTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C3BB76522ED0C38900D56534 /* MeowUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeowUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - C3BB763D2ED0C38800D56534 /* Meow */ = { + C3BB763D2ED0C38800D56534 /* App */ = { isa = PBXFileSystemSynchronizedRootGroup; - path = Meow; + path = App; sourceTree = ""; }; C3BB764B2ED0C38900D56534 /* MeowTests */ = { @@ -52,6 +57,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C3A5E8D52ED0C60D002DB10E /* Meow in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -75,7 +81,8 @@ C3BB76322ED0C38800D56534 = { isa = PBXGroup; children = ( - C3BB763D2ED0C38800D56534 /* Meow */, + C3A5E8D22ED0C5E8002DB10E /* Meow */, + C3BB763D2ED0C38800D56534 /* App */, C3BB764B2ED0C38900D56534 /* MeowTests */, C3BB76552ED0C38900D56534 /* MeowUITests */, C3BB763C2ED0C38800D56534 /* Products */, @@ -108,10 +115,11 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - C3BB763D2ED0C38800D56534 /* Meow */, + C3BB763D2ED0C38800D56534 /* App */, ); name = Meow; packageProductDependencies = ( + C3A5E8D42ED0C60D002DB10E /* Meow */, ); productName = Meow; productReference = C3BB763B2ED0C38800D56534 /* Meow.app */; @@ -578,6 +586,13 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCSwiftPackageProductDependency section */ + C3A5E8D42ED0C60D002DB10E /* Meow */ = { + isa = XCSwiftPackageProductDependency; + productName = Meow; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = C3BB76332ED0C38800D56534 /* Project object */; } diff --git a/Meow.xcodeproj/project.xcworkspace/xcuserdata/bkreeger.xcuserdatad/UserInterfaceState.xcuserstate b/Meow.xcodeproj/project.xcworkspace/xcuserdata/bkreeger.xcuserdatad/UserInterfaceState.xcuserstate index 11a777814c6483a4d75377635764fc94e03324c1..aeb479c8efa15b2f85e1cf2fc5660c55f446c098 100644 GIT binary patch literal 24995 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

KHNlm(Gc}N!s4U< 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 delta 6370 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 O-_Y_810Oy@G5H@ZHKOtW diff --git a/Meow.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/Meow.xcodeproj/xcshareddata/xcschemes/App.xcscheme new file mode 100644 index 0000000..17fb4a8 --- /dev/null +++ b/Meow.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Meow.xcodeproj/xcuserdata/bkreeger.xcuserdatad/xcschemes/xcschememanagement.plist b/Meow.xcodeproj/xcuserdata/bkreeger.xcuserdatad/xcschemes/xcschememanagement.plist index 03758d5..d3f60a2 100644 --- a/Meow.xcodeproj/xcuserdata/bkreeger.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Meow.xcodeproj/xcuserdata/bkreeger.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,11 +4,29 @@ SchemeUserState - Meow.xcscheme_^#shared#^_ + App.xcscheme_^#shared#^_ orderHint 0 + SuppressBuildableAutocreation + + C3BB763A2ED0C38800D56534 + + primary + + + C3BB76472ED0C38900D56534 + + primary + + + C3BB76512ED0C38900D56534 + + primary + + + diff --git a/Meow/.gitignore b/Meow/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/Meow/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Meow/Package.swift b/Meow/Package.swift new file mode 100644 index 0000000..f410d81 --- /dev/null +++ b/Meow/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 6.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Meow", + platforms: [.iOS(.v18), .macOS(.v15)], + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "Meow", + targets: ["Meow"] + ), + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target( + name: "Meow" + ), + .testTarget( + name: "MeowTests", + dependencies: ["Meow"] + ), + ] +) diff --git a/Meow/Sources/Meow/FactsResponse.swift b/Meow/Sources/Meow/FactsResponse.swift new file mode 100644 index 0000000..3e8ae97 --- /dev/null +++ b/Meow/Sources/Meow/FactsResponse.swift @@ -0,0 +1,10 @@ +// +// FactsResponse.swift +// Meow +// + +import Foundation + +struct FactsResponse: Codable { + let data: [String] +} diff --git a/Meow/Sources/Meow/Meow.swift b/Meow/Sources/Meow/Meow.swift new file mode 100644 index 0000000..0a53ca7 --- /dev/null +++ b/Meow/Sources/Meow/Meow.swift @@ -0,0 +1,43 @@ +// +// Meow.swift +// Meow +// + +import Foundation + +public struct Meow { + let baseURL: URL + let session: URLSession + + public init(baseURL: URL, session: URLSession = .shared) { + self.baseURL = baseURL + self.session = session + } + + public func getFacts() async throws -> [String] { + let request = try generateRequest(path: "/") + let response: FactsResponse = try await decodeRequest(request: request) + return response.data + } + + // MARK: - Private functionality + + private func generateRequest(path: String) throws -> URLRequest { + guard let url = URL(string: path, relativeTo: baseURL) else { + throw MeowError.requestError("Couldn't generate URL from path: \(path), baseURL: \(baseURL)") + } + return URLRequest(url: url) + } + + private func decodeRequest(request: URLRequest) async throws -> T { + let (data, response) = try await session.data(for: request) + guard let response = response as? HTTPURLResponse else { + throw MeowError.connectionError("Couldn't get HTTP response from request \(request)") + } + guard response.statusCode < 300 else { + let body = String(data: data, encoding: .utf8) + throw MeowError.responseError(response.statusCode, body ?? "unknown error") + } + return try JSONDecoder().decode(T.self, from: data) + } +} diff --git a/Meow/Sources/Meow/MeowError.swift b/Meow/Sources/Meow/MeowError.swift new file mode 100644 index 0000000..4db7cc7 --- /dev/null +++ b/Meow/Sources/Meow/MeowError.swift @@ -0,0 +1,12 @@ +// +// MeowError.swift +// Meow +// + +import Foundation + +public enum MeowError: LocalizedError { + case requestError(String) + case connectionError(String) + case responseError(Int, String) +} diff --git a/Meow/Tests/MeowTests/MeowTests.swift b/Meow/Tests/MeowTests/MeowTests.swift new file mode 100644 index 0000000..1456482 --- /dev/null +++ b/Meow/Tests/MeowTests/MeowTests.swift @@ -0,0 +1,19 @@ +// +// MeowTests.swift +// MeowTests +// + +import Foundation +import Testing +@testable import Meow + +@Suite("Meow Tests") +struct MeowTests { + private let baseURL = URL(string: "https://meow.meow")! + + @Test + func constructor() async throws { + let instance = Meow(baseURL: baseURL) + #expect(instance.baseURL == baseURL) + } +}