few bug fixes (#136)

This commit is contained in:
Seiike 2025-05-26 06:18:23 +02:00 committed by GitHub
parent 30aa66bf2a
commit d26f066da0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 78 additions and 44 deletions

View file

@ -12,7 +12,7 @@ struct ContinueWatchingItem: Codable, Identifiable {
let imageUrl: String let imageUrl: String
let episodeNumber: Int let episodeNumber: Int
let mediaTitle: String let mediaTitle: String
let progress: Double var progress: Double
let streamUrl: String let streamUrl: String
let fullUrl: String let fullUrl: String
let subtitles: String? let subtitles: String?

View file

@ -20,25 +20,43 @@ class ContinueWatchingManager {
} }
func save(item: ContinueWatchingItem) { func save(item: ContinueWatchingItem) {
if item.progress >= 0.9 { // Read the real playback times
let lastKey = "lastPlayedTime_\(item.fullUrl)"
let totalKey = "totalTime_\(item.fullUrl)"
let lastPlayed = UserDefaults.standard.double(forKey: lastKey)
let totalTime = UserDefaults.standard.double(forKey: totalKey)
// Compute up-to-date progress
let actualProgress: Double
if totalTime > 0 {
actualProgress = min(max(lastPlayed / totalTime, 0), 1)
} else {
actualProgress = item.progress
}
// If watched 90%, remove it
if actualProgress >= 0.9 {
remove(item: item) remove(item: item)
return return
} }
var items = fetchItems() // Otherwise update progress and re-save
var updatedItem = item
updatedItem.progress = actualProgress
var items = fetchItems()
items.removeAll { existing in items.removeAll { existing in
existing.fullUrl == item.fullUrl && existing.fullUrl == item.fullUrl &&
existing.episodeNumber == item.episodeNumber && existing.episodeNumber == item.episodeNumber &&
existing.module.metadata.sourceName == item.module.metadata.sourceName existing.module.metadata.sourceName == item.module.metadata.sourceName
} }
items.append(updatedItem)
items.append(item)
if let data = try? JSONEncoder().encode(items) { if let data = try? JSONEncoder().encode(items) {
UserDefaults.standard.set(data, forKey: storageKey) UserDefaults.standard.set(data, forKey: storageKey)
} }
} }
func fetchItems() -> [ContinueWatchingItem] { func fetchItems() -> [ContinueWatchingItem] {
guard guard

View file

@ -123,17 +123,18 @@ struct DownloadView: View {
Image(systemName: "arrow.down.circle") Image(systemName: "arrow.down.circle")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundColor(.gray) .foregroundColor(.gray)
.padding() .padding(4)
Text("No Active Downloads") Text("No Active Downloads")
.font(.title2) .font(.title2)
.foregroundColor(.gray) .foregroundColor(.gray)
.padding(3)
Text("Download episodes from the episode list") Text("Download episodes from the episode list")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.gray) .foregroundColor(.gray)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding()
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
} }
@ -143,17 +144,17 @@ struct DownloadView: View {
Image(systemName: "arrow.down.circle") Image(systemName: "arrow.down.circle")
.font(.system(size: 60)) .font(.system(size: 60))
.foregroundColor(.gray) .foregroundColor(.gray)
.padding() .padding(4)
Text("No Downloads") Text("No Downloads")
.font(.title2) .font(.title2)
.foregroundColor(.gray) .foregroundColor(.gray)
.padding(3)
Text("Your downloaded assets will appear here") Text("Your downloaded episodes will appear here")
.font(.subheadline) .font(.subheadline)
.foregroundColor(.gray) .foregroundColor(.gray)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding()
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
} }

View file

@ -369,14 +369,27 @@ struct ContinueWatchingCell: View {
} }
private func updateProgress() { private func updateProgress() {
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(item.fullUrl)") // grab the true playback times
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(item.fullUrl)") let lastPlayed = UserDefaults.standard.double(forKey: "lastPlayedTime_\(item.fullUrl)")
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(item.fullUrl)")
// compute a clean 01 ratio
let ratio: Double
if totalTime > 0 { if totalTime > 0 {
let ratio = lastPlayedTime / totalTime ratio = min(max(lastPlayed / totalTime, 0), 1)
currentProgress = max(0, min(ratio, 1))
} else { } else {
currentProgress = max(0, min(item.progress, 1)) ratio = min(max(item.progress, 0), 1)
}
currentProgress = ratio
if ratio >= 0.9 {
// >90% watched? drop it immediately
removeItem()
} else {
// otherwise persist the latest progress
var updated = item
updated.progress = ratio
ContinueWatchingManager.shared.save(item: updated)
} }
} }
} }

View file

@ -23,6 +23,11 @@ struct SettingsViewData: View {
@State private var isImageCachingEnabled: Bool = true @State private var isImageCachingEnabled: Bool = true
@State private var isMemoryOnlyMode: Bool = false @State private var isMemoryOnlyMode: Bool = false
enum ActiveAlert { case eraseData, removeDocs, removeMovPkg }
@State private var showAlert = false
@State private var activeAlert: ActiveAlert = .eraseData
var body: some View { var body: some View {
Form { Form {
// New section for cache settings // New section for cache settings
@ -86,7 +91,8 @@ struct SettingsViewData: View {
HStack { HStack {
Button(action: { Button(action: {
showRemoveDocumentsAlert = true activeAlert = .removeDocs
showAlert = true
}) { }) {
Text("Remove All Files in Documents") Text("Remove All Files in Documents")
} }
@ -109,7 +115,8 @@ struct SettingsViewData: View {
} }
Button(action: { Button(action: {
showEraseAppDataAlert = true activeAlert = .eraseData
showAlert = true
}) { }) {
Text("Erase all App Data") Text("Erase all App Data")
} }
@ -125,37 +132,32 @@ struct SettingsViewData: View {
calculateCacheSize() calculateCacheSize()
updateSizes() updateSizes()
} }
.alert(isPresented: $showEraseAppDataAlert) { .alert(isPresented: $showAlert) {
Alert( switch activeAlert {
title: Text("Erase App Data"), case .eraseData:
message: Text("Are you sure you want to erase all app data? This action cannot be undone."), return Alert(
primaryButton: .destructive(Text("Erase")) { title: Text("Erase App Data"),
eraseAppData() message: Text("Are you sure you want to erase all app data? This action cannot be undone."),
}, primaryButton: .destructive(Text("Erase")) { eraseAppData() },
secondaryButton: .cancel() secondaryButton: .cancel()
) )
} case .removeDocs:
.alert(isPresented: $showRemoveDocumentsAlert) { return Alert(
Alert( title: Text("Remove Documents"),
title: Text("Remove Documents"), message: Text("Are you sure you want to remove all files in the Documents folder? This will remove all modules."),
message: Text("Are you sure you want to remove all files in the Documents folder? This will remove all modules."), primaryButton: .destructive(Text("Remove")) { removeAllFilesInDocuments() },
primaryButton: .destructive(Text("Remove")) { secondaryButton: .cancel()
removeAllFilesInDocuments()
},
secondaryButton: .cancel()
) )
} case .removeMovPkg:
.alert(isPresented: $showRemoveMovPkgAlert) { return Alert(
Alert( title: Text("Remove Downloads"),
title: Text("Remove Downloads"), message: Text("Are you sure you want to remove all Downloads?"),
message: Text("Are you sure you want to remove all Downloads?"), primaryButton: .destructive(Text("Remove")) { removeMovPkgFiles() },
primaryButton: .destructive(Text("Remove")) { secondaryButton: .cancel()
removeMovPkgFiles()
},
secondaryButton: .cancel()
) )
}
} }
} }
// Calculate and update the combined cache size // Calculate and update the combined cache size
func calculateCacheSize() { func calculateCacheSize() {