Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions BookPlayer/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ extension AppDelegate {
} else {
let dataManager = DataManager(coreDataStack: stack)
let accountService = makeAccountService(dataManager: dataManager)
let libraryService = makeLibraryService(dataManager: dataManager)
let audioMetadataService = makeAudioMetadataService()
let libraryService = makeLibraryService(dataManager: dataManager, audioMetadataService: audioMetadataService)
let syncService = makeSyncService(accountService: accountService, libraryService: libraryService)
let playbackService = makePlaybackService(libraryService: libraryService)
let playerManager = PlayerManager(
Expand Down Expand Up @@ -571,9 +572,13 @@ extension AppDelegate {
return service
}

private func makeLibraryService(dataManager: DataManager) -> LibraryService {
private func makeAudioMetadataService() -> AudioMetadataService {
return AudioMetadataService()
}

private func makeLibraryService(dataManager: DataManager, audioMetadataService: AudioMetadataServiceProtocol) -> LibraryService {
let service = LibraryService()
service.setup(dataManager: dataManager)
service.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
return service
}

Expand Down
2 changes: 1 addition & 1 deletion BookPlayer/Coordinators/DataInitializerCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class DataInitializerCoordinator: BPLogger {

if shouldRebuildFromFiles {
let files = getLibraryFiles()
coreServices.libraryService.insertItems(from: files)
await coreServices.libraryService.insertItems(from: files)
}

await MainActor.run {
Expand Down
1 change: 1 addition & 0 deletions BookPlayer/Library/ItemList/ItemListView+Alerts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extension ItemListView {
}

Button("existing_playlist_button") {
model.pendingMoveItemIdentifiers = alertParameters.itemIdentifiers
model.selectedSetItems = Set(alertParameters.itemIdentifiers)
activeSheet = .foldersSelection
}
Expand Down
13 changes: 12 additions & 1 deletion BookPlayer/Library/ItemList/ItemListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ final class ItemListViewModel: ObservableObject {
}
}
@Published var selectedItems = [SimpleLibraryItem]()
/// Stores item identifiers from import operations to avoid race condition
/// where items may not be loaded in the UI yet when moving to a folder
var pendingMoveItemIdentifiers: [String]?

/// Search
@Published var scope: ItemListSearchScope = .all
Expand Down Expand Up @@ -410,7 +413,15 @@ extension ItemListViewModel {
}

func handleMoveIntoFolder(_ folder: SimpleLibraryItem) {
let fetchedItems = selectedItems.compactMap({ $0.relativePath })
// Use pendingMoveItemIdentifiers if available (from import operations),
// otherwise fall back to selectedItems (from manual selection)
let fetchedItems: [String]
if let pendingItems = pendingMoveItemIdentifiers {
fetchedItems = pendingItems
pendingMoveItemIdentifiers = nil
} else {
fetchedItems = selectedItems.compactMap({ $0.relativePath })
}

do {
try libraryService.moveItems(fetchedItems, inside: folder.relativePath)
Expand Down
2 changes: 1 addition & 1 deletion BookPlayer/Library/ItemList/LibraryRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ struct LibraryRootView: View {
guard !files.isEmpty else { return }

Task { @MainActor in
let processedItems = libraryService.insertItems(from: files)
let processedItems = await libraryService.insertItems(from: files)
var itemIdentifiers = processedItems.map({ $0.relativePath })
do {
await syncService.scheduleUpload(items: processedItems)
Expand Down
3 changes: 2 additions & 1 deletion BookPlayer/Library/ItemList/Views/BookView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ struct BookView: View {
@Previewable var syncService: SyncService = {
let syncService = SyncService()
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: ""))
let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: dataManager)
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
syncService.setup(
isActive: true,
libraryService: libraryService
Expand Down
3 changes: 2 additions & 1 deletion BookPlayer/Profile/Profile/ProfileListenedSectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ struct ProfileListenedSectionView: View {
@Previewable var libraryService: LibraryService = {
let libraryService = LibraryService()
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: ""))
libraryService.setup(dataManager: dataManager)
let audioMetadataService = AudioMetadataService()
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)

return libraryService
}()
Expand Down
3 changes: 2 additions & 1 deletion BookPlayer/Profile/Profile/ProfileSyncTasksSectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ struct ProfileSyncTasksSectionView: View {
#Preview {
@Previewable var syncService: SyncService = {
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: ""))
let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: dataManager)
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
let syncService = SyncService()
syncService.setup(isActive: true, libraryService: libraryService)

Expand Down
24 changes: 14 additions & 10 deletions BookPlayer/Settings/Storage/StorageViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ final class StorageViewModel: StorageViewModelProtocol {
publishedFiles.filter({ $0.showWarning })
}

func handleFix(for item: StorageItem, shouldReloadItems: Bool = true) throws {
func handleFix(for item: StorageItem, shouldReloadItems: Bool = true) async throws {
guard let fetchedBook = self.libraryService.findBooks(containing: item.fileURL)?.first else {
// create a new book
try self.createBook(from: item)
try await self.createBook(from: item)
if shouldReloadItems {
self.loadItems()
}
Expand Down Expand Up @@ -224,11 +224,15 @@ final class StorageViewModel: StorageViewModelProtocol {
}

func fixSelectedItem(_ item: StorageItem) {
do {
try handleFix(for: item)
} catch {
storageAlert = .error(errorMessage: error.localizedDescription)
showAlert = true
Task {
do {
try await handleFix(for: item)
} catch {
await MainActor.run {
storageAlert = .error(errorMessage: error.localizedDescription)
showAlert = true
}
}
}
}

Expand Down Expand Up @@ -361,8 +365,8 @@ final class StorageViewModel: StorageViewModelProtocol {
listState.reloadAll()
}

private func createBook(from item: StorageItem) throws {
let book = self.libraryService.createBook(from: item.fileURL)
private func createBook(from item: StorageItem) async throws {
let book = await self.libraryService.createBook(from: item.fileURL)
try moveBookFile(from: item, with: book)
try libraryService.moveItems([book.relativePath], inside: nil)
reloadLibraryItems()
Expand Down Expand Up @@ -450,7 +454,7 @@ final class StorageViewModel: StorageViewModelProtocol {
private func fixItemSafely(_ item: StorageItem) async -> FixResult {
do {
try await Task.detached(priority: .userInitiated) {
try self.handleFix(for: item, shouldReloadItems: false)
try await self.handleFix(for: item, shouldReloadItems: false)
}.value

return FixResult(item: item, success: true, error: nil)
Expand Down
3 changes: 2 additions & 1 deletion BookPlayerTests/DataManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class ProcessFilesTests: DataManagerTests {

let expectation = XCTestExpectation(description: "File import notification")

let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: self.dataManager)
libraryService.setup(dataManager: self.dataManager, audioMetadataService: audioMetadataService)
self.importManager = ImportManager(libraryService: libraryService)

self.subscription = self.importManager.observeFiles().sink { files in
Expand Down
3 changes: 2 additions & 1 deletion BookPlayerTests/ImportOperationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ class ImportOperationTests: XCTestCase {
let promise = XCTestExpectation(description: "Process file")
let promiseFile = expectation(forNotification: .processingFile, object: nil)
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null"))
let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: dataManager)
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
let operation = ImportOperation(files: [fileUrl],
libraryService: libraryService)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@ final class PlaybackPerformanceTests: XCTestCase {
override func setUpWithError() throws {
DataTestUtils.clearFolderContents(url: DataManager.getProcessedFolderURL())
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null"))
let audioMetadataService = AudioMetadataService()
self.sut = LibraryService()
self.sut.setup(dataManager: dataManager)
self.sut.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
_ = self.sut.getLibrary()
}

override func tearDownWithError() throws {
self.sut = nil
}

func testFolderProgressUpdatePerformance() throws {
func testFolderProgressUpdatePerformance() async throws {
/// Setup a test folder with 3000 ibooks inside it
let folder = try self.sut.createFolder(with: "test-folder", inside: nil)
let urls = Array(stride(from: 0, to: 3000, by: 1)).map({ URL(string: "test-book-\($0).mp3")! })
_ = self.sut.insertItems(from: urls, parentPath: folder.relativePath)
_ = await self.sut.insertItems(from: urls, parentPath: folder.relativePath)

self.measure(metrics: [XCTCPUMetric()]) {
/// This is called by the `PlayerManager` when the currently playing book changes its progress percentage
Expand Down
37 changes: 19 additions & 18 deletions BookPlayerTests/Services/LibraryServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ class LibraryServiceTests: XCTestCase {
override func setUp() {
DataTestUtils.clearFolderContents(url: DataManager.getProcessedFolderURL())
let dataManager = DataManager(coreDataStack: CoreDataStack(testPath: "/dev/null"))
let audioMetadataService = AudioMetadataService()
self.sut = LibraryService()
self.sut.setup(dataManager: dataManager)
self.sut.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
_ = self.sut.getLibrary()
}

Expand Down Expand Up @@ -71,14 +72,14 @@ class LibraryServiceTests: XCTestCase {
XCTAssert(currentTheme?.title == "Default / Dark")
}

func testCreateBook() {
func testCreateBook() async {
let filename = "test-book.txt"
let bookContents = "bookcontents".data(using: .utf8)!
let processedFolder = DataManager.getProcessedFolderURL()

// Add test file to Processed folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)
let newBook = self.sut.createBook(from: fileUrl)
let newBook = await self.sut.createBook(from: fileUrl)
XCTAssert(newBook.title == "test-book.txt")
XCTAssert(newBook.relativePath == "test-book.txt")
}
Expand Down Expand Up @@ -657,7 +658,7 @@ class InsertBooksTests: LibraryServiceTests {
XCTAssert(library.items?.count == 0)
}

func testInsertOneBookInLibrary() throws {
func testInsertOneBookInLibrary() async throws {
let library = self.sut.getLibrary()

let filename = "file.txt"
Expand All @@ -667,13 +668,13 @@ class InsertBooksTests: LibraryServiceTests {
// Add test file to Processed folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)

let processedItems = self.sut.insertItems(from: [fileUrl])
let processedItems = await self.sut.insertItems(from: [fileUrl])

XCTAssert(library.items?.count == 1)
XCTAssert(processedItems.count == 1)
}

func testInsertMultipleBooksInLibrary() throws {
func testInsertMultipleBooksInLibrary() async throws {
let library = self.sut.getLibrary()

let filename1 = "file1.txt"
Expand All @@ -686,13 +687,13 @@ class InsertBooksTests: LibraryServiceTests {
let file1Url = DataTestUtils.generateTestFile(name: filename1, contents: book1Contents, destinationFolder: processedFolder)
let file2Url = DataTestUtils.generateTestFile(name: filename2, contents: book2Contents, destinationFolder: processedFolder)

let processedItems = self.sut.insertItems(from: [file1Url, file2Url])
let processedItems = await self.sut.insertItems(from: [file1Url, file2Url])

XCTAssert(library.items?.count == 2)
XCTAssert(processedItems.count == 2)
}

func testInsertEmptyBooksIntoPlaylist() throws {
func testInsertEmptyBooksIntoPlaylist() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder", inside: nil)
Expand All @@ -703,7 +704,7 @@ class InsertBooksTests: LibraryServiceTests {
XCTAssert(folder.items?.count == 0)
}

func testInsertOneBookIntoPlaylist() throws {
func testInsertOneBookIntoPlaylist() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder", inside: nil)
Expand All @@ -718,15 +719,15 @@ class InsertBooksTests: LibraryServiceTests {
// Add test file to Documents folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)

let processedItems = sut.insertItems(from: [fileUrl])
let processedItems = await sut.insertItems(from: [fileUrl])
.map({ $0.relativePath })
try sut.moveItems(processedItems, inside: folder.relativePath)
XCTAssert(library.items?.count == 1)
XCTAssert(folder.items?.count == 1)
XCTAssert(processedItems.count == 1)
}

func testInsertMultipleBooksIntoPlaylist() throws {
func testInsertMultipleBooksIntoPlaylist() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder", inside: nil)
Expand All @@ -744,7 +745,7 @@ class InsertBooksTests: LibraryServiceTests {
let file1Url = DataTestUtils.generateTestFile(name: filename1, contents: book1Contents, destinationFolder: processedFolder)
let file2Url = DataTestUtils.generateTestFile(name: filename2, contents: book2Contents, destinationFolder: processedFolder)

let processedItems = sut.insertItems(from: [file1Url, file2Url])
let processedItems = await sut.insertItems(from: [file1Url, file2Url])
.map({ $0.relativePath })
try sut.moveItems(processedItems, inside: folder.relativePath)

Expand All @@ -753,7 +754,7 @@ class InsertBooksTests: LibraryServiceTests {
XCTAssert(processedItems.count == 2)
}

func testInsertExistingBookFromLibraryIntoPlaylist() throws {
func testInsertExistingBookFromLibraryIntoPlaylist() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder", inside: nil)
Expand All @@ -768,7 +769,7 @@ class InsertBooksTests: LibraryServiceTests {
// Add test file to Documents folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)

let processedItems = self.sut.insertItems(from: [fileUrl])
let processedItems = await self.sut.insertItems(from: [fileUrl])
.map({ $0.relativePath })

XCTAssert(library.items?.count == 2)
Expand All @@ -780,7 +781,7 @@ class InsertBooksTests: LibraryServiceTests {
XCTAssert(folder.items?.count == 1)
}

func testInsertExistingBookFromPlaylistIntoLibrary() throws {
func testInsertExistingBookFromPlaylistIntoLibrary() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder", inside: nil)
Expand All @@ -795,7 +796,7 @@ class InsertBooksTests: LibraryServiceTests {
// Add test file to Documents folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)

let processedItems = self.sut.insertItems(from: [fileUrl])
let processedItems = await self.sut.insertItems(from: [fileUrl])
.map({ $0.relativePath })

try self.sut.moveItems(processedItems, inside: folder.relativePath)
Expand All @@ -810,7 +811,7 @@ class InsertBooksTests: LibraryServiceTests {
XCTAssert(folder.items?.count == 0)
}

func testInsertExistingBookFromPlaylistIntoPlaylist() throws {
func testInsertExistingBookFromPlaylistIntoPlaylist() async throws {
let library = self.sut.getLibrary()

_ = try self.sut.createFolder(with: "test-folder1", inside: nil)
Expand All @@ -827,7 +828,7 @@ class InsertBooksTests: LibraryServiceTests {
// Add test file to Processed folder
let fileUrl = DataTestUtils.generateTestFile(name: filename, contents: bookContents, destinationFolder: processedFolder)

let processedItems = self.sut.insertItems(from: [fileUrl])
let processedItems = await self.sut.insertItems(from: [fileUrl])
.map({ $0.relativePath })

try self.sut.moveItems(processedItems, inside: folder1.relativePath)
Expand Down
3 changes: 2 additions & 1 deletion BookPlayerTests/Support/StubFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ class StubFactory {
}

public class func library(dataManager: DataManager) -> Library {
let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: dataManager)
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
return libraryService.getLibrary()
}
}
3 changes: 2 additions & 1 deletion BookPlayerWatch/ExtensionDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ class ExtensionDelegate: NSObject, WKApplicationDelegate, ObservableObject {
let dataManager = DataManager(coreDataStack: stack)
let accountService = AccountService()
accountService.setup(dataManager: dataManager)
let audioMetadataService = AudioMetadataService()
let libraryService = LibraryService()
libraryService.setup(dataManager: dataManager)
libraryService.setup(dataManager: dataManager, audioMetadataService: audioMetadataService)
let syncService = SyncService()
syncService.setup(
isActive: accountService.hasSyncEnabled(),
Expand Down
Loading