mirror of
https://github.com/yattee/yattee.git
synced 2025-08-05 02:04:07 +00:00
Merge branch 'main' into use-mpvkit
This commit is contained in:
@@ -47,7 +47,7 @@ final class AppleAVPlayerViewController: UIViewController {
|
||||
infoViewControllers.append(infoViewController([.chapters], title: "Chapters"))
|
||||
infoViewControllers.append(infoViewController([.comments], title: "Comments"))
|
||||
|
||||
var queueSections = [NowPlayingView.ViewSection.playingNext]
|
||||
let queueSections = [NowPlayingView.ViewSection.playingNext]
|
||||
|
||||
infoViewControllers.append(contentsOf: [
|
||||
infoViewController([.related], title: "Related"),
|
||||
|
@@ -7,19 +7,8 @@ struct ControlBackgroundModifier: ViewModifier {
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
if enabled {
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
content
|
||||
.background(.thinMaterial)
|
||||
} else {
|
||||
content
|
||||
#if os(macOS)
|
||||
.background(VisualEffectBlur(material: .hudWindow))
|
||||
#elseif os(iOS)
|
||||
.background(VisualEffectBlur(blurStyle: .systemThinMaterial).edgesIgnoringSafeArea(edgesIgnoringSafeArea))
|
||||
#else
|
||||
content
|
||||
.background(.thinMaterial)
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
content
|
||||
}
|
||||
|
@@ -25,9 +25,8 @@ struct OpeningStream: View {
|
||||
if let selection = player.streamSelection {
|
||||
if selection.isLocal {
|
||||
return "Opening file...".localized()
|
||||
} else {
|
||||
return String(format: "Opening %@ stream...".localized(), selection.shortQuality)
|
||||
}
|
||||
return String(format: "Opening %@ stream...".localized(), selection.shortQuality)
|
||||
}
|
||||
|
||||
return "Loading streams...".localized()
|
||||
|
@@ -193,8 +193,11 @@ struct PlayerControls: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
#if os(tvOS)
|
||||
.onChange(of: model.presentingControls) { newValue in
|
||||
if newValue { focusedField = .play }
|
||||
else { focusedField = nil }
|
||||
if newValue {
|
||||
focusedField = .play
|
||||
} else {
|
||||
focusedField = nil
|
||||
}
|
||||
}
|
||||
.onChange(of: focusedField) { _ in model.resetTimer() }
|
||||
#else
|
||||
@@ -252,8 +255,6 @@ struct PlayerControls: View {
|
||||
{
|
||||
ThumbnailView(url: url)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.transition(.opacity)
|
||||
.animation(.default)
|
||||
} else if player.videoForDisplay == nil {
|
||||
Color.black
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ struct TVControls: UIViewRepresentable {
|
||||
|
||||
func updateUIView(_: UIView, context _: Context) {}
|
||||
|
||||
func makeCoordinator() -> TVControls.Coordinator {
|
||||
func makeCoordinator() -> Self.Coordinator {
|
||||
Coordinator(controlsArea)
|
||||
}
|
||||
|
||||
|
@@ -103,7 +103,9 @@ struct TimelineView: View {
|
||||
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxHeight: 300, alignment: .bottom)
|
||||
#endif
|
||||
.offset(x: thumbTooltipOffset)
|
||||
.overlay(GeometryReader { proxy in
|
||||
Color.clear
|
||||
@@ -114,8 +116,9 @@ struct TimelineView: View {
|
||||
tooltipSize = proxy.size
|
||||
}
|
||||
})
|
||||
|
||||
#if os(tvOS)
|
||||
.frame(height: 80)
|
||||
#endif
|
||||
.opacity(dragging ? 1 : 0)
|
||||
.animation(.easeOut, value: thumbTooltipOffset)
|
||||
HStack(spacing: 4) {
|
||||
@@ -161,14 +164,6 @@ struct TimelineView: View {
|
||||
self.size = size
|
||||
}
|
||||
})
|
||||
.frame(maxHeight: playerControlsLayout.timelineHeight)
|
||||
#if !os(tvOS)
|
||||
.gesture(DragGesture(minimumDistance: 0).onEnded { value in
|
||||
let target = (value.location.x / size.width) * units
|
||||
self.playerTime.currentTime = .secondsInDefaultTimescale(target)
|
||||
player.backend.seek(to: target, seekType: .userInteracted)
|
||||
})
|
||||
#endif
|
||||
|
||||
durationView
|
||||
.shadow(radius: 3)
|
||||
@@ -177,8 +172,14 @@ struct TimelineView: View {
|
||||
.frame(minWidth: 30, alignment: .trailing)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.highPriorityGesture(
|
||||
|
||||
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
||||
.zIndex(2)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
#if !os(tvOS)
|
||||
.gesture(
|
||||
DragGesture(minimumDistance: 5, coordinateSpace: .global)
|
||||
.onChanged { value in
|
||||
if !dragging {
|
||||
@@ -210,11 +211,7 @@ struct TimelineView: View {
|
||||
controls.resetTimer()
|
||||
}
|
||||
)
|
||||
#endif
|
||||
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
||||
.zIndex(2)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ViewBuilder var durationView: some View {
|
||||
|
@@ -70,17 +70,15 @@ struct PlayerBackendView: View {
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom != .pad {
|
||||
return verticalSizeClass == .compact ? safeAreaModel.safeArea.top : 0
|
||||
} else {
|
||||
return safeAreaModel.safeArea.top.isZero ? safeAreaModel.safeArea.bottom : safeAreaModel.safeArea.top
|
||||
}
|
||||
return safeAreaModel.safeArea.top.isZero ? safeAreaModel.safeArea.bottom : safeAreaModel.safeArea.top
|
||||
}
|
||||
|
||||
var controlsBottomPadding: Double {
|
||||
if UIDevice.current.userInterfaceIdiom != .pad {
|
||||
return player.playingFullScreen || verticalSizeClass == .compact ? safeAreaModel.safeArea.bottom : 0
|
||||
} else {
|
||||
return player.playingFullScreen ? safeAreaModel.safeArea.bottom : 0
|
||||
}
|
||||
return player.playingFullScreen ? safeAreaModel.safeArea.bottom : 0
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -18,8 +18,9 @@ struct RelatedView: View {
|
||||
|
||||
Color.clear.padding(.bottom, 50)
|
||||
.listRowBackground(Color.clear)
|
||||
.backport
|
||||
.listRowSeparator(false)
|
||||
#if os(iOS)
|
||||
.listRowSeparator(.hidden)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -219,25 +219,17 @@ struct CommentView: View {
|
||||
}
|
||||
|
||||
private var commentText: some View {
|
||||
Group {
|
||||
let text = Text(comment.text)
|
||||
#if os(macOS)
|
||||
.font(.system(size: 14))
|
||||
#elseif os(iOS)
|
||||
.font(.system(size: 15))
|
||||
#endif
|
||||
.lineSpacing(3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
text
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
} else {
|
||||
text
|
||||
}
|
||||
}
|
||||
Text(comment.text)
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
#if os(macOS)
|
||||
.font(.system(size: 14))
|
||||
#elseif os(iOS)
|
||||
.font(.system(size: 15))
|
||||
#endif
|
||||
.lineSpacing(3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
|
||||
private func openChannelAction() {
|
||||
|
@@ -32,13 +32,8 @@ struct CommentsView: View {
|
||||
|
||||
struct CommentsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
CommentsView()
|
||||
.previewInterfaceOrientation(.landscapeRight)
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
|
||||
CommentsView()
|
||||
.previewInterfaceOrientation(.landscapeRight)
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
||||
|
@@ -79,15 +79,10 @@ struct InspectorView: View {
|
||||
Text(detail.localized())
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
let value = Text(value).lineLimit(1)
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
value
|
||||
#if !os(tvOS)
|
||||
Text(value).lineLimit(1)
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
} else {
|
||||
value
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.font(.caption)
|
||||
}
|
||||
|
@@ -30,8 +30,9 @@ struct PlayerQueueView: View {
|
||||
#endif
|
||||
Color.clear.padding(.bottom, 50)
|
||||
.listRowBackground(Color.clear)
|
||||
.backport
|
||||
.listRowSeparator(false)
|
||||
#if os(iOS)
|
||||
.listRowSeparator(.hidden)
|
||||
#endif
|
||||
}
|
||||
.environment(\.inNavigationView, false)
|
||||
}
|
||||
|
@@ -59,23 +59,15 @@ struct VideoDescription: View {
|
||||
|
||||
@ViewBuilder var textDescription: some View {
|
||||
#if !os(iOS)
|
||||
Group {
|
||||
if #available(macOS 12, *) {
|
||||
Text(description)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
} else {
|
||||
Text(description)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
||||
}
|
||||
}
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.system(size: 14))
|
||||
.lineSpacing(3)
|
||||
Text(description)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.system(size: 14))
|
||||
.lineSpacing(3)
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -177,7 +169,8 @@ struct VideoDescription: View {
|
||||
{
|
||||
player.backend.seek(to: Double(time), seekType: .userInteracted)
|
||||
return
|
||||
} else if destination != nil {
|
||||
}
|
||||
if destination != nil {
|
||||
urlToOpen = yatteeURL
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ struct VideoDetails: View {
|
||||
|
||||
struct ChannelView: View {
|
||||
@ObservedObject private var model = PlayerModel.shared
|
||||
@Binding var detailsVisibility: Bool
|
||||
|
||||
var video: Video? { model.videoForDisplay }
|
||||
|
||||
@@ -33,14 +34,19 @@ struct VideoDetails: View {
|
||||
guard let channel = video?.channel else { return }
|
||||
NavigationModel.shared.openChannel(channel, navigationStyle: .sidebar)
|
||||
} label: {
|
||||
ChannelAvatarView(
|
||||
channel: video?.channel,
|
||||
video: video
|
||||
)
|
||||
.frame(maxWidth: 40, maxHeight: 40)
|
||||
.padding(.trailing, 5)
|
||||
if detailsVisibility {
|
||||
ChannelAvatarView(
|
||||
channel: video?.channel,
|
||||
video: video
|
||||
)
|
||||
} else {
|
||||
Circle()
|
||||
.foregroundColor(Color(white: 0.6).opacity(0.5))
|
||||
}
|
||||
}
|
||||
.frame(width: 40, height: 40)
|
||||
.buttonStyle(.plain)
|
||||
.padding(.trailing, 5)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack {
|
||||
@@ -56,18 +62,14 @@ struct VideoDetails: View {
|
||||
}
|
||||
|
||||
if let video, !video.isLocal {
|
||||
Group {
|
||||
Text("•")
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "person.2.fill")
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "person.2.fill")
|
||||
|
||||
if let channel = model.videoForDisplay?.channel {
|
||||
if let subscriptions = channel.subscriptionsString {
|
||||
Text(subscriptions)
|
||||
} else {
|
||||
Text("1234").redacted(reason: .placeholder)
|
||||
}
|
||||
if let channel = model.videoForDisplay?.channel {
|
||||
if let subscriptions = channel.subscriptionsString {
|
||||
Text(subscriptions)
|
||||
} else {
|
||||
Text("1234").redacted(reason: .placeholder)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,8 +96,6 @@ struct VideoDetails: View {
|
||||
HStack(spacing: 4) {
|
||||
publishedDateSection
|
||||
|
||||
Text("•")
|
||||
|
||||
HStack(spacing: 4) {
|
||||
if model.videoBeingOpened != nil || video?.viewsCount != nil {
|
||||
Image(systemName: "eye")
|
||||
@@ -194,7 +194,7 @@ struct VideoDetails: View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
TitleView()
|
||||
if video != nil, !video!.isLocal {
|
||||
ChannelView()
|
||||
ChannelView(detailsVisibility: $detailsVisibility)
|
||||
.layoutPriority(1)
|
||||
.padding(.bottom, 6)
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
||||
#endif
|
||||
}
|
||||
|
||||
var ratio: CGFloat? {
|
||||
var ratio: CGFloat? { // swiftlint:disable:this no_cgfloat
|
||||
fullScreen ? detailsHiddenInFullScreen ? nil : usedAspectRatio : usedAspectRatio
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
||||
guard !fullScreen else {
|
||||
if detailsHiddenInFullScreen {
|
||||
return geometry.size.height
|
||||
} else {
|
||||
return geometry.size.width / usedAspectRatio
|
||||
}
|
||||
|
||||
return geometry.size.width / usedAspectRatio
|
||||
}
|
||||
|
||||
return max(geometry.size.height - VideoPlayerView.defaultMinimumHeightLeft, 0)
|
||||
|
@@ -274,7 +274,11 @@ struct VideoPlayerView: View {
|
||||
)
|
||||
.onHover { hovering in
|
||||
hoveringPlayer = hovering
|
||||
hovering ? player.controls.show() : player.controls.hide()
|
||||
if hovering {
|
||||
player.controls.show()
|
||||
} else {
|
||||
player.controls.hide()
|
||||
}
|
||||
}
|
||||
.gesture(player.controls.presentingOverlays ? nil : playerDragGesture)
|
||||
#if os(macOS)
|
||||
@@ -290,9 +294,6 @@ struct VideoPlayerView: View {
|
||||
}
|
||||
})
|
||||
#endif
|
||||
|
||||
.background(Color.black)
|
||||
|
||||
if !detailsHiddenInFullScreen {
|
||||
VideoDetails(
|
||||
video: player.videoForDisplay,
|
||||
|
Reference in New Issue
Block a user