Files
terebi/Sources/App/PlaybackQueue.swift
T

63 lines
2.3 KiB
Swift

import Foundation
struct PlaybackQueue {
struct Item: Identifiable {
let id = UUID()
let url: URL
}
private(set) var items: [Item] = []
private(set) var currentID: UUID?
var currentURL: URL? { items.first { $0.id == currentID }?.url }
private var currentIndex: Int? { items.firstIndex { $0.id == currentID } }
var canPrevious: Bool { currentIndex.map { $0 > 0 } ?? false }
var canNext: Bool { currentIndex.map { $0 + 1 < items.count } ?? false }
mutating func replace(_ urls: [URL]) {
items = sortedFiles(urls).map { Item(url: $0) }
currentID = items.first?.id
}
mutating func append(_ urls: [URL]) {
items.append(contentsOf: sortedFiles(urls).map { Item(url: $0) })
}
mutating func select(_ id: UUID) {
guard items.contains(where: { $0.id == id }) else { return }
currentID = id
}
mutating func advance(_ offset: Int) -> URL? {
guard let index = currentIndex else { return nil }
let (target, overflow) = index.addingReportingOverflow(offset)
guard !overflow, items.indices.contains(target) else { return nil }
currentID = items[target].id
return items[target].url
}
mutating func remove(_ id: UUID) -> URL? {
guard let index = items.firstIndex(where: { $0.id == id }) else { return nil }
let wasCurrent = currentID == id
items.remove(at: index)
guard wasCurrent else { return nil }
currentID = items.indices.contains(index) ? items[index].id : nil
return currentURL
}
mutating func move(fromOffsets offsets: IndexSet, toOffset destination: Int) {
guard !offsets.isEmpty, offsets.allSatisfy(items.indices.contains),
(0...items.count).contains(destination) else { return }
let moving = offsets.map { items[$0] }
for index in offsets.reversed() { items.remove(at: index) }
let insertion = destination - offsets.filter { $0 < destination }.count
items.insert(contentsOf: moving, at: insertion)
}
private func sortedFiles(_ urls: [URL]) -> [URL] {
urls.filter(\.isFileURL).sorted {
let order = $0.lastPathComponent.localizedStandardCompare($1.lastPathComponent)
return order == .orderedSame ? $0.path < $1.path : order == .orderedAscending
}
}
}