yattee/Shared/Player/Video Details/CommentView.swift

253 lines
7.2 KiB
Swift
Raw Normal View History

2021-12-04 19:35:41 +00:00
import SDWebImageSwiftUI
import SwiftUI
struct CommentView: View {
let comment: Comment
@Binding var repliesID: Comment.ID?
2021-12-17 19:46:49 +00:00
@State private var subscribed = false
2021-12-04 19:35:41 +00:00
#if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif
2021-12-17 19:46:49 +00:00
@Environment(\.colorScheme) private var colorScheme
2021-12-04 19:35:41 +00:00
@Environment(\.navigationStyle) private var navigationStyle
@ObservedObject private var comments = CommentsModel.shared
2022-12-11 15:15:42 +00:00
var subscriptions = SubscribedChannelsModel.shared
2021-12-04 19:35:41 +00:00
var body: some View {
VStack(alignment: .leading) {
HStack(spacing: 10) {
2021-12-17 19:46:49 +00:00
HStack(spacing: 10) {
ZStack(alignment: .bottomTrailing) {
authorAvatar
if subscribed {
Image(systemName: "star.circle.fill")
#if os(tvOS)
.background(Color.background(scheme: colorScheme))
#else
.background(Color.background)
#endif
.clipShape(Circle())
.foregroundColor(.secondary)
}
}
.onAppear {
subscribed = subscriptions.isSubscribing(comment.channel.id)
}
2021-12-04 19:35:41 +00:00
2021-12-17 19:46:49 +00:00
authorAndTime
}
.contextMenu {
Button(action: openChannelAction) {
Label("\(comment.channel.name) Channel", systemImage: "rectangle.stack.fill.badge.person.crop")
}
}
2021-12-04 19:35:41 +00:00
2021-12-17 19:46:49 +00:00
Spacer()
2021-12-04 19:35:41 +00:00
2021-12-17 19:46:49 +00:00
Group {
#if os(iOS)
if horizontalSizeClass == .regular {
Group {
statusIcons
likes
2021-12-04 19:35:41 +00:00
}
} else {
2021-12-17 19:46:49 +00:00
VStack(alignment: .trailing, spacing: 8) {
likes
statusIcons
2021-12-04 19:35:41 +00:00
}
}
2021-12-17 19:46:49 +00:00
#else
2021-12-04 19:35:41 +00:00
statusIcons
likes
2021-12-17 19:46:49 +00:00
#endif
}
2021-12-04 19:35:41 +00:00
}
2021-12-17 19:46:49 +00:00
#if os(tvOS)
.font(.system(size: 25).bold())
#else
.font(.system(size: 15))
#endif
2021-12-04 19:35:41 +00:00
Group {
commentText
if comment.hasReplies {
HStack(spacing: repliesButtonStackSpacing) {
repliesButton
ProgressView()
2022-12-10 02:01:59 +00:00
.scaleEffect(Constants.progressViewScale, anchor: .center)
.opacity(repliesID == comment.id && !comments.repliesLoaded ? 1 : 0)
.frame(maxHeight: 0)
}
2021-12-04 19:35:41 +00:00
if comment.id == repliesID {
repliesList
}
}
}
}
#if os(tvOS)
.padding(.horizontal, 20)
#endif
2022-06-24 23:39:29 +00:00
.padding(.bottom, 10)
2021-12-04 19:35:41 +00:00
}
private var authorAvatar: some View {
2022-11-10 18:11:19 +00:00
WebImage(url: URL(string: comment.authorAvatarURL)!, options: [.lowPriority])
2021-12-04 19:35:41 +00:00
.resizable()
.placeholder {
Rectangle().fill(Color("PlaceholderColor"))
}
2021-12-24 19:21:11 +00:00
.retryOnAppear(true)
2021-12-04 19:35:41 +00:00
.indicator(.activity)
.mask(RoundedRectangle(cornerRadius: 60))
#if os(tvOS)
2021-12-17 19:46:49 +00:00
.frame(width: 80, height: 80, alignment: .leading)
2021-12-04 19:35:41 +00:00
.focusable()
2021-12-17 19:46:49 +00:00
#else
.frame(width: 45, height: 45, alignment: .leading)
2021-12-04 19:35:41 +00:00
#endif
}
private var authorAndTime: some View {
VStack(alignment: .leading) {
Text(comment.author)
2021-12-17 19:46:49 +00:00
#if os(tvOS)
.font(.system(size: 30).bold())
#else
.font(.system(size: 14).bold())
#endif
2021-12-04 19:35:41 +00:00
Text(comment.time)
2021-12-17 19:46:49 +00:00
.font(.caption2)
2021-12-04 19:35:41 +00:00
.foregroundColor(.secondary)
}
.lineLimit(1)
}
private var statusIcons: some View {
HStack(spacing: 15) {
if comment.pinned {
Image(systemName: "pin.fill")
}
if comment.hearted {
Image(systemName: "heart.fill")
}
}
2021-12-17 19:46:49 +00:00
#if !os(tvOS)
.font(.system(size: 12))
#endif
2021-12-04 19:35:41 +00:00
.foregroundColor(.secondary)
}
private var likes: some View {
Group {
if comment.likeCount > 0 {
HStack(spacing: 5) {
Image(systemName: "hand.thumbsup")
Text("\(comment.likeCount.formattedAsAbbreviation())")
}
2021-12-17 19:46:49 +00:00
#if !os(tvOS)
.font(.system(size: 12))
#endif
2021-12-04 19:35:41 +00:00
}
}
.foregroundColor(.secondary)
}
private var repliesButton: some View {
Button {
repliesID = repliesID == comment.id ? nil : comment.id
guard !repliesID.isNil, !comment.repliesPage.isNil else {
return
}
comments.loadReplies(page: comment.repliesPage!)
} label: {
HStack(spacing: 5) {
Image(systemName: repliesID == comment.id ? "arrow.turn.left.up" : "arrow.turn.right.down")
2021-12-04 19:35:41 +00:00
Text("Replies")
}
#if os(tvOS)
.padding(10)
#endif
}
.buttonStyle(.plain)
.padding(.vertical, 2)
2021-12-04 19:35:41 +00:00
#if os(tvOS)
.padding(.leading, 5)
#else
2021-12-17 19:46:49 +00:00
.font(.system(size: 13))
2021-12-04 19:35:41 +00:00
.foregroundColor(.secondary)
#endif
}
private var repliesButtonStackSpacing: Double {
#if os(tvOS)
24
#elseif os(iOS)
4
#else
2
#endif
}
2021-12-04 19:35:41 +00:00
private var repliesList: some View {
Group {
let last = comments.replies.last
ForEach(comments.replies) { comment in
2023-04-22 13:08:33 +00:00
Self(comment: comment, repliesID: $repliesID)
2021-12-04 19:35:41 +00:00
#if os(tvOS)
.focusable()
#endif
if comment != last {
Divider()
.padding(.vertical, 5)
}
}
}
.padding(.leading, 22)
2021-12-04 19:35:41 +00:00
}
private var commentText: some View {
2023-07-01 16:38:11 +00:00
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)
2021-12-04 19:35:41 +00:00
}
private func openChannelAction() {
NavigationModel.shared.openChannel(
2021-12-17 19:46:49 +00:00
comment.channel,
2022-06-30 08:05:32 +00:00
navigationStyle: navigationStyle
2021-12-17 19:46:49 +00:00
)
2021-12-04 19:35:41 +00:00
}
}
struct CommentView_Previews: PreviewProvider {
static var fixture: Comment {
Comment.fixture
}
static var previews: some View {
CommentView(comment: fixture, repliesID: .constant(fixture.id))
2021-12-17 19:46:49 +00:00
.padding(5)
}
}