More uniform comments UI

This commit is contained in:
Arkadiusz Fal 2021-12-17 20:46:49 +01:00
parent 008cd1553d
commit 923f0c0356
4 changed files with 117 additions and 67 deletions

View File

@ -8,7 +8,8 @@ final class CommentsModel: ObservableObject {
@Published var nextPage: String? @Published var nextPage: String?
@Published var firstPage = true @Published var firstPage = true
@Published var loaded = true @Published var loading = false
@Published var loaded = false
@Published var disabled = false @Published var disabled = false
@Published var replies = [Comment]() @Published var replies = [Comment]()
@ -18,16 +19,16 @@ final class CommentsModel: ObservableObject {
var accounts: AccountsModel! var accounts: AccountsModel!
var player: PlayerModel! var player: PlayerModel!
var instance: Instance? { static var instance: Instance? {
InstancesModel.find(Defaults[.commentsInstanceID]) InstancesModel.find(Defaults[.commentsInstanceID])
} }
var api: VideosAPI? { var api: VideosAPI? {
instance.isNil ? nil : PipedAPI(account: instance!.anonymousAccount) Self.instance.isNil ? nil : PipedAPI(account: Self.instance!.anonymousAccount)
} }
static var enabled: Bool { static var enabled: Bool {
!Defaults[.commentsInstanceID].isNil && !Defaults[.commentsInstanceID]!.isEmpty !instance.isNil
} }
#if !os(tvOS) #if !os(tvOS)
@ -41,13 +42,15 @@ final class CommentsModel: ObservableObject {
} }
func load(page: String? = nil) { func load(page: String? = nil) {
guard Self.enabled else { guard Self.enabled, !loading else {
return return
} }
reset() reset()
guard !instance.isNil, loading = true
guard !Self.instance.isNil,
!(player?.currentVideo.isNil ?? true) !(player?.currentVideo.isNil ?? true)
else { else {
return return
@ -65,6 +68,7 @@ final class CommentsModel: ObservableObject {
} }
} }
.onCompletion { [weak self] _ in .onCompletion { [weak self] _ in
self?.loading = false
self?.loaded = true self?.loaded = true
} }
} }
@ -91,9 +95,10 @@ final class CommentsModel: ObservableObject {
.onSuccess { [weak self] response in .onSuccess { [weak self] response in
if let page: CommentsPage = response.typedContent() { if let page: CommentsPage = response.typedContent() {
self?.replies = page.comments self?.replies = page.comments
self?.repliesLoaded = true
} }
} }
.onCompletion { [weak self] _ in .onFailure { [weak self] _ in
self?.repliesLoaded = true self?.repliesLoaded = true
} }
} }
@ -104,6 +109,7 @@ final class CommentsModel: ObservableObject {
firstPage = true firstPage = true
nextPage = nil nextPage = nil
loaded = false loaded = false
loading = false
replies = [] replies = []
repliesLoaded = false repliesLoaded = false
} }

View File

@ -1,65 +1,81 @@
import SDWebImageSwiftUI import SDWebImageSwiftUI
import SwiftUI import SwiftUI
struct CommentView: View { struct CommentView: View {
let comment: Comment let comment: Comment
@Binding var repliesID: Comment.ID? @Binding var repliesID: Comment.ID?
@State private var subscribed = false
#if os(iOS) #if os(iOS)
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
#endif #endif
@Environment(\.colorScheme) private var colorScheme
@Environment(\.navigationStyle) private var navigationStyle @Environment(\.navigationStyle) private var navigationStyle
@EnvironmentObject<CommentsModel> private var comments @EnvironmentObject<CommentsModel> private var comments
@EnvironmentObject<NavigationModel> private var navigation @EnvironmentObject<NavigationModel> private var navigation
@EnvironmentObject<PlayerModel> private var player @EnvironmentObject<PlayerModel> private var player
@EnvironmentObject<RecentsModel> private var recents @EnvironmentObject<RecentsModel> private var recents
@EnvironmentObject<SubscriptionsModel> private var subscriptions
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
HStack(alignment: .center, spacing: 10) { HStack(alignment: .center, spacing: 10) {
HStack(spacing: 10) {
ZStack(alignment: .bottomTrailing) {
authorAvatar authorAvatar
#if os(iOS) if subscribed {
Group { Image(systemName: "star.circle.fill")
if horizontalSizeClass == .regular { #if os(tvOS)
HStack(spacing: 20) { .background(Color.background(scheme: colorScheme))
#else
.background(Color.background)
#endif
.clipShape(Circle())
.foregroundColor(.secondary)
}
}
.onAppear {
subscribed = subscriptions.isSubscribing(comment.channel.id)
}
authorAndTime authorAndTime
}
.contextMenu {
Button(action: openChannelAction) {
Label("\(comment.channel.name) Channel", systemImage: "rectangle.stack.fill.badge.person.crop")
}
}
Spacer() Spacer()
Group {
#if os(iOS)
if horizontalSizeClass == .regular {
Group { Group {
statusIcons statusIcons
likes likes
} }
}
} else { } else {
HStack(alignment: .center, spacing: 20) {
authorAndTime
Spacer()
VStack(alignment: .trailing, spacing: 8) { VStack(alignment: .trailing, spacing: 8) {
likes likes
statusIcons statusIcons
} }
} }
}
}
.font(.system(size: 15))
#else #else
HStack(spacing: 20) {
authorAndTime
Spacer()
statusIcons statusIcons
likes likes
}
#endif #endif
} }
}
#if os(tvOS)
.font(.system(size: 25).bold())
#else
.font(.system(size: 15))
#endif
Group { Group {
commentText commentText
@ -94,23 +110,25 @@ struct CommentView: View {
.retryOnAppear(false) .retryOnAppear(false)
.indicator(.activity) .indicator(.activity)
.mask(RoundedRectangle(cornerRadius: 60)) .mask(RoundedRectangle(cornerRadius: 60))
.frame(width: 45, height: 45, alignment: .leading)
.contextMenu {
Button(action: openChannelAction) {
Label("\(comment.channel.name) Channel", systemImage: "rectangle.stack.fill.badge.person.crop")
}
}
#if os(tvOS) #if os(tvOS)
.frame(width: 80, height: 80, alignment: .leading)
.focusable() .focusable()
#else
.frame(width: 45, height: 45, alignment: .leading)
#endif #endif
} }
private var authorAndTime: some View { private var authorAndTime: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text(comment.author) Text(comment.author)
.fontWeight(.bold) #if os(tvOS)
.font(.system(size: 30).bold())
#else
.font(.system(size: 14).bold())
#endif
Text(comment.time) Text(comment.time)
.font(.caption2)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
.lineLimit(1) .lineLimit(1)
@ -125,6 +143,9 @@ struct CommentView: View {
Image(systemName: "heart.fill") Image(systemName: "heart.fill")
} }
} }
#if !os(tvOS)
.font(.system(size: 12))
#endif
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
@ -135,6 +156,9 @@ struct CommentView: View {
Image(systemName: "hand.thumbsup") Image(systemName: "hand.thumbsup")
Text("\(comment.likeCount.formattedAsAbbreviation())") Text("\(comment.likeCount.formattedAsAbbreviation())")
} }
#if !os(tvOS)
.font(.system(size: 12))
#endif
} }
} }
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -163,6 +187,7 @@ struct CommentView: View {
#if os(tvOS) #if os(tvOS)
.padding(.leading, 5) .padding(.leading, 5)
#else #else
.font(.system(size: 13))
.foregroundColor(.secondary) .foregroundColor(.secondary)
#endif #endif
} }
@ -181,7 +206,7 @@ struct CommentView: View {
#if os(macOS) #if os(macOS)
0.4 0.4
#else #else
0.8 0.6
#endif #endif
} }
@ -226,17 +251,13 @@ struct CommentView: View {
} }
private func openChannelAction() { private func openChannelAction() {
player.presentingPlayer = false NavigationModel.openChannel(
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { comment.channel,
let recent = RecentItem(from: comment.channel) player: player,
recents.add(recent) recents: recents,
navigation.presentingChannel = true navigation: navigation,
navigationStyle: navigationStyle
if navigationStyle == .sidebar { )
navigation.sidebarSectionChanged.toggle()
navigation.tabSelection = .recentlyOpened(recent.tag)
}
}
} }
} }
@ -247,5 +268,7 @@ struct CommentView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
CommentView(comment: fixture, repliesID: .constant(fixture.id)) CommentView(comment: fixture, repliesID: .constant(fixture.id))
.environmentObject(SubscriptionsModel())
.padding(5)
} }
} }

View File

@ -16,6 +16,9 @@ struct CommentsView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
} else if !comments.loaded { } else if !comments.loaded {
progressView progressView
.onAppear {
comments.load()
}
} else { } else {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
@ -48,6 +51,7 @@ struct CommentsView: View {
} }
} }
} }
.font(.system(size: 13))
.buttonStyle(.plain) .buttonStyle(.plain)
.padding(.vertical, 8) .padding(.vertical, 8)
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -56,11 +60,6 @@ struct CommentsView: View {
} }
} }
.padding(.horizontal) .padding(.horizontal)
.onAppear {
if !comments.loaded {
comments.load()
}
}
} }
private var progressView: some View { private var progressView: some View {

View File

@ -117,6 +117,14 @@ struct NowPlayingView: View {
} }
if sections.contains(.comments) { if sections.contains(.comments) {
if !comments.loaded {
VStack(alignment: .center) {
progressView
.onAppear {
comments.load()
}
}
} else {
Section { Section {
ForEach(comments.all) { comment in ForEach(comments.all) { comment in
CommentView(comment: comment, repliesID: $repliesID) CommentView(comment: comment, repliesID: $repliesID)
@ -124,6 +132,7 @@ struct NowPlayingView: View {
} }
} }
} }
}
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
.padding(.vertical, 20) .padding(.vertical, 20)
} }
@ -137,6 +146,19 @@ struct NowPlayingView: View {
.font((inInfoViewController ? Font.system(size: 40) : .title3).bold()) .font((inInfoViewController ? Font.system(size: 40) : .title3).bold())
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
private var progressView: some View {
VStack {
Spacer()
HStack {
Spacer()
ProgressView()
Spacer()
}
Spacer()
}
}
} }
struct NowPlayingView_Previews: PreviewProvider { struct NowPlayingView_Previews: PreviewProvider {