FIx for episodecells getting stuck (#177)

* Fixed episodecells getting stuck sliding

* Enabled device scaling for ipad

not good enough yet, not applied everywhere cuz idk where to apply exactly 💯

* Fixed blur in continue watching cells

* Keyboard controls player

* fixed downloadview buttons

* Reduced tab bar outline opacity

* Increased module selector hitbox

* Fixed module add view

* Fixed mediainfoview issues (description) + changed settingsviewdata footer

medainfoview:
1: no swipe to go back
2: image shadows were fucked

* Fixes

* Splashscreen

* Update Contents.json

* Episodecell getting stuck fix
This commit is contained in:
50/50 2025-06-12 15:05:05 +02:00 committed by GitHub
parent b66ddb1679
commit c0742c6e20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 106 additions and 44 deletions

View file

@ -40,11 +40,12 @@ struct EpisodeCell: View {
@State private var activeDownloadTask: AVAssetDownloadTask?
@State private var swipeOffset: CGFloat = 0
@State private var isShowingActions = false
@State private var isShowingActions: Bool = false
@State private var actionButtonWidth: CGFloat = 60
@State private var dragState: DragState = .inactive
@State private var retryAttempts = 0
private let maxRetryAttempts = 3
@State private var retryAttempts: Int = 0
private let maxRetryAttempts: Int = 3
private let initialBackoffDelay: TimeInterval = 1.0
@ObservedObject private var jsController = JSController.shared
@ -105,11 +106,6 @@ struct EpisodeCell: View {
actionButtonsBackground
episodeCellContent
.offset(x: swipeOffset)
.animation(.spring(response: 0.3, dampingFraction: 0.8), value: swipeOffset)
.contextMenu { contextMenuContent }
.gesture(swipeGesture)
.onTapGesture { handleTap() }
}
.onAppear { setupOnAppear() }
.onDisappear { activeDownloadTask = nil }
@ -158,7 +154,22 @@ private extension EpisodeCell {
.frame(maxWidth: .infinity)
.background(cellBackground)
.clipShape(RoundedRectangle(cornerRadius: 15))
.offset(x: swipeOffset + dragState.translation.width)
.zIndex(1)
.scaleEffect(dragState.isActive ? 0.98 : 1.0)
.animation(.spring(response: 0.4, dampingFraction: 0.8), value: swipeOffset)
.animation(.spring(response: 0.3, dampingFraction: 0.6), value: dragState.isActive)
.contextMenu { contextMenuContent }
.simultaneousGesture(
DragGesture(coordinateSpace: .local)
.onChanged { value in
handleDragChanged(value)
}
.onEnded { value in
handleDragEnded(value)
}
)
.onTapGesture { handleTap() }
}
var cellBackground: some View {
@ -286,52 +297,98 @@ private extension EpisodeCell {
}
}
private extension EpisodeCell {
var swipeGesture: some Gesture {
DragGesture(minimumDistance: 10)
.onChanged { value in
handleSwipeChanged(value)
}
.onEnded { value in
handleSwipeEnded(value)
}
}
func handleSwipeChanged(_ value: DragGesture.Value) {
let horizontalTranslation = value.translation.width
let verticalTranslation = value.translation.height
enum DragState {
case inactive
case pressing
case dragging(translation: CGSize)
guard abs(horizontalTranslation) > abs(verticalTranslation) * 1.5 else { return }
var translation: CGSize {
switch self {
case .inactive, .pressing:
return .zero
case .dragging(let translation):
return translation
}
}
if horizontalTranslation < 0 {
let maxSwipe = calculateMaxSwipeDistance()
swipeOffset = max(horizontalTranslation, -maxSwipe)
} else if isShowingActions {
let maxSwipe = calculateMaxSwipeDistance()
swipeOffset = max(horizontalTranslation - maxSwipe, -maxSwipe)
var isActive: Bool {
switch self {
case .inactive:
return false
case .pressing, .dragging:
return true
}
}
var isDragging: Bool {
switch self {
case .dragging:
return true
default:
return false
}
}
}
func handleSwipeEnded(_ value: DragGesture.Value) {
let horizontalTranslation = value.translation.width
let verticalTranslation = value.translation.height
func handleDragChanged(_ value: DragGesture.Value) {
let translation = value.translation
let velocity = value.velocity
guard abs(horizontalTranslation) > abs(verticalTranslation) * 1.5 else { return }
let isHorizontalGesture = abs(translation.width) > abs(translation.height)
let hasSignificantHorizontalMovement = abs(translation.width) > 10
let maxSwipe = calculateMaxSwipeDistance()
let threshold = maxSwipe * 0.2
if isHorizontalGesture && hasSignificantHorizontalMovement {
dragState = .dragging(translation: .zero)
let proposedOffset = swipeOffset + translation.width
let maxSwipe = calculateMaxSwipeDistance()
if translation.width < 0 {
let newOffset = max(proposedOffset, -maxSwipe)
if proposedOffset < -maxSwipe {
let resistance = abs(proposedOffset + maxSwipe) * 0.15
swipeOffset = -maxSwipe - resistance
} else {
swipeOffset = newOffset
}
} else if isShowingActions {
swipeOffset = max(proposedOffset, -maxSwipe)
}
} else if !hasSignificantHorizontalMovement {
dragState = .inactive
}
}
func handleDragEnded(_ value: DragGesture.Value) {
let translation = value.translation
let velocity = value.velocity
withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {
if horizontalTranslation < -threshold && !isShowingActions {
swipeOffset = -maxSwipe
isShowingActions = true
} else if horizontalTranslation > threshold && isShowingActions {
swipeOffset = 0
isShowingActions = false
} else {
swipeOffset = isShowingActions ? -maxSwipe : 0
dragState = .inactive
let isHorizontalGesture = abs(translation.width) > abs(translation.height)
let hasSignificantHorizontalMovement = abs(translation.width) > 10
if isHorizontalGesture && hasSignificantHorizontalMovement {
let maxSwipe = calculateMaxSwipeDistance()
let threshold = maxSwipe * 0.3
let velocityThreshold: CGFloat = 500
withAnimation(.spring(response: 0.4, dampingFraction: 0.8)) {
if translation.width < -threshold || velocity.width < -velocityThreshold {
swipeOffset = -maxSwipe
isShowingActions = true
} else if translation.width > threshold || velocity.width > velocityThreshold {
swipeOffset = 0
isShowingActions = false
} else {
swipeOffset = isShowingActions ? -maxSwipe : 0
}
}
} else {
withAnimation(.spring(response: 0.4, dampingFraction: 0.8)) {
swipeOffset = isShowingActions ? -calculateMaxSwipeDistance() : 0
}
}
}

View file

@ -24,6 +24,11 @@ struct SplashScreenView: View {
.cornerRadius(24)
.scaleEffect(isAnimating ? 1.2 : 1.0)
.opacity(isAnimating ? 1.0 : 0.0)
Text("Sora")
.font(.largeTitle)
.fontWeight(.bold)
.opacity(isAnimating ? 1.0 : 0.0)
}
.onAppear {
withAnimation(.easeIn(duration: 0.5)) {