mirror of
https://github.com/cranci1/Sora.git
synced 2026-04-21 08:32:00 +00:00
replace custom swipe logic with swiftUIs native .swipeactions (#251)
* replace custom swipe logic with swiftUIs native .swipeactions * use uservars * Fixed formatting and also watched status method * add back the horizontal slider * removed silly git text --------- Co-authored-by: cranci1 <100066266+cranci1@users.noreply.github.com>
This commit is contained in:
parent
db48f1eab9
commit
9271c3e122
1 changed files with 116 additions and 70 deletions
|
|
@ -24,7 +24,6 @@ struct EpisodeCell: View {
|
||||||
let tmdbID: Int?
|
let tmdbID: Int?
|
||||||
let seasonNumber: Int?
|
let seasonNumber: Int?
|
||||||
|
|
||||||
//receives the set of filler episode numbers (from MediaInfoView)
|
|
||||||
let fillerEpisodes: Set<Int>?
|
let fillerEpisodes: Set<Int>?
|
||||||
|
|
||||||
let isMultiSelectMode: Bool
|
let isMultiSelectMode: Bool
|
||||||
|
|
@ -47,6 +46,7 @@ struct EpisodeCell: View {
|
||||||
@State private var isShowingActions: Bool = false
|
@State private var isShowingActions: Bool = false
|
||||||
@State private var actionButtonWidth: CGFloat = 60
|
@State private var actionButtonWidth: CGFloat = 60
|
||||||
@State private var dragState: DragState = .inactive
|
@State private var dragState: DragState = .inactive
|
||||||
|
@State private var dragStart: CGPoint?
|
||||||
|
|
||||||
@State private var retryAttempts: Int = 0
|
@State private var retryAttempts: Int = 0
|
||||||
private var malIDFromParent: Int? { malID }
|
private var malIDFromParent: Int? { malID }
|
||||||
|
|
@ -57,8 +57,8 @@ struct EpisodeCell: View {
|
||||||
@EnvironmentObject var moduleManager: ModuleManager
|
@EnvironmentObject var moduleManager: ModuleManager
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
@AppStorage("selectedAppearance") private var selectedAppearance: Appearance = .system
|
@AppStorage("selectedAppearance") private var selectedAppearance: Appearance = .system
|
||||||
|
@AppStorage("remainingTimePercentage") private var remainingTimePercentage: Double = 90.0
|
||||||
|
|
||||||
// Filler state (derived from passed-in fillerEpisodes)
|
|
||||||
@State private var isFiller: Bool = false
|
@State private var isFiller: Bool = false
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
|
@ -114,14 +114,9 @@ struct EpisodeCell: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
|
||||||
actionButtonsBackground
|
|
||||||
|
|
||||||
episodeCellContent
|
episodeCellContent
|
||||||
}
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
setupOnAppear()
|
setupOnAppear()
|
||||||
// set filler state based on passed-in set (if available)
|
|
||||||
let epNum = episodeID + 1
|
let epNum = episodeID + 1
|
||||||
if let set = fillerEpisodes {
|
if let set = fillerEpisodes {
|
||||||
self.isFiller = set.contains(epNum)
|
self.isFiller = set.contains(epNum)
|
||||||
|
|
@ -171,6 +166,7 @@ private extension EpisodeCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
var episodeCellContent: some View {
|
var episodeCellContent: some View {
|
||||||
|
ZStack {
|
||||||
HStack {
|
HStack {
|
||||||
episodeThumbnail
|
episodeThumbnail
|
||||||
episodeInfo
|
episodeInfo
|
||||||
|
|
@ -196,14 +192,64 @@ private extension EpisodeCell {
|
||||||
.animation(.spring(response: 0.3, dampingFraction: 0.6), value: dragState.isActive)
|
.animation(.spring(response: 0.3, dampingFraction: 0.6), value: dragState.isActive)
|
||||||
.contextMenu { contextMenuContent }
|
.contextMenu { contextMenuContent }
|
||||||
.simultaneousGesture(
|
.simultaneousGesture(
|
||||||
DragGesture(coordinateSpace: .local)
|
DragGesture(minimumDistance: 20, coordinateSpace: .local)
|
||||||
.onChanged { value in
|
.onChanged { value in
|
||||||
|
let translation = value.translation
|
||||||
|
if abs(translation.width) > abs(translation.height) * 2.0 && abs(translation.width) > 30 {
|
||||||
handleDragChanged(value)
|
handleDragChanged(value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.onEnded { value in
|
.onEnded { value in
|
||||||
|
let translation = value.translation
|
||||||
|
if abs(translation.width) > abs(translation.height) * 2.0 && abs(translation.width) > 30 {
|
||||||
handleDragEnded(value)
|
handleDragEnded(value)
|
||||||
|
} else {
|
||||||
|
dragStart = nil
|
||||||
|
dragState = .inactive
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
handleTap()
|
||||||
|
}
|
||||||
|
|
||||||
|
actionButtonsBackground
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(cellBackground)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||||
|
.contextMenu { contextMenuContent }
|
||||||
|
.swipeActions(edge: .trailing) {
|
||||||
|
|
||||||
|
Button(action: { downloadEpisode() }) {
|
||||||
|
Label("Download", systemImage: "arrow.down.circle")
|
||||||
|
}
|
||||||
|
.tint(.blue)
|
||||||
|
|
||||||
|
if progress <= remainingTimePercentage {
|
||||||
|
Button(action: { markAsWatched() }) {
|
||||||
|
Label("Watched", systemImage: "checkmark.circle")
|
||||||
|
}
|
||||||
|
.tint(.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
if progress != 0 {
|
||||||
|
Button(action: { resetProgress() }) {
|
||||||
|
Label("Reset", systemImage: "arrow.counterclockwise")
|
||||||
|
}
|
||||||
|
.tint(.orange)
|
||||||
|
}
|
||||||
|
|
||||||
|
if episodeIndex > 0 {
|
||||||
|
Button(action: { onMarkAllPrevious() }) {
|
||||||
|
Label("All Prev", systemImage: "checkmark.circle.fill")
|
||||||
|
}
|
||||||
|
.tint(.purple)
|
||||||
|
}
|
||||||
|
}
|
||||||
.onTapGesture { handleTap() }
|
.onTapGesture { handleTap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,7 +331,7 @@ private extension EpisodeCell {
|
||||||
|
|
||||||
var contextMenuContent: some View {
|
var contextMenuContent: some View {
|
||||||
Group {
|
Group {
|
||||||
if progress <= 0.9 {
|
if progress <= remainingTimePercentage {
|
||||||
Button(action: markAsWatched) {
|
Button(action: markAsWatched) {
|
||||||
Label("Mark Episode as Watched", systemImage: "checkmark.circle")
|
Label("Mark Episode as Watched", systemImage: "checkmark.circle")
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +366,7 @@ private extension EpisodeCell {
|
||||||
closeActionsAndPerform { downloadEpisode() }
|
closeActionsAndPerform { downloadEpisode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
if progress <= 0.9 {
|
if progress >= (remainingTimePercentage / 100.0) {
|
||||||
ActionButton(
|
ActionButton(
|
||||||
icon: "checkmark.circle",
|
icon: "checkmark.circle",
|
||||||
label: "Watched",
|
label: "Watched",
|
||||||
|
|
@ -470,7 +516,7 @@ private extension EpisodeCell {
|
||||||
func calculateMaxSwipeDistance() -> CGFloat {
|
func calculateMaxSwipeDistance() -> CGFloat {
|
||||||
var buttonCount = 1
|
var buttonCount = 1
|
||||||
|
|
||||||
if progress <= 0.9 { buttonCount += 1 }
|
if progress >= (remainingTimePercentage / 100.0) { buttonCount += 1 }
|
||||||
if progress != 0 { buttonCount += 1 }
|
if progress != 0 { buttonCount += 1 }
|
||||||
if episodeIndex > 0 { buttonCount += 1 }
|
if episodeIndex > 0 { buttonCount += 1 }
|
||||||
|
|
||||||
|
|
@ -495,7 +541,9 @@ private extension EpisodeCell {
|
||||||
action()
|
action()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension EpisodeCell {
|
||||||
func markAsWatched() {
|
func markAsWatched() {
|
||||||
let defaults = UserDefaults.standard
|
let defaults = UserDefaults.standard
|
||||||
let totalTime = 1000.0
|
let totalTime = 1000.0
|
||||||
|
|
@ -521,7 +569,6 @@ private extension EpisodeCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func resetProgress() {
|
func resetProgress() {
|
||||||
let userDefaults = UserDefaults.standard
|
let userDefaults = UserDefaults.standard
|
||||||
userDefaults.set(0.0, forKey: "lastPlayedTime_\(episode)")
|
userDefaults.set(0.0, forKey: "lastPlayedTime_\(episode)")
|
||||||
|
|
@ -981,7 +1028,6 @@ private extension EpisodeCell {
|
||||||
}.resume()
|
}.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func handleFetchFailure(error: Error) {
|
func handleFetchFailure(error: Error) {
|
||||||
Logger.shared.log("Episode details fetch error: \(error.localizedDescription)", type: "Error")
|
Logger.shared.log("Episode details fetch error: \(error.localizedDescription)", type: "Error")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue