Skip to content

Commit

Permalink
Merge branch 'feature/swift-6'
Browse files Browse the repository at this point in the history
  • Loading branch information
mbernson committed Jan 26, 2025
2 parents 6290a99 + 7be74f2 commit 51472fd
Show file tree
Hide file tree
Showing 17 changed files with 105 additions and 114 deletions.
2 changes: 1 addition & 1 deletion CCCApi/Sources/CCCApi/ApiService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ApiService {

public static let shared = ApiService()

public init() {
private init() {
session = URLSession(configuration: .default)

// Format should be: yyyy-MM-dd'T'HH:mm:ss.mmm+hh:mm
Expand Down
4 changes: 2 additions & 2 deletions CCCApi/Sources/CCCApi/Models/Conference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct ConferencesResponse: Decodable {
}

/// e.g. the congress or lecture series like datengarten or openchaos
public struct Conference: Decodable, Identifiable {
public struct Conference: Decodable, Identifiable, Sendable {
public let acronym: String
public let slug: String
public let title: String
Expand Down Expand Up @@ -84,7 +84,7 @@ public struct Conference: Decodable, Identifiable {
}
}

public struct AspectRatio: Decodable {
public struct AspectRatio: Decodable, Sendable {
public let width: Double
public let height: Double

Expand Down
2 changes: 1 addition & 1 deletion CCCApi/Sources/CCCApi/Models/Recording.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

/// A recording is a file that belongs to a talk (event).
/// These can be video or audio recordings of the talk in different formats and languages (live-translation), subtitle tracks as srt or slides as pdf.
public struct Recording: Decodable, Identifiable, Equatable {
public struct Recording: Decodable, Identifiable, Equatable, Sendable {
/// approximate file size in megabytes
public let size: Int?
/// duration in seconds
Expand Down
4 changes: 2 additions & 2 deletions CCCApi/Sources/CCCApi/Models/Talk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ typealias Event = Talk

/// Every talk (alias event, in other systems also called lecture or session) is assigned to exactly one conference (e.g. the congress or lecture series like datengarten or openchaos) and consists of multiple files alias recordings.
/// These files can be video or audio recordings of the talk in different formats and languages (live-translation), subtitle tracks as srt or slides as pdf.
public struct Talk: Decodable, Identifiable, Equatable {
public struct Talk: Decodable, Identifiable, Equatable, Sendable {
public var id: String { guid }

public let guid: String
Expand Down Expand Up @@ -144,7 +144,7 @@ struct TalkExtended: Decodable {
}
}

public struct RelatedTalk: Decodable, Equatable {
public struct RelatedTalk: Decodable, Equatable, Sendable {
let eventID: Int
let eventGUID: String
let weight: Int
Expand Down
4 changes: 2 additions & 2 deletions CCCTube.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,3,6,7";
TVOS_DEPLOYMENT_TARGET = 17.6;
XROS_DEPLOYMENT_TARGET = 2.0;
Expand Down Expand Up @@ -704,7 +704,7 @@
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,3,6,7";
TVOS_DEPLOYMENT_TARGET = 17.6;
XROS_DEPLOYMENT_TARGET = 2.0;
Expand Down
32 changes: 21 additions & 11 deletions CCCTube/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import CCCApi
import SwiftUI

struct ContentView: View {
@State var api: ApiService = .shared
@State private var talk: TalkToPlay?
@State var error: Error?

var body: some View {
TabView {
Expand Down Expand Up @@ -50,6 +50,7 @@ struct ContentView: View {
#endif
}
}
.alert("Failed to load data from the media.ccc.de API", error: $error)
.fullScreenCover(item: $talk) { talk in
NavigationStack {
TalkView(talk: talk.talk, selectedRecording: talk.recordingToPlay)
Expand All @@ -59,17 +60,26 @@ struct ContentView: View {
let factory = URLParser()
guard let route = factory.parseURL(url) else { return }
Task {
switch route {
case let .openTalk(id):
let talk = try await api.talk(id: id)
self.talk = TalkToPlay(talk: talk, recordingToPlay: nil)
case let .playTalk(id):
let talk = try await api.talk(id: id)
let recordings = try await api.recordings(for: talk)
let recording = recordings.first(where: { $0.isHighQuality }) ?? recordings.first(where: { $0.isVideo })
self.talk = TalkToPlay(talk: talk, recordingToPlay: recording)
}
await openRoute(route: route)
}
}
}

func openRoute(route: URLRoute) async {
let api = ApiService.shared
do {
switch route {
case let .openTalk(id):
let talk = try await api.talk(id: id)
self.talk = TalkToPlay(talk: talk, recordingToPlay: nil)
case let .playTalk(id):
let talk = try await api.talk(id: id)
let recordings = try await api.recordings(for: talk)
let recording = recordings.first(where: { $0.isHighQuality }) ?? recordings.first(where: { $0.isVideo })
self.talk = TalkToPlay(talk: talk, recordingToPlay: recording)
}
} catch {
self.error = error
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion CCCTube/Features/Browse/BrowseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ struct BrowseView: View {
@State var talks: [Talk] = []
@State var isLoading = true
@State var error: Error?
@State var api: ApiService = .shared

var body: some View {
NavigationStack {
Expand Down Expand Up @@ -74,6 +73,7 @@ struct BrowseView: View {
isLoading = true
defer { isLoading = false }
do {
let api = ApiService.shared
switch query {
case .recent:
talks = try await api.recentTalks()
Expand Down
4 changes: 1 addition & 3 deletions CCCTube/Features/Conferences/ConferenceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ struct ConferenceView: View {
@State var isLoading = true
@State var error: Error?

@State var api: ApiService = .shared

var body: some View {
ScrollView {
#if os(tvOS)
Expand Down Expand Up @@ -58,7 +56,7 @@ struct ConferenceView: View {
isLoading = true
defer { isLoading = false }
do {
talks = try await api.conference(acronym: conference.acronym).events ?? []
talks = try await ApiService.shared.conference(acronym: conference.acronym).events ?? []
} catch is CancellationError {
} catch {
self.error = error
Expand Down
4 changes: 1 addition & 3 deletions CCCTube/Features/Conferences/ConferencesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ struct ConferencesView: View {
@State var filterQuery = ""
@State var error: Error?

@State var api: ApiService = .shared

var body: some View {
NavigationStack {
ScrollView {
Expand All @@ -39,7 +37,7 @@ struct ConferencesView: View {

func refresh() async {
do {
conferences = try await api.conferences()
conferences = try await ApiService.shared.conferences()
.filter { conference in
conference.eventLastReleasedAt != nil
}
Expand Down
22 changes: 22 additions & 0 deletions CCCTube/Features/Search/SearchContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// SearchContext.swift
// CCCTube
//
// Created by Mathijs Bernson on 31/07/2022.
//

import Combine
import Foundation

final class SearchContext: ObservableObject {
private var searchQuerySubject = PassthroughSubject<String, Never>()
var searchQueryPublisher: AnyPublisher<String, Never> {
searchQuerySubject
.debounce(for: .seconds(1.0), scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
}

func send(query: String) {
searchQuerySubject.send(query)
}
}
45 changes: 36 additions & 9 deletions CCCTube/Features/Search/SearchView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,33 @@ import CCCApi
import SwiftUI

struct SearchView: View {
@State var viewModel = SearchViewModel()
@State var searchContext = SearchContext()
@State var results: [Talk] = []
@State var query = ""
@State var isLoading = false
@State var error: Error?
@State var suggestions: [SearchSuggestion] = SearchSuggestion.defaultSuggestions.shuffled()

var body: some View {
NavigationStack {
Group {
#if os(tvOS)
List {
ForEach(viewModel.results) { talk in
ForEach(results) { talk in
NavigationLink {
TalkView(talk: talk)
} label: {
TalkListItem(talk: talk)
}

}
}
#else
if viewModel.isLoading {
if isLoading {
ProgressView()
} else if viewModel.results.isEmpty && !query.isEmpty {
} else if results.isEmpty && !query.isEmpty {
Text("No talks found")
} else if viewModel.results.isEmpty {
} else if results.isEmpty {
List {
ForEach(suggestions) { suggestion in
Button(suggestion.title) {
Expand All @@ -44,7 +48,7 @@ struct SearchView: View {
.listStyle(.plain)
} else {
ScrollView {
TalksGrid(talks: viewModel.results)
TalksGrid(talks: results)
}
}
#endif
Expand All @@ -54,7 +58,10 @@ struct SearchView: View {
#endif
.searchable(text: $query, prompt: "Search talks...")
.onChange(of: query) { _, query in
viewModel.updateSearchQuery(query)
searchContext.send(query: query)
}
.onReceive(searchContext.searchQueryPublisher) { query in
runSearch(query)
}
#if os(tvOS)
.searchSuggestions {
Expand All @@ -65,12 +72,32 @@ struct SearchView: View {
#endif
.onAppear(perform: runSearch)
.onSubmit(of: .search, runSearch)
.alert("Failed to load data from the media.ccc.de API", error: $viewModel.error)
.alert("Failed to load data from the media.ccc.de API", error: $error)
}
}

func runSearch() {
viewModel.search(query: query)
runSearch(query)
}

func runSearch(_ query: String) {
if query.isEmpty {
results.removeAll()
} else {
Task {
await search(query)
}
}
}

func search(_ query: String) async {
isLoading = true
defer { isLoading = false }
do {
results = try await ApiService.shared.searchTalks(query: query)
} catch {
self.error = error
}
}
}

Expand Down
46 changes: 0 additions & 46 deletions CCCTube/Features/Search/SearchViewModel.swift

This file was deleted.

9 changes: 3 additions & 6 deletions CCCTube/Features/Talk/TalkMetadataFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ struct TalkMetadataFactory {
return item
}

func createArtworkMetadataItem(forURL url: URL) async throws -> AVMetadataItem? {
let imageData = try await fetchImagePngData(forURL: url)
guard let imageData else { return nil }
func createArtworkMetadataItem(imageData: Data) -> AVMetadataItem? {
let thumbnailMetadata = AVMutableMetadataItem()
thumbnailMetadata.identifier = .commonIdentifierArtwork
thumbnailMetadata.dataType = kCMMetadataBaseDataType_PNG as String
Expand All @@ -62,9 +60,8 @@ struct TalkMetadataFactory {
return thumbnailMetadata
}

private func fetchImagePngData(forURL url: URL) async throws -> Data? {
func fetchImageData(forURL url: URL) async throws -> Data? {
let (imageData, _) = try await URLSession.shared.data(from: url)
let image = UIImage(data: imageData)
return image?.pngData()
return imageData
}
}
Loading

0 comments on commit 51472fd

Please sign in to comment.