Skip to content

Commit ea7351a

Browse files
committed
Initial commit
0 parents  commit ea7351a

31 files changed

+1270
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
7+
mb.log
8+
mb.pid

Podcasts.xcodeproj/project.pbxproj

Lines changed: 615 additions & 0 deletions
Large diffs are not rendered by default.

Podcasts.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"pins" : [
3+
{
4+
"identity" : "alamofire",
5+
"kind" : "remoteSourceControl",
6+
"location" : "https://github.com/Alamofire/Alamofire.git",
7+
"state" : {
8+
"revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a",
9+
"version" : "5.9.1"
10+
}
11+
}
12+
],
13+
"version" : 2
14+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1520"
4+
version = "1.7">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "BDFCA9932BBE8631009FDE51"
18+
BuildableName = "Podcasts.app"
19+
BlueprintName = "Podcasts"
20+
ReferencedContainer = "container:Podcasts.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<TestPlans>
31+
<TestPlanReference
32+
reference = "container:Podcasts.xctestplan"
33+
default = "YES">
34+
</TestPlanReference>
35+
</TestPlans>
36+
<Testables>
37+
<TestableReference
38+
skipped = "NO">
39+
<BuildableReference
40+
BuildableIdentifier = "primary"
41+
BlueprintIdentifier = "BDFCA9AD2BBE8634009FDE51"
42+
BuildableName = "PodcastsUITests.xctest"
43+
BlueprintName = "PodcastsUITests"
44+
ReferencedContainer = "container:Podcasts.xcodeproj">
45+
</BuildableReference>
46+
</TestableReference>
47+
</Testables>
48+
</TestAction>
49+
<LaunchAction
50+
buildConfiguration = "Debug"
51+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
52+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
53+
launchStyle = "0"
54+
useCustomWorkingDirectory = "NO"
55+
ignoresPersistentStateOnLaunch = "NO"
56+
debugDocumentVersioning = "YES"
57+
debugServiceExtension = "internal"
58+
allowLocationSimulation = "YES">
59+
<BuildableProductRunnable
60+
runnableDebuggingMode = "0">
61+
<BuildableReference
62+
BuildableIdentifier = "primary"
63+
BlueprintIdentifier = "BDFCA9932BBE8631009FDE51"
64+
BuildableName = "Podcasts.app"
65+
BlueprintName = "Podcasts"
66+
ReferencedContainer = "container:Podcasts.xcodeproj">
67+
</BuildableReference>
68+
</BuildableProductRunnable>
69+
</LaunchAction>
70+
<ProfileAction
71+
buildConfiguration = "Release"
72+
shouldUseLaunchSchemeArgsEnv = "YES"
73+
savedToolIdentifier = ""
74+
useCustomWorkingDirectory = "NO"
75+
debugDocumentVersioning = "YES">
76+
<BuildableProductRunnable
77+
runnableDebuggingMode = "0">
78+
<BuildableReference
79+
BuildableIdentifier = "primary"
80+
BlueprintIdentifier = "BDFCA9932BBE8631009FDE51"
81+
BuildableName = "Podcasts.app"
82+
BlueprintName = "Podcasts"
83+
ReferencedContainer = "container:Podcasts.xcodeproj">
84+
</BuildableReference>
85+
</BuildableProductRunnable>
86+
</ProfileAction>
87+
<AnalyzeAction
88+
buildConfiguration = "Debug">
89+
</AnalyzeAction>
90+
<ArchiveAction
91+
buildConfiguration = "Release"
92+
revealArchiveInOrganizer = "YES">
93+
</ArchiveAction>
94+
</Scheme>

Podcasts.xctestplan

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"configurations" : [
3+
{
4+
"id" : "2DF8FA6B-37F6-46A1-A50D-4AF76C1966F3",
5+
"name" : "Test Scheme Action",
6+
"options" : {
7+
8+
}
9+
}
10+
],
11+
"defaultOptions" : {
12+
"targetForVariableExpansion" : {
13+
"containerPath" : "container:Podcasts.xcodeproj",
14+
"identifier" : "BDFCA9932BBE8631009FDE51",
15+
"name" : "Podcasts"
16+
}
17+
},
18+
"testTargets" : [
19+
{
20+
"parallelizable" : true,
21+
"target" : {
22+
"containerPath" : "container:Podcasts.xcodeproj",
23+
"identifier" : "BDFCA9AD2BBE8634009FDE51",
24+
"name" : "PodcastsUITests"
25+
}
26+
}
27+
],
28+
"version" : 1
29+
}

Podcasts/Api/ApiError.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// ApiError.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import Alamofire
9+
import Foundation
10+
11+
enum ApiError: Error, Equatable, LocalizedError {
12+
case decoding
13+
case noInternet
14+
case noPodcasts
15+
case other(String)
16+
17+
init(error: AFError) {
18+
if error.isResponseSerializationError {
19+
self = .decoding
20+
} else if error.isSessionTaskError {
21+
self = .noInternet
22+
} else if let statusCode = error.responseCode, !(200 ..< 300).contains(statusCode) {
23+
self = .other("Error: \(statusCode)")
24+
} else {
25+
self = .other(error.localizedDescription)
26+
}
27+
}
28+
29+
var errorDescription: String? {
30+
switch self {
31+
case .decoding:
32+
return "JSON Decoding failed"
33+
case .noInternet:
34+
return "No Internet"
35+
case .noPodcasts:
36+
return "No podcasts found"
37+
case let .other(description):
38+
return description
39+
}
40+
}
41+
}

Podcasts/Api/Host.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Host.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
import Foundation
8+
9+
enum Host {
10+
static var lists: URL {
11+
URL(string: "https://lists.pocketcasts.com")!
12+
}
13+
14+
static var images: URL {
15+
URL(string: "https://static.pocketcasts.com")!
16+
}
17+
}

Podcasts/Api/ImageAPI.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// ImageAPI.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import Alamofire
9+
import Combine
10+
import Foundation
11+
import UIKit
12+
13+
struct ImageAPI {
14+
func makeImageURL(podcast: Podcast) -> URL {
15+
Host.images.appendingPathComponent("discover/images/400/\(podcast.id).jpg")
16+
}
17+
}

Podcasts/Api/PodcastAPI.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// PodcastAPI.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import Alamofire
9+
import Combine
10+
import Foundation
11+
import UIKit
12+
13+
struct PodcastAPI {
14+
func getPodcasts() -> AnyPublisher<Feed, ApiError> {
15+
let url = Host.lists.appendingPathComponent("trending.json")
16+
let headers: HTTPHeaders = [
17+
"Accept": "application/json",
18+
"Cache-Control": "no-cache, no-store, must-revalidate",
19+
]
20+
21+
return AF
22+
.request(url, method: .get, headers: headers)
23+
.validate()
24+
.publishDecodable(type: Feed.self)
25+
.value()
26+
.receive(on: DispatchQueue.main)
27+
.mapError(ApiError.init(error:))
28+
.eraseToAnyPublisher()
29+
}
30+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"colors" : [
3+
{
4+
"idiom" : "universal"
5+
}
6+
],
7+
"info" : {
8+
"author" : "xcode",
9+
"version" : 1
10+
}
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "icon.png",
5+
"idiom" : "universal",
6+
"platform" : "ios",
7+
"size" : "1024x1024"
8+
}
9+
],
10+
"info" : {
11+
"author" : "xcode",
12+
"version" : 1
13+
}
14+
}
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"author" : "xcode",
4+
"version" : 1
5+
}
6+
}

Podcasts/Models/Feed.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Feed.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import Foundation
9+
10+
struct Feed: Codable {
11+
let podcasts: [Podcast]
12+
}

Podcasts/Models/Podcast.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Podcast.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import Foundation
9+
10+
struct Podcast: Codable, Identifiable, Equatable, Hashable {
11+
enum CodingKeys: String, CodingKey {
12+
case title
13+
case author
14+
case description
15+
case id = "uuid"
16+
case url = "website"
17+
}
18+
19+
let title: String
20+
let author: String
21+
let description: String
22+
let id: String
23+
let url: String?
24+
}

Podcasts/PodcastsApp.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// PodcastsApp.swift
3+
// Podcasts
4+
//
5+
// Created by Tieme van Veen on 04/04/2024.
6+
//
7+
8+
import SwiftUI
9+
10+
@main
11+
struct PodcastsApp: App {
12+
var body: some Scene {
13+
WindowGroup {
14+
FeedView()
15+
}
16+
}
17+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"author" : "xcode",
4+
"version" : 1
5+
}
6+
}

0 commit comments

Comments
 (0)