mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Channels performance improvements
Add settings: Show channel avatars in channels lists Show channel avatars in videos lists Fix #508
This commit is contained in:
parent
37a96a01db
commit
3c9e04d243
@ -18,12 +18,14 @@ struct FeedCacheModel: CacheModel {
|
|||||||
)
|
)
|
||||||
|
|
||||||
func storeFeed(account: Account, videos: [Video]) {
|
func storeFeed(account: Account, videos: [Video]) {
|
||||||
let date = iso8601DateFormatter.string(from: Date())
|
DispatchQueue.global(qos: .background).async {
|
||||||
logger.info("caching feed \(account.feedCacheKey) -- \(date)")
|
let date = iso8601DateFormatter.string(from: Date())
|
||||||
let feedTimeObject: JSON = ["date": date]
|
logger.info("caching feed \(account.feedCacheKey) -- \(date)")
|
||||||
let videosObject: JSON = ["videos": videos.prefix(cacheLimit).map { $0.json.object }]
|
let feedTimeObject: JSON = ["date": date]
|
||||||
try? storage?.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey))
|
let videosObject: JSON = ["videos": videos.prefix(cacheLimit).map { $0.json.object }]
|
||||||
try? storage?.setObject(videosObject, forKey: account.feedCacheKey)
|
try? storage?.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey))
|
||||||
|
try? storage?.setObject(videosObject, forKey: account.feedCacheKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveFeed(account: Account) -> [Video] {
|
func retrieveFeed(account: Account) -> [Video] {
|
||||||
|
@ -85,7 +85,6 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
|
|||||||
self.error = nil
|
self.error = nil
|
||||||
if let channels: [Channel] = resource.typedContent() {
|
if let channels: [Channel] = resource.typedContent() {
|
||||||
self.channels = channels
|
self.channels = channels
|
||||||
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
|
||||||
self.storeChannels(account: account, channels: channels)
|
self.storeChannels(account: account, channels: channels)
|
||||||
FeedModel.shared.calculateUnwatchedFeed()
|
FeedModel.shared.calculateUnwatchedFeed()
|
||||||
onSuccess()
|
onSuccess()
|
||||||
@ -95,7 +94,6 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func loadCachedChannels(_ account: Account) {
|
func loadCachedChannels(_ account: Account) {
|
||||||
let cache = getChannels(account: account)
|
let cache = getChannels(account: account)
|
||||||
if !cache.isEmpty {
|
if !cache.isEmpty {
|
||||||
@ -106,16 +104,18 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func storeChannels(account: Account, channels: [Channel]) {
|
func storeChannels(account: Account, channels: [Channel]) {
|
||||||
let date = iso8601DateFormatter.string(from: Date())
|
DispatchQueue.global(qos: .background).async {
|
||||||
logger.info("caching channels \(channelsDateCacheKey(account)) -- \(date)")
|
let date = self.iso8601DateFormatter.string(from: Date())
|
||||||
|
self.logger.info("caching channels \(self.channelsDateCacheKey(account)) -- \(date)")
|
||||||
|
|
||||||
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
||||||
|
|
||||||
let dateObject: JSON = ["date": date]
|
let dateObject: JSON = ["date": date]
|
||||||
let channelsObject: JSON = ["channels": channels.map(\.json).map(\.object)]
|
let channelsObject: JSON = ["channels": channels.map(\.json).map(\.object)]
|
||||||
|
|
||||||
try? storage?.setObject(dateObject, forKey: channelsDateCacheKey(account))
|
try? self.storage?.setObject(dateObject, forKey: self.channelsDateCacheKey(account))
|
||||||
try? storage?.setObject(channelsObject, forKey: channelsCacheKey(account))
|
try? self.storage?.setObject(channelsObject, forKey: self.channelsCacheKey(account))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getChannels(account: Account) -> [Channel] {
|
func getChannels(account: Account) -> [Channel] {
|
||||||
|
@ -9,11 +9,13 @@ struct ChannelAvatarView: View {
|
|||||||
@ObservedObject private var accounts = AccountsModel.shared
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@ObservedObject private var subscribedChannels = SubscribedChannelsModel.shared
|
@ObservedObject private var subscribedChannels = SubscribedChannelsModel.shared
|
||||||
|
|
||||||
|
@State private var url: URL?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
Group {
|
Group {
|
||||||
Group {
|
Group {
|
||||||
if let url = channel?.thumbnailURLOrCached {
|
if let url {
|
||||||
ThumbnailView(url: url)
|
ThumbnailView(url: url)
|
||||||
} else {
|
} else {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -31,6 +33,7 @@ struct ChannelAvatarView: View {
|
|||||||
.font(.system(size: 20))
|
.font(.system(size: 20))
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
}
|
}
|
||||||
|
.onAppear(perform: updateURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
@ -54,6 +57,16 @@ struct ChannelAvatarView: View {
|
|||||||
}
|
}
|
||||||
.imageScale(.small)
|
.imageScale(.small)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateURL() {
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
|
if let url = channel?.thumbnailURLOrCached {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChannelAvatarView_Previews: PreviewProvider {
|
struct ChannelAvatarView_Previews: PreviewProvider {
|
||||||
|
@ -61,7 +61,8 @@ struct ChannelListItem: View {
|
|||||||
private var label: some View {
|
private var label: some View {
|
||||||
HStack(alignment: .top, spacing: 12) {
|
HStack(alignment: .top, spacing: 12) {
|
||||||
VStack {
|
VStack {
|
||||||
ChannelAvatarView(channel: channel)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
|
.id("channel-avatar-\(channel.id)")
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.frame(width: 90, height: 90)
|
.frame(width: 90, height: 90)
|
||||||
#else
|
#else
|
||||||
|
@ -205,6 +205,7 @@ struct ChannelVideosView: View {
|
|||||||
|
|
||||||
var thumbnail: some View {
|
var thumbnail: some View {
|
||||||
ChannelAvatarView(channel: store.item?.channel)
|
ChannelAvatarView(channel: store.item?.channel)
|
||||||
|
.id("channel-avatar-\(store.item?.channel?.id ?? "")")
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.frame(width: 80, height: 80, alignment: .trailing)
|
.frame(width: 80, height: 80, alignment: .trailing)
|
||||||
#else
|
#else
|
||||||
|
@ -148,6 +148,9 @@ extension Defaults.Keys {
|
|||||||
#endif
|
#endif
|
||||||
static let expandVideoDescription = Key<Bool>("expandVideoDescription", default: expandVideoDescriptionDefault)
|
static let expandVideoDescription = Key<Bool>("expandVideoDescription", default: expandVideoDescriptionDefault)
|
||||||
|
|
||||||
|
static let showChannelAvatarInChannelsLists = Key<Bool>("showChannelAvatarInChannelsLists", default: true)
|
||||||
|
static let showChannelAvatarInVideosListing = Key<Bool>("showChannelAvatarInVideosListing", default: true)
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
static let pauseOnHidingPlayerDefault = true
|
static let pauseOnHidingPlayerDefault = true
|
||||||
#else
|
#else
|
||||||
|
@ -50,6 +50,8 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
|||||||
var recents = RecentsModel.shared
|
var recents = RecentsModel.shared
|
||||||
@ObservedObject private var navigation = NavigationModel.shared
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
|
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
var recent: RecentItem
|
var recent: RecentItem
|
||||||
var systemImage: String?
|
var systemImage: String?
|
||||||
let destination: DestinationContent
|
let destination: DestinationContent
|
||||||
@ -71,9 +73,10 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
|||||||
HStack {
|
HStack {
|
||||||
if recent.type == .channel,
|
if recent.type == .channel,
|
||||||
let channel = recent.channel,
|
let channel = recent.channel,
|
||||||
channel.thumbnailURLOrCached != nil
|
showChannelAvatarInChannelsLists
|
||||||
{
|
{
|
||||||
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
|
.id("channel-avatar-\(channel.id)")
|
||||||
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
||||||
|
|
||||||
Text(channel.name)
|
Text(channel.name)
|
||||||
|
@ -8,6 +8,11 @@ struct AppSidebarSubscriptions: View {
|
|||||||
@ObservedObject private var subscriptions = SubscribedChannelsModel.shared
|
@ObservedObject private var subscriptions = SubscribedChannelsModel.shared
|
||||||
|
|
||||||
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
||||||
|
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
|
@State private var channelLinkActive = false
|
||||||
|
@State private var channelForLink: Channel?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section(header: Text("Subscriptions")) {
|
Section(header: Text("Subscriptions")) {
|
||||||
@ -16,9 +21,10 @@ struct AppSidebarSubscriptions: View {
|
|||||||
LazyView(ChannelVideosView(channel: channel))
|
LazyView(ChannelVideosView(channel: channel))
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
if channel.thumbnailURLOrCached != nil {
|
if showChannelAvatarInChannelsLists {
|
||||||
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
||||||
|
|
||||||
Text(channel.name)
|
Text(channel.name)
|
||||||
} else {
|
} else {
|
||||||
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
||||||
@ -26,13 +32,10 @@ struct AppSidebarSubscriptions: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
.lineLimit(1)
|
||||||
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
||||||
}
|
}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
if subscriptions.isSubscribing(channel.id) {
|
|
||||||
toggleWatchedButton(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button("Unsubscribe") {
|
Button("Unsubscribe") {
|
||||||
navigation.presentUnsubscribeAlert(channel, subscriptions: subscriptions)
|
navigation.presentUnsubscribeAlert(channel, subscriptions: subscriptions)
|
||||||
}
|
}
|
||||||
@ -41,31 +44,6 @@ struct AppSidebarSubscriptions: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func toggleWatchedButton(_ channel: Channel) -> some View {
|
|
||||||
if feed.canMarkChannelAsWatched(channel.id) {
|
|
||||||
markChannelAsWatchedButton(channel)
|
|
||||||
} else {
|
|
||||||
markChannelAsUnwatchedButton(channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func markChannelAsWatchedButton(_ channel: Channel) -> some View {
|
|
||||||
Button {
|
|
||||||
feed.markChannelAsWatched(channel.id)
|
|
||||||
} label: {
|
|
||||||
Label("Mark channel feed as watched", systemImage: "checkmark.circle.fill")
|
|
||||||
}
|
|
||||||
.disabled(!feed.canMarkAllFeedAsWatched)
|
|
||||||
}
|
|
||||||
|
|
||||||
func markChannelAsUnwatchedButton(_ channel: Channel) -> some View {
|
|
||||||
Button {
|
|
||||||
feed.markChannelAsUnwatched(channel.id)
|
|
||||||
} label: {
|
|
||||||
Label("Mark channel feed as unwatched", systemImage: "checkmark.circle")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppSidebarSubscriptions_Previews: PreviewProvider {
|
struct AppSidebarSubscriptions_Previews: PreviewProvider {
|
||||||
|
@ -25,6 +25,8 @@ struct BrowsingSettings: View {
|
|||||||
@Default(.playerButtonIsExpanded) private var playerButtonIsExpanded
|
@Default(.playerButtonIsExpanded) private var playerButtonIsExpanded
|
||||||
@Default(.playerBarMaxWidth) private var playerBarMaxWidth
|
@Default(.playerBarMaxWidth) private var playerBarMaxWidth
|
||||||
@Default(.expandChannelDescription) private var expandChannelDescription
|
@Default(.expandChannelDescription) private var expandChannelDescription
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
@ObservedObject private var accounts = AccountsModel.shared
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
@ -186,6 +188,9 @@ struct BrowsingSettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toggle("Keep channels with unwatched videos on top of subscriptions list", isOn: $keepChannelsWithUnwatchedFeedOnTop)
|
Toggle("Keep channels with unwatched videos on top of subscriptions list", isOn: $keepChannelsWithUnwatchedFeedOnTop)
|
||||||
|
|
||||||
|
Toggle("Show channel avatars in channels lists", isOn: $showChannelAvatarInChannelsLists)
|
||||||
|
Toggle("Show channel avatars in videos lists", isOn: $showChannelAvatarInVideosListing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ struct SettingsView: View {
|
|||||||
private var windowHeight: Double {
|
private var windowHeight: Double {
|
||||||
switch selection {
|
switch selection {
|
||||||
case .browsing:
|
case .browsing:
|
||||||
return 720
|
return 800
|
||||||
case .player:
|
case .player:
|
||||||
return 480
|
return 480
|
||||||
case .controls:
|
case .controls:
|
||||||
|
@ -12,6 +12,7 @@ struct ChannelsView: View {
|
|||||||
@Default(.showCacheStatus) private var showCacheStatus
|
@Default(.showCacheStatus) private var showCacheStatus
|
||||||
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
||||||
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
@State private var channelLinkActive = false
|
@State private var channelLinkActive = false
|
||||||
@State private var channelForLink: Channel?
|
@State private var channelForLink: Channel?
|
||||||
@ -21,10 +22,9 @@ struct ChannelsView: View {
|
|||||||
Section(header: header) {
|
Section(header: header) {
|
||||||
ForEach(channels) { channel in
|
ForEach(channels) { channel in
|
||||||
let label = HStack {
|
let label = HStack {
|
||||||
if let url = channel.thumbnailURLOrCached {
|
if showChannelAvatarInChannelsLists {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
.frame(width: 35, height: 35)
|
.frame(width: 35, height: 35)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 35))
|
|
||||||
} else {
|
} else {
|
||||||
Image(systemName: RecentsModel.symbolSystemImage(channel.name))
|
Image(systemName: RecentsModel.symbolSystemImage(channel.name))
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
|
@ -16,6 +16,7 @@ struct VideoBanner: View {
|
|||||||
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
||||||
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
||||||
@Default(.roundedThumbnails) private var roundedThumbnails
|
@Default(.roundedThumbnails) private var roundedThumbnails
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
@Environment(\.inChannelView) private var inChannelView
|
@Environment(\.inChannelView) private var inChannelView
|
||||||
@Environment(\.inNavigationView) private var inNavigationView
|
@Environment(\.inNavigationView) private var inNavigationView
|
||||||
@ -85,10 +86,9 @@ struct VideoBanner: View {
|
|||||||
if !inChannelView, !video.isLocal || video.localStreamIsRemoteURL {
|
if !inChannelView, !video.isLocal || video.localStreamIsRemoteURL {
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if let url = video.channel.thumbnailURLOrCached, video != .fixture {
|
if video != .fixture, showChannelAvatarInVideosListing {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channelLabel
|
channelLabel
|
||||||
|
@ -24,6 +24,7 @@ struct VideoCell: View {
|
|||||||
@Default(.watchedVideoStyle) private var watchedVideoStyle
|
@Default(.watchedVideoStyle) private var watchedVideoStyle
|
||||||
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
||||||
@Default(.watchedVideoPlayNowBehavior) private var watchedVideoPlayNowBehavior
|
@Default(.watchedVideoPlayNowBehavior) private var watchedVideoPlayNowBehavior
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
private var navigation: NavigationModel { .shared }
|
private var navigation: NavigationModel { .shared }
|
||||||
private var player: PlayerModel { .shared }
|
private var player: PlayerModel { .shared }
|
||||||
@ -161,17 +162,22 @@ struct VideoCell: View {
|
|||||||
|
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if !inChannelView,
|
if !inChannelView,
|
||||||
let url = video.channel.thumbnailURLOrCached,
|
showChannelAvatarInVideosListing,
|
||||||
video != .fixture
|
video != .fixture
|
||||||
{
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
ThumbnailView(url: url)
|
if showChannelAvatarInVideosListing {
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.clipShape(Circle())
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
|
} else {
|
||||||
|
channelLabel(badge: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !channelOnThumbnail, !inChannelView {
|
if !channelOnThumbnail,
|
||||||
|
!inChannelView
|
||||||
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
channelLabel(badge: false)
|
channelLabel(badge: false)
|
||||||
}
|
}
|
||||||
@ -264,12 +270,9 @@ struct VideoCell: View {
|
|||||||
if !channelOnThumbnail, !inChannelView {
|
if !channelOnThumbnail, !inChannelView {
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if let url = video.channel.thumbnailURLOrCached,
|
if video != .fixture, showChannelAvatarInVideosListing {
|
||||||
video != .fixture
|
ChannelAvatarView(channel: video.channel)
|
||||||
{
|
|
||||||
ThumbnailView(url: url)
|
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channelLabel(badge: false)
|
channelLabel(badge: false)
|
||||||
@ -295,9 +298,8 @@ struct VideoCell: View {
|
|||||||
video != .fixture
|
video != .fixture
|
||||||
{
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +167,7 @@ struct ControlsBar: View {
|
|||||||
channel: model.videoForDisplay?.channel,
|
channel: model.videoForDisplay?.channel,
|
||||||
video: model.videoForDisplay
|
video: model.videoForDisplay
|
||||||
)
|
)
|
||||||
|
.id("channel-avatar-\(model.videoForDisplay?.id ?? "")")
|
||||||
.frame(width: barHeight - 10, height: barHeight - 10)
|
.frame(width: barHeight - 10, height: barHeight - 10)
|
||||||
}
|
}
|
||||||
.contextMenu { contextMenu }
|
.contextMenu { contextMenu }
|
||||||
@ -176,12 +177,13 @@ struct ControlsBar: View {
|
|||||||
channel: model.videoForDisplay?.channel,
|
channel: model.videoForDisplay?.channel,
|
||||||
video: model.videoForDisplay
|
video: model.videoForDisplay
|
||||||
)
|
)
|
||||||
|
.id("channel-avatar-\(model.videoForDisplay?.id ?? "")")
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.highPriorityGesture(playerButtonDoubleTapGesture != .nothing ? doubleTapGesture : nil)
|
.highPriorityGesture(playerButtonDoubleTapGesture != .nothing ? doubleTapGesture : nil)
|
||||||
.gesture(playerButtonSingleTapGesture != .nothing ? singleTapGesture : nil)
|
.gesture(playerButtonSingleTapGesture != .nothing ? singleTapGesture : nil)
|
||||||
#endif
|
#endif
|
||||||
.frame(width: barHeight - 10, height: barHeight - 10)
|
.frame(width: barHeight - 10, height: barHeight - 10)
|
||||||
.contextMenu { contextMenu }
|
.contextMenu { contextMenu }
|
||||||
}
|
}
|
||||||
|
|
||||||
if expansionState == .full {
|
if expansionState == .full {
|
||||||
|
Loading…
Reference in New Issue
Block a user