Skip to content

Commit

Permalink
Added path field to the DownloadData model. (#70)
Browse files Browse the repository at this point in the history
* Added path field to the DownloadData model.
All control over files was refactored using the new path field.

* Fix CourseContainerViewModelTests
  • Loading branch information
volodymyr-chekyrta authored Sep 8, 2023
1 parent eea114b commit 89530b4
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22F82" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22G90" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="CDDownloadData" representedClassName="CDDownloadData" syncable="YES" codeGenerationType="class">
<attribute name="courseId" optional="YES" attributeType="String"/>
<attribute name="fileName" optional="YES" attributeType="String"/>
<attribute name="id" optional="YES" attributeType="String"/>
<attribute name="path" optional="YES" attributeType="String"/>
<attribute name="progress" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="resumeData" optional="YES" attributeType="Binary"/>
<attribute name="state" optional="YES" attributeType="String"/>
Expand Down
3 changes: 2 additions & 1 deletion Core/Core/Data/Persistence/CorePersistenceProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import Combine

public protocol CorePersistenceProtocol {
func publisher() -> AnyPublisher<Int, Never>
func getAllDownloadData() -> [DownloadData]
func addToDownloadQueue(blocks: [CourseBlock])
func getNextBlockForDownloading() -> DownloadData?
func getDownloadsForCourse(_ courseId: String) -> [DownloadData]
func downloadData(by blockId: String) -> DownloadData?
func updateDownloadState(id: String, state: DownloadState, resumeData: Data?)
func updateDownloadState(id: String, state: DownloadState, path: String?, resumeData: Data?)
func deleteDownloadData(id: String) throws
func saveDownloadData(data: DownloadData)
}
Expand Down
51 changes: 30 additions & 21 deletions Core/Core/Network/DownloadManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public struct DownloadData {
public let id: String
public let courseId: String
public let url: String
public let path: String?
public let fileName: String
public let progress: Double
public let resumeData: Data?
Expand All @@ -34,6 +35,7 @@ public struct DownloadData {
id: String,
courseId: String,
url: String,
path: String?,
fileName: String,
progress: Double,
resumeData: Data?,
Expand All @@ -43,6 +45,7 @@ public struct DownloadData {
self.id = id
self.courseId = courseId
self.url = url
self.path = path
self.fileName = fileName
self.progress = progress
self.resumeData = resumeData
Expand Down Expand Up @@ -145,6 +148,7 @@ public class DownloadManager: DownloadManagerProtocol {
persistence.updateDownloadState(
id: download.id,
state: .inProgress,
path: nil,
resumeData: download.resumeData
)
self.isDownloadingInProgress = true
Expand All @@ -161,10 +165,11 @@ public class DownloadManager: DownloadManagerProtocol {
downloadRequest?.responseData(completionHandler: { [weak self] data in
guard let self else { return }
if let data = data.value, let url = self.videosFolderUrl() {
self.saveFile(file: fileName, data: data, url: url)
let fileUrl = self.saveFile(fileName: fileName, data: data, folderURL: url)
self.persistence.updateDownloadState(
id: download.id,
state: .finished,
path: fileUrl?.absoluteString,
resumeData: nil
)
try? self.newDownload()
Expand All @@ -183,33 +188,37 @@ public class DownloadManager: DownloadManagerProtocol {
self.persistence.updateDownloadState(
id: currentDownload.id,
state: .paused,
path: nil,
resumeData: resumeData
)
})
}

public func deleteFile(blocks: [CourseBlock]) {
for block in blocks {
if let url = block.videoUrl,
let fileName = URL(string: url)?.lastPathComponent, let folderUrl = videosFolderUrl() {
do {
let fileUrl = folderUrl.appendingPathComponent(fileName)
try persistence.deleteDownloadData(id: block.id)
try FileManager.default.removeItem(at: fileUrl)
print("File deleted successfully")
} catch {
print("Error deleting file: \(error.localizedDescription)")
}
let downloadData = persistence.downloadData(by: block.id)
guard let path = persistence.downloadData(by: block.id)?.path,
let fileUrl = URL(string: path) else { return }

do {
try persistence.deleteDownloadData(id: block.id)
try FileManager.default.removeItem(at: fileUrl)
print("File deleted successfully")
} catch {
print("Error deleting file: \(error.localizedDescription)")
}
}
}

public func deleteAllFiles() {
if let folderUrl = videosFolderUrl() {
do {
try FileManager.default.removeItem(at: folderUrl)
} catch {
NSLog("Error deleting All files: \(error.localizedDescription)")
let downloadData = persistence.getAllDownloadData()
downloadData.forEach {
if let path = $0.path, let fileURL = URL(string: path) {
do {
try FileManager.default.removeItem(at: fileURL)
} catch {
NSLog("Error deleting All files: \(error.localizedDescription)")
}
}
}
}
Expand All @@ -219,9 +228,7 @@ public class DownloadManager: DownloadManagerProtocol {
data.url.count > 0,
data.state == .finished else { return nil }

let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let directoryURL = documentDirectoryURL.appendingPathComponent("Files", isDirectory: true)
return directoryURL.appendingPathComponent(data.fileName)
return URL(string: data.path ?? "")
}

private func videosFolderUrl() -> URL? {
Expand All @@ -245,13 +252,15 @@ public class DownloadManager: DownloadManagerProtocol {
}
}

private func saveFile(file: String, data: Data, url: URL) {
let fileURL = url.appendingPathComponent(file)
private func saveFile(fileName: String, data: Data, folderURL: URL) -> URL? {
let fileURL = folderURL.appendingPathComponent(fileName)
do {
try data.write(to: fileURL)
return fileURL
} catch {
print("SaveFile Error", error.localizedDescription)
}
return nil
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ final class CourseContainerViewModelTests: XCTestCase {
id: "1",
courseId: "course123",
url: "https://example.com/file.mp4",
path: nil,
fileName: "file.mp4",
progress: 0,
resumeData: nil,
Expand Down Expand Up @@ -739,6 +740,7 @@ final class CourseContainerViewModelTests: XCTestCase {
id: "1",
courseId: "course123",
url: "https://example.com/file.mp4",
path: "file://../file.mp4",
fileName: "file.mp4",
progress: 0,
resumeData: nil,
Expand Down Expand Up @@ -860,6 +862,7 @@ final class CourseContainerViewModelTests: XCTestCase {
id: "1",
courseId: "course123",
url: "https://example.com/file.mp4",
path: nil,
fileName: "file.mp4",
progress: 0,
resumeData: nil,
Expand Down
24 changes: 23 additions & 1 deletion OpenEdX/Data/CorePersistence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ public class CorePersistence: CorePersistenceProtocol {
.eraseToAnyPublisher()
}

public func getAllDownloadData() -> [DownloadData] {
let request = CDDownloadData.fetchRequest()
guard let downloadData = try? context.fetch(request) else { return [] }
return downloadData.map {
DownloadData(
id: $0.id ?? "",
courseId: $0.courseId ?? "",
url: $0.url ?? "",
path: $0.path,
fileName: $0.fileName ?? "",
progress: $0.progress,
resumeData: $0.resumeData,
state: DownloadState(rawValue: $0.state ?? "") ?? .waiting,
type: DownloadType(rawValue: $0.type ?? "") ?? .video
)
}
}

public func addToDownloadQueue(blocks: [CourseBlock]) {
for block in blocks {
let request = CDDownloadData.fetchRequest()
Expand Down Expand Up @@ -72,6 +90,7 @@ public class CorePersistence: CorePersistenceProtocol {
id: data.id ?? "",
courseId: data.courseId ?? "",
url: data.url ?? "",
path: data.path,
fileName: data.fileName ?? "",
progress: data.progress,
resumeData: data.resumeData,
Expand All @@ -89,6 +108,7 @@ public class CorePersistence: CorePersistenceProtocol {
id: $0.id ?? "",
courseId: $0.courseId ?? "",
url: $0.url ?? "",
path: $0.path,
fileName: $0.fileName ?? "",
progress: $0.progress,
resumeData: $0.resumeData,
Expand All @@ -106,6 +126,7 @@ public class CorePersistence: CorePersistenceProtocol {
id: downloadData.id ?? "",
courseId: downloadData.courseId ?? "",
url: downloadData.url ?? "",
path: downloadData.path,
fileName: downloadData.fileName ?? "",
progress: downloadData.progress,
resumeData: downloadData.resumeData,
Expand All @@ -114,12 +135,13 @@ public class CorePersistence: CorePersistenceProtocol {
)
}

public func updateDownloadState(id: String, state: DownloadState, resumeData: Data?) {
public func updateDownloadState(id: String, state: DownloadState, path: String?, resumeData: Data?) {
context.performAndWait {
let request = CDDownloadData.fetchRequest()
request.predicate = NSPredicate(format: "id = %@", id)
guard let downloadData = try? context.fetch(request).first else { return }
downloadData.state = state.rawValue
downloadData.path = path
downloadData.resumeData = resumeData
do {
try context.save()
Expand Down
8 changes: 6 additions & 2 deletions OpenEdX/Data/DatabaseManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ class DatabaseManager: CoreDataHandlerProtocol {
}

// Re-create the persistent container
persistentContainer = createContainer()
context = createContext()
persistentContainer.loadPersistentStores { _, error in
if let error = error {
print("Unresolved error \(error)")
fatalError()
}
}
}
}

0 comments on commit 89530b4

Please sign in to comment.