Implement incremental sync and offline recovery

This commit is contained in:
diyaa
2026-06-15 22:31:23 +02:00
parent fa7727d572
commit 295c6c1d9b
25 changed files with 2293 additions and 494 deletions
@@ -153,6 +153,36 @@ final class iPhoneLibraryViewModelFavoritesTests: XCTestCase {
XCTAssertTrue(try XCTUnwrap(remoteRow(in: viewModel, trackID: secondTrack.trackId)).isFavorite)
}
func testFavoritesRemainIntactAcrossLibrarySync() async throws {
let track = makeRemoteTrack(
trackId: "remote-sync-favorite",
assetId: "asset-sync-favorite",
title: "Sync Favorite"
)
let favoriteStore = InMemoryFavoriteTrackStore()
let viewModel = makeViewModel(
remoteTracks: [track],
downloadStates: [makeDownloadedState(for: track)],
favoriteTrackStore: favoriteStore,
audioFiles: [localFilePath(for: track): Data([0x5])],
apiClient: StubVelodyAPIClient(
environment: ServerEnvironment(
baseURL: ServerEnvironment.defaultLocalBaseURL,
appVersion: "Tests"
)
)
)
await viewModel.loadIfNeeded()
await viewModel.toggleFavorite(trackID: track.trackId)
await viewModel.refreshSync()
XCTAssertTrue(try XCTUnwrap(remoteRow(in: viewModel, trackID: track.trackId)).isFavorite)
XCTAssertTrue(try XCTUnwrap(offlineRow(in: viewModel, trackID: track.trackId)).isFavorite)
let savedFavorites = try await favoriteStore.loadFavoriteTracks()
XCTAssertEqual(savedFavorites.map(\.remoteTrackId), [track.trackId])
}
func testToggleFavoriteRepeatedlyLeavesSingleStableRecord() async throws {
let track = makeRemoteTrack(
trackId: "remote-repeat",
@@ -285,4 +315,41 @@ final class iPhoneLibraryViewModelFavoritesTests: XCTestCase {
XCTAssertTrue(remoteTrack.isFavorite)
XCTAssertTrue(viewModel.availableOfflineTracks.isEmpty)
}
func testFailedDownloadKeepsFavoriteAndShowsRetry() async throws {
let track = makeRemoteTrack(
trackId: "remote-interrupted-favorite",
assetId: "asset-interrupted-favorite",
title: "Interrupted Favorite"
)
let viewModel = makeViewModel(
remoteTracks: [track],
downloadStates: [
RemoteTrackDownloadState(
remoteTrackId: track.trackId,
assetId: track.assetId,
localFilePath: "",
downloadedAt: nil,
downloadStatus: .failed,
lastDownloadError: "The previous download did not finish. Try again."
),
],
favoriteTrackStore: InMemoryFavoriteTrackStore(tracks: [
FavoriteTrackRecord(
remoteTrackId: track.trackId,
favoritedAt: Date(timeIntervalSince1970: 7_000)
),
])
)
await viewModel.loadIfNeeded()
let remoteTrack = try XCTUnwrap(remoteRow(in: viewModel, trackID: track.trackId))
XCTAssertEqual(remoteTrack.status, .failed)
XCTAssertEqual(remoteTrack.downloadButtonTitle, "Retry")
XCTAssertTrue(remoteTrack.canDownload)
XCTAssertTrue(remoteTrack.isFavorite)
XCTAssertTrue(viewModel.availableOfflineTracks.isEmpty)
}
}