mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
Mark all previous watched option added (#34)
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
This commit is contained in:
commit
801390ca70
4 changed files with 78 additions and 39 deletions
|
|
@ -758,3 +758,4 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
|
||||
// yes? Like the plural of the famous american rapper ye? -IBHRAD
|
||||
// low taper fade the meme is massive -cranci
|
||||
// cranci still doesnt have a job -seiike
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ struct LibraryView: View {
|
|||
Image(systemName: "play.circle")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.secondary)
|
||||
Text("No items to continue watching")
|
||||
Text("No items to continue watching.")
|
||||
.font(.headline)
|
||||
Text("Recently watched content will appear here")
|
||||
Text("Recently watched content will appear here.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
|
@ -58,9 +58,9 @@ struct LibraryView: View {
|
|||
Image(systemName: "magazine")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.secondary)
|
||||
Text("No Items saved")
|
||||
Text("You have no items saved.")
|
||||
.font(.headline)
|
||||
Text("Bookmark items for easy access later")
|
||||
Text("Bookmark items for an easier access later.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,44 +15,31 @@ struct EpisodeLink: Identifiable {
|
|||
}
|
||||
|
||||
struct EpisodeCell: View {
|
||||
let episodeIndex: Int
|
||||
let episode: String
|
||||
let episodeID: Int
|
||||
let progress: Double
|
||||
let itemID: Int
|
||||
|
||||
let onTap: (String) -> Void
|
||||
let onMarkAllPrevious: () -> Void
|
||||
|
||||
@State private var episodeTitle: String = ""
|
||||
@State private var episodeImageUrl: String = ""
|
||||
@State private var isLoading: Bool = true
|
||||
@State private var currentProgress: Double = 0.0
|
||||
let onTap: (String) -> Void
|
||||
|
||||
private func markAsWatched() {
|
||||
UserDefaults.standard.set(99999999.0, forKey: "lastPlayedTime_\(episode)")
|
||||
UserDefaults.standard.set(99999999.0, forKey: "totalTime_\(episode)")
|
||||
updateProgress()
|
||||
}
|
||||
|
||||
private func resetProgress() {
|
||||
UserDefaults.standard.set(0.0, forKey: "lastPlayedTime_\(episode)")
|
||||
UserDefaults.standard.set(0.0, forKey: "totalTime_\(episode)")
|
||||
updateProgress()
|
||||
}
|
||||
|
||||
private func updateProgress() {
|
||||
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(episode)")
|
||||
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(episode)")
|
||||
currentProgress = totalTime > 0 ? lastPlayedTime / totalTime : 0
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ZStack {
|
||||
KFImage(URL(string: episodeImageUrl.isEmpty ? "https://raw.githubusercontent.com/cranci1/Sora/refs/heads/main/assets/banner2.png" : episodeImageUrl))
|
||||
.resizable()
|
||||
.aspectRatio(16/9, contentMode: .fill)
|
||||
.frame(width: 100, height: 56)
|
||||
.cornerRadius(8)
|
||||
|
||||
KFImage(URL(string: episodeImageUrl.isEmpty
|
||||
? "https://raw.githubusercontent.com/cranci1/Sora/refs/heads/main/assets/banner2.png"
|
||||
: episodeImageUrl))
|
||||
.resizable()
|
||||
.aspectRatio(16/9, contentMode: .fill)
|
||||
.frame(width: 100, height: 56)
|
||||
.cornerRadius(8)
|
||||
|
||||
if isLoading {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle())
|
||||
|
|
@ -76,31 +63,56 @@ struct EpisodeCell: View {
|
|||
}
|
||||
.contentShape(Rectangle())
|
||||
.contextMenu {
|
||||
if currentProgress <= 0.9 {
|
||||
if progress <= 0.9 {
|
||||
Button(action: markAsWatched) {
|
||||
Label("Mark as Watched", systemImage: "checkmark.circle")
|
||||
}
|
||||
}
|
||||
|
||||
if currentProgress != 0 {
|
||||
// Only show reset if progress is nonzero
|
||||
if progress != 0 {
|
||||
Button(action: resetProgress) {
|
||||
Label("Reset Progress", systemImage: "arrow.counterclockwise")
|
||||
}
|
||||
}
|
||||
|
||||
if episodeIndex > 0 {
|
||||
Button(action: onMarkAllPrevious) {
|
||||
Label("Mark All Previous Watched", systemImage: "checkmark.circle.fill")
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
if UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil ||
|
||||
UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata") {
|
||||
if UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil
|
||||
|| UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata") {
|
||||
fetchEpisodeDetails()
|
||||
}
|
||||
updateProgress()
|
||||
currentProgress = progress
|
||||
}
|
||||
.onTapGesture {
|
||||
onTap(episodeImageUrl)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchEpisodeDetails() {
|
||||
private func markAsWatched() {
|
||||
UserDefaults.standard.set(99999999.0, forKey: "lastPlayedTime_\(episode)")
|
||||
UserDefaults.standard.set(99999999.0, forKey: "totalTime_\(episode)")
|
||||
updateProgress()
|
||||
}
|
||||
|
||||
private func resetProgress() {
|
||||
UserDefaults.standard.set(0.0, forKey: "lastPlayedTime_\(episode)")
|
||||
UserDefaults.standard.set(0.0, forKey: "totalTime_\(episode)")
|
||||
updateProgress()
|
||||
}
|
||||
|
||||
private func updateProgress() {
|
||||
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(episode)")
|
||||
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(episode)")
|
||||
currentProgress = totalTime > 0 ? lastPlayedTime / totalTime : 0
|
||||
}
|
||||
|
||||
private func fetchEpisodeDetails() {
|
||||
guard let url = URL(string: "https://api.ani.zip/mappings?anilist_id=\(itemID)") else {
|
||||
isLoading = false
|
||||
return
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ struct MediaInfoView: View {
|
|||
@State var isRefetching: Bool = true
|
||||
@State var isFetchingEpisode: Bool = false
|
||||
|
||||
@State private var refreshTrigger: Bool = false
|
||||
|
||||
@State private var selectedEpisodeNumber: Int = 0
|
||||
@State private var selectedEpisodeImage: String = ""
|
||||
|
||||
|
|
@ -54,6 +56,8 @@ struct MediaInfoView: View {
|
|||
} else {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
|
||||
// MARK: - Top media info
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
KFImage(URL(string: imageUrl))
|
||||
.placeholder {
|
||||
|
|
@ -121,6 +125,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Synopsis section
|
||||
if !synopsis.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack(alignment: .center) {
|
||||
|
|
@ -144,6 +149,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Action buttons
|
||||
HStack {
|
||||
Button(action: {
|
||||
playFirstUnwatchedEpisode()
|
||||
|
|
@ -204,21 +210,41 @@ struct MediaInfoView: View {
|
|||
}
|
||||
}
|
||||
|
||||
//MARK: - Mark all prevoius logic
|
||||
ForEach(episodeLinks.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = episodeLinks[i]
|
||||
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(ep.href)")
|
||||
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(ep.href)")
|
||||
let progress = totalTime > 0 ? lastPlayedTime / totalTime : 0
|
||||
|
||||
EpisodeCell(episode: ep.href, episodeID: ep.number - 1, progress: progress, itemID: itemID ?? 0, onTap: { imageUrl in
|
||||
EpisodeCell(
|
||||
episodeIndex: i,
|
||||
episode: ep.href,
|
||||
episodeID: ep.number - 1,
|
||||
progress: progress,
|
||||
itemID: itemID ?? 0,
|
||||
onTap: { imageUrl in
|
||||
if !isFetchingEpisode {
|
||||
selectedEpisodeNumber = ep.number
|
||||
selectedEpisodeImage = imageUrl
|
||||
fetchStream(href: ep.href)
|
||||
AnalyticsManager.shared.sendEvent(event: "watch", additionalData: ["title": title, "episode": ep.number])
|
||||
AnalyticsManager.shared.sendEvent(
|
||||
event: "watch",
|
||||
additionalData: ["title": title, "episode": ep.number]
|
||||
)
|
||||
}
|
||||
},
|
||||
onMarkAllPrevious: {
|
||||
for idx in 0..<i {
|
||||
let href = episodeLinks[idx].href
|
||||
UserDefaults.standard.set(99999999.0, forKey: "lastPlayedTime_\(href)")
|
||||
UserDefaults.standard.set(99999999.0, forKey: "totalTime_\(href)")
|
||||
}
|
||||
refreshTrigger.toggle() // Force the UI to refresh
|
||||
Logger.shared.log("Marked \(ep.number) episodes watched within anime \"\(title)\".", type: "General")
|
||||
}
|
||||
)
|
||||
.id(refreshTrigger) // Attaches the refresh trigger so that changes re-create the cell
|
||||
.disabled(isFetchingEpisode)
|
||||
}
|
||||
}
|
||||
|
|
@ -262,7 +288,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
.onAppear {
|
||||
if !hasFetched {
|
||||
DropManager.shared.showDrop(title: "Fetching Data", subtitle: "Please wait while fetching", duration: 1.0, icon: UIImage(systemName: "arrow.triangle.2.circlepath"))
|
||||
DropManager.shared.showDrop(title: "Fetching Data", subtitle: "Please wait while fetching.", duration: 1.0, icon: UIImage(systemName: "arrow.triangle.2.circlepath"))
|
||||
fetchDetails()
|
||||
fetchItemID(byTitle: title) { result in
|
||||
switch result {
|
||||
|
|
|
|||
Loading…
Reference in a new issue