Fix ContentUnavailableView centering on Apple TV

On tvOS, ContentUnavailableView inside a Group doesn't expand to fill
available space — it sizes to content and aligns top-leading. Add
.frame(maxWidth: .infinity, maxHeight: .infinity) to all instances
so they center correctly in their parent containers.
This commit is contained in:
Arkadiusz Fal
2026-02-25 21:48:59 +01:00
parent f14ed4c2cb
commit 0fdac499bb
28 changed files with 62 additions and 6 deletions

View File

@@ -841,6 +841,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noDescription"), systemImage: "text.alignleft") Label(String(localized: "channel.noDescription"), systemImage: "text.alignleft")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
} }
@@ -869,6 +870,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noVideos"), systemImage: "play.rectangle") Label(String(localized: "channel.noVideos"), systemImage: "play.rectangle")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else if !filteredVideos.isEmpty { } else if !filteredVideos.isEmpty {
VideoListContent(listStyle: listStyle) { VideoListContent(listStyle: listStyle) {
@@ -965,6 +967,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noVideos"), systemImage: "play.rectangle") Label(String(localized: "channel.noVideos"), systemImage: "play.rectangle")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -1006,6 +1009,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noPlaylists"), systemImage: "list.bullet.rectangle") Label(String(localized: "channel.noPlaylists"), systemImage: "list.bullet.rectangle")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else if !playlists.isEmpty { } else if !playlists.isEmpty {
VideoListContent(listStyle: listStyle) { VideoListContent(listStyle: listStyle) {
@@ -1068,6 +1072,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noPlaylists"), systemImage: "list.bullet.rectangle") Label(String(localized: "channel.noPlaylists"), systemImage: "list.bullet.rectangle")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -1110,6 +1115,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noShorts"), systemImage: "bolt") Label(String(localized: "channel.noShorts"), systemImage: "bolt")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else if !filteredShorts.isEmpty { } else if !filteredShorts.isEmpty {
VideoListContent(listStyle: listStyle) { VideoListContent(listStyle: listStyle) {
@@ -1186,6 +1192,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noShorts"), systemImage: "bolt") Label(String(localized: "channel.noShorts"), systemImage: "bolt")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -1228,6 +1235,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noStreams"), systemImage: "video") Label(String(localized: "channel.noStreams"), systemImage: "video")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else if !filteredStreams.isEmpty { } else if !filteredStreams.isEmpty {
VideoListContent(listStyle: listStyle) { VideoListContent(listStyle: listStyle) {
@@ -1304,6 +1312,7 @@ struct ChannelView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "channel.noStreams"), systemImage: "video") Label(String(localized: "channel.noStreams"), systemImage: "video")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -1329,6 +1338,7 @@ struct ChannelView: View {
.padding(.vertical, 40) .padding(.vertical, 40)
} else if searchResults.items.isEmpty { } else if searchResults.items.isEmpty {
ContentUnavailableView.search(text: searchText) ContentUnavailableView.search(text: searchText)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else { } else {
switch layout { switch layout {
@@ -1519,6 +1529,7 @@ struct ChannelView: View {
} }
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Helpers // MARK: - Helpers

View File

@@ -180,12 +180,14 @@ struct BookmarksListView: View {
private var emptyView: some View { private var emptyView: some View {
if !searchText.isEmpty { if !searchText.isEmpty {
ContentUnavailableView.search(text: searchText) ContentUnavailableView.search(text: searchText)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "home.bookmarks.title"), systemImage: "bookmark") Label(String(localized: "home.bookmarks.title"), systemImage: "bookmark")
} description: { } description: {
Text(String(localized: "home.bookmarks.empty")) Text(String(localized: "home.bookmarks.empty"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -108,6 +108,7 @@ struct ContinueWatchingView: View {
} description: { } description: {
Text(String(localized: "home.continueWatching.empty")) Text(String(localized: "home.continueWatching.empty"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
private var listContent: some View { private var listContent: some View {

View File

@@ -206,12 +206,14 @@ struct HistoryListView: View {
private var emptyView: some View { private var emptyView: some View {
if !searchText.isEmpty { if !searchText.isEmpty {
ContentUnavailableView.search(text: searchText) ContentUnavailableView.search(text: searchText)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "home.history.title"), systemImage: "clock") Label(String(localized: "home.history.title"), systemImage: "clock")
} description: { } description: {
Text(String(localized: "home.history.empty")) Text(String(localized: "home.history.empty"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -76,6 +76,7 @@ struct PlaylistsListView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - List Content // MARK: - List Content

View File

@@ -590,6 +590,7 @@ struct InstanceBrowseView: View {
} description: { } description: {
Text(String(localized: "playlists.empty.description")) Text(String(localized: "playlists.empty.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Empty View // MARK: - Empty View
@@ -600,6 +601,7 @@ struct InstanceBrowseView: View {
} description: { } description: {
Text(String(localized: "instance.browse.noVideos")) Text(String(localized: "instance.browse.noVideos"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Error View // MARK: - Error View
@@ -615,6 +617,7 @@ struct InstanceBrowseView: View {
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Search Results // MARK: - Search Results
@@ -778,6 +781,7 @@ struct InstanceBrowseView: View {
} description: { } description: {
Text(String(localized: "search.hint.description")) Text(String(localized: "search.hint.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
@ViewBuilder @ViewBuilder
@@ -815,6 +819,7 @@ struct InstanceBrowseView: View {
} description: { } description: {
Text(String(localized: "search.noResults.description")) Text(String(localized: "search.noResults.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
private func searchErrorView(_ error: String) -> some View { private func searchErrorView(_ error: String) -> some View {
@@ -828,6 +833,7 @@ struct InstanceBrowseView: View {
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Data Loading // MARK: - Data Loading

View File

@@ -71,12 +71,14 @@ struct MediaBrowserView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if files.isEmpty { } else if files.isEmpty {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "mediaBrowser.emptyFolder"), systemImage: "folder") Label(String(localized: "mediaBrowser.emptyFolder"), systemImage: "folder")
} description: { } description: {
Text(String(localized: "mediaBrowser.emptyFolder.description")) Text(String(localized: "mediaBrowser.emptyFolder.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
fileList fileList
} }

View File

@@ -49,6 +49,7 @@ struct MediaSourcesView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
sourcesList sourcesList
} }

View File

@@ -136,6 +136,7 @@ struct UnifiedPlaylistDetailView: View {
systemImage: "list.bullet.rectangle", systemImage: "list.bullet.rectangle",
description: Text(String(localized: "playlist.notFound.description")) description: Text(String(localized: "playlist.notFound.description"))
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }
.navigationTitle(title.isEmpty ? String(localized: "playlist.title") : title) .navigationTitle(title.isEmpty ? String(localized: "playlist.title") : title)
@@ -507,6 +508,7 @@ struct UnifiedPlaylistDetailView: View {
} description: { } description: {
Text(String(localized: "playlist.empty.description")) Text(String(localized: "playlist.empty.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.top, 40) .padding(.top, 40)
} }
@@ -547,6 +549,7 @@ struct UnifiedPlaylistDetailView: View {
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Data Loading // MARK: - Data Loading

View File

@@ -657,6 +657,7 @@ struct SearchView: View {
} description: { } description: {
Text(String(localized: "search.noResults.description")) Text(String(localized: "search.noResults.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier("search.noResults") .accessibilityIdentifier("search.noResults")
} }
@@ -670,6 +671,7 @@ struct SearchView: View {
Task { await searchViewModel?.search(query: searchTextBinding.wrappedValue) } Task { await searchViewModel?.search(query: searchTextBinding.wrappedValue) }
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
/// Queue source for search results /// Queue source for search results

View File

@@ -47,6 +47,7 @@ struct ContributorsView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
contributorsList contributorsList
} }

View File

@@ -138,6 +138,7 @@ struct ImportPlaylistsView: View {
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier(AccessibilityID.errorMessage) .accessibilityIdentifier(AccessibilityID.errorMessage)
} }
@@ -147,6 +148,7 @@ struct ImportPlaylistsView: View {
systemImage: "list.bullet.rectangle", systemImage: "list.bullet.rectangle",
description: Text(String(localized: "import.playlists.emptyDescription")) description: Text(String(localized: "import.playlists.emptyDescription"))
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier(AccessibilityID.emptyState) .accessibilityIdentifier(AccessibilityID.emptyState)
} }

View File

@@ -109,6 +109,7 @@ struct ImportSubscriptionsView: View {
} }
.buttonStyle(.bordered) .buttonStyle(.bordered)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier(AccessibilityID.errorMessage) .accessibilityIdentifier(AccessibilityID.errorMessage)
} }
@@ -118,6 +119,7 @@ struct ImportSubscriptionsView: View {
systemImage: "person.2.slash", systemImage: "person.2.slash",
description: Text(String(localized: "import.subscriptions.emptyDescription")) description: Text(String(localized: "import.subscriptions.emptyDescription"))
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier(AccessibilityID.emptyState) .accessibilityIdentifier(AccessibilityID.emptyState)
} }

View File

@@ -38,6 +38,7 @@ struct LegacyDataImportView: View {
systemImage: "doc.questionmark", systemImage: "doc.questionmark",
description: Text(String(localized: "migration.noDataFoundDescription")) description: Text(String(localized: "migration.noDataFoundDescription"))
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
importContent importContent
} }

View File

@@ -109,6 +109,7 @@ struct LogViewerView: View {
Text(String(localized: "settings.advanced.logs.disabled")) Text(String(localized: "settings.advanced.logs.disabled"))
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
List(loggingService.filteredEntries) { entry in List(loggingService.filteredEntries) { entry in
LogEntryRow(entry: entry) LogEntryRow(entry: entry)

View File

@@ -81,6 +81,7 @@ struct NetworkShareDiscoverySheet: View {
service.startDiscovery() service.startDiscovery()
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} else { } else {
// Group shares by type // Group shares by type
@@ -124,6 +125,7 @@ struct NetworkShareDiscoverySheet: View {
} description: { } description: {
Text(String(localized: "discovery.unavailable.description")) Text(String(localized: "discovery.unavailable.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -182,6 +182,7 @@ struct ManageChannelNotificationsView: View {
} description: { } description: {
Text(errorMessage) Text(errorMessage)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if subscriptions.isEmpty { } else if subscriptions.isEmpty {
ContentUnavailableView { ContentUnavailableView {
Label( Label(
@@ -191,6 +192,7 @@ struct ManageChannelNotificationsView: View {
} description: { } description: {
Text(String(localized: "settings.notifications.noSubscriptions.description")) Text(String(localized: "settings.notifications.noSubscriptions.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
ForEach(subscriptions, id: \.channelID) { subscription in ForEach(subscriptions, id: \.channelID) { subscription in
ChannelNotificationToggle(subscription: subscription) ChannelNotificationToggle(subscription: subscription)

View File

@@ -117,12 +117,14 @@ struct PeerTubeInstancesExploreView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if displayedInstances.isEmpty { } else if displayedInstances.isEmpty {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "peertube.explore.noResults"), systemImage: "magnifyingglass") Label(String(localized: "peertube.explore.noResults"), systemImage: "magnifyingglass")
} description: { } description: {
Text(String(localized: "peertube.explore.noResults.description")) Text(String(localized: "peertube.explore.noResults.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
instancesList instancesList
} }

View File

@@ -72,6 +72,7 @@ struct ButtonConfigurationView: View {
String(localized: "settings.playerControls.buttonNotFound"), String(localized: "settings.playerControls.buttonNotFound"),
systemImage: "exclamationmark.triangle" systemImage: "exclamationmark.triangle"
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -283,6 +283,7 @@ struct MiniPlayerButtonConfigurationView: View {
String(localized: "settings.playerControls.buttonNotFound"), String(localized: "settings.playerControls.buttonNotFound"),
systemImage: "exclamationmark.triangle" systemImage: "exclamationmark.triangle"
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -41,6 +41,7 @@ struct PillButtonConfigurationView: View {
String(localized: "settings.playerControls.buttonNotFound"), String(localized: "settings.playerControls.buttonNotFound"),
systemImage: "exclamationmark.triangle" systemImage: "exclamationmark.triangle"
) )
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }

View File

@@ -90,6 +90,7 @@ struct SourcesListView: View {
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier("sources.view") .accessibilityIdentifier("sources.view")
} }

View File

@@ -30,6 +30,7 @@ struct TranslationContributorsView: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "settings.translators.empty"), systemImage: "globe") Label(String(localized: "settings.translators.empty"), systemImage: "globe")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
contributorsList contributorsList
} }

View File

@@ -91,6 +91,7 @@ struct ManageChannelsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.channels.empty")) Text(String(localized: "subscriptions.channels.empty"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
channelsView channelsView
} }
@@ -232,6 +233,7 @@ struct ManageChannelsView: View {
Group { Group {
if filteredChannels.isEmpty { if filteredChannels.isEmpty {
ContentUnavailableView.search(text: searchText) ContentUnavailableView.search(text: searchText)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
switch layout { switch layout {
case .list: case .list:
@@ -247,6 +249,7 @@ struct ManageChannelsView: View {
Group { Group {
if filteredChannels.isEmpty { if filteredChannels.isEmpty {
ContentUnavailableView.search(text: searchText) ContentUnavailableView.search(text: searchText)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
switch layout { switch layout {
case .list: case .list:

View File

@@ -423,7 +423,7 @@ struct SubscriptionsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.noVideosFromChannel.description")) Text(String(localized: "subscriptions.noVideosFromChannel.description"))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else { } else {
ForEach(Array(filteredVideos.enumerated()), id: \.element.id) { index, video in ForEach(Array(filteredVideos.enumerated()), id: \.element.id) { index, video in
@@ -596,7 +596,7 @@ struct SubscriptionsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.noVideosFromChannel.description")) Text(String(localized: "subscriptions.noVideosFromChannel.description"))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} else { } else {
VideoGridContent(columns: gridConfig.effectiveColumns) { VideoGridContent(columns: gridConfig.effectiveColumns) {
@@ -691,7 +691,7 @@ struct SubscriptionsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.empty.description")) Text(String(localized: "subscriptions.empty.description"))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -702,7 +702,7 @@ struct SubscriptionsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.yatteeServerRequired.description")) Text(String(localized: "subscriptions.yatteeServerRequired.description"))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -713,7 +713,7 @@ struct SubscriptionsView: View {
} description: { } description: {
Text(String(localized: "subscriptions.notAuthenticated.description")) Text(String(localized: "subscriptions.notAuthenticated.description"))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }
@@ -727,7 +727,7 @@ struct SubscriptionsView: View {
Task { await loadFeed(forceRefresh: true) } Task { await loadFeed(forceRefresh: true) }
} }
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.vertical, 40) .padding(.vertical, 40)
} }

View File

@@ -415,6 +415,7 @@ struct DownloadQualitySheet: View {
} description: { } description: {
Text(String(localized: "download.noStreams.description")) Text(String(localized: "download.noStreams.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(Array(videoStreams.enumerated()), id: \.element.url) { index, stream in ForEach(Array(videoStreams.enumerated()), id: \.element.url) { index, stream in
@@ -448,6 +449,7 @@ struct DownloadQualitySheet: View {
ContentUnavailableView { ContentUnavailableView {
Label(String(localized: "download.noAudio.title"), systemImage: "speaker.slash") Label(String(localized: "download.noAudio.title"), systemImage: "speaker.slash")
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
VStack(spacing: 0) { VStack(spacing: 0) {
ForEach(Array(audioStreams.enumerated()), id: \.element.url) { index, stream in ForEach(Array(audioStreams.enumerated()), id: \.element.url) { index, stream in

View File

@@ -74,6 +74,7 @@ struct PlaylistSelectorSheet: View {
} description: { } description: {
Text(String(localized: "playlist.empty.description")) Text(String(localized: "playlist.empty.description"))
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
} }
} }

View File

@@ -532,6 +532,7 @@ struct VideoInfoView: View {
} }
} }
} }
.frame(maxWidth: .infinity, maxHeight: .infinity)
} }
// MARK: - Header Section // MARK: - Header Section