This commit is contained in:
Francesco 2025-05-24 16:22:02 +02:00
parent a3e84bd865
commit 92061e868a
6 changed files with 0 additions and 473 deletions

View file

@ -14,10 +14,6 @@ struct ContentView: View {
.tabItem {
Label("Library", systemImage: "books.vertical")
}
DownloadView()
.tabItem {
Label("Downloads", systemImage: "arrow.down.app.fill")
}
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")

View file

@ -105,21 +105,9 @@ struct EpisodeCell: View {
var body: some View {
HStack {
if isMultiSelectMode {
Button(action: {
onSelectionChanged?(!isSelected)
}) {
Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
.foregroundColor(isSelected ? .accentColor : .secondary)
.font(.title3)
}
.buttonStyle(PlainButtonStyle())
}
episodeThumbnail
episodeInfo
Spacer()
downloadStatusView
CircularProgressBar(progress: currentProgress)
.frame(width: 40, height: 40)
}
@ -292,14 +280,6 @@ struct EpisodeCell: View {
private var contextMenuContent: some View {
Group {
if case .notDownloaded = downloadStatus {
Button(action: {
showDownloadConfirmation = true
}) {
Label("Download Episode", systemImage: "arrow.down.circle")
}
}
if progress <= 0.9 {
Button(action: markAsWatched) {
Label("Mark as Watched", systemImage: "checkmark.circle")

View file

@ -157,14 +157,6 @@ struct MediaInfoView: View {
isFetchingEpisode = false
showStreamLoadingView = false
}
.sheet(isPresented: $showRangeInput) {
RangeSelectionSheet(
totalEpisodes: episodeLinks.count,
onSelectionComplete: { startEpisode, endEpisode in
selectEpisodeRange(start: startEpisode, end: endEpisode)
}
)
}
}
@ViewBuilder
@ -397,213 +389,13 @@ struct MediaInfoView: View {
.fontWeight(.bold)
Spacer()
multiSelectControls
episodeNavigationSection
}
if isMultiSelectMode && !selectedEpisodes.isEmpty {
multiSelectActionBar
}
episodeListSection
}
}
@ViewBuilder
private var multiSelectControls: some View {
if isMultiSelectMode {
if useIconOnlyButtons {
HStack(spacing: multiselectButtonSpacing) {
Menu {
Button(action: {
selectedEpisodes.removeAll()
}) {
Label("Clear All", systemImage: "clear")
}
Button(action: {
showRangeInput = true
}) {
Label("Range Select", systemImage: "list.bullet.rectangle")
}
} label: {
Image(systemName: "ellipsis.circle")
.font(.system(size: 18, weight: .medium))
.foregroundColor(.primary)
.frame(width: 36, height: 36)
.background(Color(UIColor.tertiarySystemFill))
.clipShape(Circle())
}
Spacer()
Button(action: {
selectAllVisibleEpisodes()
}) {
Image(systemName: "checkmark.circle")
.font(.system(size: 18, weight: .medium))
.foregroundColor(.primary)
.frame(width: 36, height: 36)
.background(Color(UIColor.tertiarySystemFill))
.clipShape(Circle())
}
Button(action: {
isMultiSelectMode = false
selectedEpisodes.removeAll()
}) {
Text("Done")
.font(.system(size: 15, weight: .semibold))
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.accentColor)
.cornerRadius(18)
}
}
.padding(.horizontal, multiselectPadding)
.padding(.vertical, 8)
} else {
HStack(spacing: multiselectButtonSpacing) {
Button(action: {
selectedEpisodes.removeAll()
}) {
HStack(spacing: 6) {
Image(systemName: "clear")
Text("Clear")
}
.font(.system(size: 14, weight: .medium))
.foregroundColor(.primary)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(Color(UIColor.tertiarySystemFill))
.cornerRadius(8)
}
Button(action: {
showRangeInput = true
}) {
HStack(spacing: 6) {
Image(systemName: "list.bullet.rectangle")
Text("Range")
}
.font(.system(size: 14, weight: .medium))
.foregroundColor(.primary)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(Color(UIColor.tertiarySystemFill))
.cornerRadius(8)
}
Spacer()
Button(action: {
selectAllVisibleEpisodes()
}) {
HStack(spacing: 6) {
Image(systemName: "checkmark.circle")
Text("Select All")
}
.font(.system(size: 14, weight: .medium))
.foregroundColor(.primary)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(Color(UIColor.tertiarySystemFill))
.cornerRadius(8)
}
Button(action: {
isMultiSelectMode = false
selectedEpisodes.removeAll()
}) {
Text("Done")
.font(.system(size: 15, weight: .semibold))
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.accentColor)
.cornerRadius(8)
}
}
.padding(.horizontal, multiselectPadding)
.padding(.vertical, 10)
.background(Color(UIColor.secondarySystemBackground).opacity(0.6))
.cornerRadius(12)
}
} else {
HStack {
Spacer()
Button(action: {
isMultiSelectMode = true
}) {
HStack(spacing: 6) {
Image(systemName: "checkmark.circle")
Text("Select Episodes")
}
}
.font(.system(size: 15, weight: .medium))
.foregroundColor(.accentColor)
.padding(.horizontal, 16)
.padding(.vertical, 10)
.background(Color.accentColor.opacity(0.1))
.cornerRadius(8)
}
.padding(.horizontal, 16)
}
}
@ViewBuilder
private var multiSelectActionBar: some View {
VStack(spacing: 0) {
Rectangle()
.fill(Color(UIColor.separator))
.frame(height: 0.5)
HStack(spacing: 12) {
HStack(spacing: 6) {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.accentColor)
Text("\(selectedEpisodes.count) selected")
.font(.system(size: 15, weight: .medium))
.foregroundColor(.primary)
}
Spacer()
if isBulkDownloading {
HStack(spacing: 8) {
ProgressView()
.scaleEffect(0.8)
Text(bulkDownloadProgress)
.font(.system(size: 13))
.foregroundColor(.secondary)
}
} else {
Button(action: {
startBulkDownload()
}) {
HStack(spacing: 6) {
Image(systemName: "arrow.down.circle.fill")
Text("Download")
}
.font(.system(size: 15, weight: .semibold))
.foregroundColor(.white)
.padding(.horizontal, 20)
.padding(.vertical, 10)
.background(Color.accentColor)
.cornerRadius(8)
}
.disabled(selectedEpisodes.isEmpty)
.opacity(selectedEpisodes.isEmpty ? 0.6 : 1.0)
}
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
}
.background(Color(UIColor.systemBackground))
}
@ViewBuilder
private var episodeNavigationSection: some View {
Group {
@ -731,8 +523,6 @@ struct MediaInfoView: View {
userDefaults.synchronize()
Logger.shared.log("Marked episodes watched within season \(selectedSeason + 1) of \"\(title)\".", type: "General")
} else {
// Handle non-season case if needed
}
}
@ -1679,138 +1469,3 @@ struct MediaInfoView: View {
}.resume()
}
}
struct RangeSelectionSheet: View {
let totalEpisodes: Int
let onSelectionComplete: (Int, Int) -> Void
@State private var startEpisode: String = "1"
@State private var endEpisode: String = ""
@State private var showError: Bool = false
@State private var errorMessage: String = ""
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationView {
VStack(spacing: 20) {
Text("Select Episode Range")
.font(.title2)
.fontWeight(.bold)
.padding(.top)
VStack(alignment: .leading, spacing: 16) {
HStack {
Text("From Episode:")
.frame(width: 100, alignment: .leading)
TextField("1", text: $startEpisode)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numberPad)
}
HStack {
Text("To Episode:")
.frame(width: 100, alignment: .leading)
TextField("\(totalEpisodes)", text: $endEpisode)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numberPad)
}
}
.padding(.horizontal)
if !startEpisode.isEmpty && !endEpisode.isEmpty {
let preview = generatePreviewText()
if !preview.isEmpty {
VStack(alignment: .leading, spacing: 8) {
Text("Preview:")
.font(.headline)
Text(preview)
.font(.caption)
.foregroundColor(.secondary)
.padding()
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(8)
}
.padding(.horizontal)
}
}
Spacer()
HStack(spacing: 16) {
Button("Cancel") {
dismiss()
}
.foregroundColor(.secondary)
.padding()
.frame(maxWidth: .infinity)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(10)
Button("Select") {
validateAndSelect()
}
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(Color.accentColor)
.cornerRadius(10)
.disabled(!isValidRange())
}
.padding(.horizontal)
.padding(.bottom)
}
.navigationBarTitleDisplayMode(.inline)
.navigationBarTitle("Episode Range")
.navigationBarItems(trailing: Button("Done") { dismiss() })
}
.onAppear {
endEpisode = "\(totalEpisodes)"
}
.alert("Invalid Range", isPresented: $showError) {
Button("OK") { }
} message: {
Text(errorMessage)
}
}
private func isValidRange() -> Bool {
guard let start = Int(startEpisode),
let end = Int(endEpisode) else { return false }
return start >= 1 && end <= totalEpisodes && start <= end
}
private func generatePreviewText() -> String {
guard let start = Int(startEpisode),
let end = Int(endEpisode),
isValidRange() else { return "" }
let count = end - start + 1
return "Will select \(count) episode\(count == 1 ? "" : "s"): Episodes \(start)-\(end)"
}
private func validateAndSelect() {
guard let start = Int(startEpisode),
let end = Int(endEpisode) else {
errorMessage = "Please enter valid episode numbers"
showError = true
return
}
guard start >= 1 && end <= totalEpisodes else {
errorMessage = "Episode numbers must be between 1 and \(totalEpisodes)"
showError = true
return
}
guard start <= end else {
errorMessage = "Start episode must be less than or equal to end episode"
showError = true
return
}
onSelectionComplete(start, end)
dismiss()
}
}

View file

@ -1,94 +0,0 @@
//
// SettingsViewPerformance.swift
// Sora
//
// Created by Claude on 19/06/24.
//
import SwiftUI
struct SettingsViewPerformance: View {
@ObservedObject private var performanceMonitor = PerformanceMonitor.shared
@State private var showResetConfirmation = false
var body: some View {
Form {
Section(header: Text("Performance Monitoring")) {
Toggle("Enable Performance Monitoring", isOn: Binding(
get: { performanceMonitor.isEnabled },
set: { performanceMonitor.setEnabled($0) }
))
Button(action: {
showResetConfirmation = true
}) {
HStack {
Text("Reset Metrics")
.foregroundColor(.primary)
Spacer()
Image(systemName: "arrow.clockwise")
}
}
.disabled(!performanceMonitor.isEnabled)
Button(action: {
performanceMonitor.logMetrics()
DropManager.shared.showDrop(title: "Metrics Logged", subtitle: "Check logs for details", duration: 1.0, icon: UIImage(systemName: "doc.text"))
}) {
HStack {
Text("Log Current Metrics")
.foregroundColor(.primary)
Spacer()
Image(systemName: "doc.text")
}
}
.disabled(!performanceMonitor.isEnabled)
}
if performanceMonitor.isEnabled {
Section(header: Text("About Performance Monitoring"), footer: Text("Performance monitoring helps track app resource usage and identify potential issues with network requests, cache efficiency, and memory management.")) {
Text("Performance monitoring helps track app resource usage and identify potential issues with network requests, cache efficiency, and memory management.")
.font(.footnote)
.foregroundColor(.secondary)
}
}
}
.navigationTitle("Performance")
.alert(isPresented: $showResetConfirmation) {
Alert(
title: Text("Reset Performance Metrics"),
message: Text("Are you sure you want to reset all performance metrics? This action cannot be undone."),
primaryButton: .destructive(Text("Reset")) {
performanceMonitor.resetMetrics()
DropManager.shared.showDrop(title: "Metrics Reset", subtitle: "", duration: 1.0, icon: UIImage(systemName: "arrow.clockwise"))
},
secondaryButton: .cancel()
)
}
}
}
struct MetricRow: View {
let title: String
let value: String
var body: some View {
HStack {
Text(title)
.font(.system(size: 15))
.foregroundColor(.secondary)
Spacer()
Text(value)
.font(.system(size: 15, weight: .medium))
.foregroundColor(.primary)
}
}
}
struct SettingsViewPerformance_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
SettingsViewPerformance()
}
}
}

View file

@ -18,9 +18,6 @@ struct SettingsView: View {
NavigationLink(destination: SettingsViewPlayer()) {
Text("Media Player")
}
NavigationLink(destination: SettingsViewDownloads().environmentObject(JSController.shared)) {
Text("Downloads")
}
NavigationLink(destination: SettingsViewModule()) {
Text("Modules")
}
@ -36,9 +33,6 @@ struct SettingsView: View {
NavigationLink(destination: SettingsViewLogger()) {
Text("Logs")
}
NavigationLink(destination: SettingsViewPerformance()) {
Text("Performance")
}
}
Section(header: Text("Info")) {

View file

@ -76,7 +76,6 @@
722248662DCBC13E00CABE2D /* JSController-Downloads.swift in Sources */ = {isa = PBXBuildFile; fileRef = 722248652DCBC13E00CABE2D /* JSController-Downloads.swift */; };
72443C7D2DC8036500A61321 /* DownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72443C7C2DC8036500A61321 /* DownloadView.swift */; };
72443C7F2DC8038300A61321 /* SettingsViewDownloads.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72443C7E2DC8038300A61321 /* SettingsViewDownloads.swift */; };
7272206E2DD6336100C2A4A2 /* SettingsViewPerformance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7272206D2DD6336100C2A4A2 /* SettingsViewPerformance.swift */; };
727220712DD642B100C2A4A2 /* JSController-StreamTypeDownload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7272206F2DD642B100C2A4A2 /* JSController-StreamTypeDownload.swift */; };
727220722DD642B100C2A4A2 /* JSController+MP4Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = 727220702DD642B100C2A4A2 /* JSController+MP4Download.swift */; };
72AC3A012DD4DAEB00C60B96 /* ImagePrefetchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AC39FE2DD4DAEA00C60B96 /* ImagePrefetchManager.swift */; };
@ -155,7 +154,6 @@
722248652DCBC13E00CABE2D /* JSController-Downloads.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Downloads.swift"; sourceTree = "<group>"; };
72443C7C2DC8036500A61321 /* DownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadView.swift; sourceTree = "<group>"; };
72443C7E2DC8038300A61321 /* SettingsViewDownloads.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewDownloads.swift; sourceTree = "<group>"; };
7272206D2DD6336100C2A4A2 /* SettingsViewPerformance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewPerformance.swift; sourceTree = "<group>"; };
7272206F2DD642B100C2A4A2 /* JSController-StreamTypeDownload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-StreamTypeDownload.swift"; sourceTree = "<group>"; };
727220702DD642B100C2A4A2 /* JSController+MP4Download.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController+MP4Download.swift"; sourceTree = "<group>"; };
72AC39FD2DD4DAEA00C60B96 /* EpisodeMetadataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeMetadataManager.swift; sourceTree = "<group>"; };
@ -278,7 +276,6 @@
133D7C832D2BE2630075467E /* SettingsSubViews */ = {
isa = PBXGroup;
children = (
7272206D2DD6336100C2A4A2 /* SettingsViewPerformance.swift */,
1E9FF1D22D403E42008AC100 /* SettingsViewLoggerFilter.swift */,
1399FAD32D3AB38C00E97C31 /* SettingsViewLogger.swift */,
133D7C842D2BE2630075467E /* SettingsViewModule.swift */,
@ -637,7 +634,6 @@
13DB468E2D90093A008CBC03 /* Anilist-Token.swift in Sources */,
1EAC7A322D888BC50083984D /* MusicProgressSlider.swift in Sources */,
722248632DCBAA4700CABE2D /* JSController-HeaderManager.swift in Sources */,
7272206E2DD6336100C2A4A2 /* SettingsViewPerformance.swift in Sources */,
722248642DCBAA4700CABE2D /* JSController+M3U8Download.swift in Sources */,
133D7C942D2BE2640075467E /* JSController.swift in Sources */,
133D7C922D2BE2640075467E /* URLSession.swift in Sources */,