From 3779b7ed1f86a61cbf3d3251b83a7674dfc2c9bd Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 7 May 2023 21:45:07 +0200 Subject: [PATCH] Add scrollbars in video details and button to scroll comments to top Added player settings to disable scroll to top button Fix #439 --- Shared/Defaults.swift | 4 ++ .../Player/Video Details/CommentsView.swift | 12 +----- .../Player/Video Details/VideoDetails.swift | 43 ++++++++++++++++--- Shared/Settings/PlayerSettings.swift | 14 ++++++ 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index c84afa25..297c22a7 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -136,6 +136,10 @@ extension Defaults.Keys { static let seekGestureSpeed = Key("seekGestureSpeed", default: 0.5) static let seekGestureSensitivity = Key("seekGestureSensitivity", default: 30.0) static let showKeywords = Key("showKeywords", default: false) + #if !os(tvOS) + static let showScrollToTopInComments = Key("showScrollToTopInComments", default: true) + #endif + #if os(iOS) static let expandVideoDescriptionDefault = Constants.isIPad #else diff --git a/Shared/Player/Video Details/CommentsView.swift b/Shared/Player/Video Details/CommentsView.swift index 19986443..04242bab 100644 --- a/Shared/Player/Video Details/CommentsView.swift +++ b/Shared/Player/Video Details/CommentsView.swift @@ -1,7 +1,6 @@ import SwiftUI struct CommentsView: View { - var embedInScrollView = false @State private var repliesID: Comment.ID? @ObservedObject private var comments = CommentsModel.shared @@ -16,7 +15,7 @@ struct CommentsView: View { PlaceholderProgressView() } else { let last = comments.all.last - let commentsStack = LazyVStack { + LazyVStack { ForEach(comments.all) { comment in CommentView(comment: comment, repliesID: $repliesID) .onAppear { @@ -25,15 +24,6 @@ struct CommentsView: View { .borderBottom(height: comment != last ? 0.5 : 0, color: Color("ControlsBorderColor")) } } - - if embedInScrollView { - ScrollView(.vertical, showsIndicators: false) { - commentsStack - Color.clear.frame(height: 50) - } - } else { - commentsStack - } } } .padding(.horizontal) diff --git a/Shared/Player/Video Details/VideoDetails.swift b/Shared/Player/Video Details/VideoDetails.swift index 0aea6079..fe1c836b 100644 --- a/Shared/Player/Video Details/VideoDetails.swift +++ b/Shared/Player/Video Details/VideoDetails.swift @@ -4,6 +4,8 @@ import SDWebImageSwiftUI import SwiftUI struct VideoDetails: View { + static let pageMenuID = "pageMenu" + struct TitleView: View { @ObservedObject private var model = PlayerModel.shared @State private var titleSize = CGSize.zero @@ -170,12 +172,15 @@ struct VideoDetails: View { @Environment(\.colorScheme) private var colorScheme @ObservedObject private var accounts = AccountsModel.shared - let comments = CommentsModel.shared + @ObservedObject private var comments = CommentsModel.shared @ObservedObject private var player = PlayerModel.shared @Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike @Default(.playerSidebar) private var playerSidebar @Default(.showInspector) private var showInspector + #if !os(tvOS) + @Default(.showScrollToTopInComments) private var showScrollToTopInComments + #endif @Default(.expandVideoDescription) private var expandVideoDescription var body: some View { @@ -211,7 +216,10 @@ struct VideoDetails: View { .animation(nil, value: player.currentItem) .frame(minWidth: 0, maxWidth: .infinity) - pageView + ScrollViewReader { proxy in + pageView + .overlay(scrollToTopButton(proxy), alignment: .bottomTrailing) + } #if os(iOS) .opacity(detailsVisibility ? 1 : 0) #endif @@ -266,9 +274,10 @@ struct VideoDetails: View { } var pageView: some View { - ScrollView(.vertical, showsIndicators: false) { + ScrollView(.vertical) { LazyVStack { pageMenu + .id(Self.pageMenuID) .padding(5) switch page { @@ -319,7 +328,6 @@ struct VideoDetails: View { .padding(.top, 20) } } - .padding(.bottom, 60) } } .onAppear { @@ -338,12 +346,13 @@ struct VideoDetails: View { .padding(.horizontal) case .comments: - CommentsView(embedInScrollView: false) + CommentsView() .onAppear { comments.loadIfNeeded() } } } + .padding(.bottom, 60) } #if os(iOS) .onAppear { @@ -365,6 +374,30 @@ struct VideoDetails: View { } } + @ViewBuilder func scrollToTopButton(_ proxy: ScrollViewProxy) -> some View { + #if !os(tvOS) + if showScrollToTopInComments, + page == .comments, + comments.loaded, + comments.all.count > 3 + { + Button { + withAnimation { + proxy.scrollTo(Self.pageMenuID) + } + } label: { + Label("Scroll to top", systemImage: "arrow.up") + .padding(8) + .foregroundColor(.white) + .background(Circle().opacity(0.8).foregroundColor(.accentColor)) + } + .padding() + .labelStyle(.iconOnly) + .buttonStyle(.plain) + } + #endif + } + var descriptionHeader: some View { HStack { Text("Description".localized()) diff --git a/Shared/Settings/PlayerSettings.swift b/Shared/Settings/PlayerSettings.swift index 869ad747..8da1fe78 100644 --- a/Shared/Settings/PlayerSettings.swift +++ b/Shared/Settings/PlayerSettings.swift @@ -8,6 +8,9 @@ struct PlayerSettings: View { @Default(.playerSidebar) private var playerSidebar @Default(.showKeywords) private var showKeywords + #if !os(tvOS) + @Default(.showScrollToTopInComments) private var showScrollToTopInComments + #endif @Default(.expandVideoDescription) private var expandVideoDescription @Default(.pauseOnHidingPlayer) private var pauseOnHidingPlayer #if os(iOS) @@ -86,6 +89,11 @@ struct PlayerSettings: View { if !accounts.isEmpty { keywordsToggle + + #if !os(tvOS) + showScrollToTopInCommentsToggle + #endif + #if !os(tvOS) expandVideoDescriptionToggle #endif @@ -160,6 +168,12 @@ struct PlayerSettings: View { .modifier(SettingsPickerModifier()) } + #if !os(tvOS) + private var showScrollToTopInCommentsToggle: some View { + Toggle("Show scroll to top button in comments", isOn: $showScrollToTopInComments) + } + #endif + private var keywordsToggle: some View { Toggle("Show keywords", isOn: $showKeywords) }