mirror of
https://github.com/yattee/yattee.git
synced 2026-05-12 18:35:05 +00:00
Polish Search view layout on tvOS
- Disable scroll clipping so focused source/channel/playlist cards show full halo - Remove rounded clip on source picker row that cut the Menu focus effect - Replace tappable recents header Button with a plain label on tvOS - Add vertical spacing between recent search items - Widen recent channel and playlist cards and reserve space for two-line titles - Increase horizontal spacing between cards so focus halos don't collide
This commit is contained in:
@@ -22,7 +22,13 @@ struct ChannelCardGridView: View {
|
||||
private var subscriberFont: Font { isCompact ? .caption2 : .caption }
|
||||
|
||||
/// Minimum height for channel name to reserve space for 2 lines
|
||||
private var titleMinHeight: CGFloat { isCompact ? 32 : 40 }
|
||||
private var titleMinHeight: CGFloat {
|
||||
#if os(tvOS)
|
||||
isCompact ? 56 : 80
|
||||
#else
|
||||
isCompact ? 32 : 40
|
||||
#endif
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: isCompact ? 8 : 12) {
|
||||
@@ -46,7 +52,9 @@ struct ChannelCardGridView: View {
|
||||
.fontWeight(.medium)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(minHeight: titleMinHeight, alignment: .top)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: titleMinHeight, alignment: .top)
|
||||
|
||||
// Subscriber count row - reserve space even when nil
|
||||
HStack(spacing: 4) {
|
||||
|
||||
@@ -17,6 +17,14 @@ struct PlaylistCardView: View {
|
||||
|
||||
private var titleFont: Font { isCompact ? .caption : .subheadline }
|
||||
private var authorFont: Font { isCompact ? .caption2 : .caption }
|
||||
|
||||
private var metadataHeight: CGFloat {
|
||||
#if os(tvOS)
|
||||
isCompact ? 90 : 110
|
||||
#else
|
||||
isCompact ? 50 : 58
|
||||
#endif
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: isCompact ? 4 : 8) {
|
||||
@@ -61,15 +69,17 @@ struct PlaylistCardView: View {
|
||||
.fontWeight(.medium)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.leading)
|
||||
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Text(playlist.authorName)
|
||||
.font(authorFont)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
|
||||
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
.frame(height: isCompact ? 50 : 58)
|
||||
.frame(height: metadataHeight)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
@@ -362,6 +362,22 @@ struct SearchView: View {
|
||||
|
||||
// MARK: - Views
|
||||
|
||||
private var recentItemsSpacing: CGFloat {
|
||||
#if os(tvOS)
|
||||
16
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
}
|
||||
|
||||
private var horizontalCardSpacing: CGFloat {
|
||||
#if os(tvOS)
|
||||
48
|
||||
#else
|
||||
16
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Instance picker for selecting search source when multiple instances are available
|
||||
@ViewBuilder
|
||||
private var instancePickerView: some View {
|
||||
@@ -393,7 +409,9 @@ struct SearchView: View {
|
||||
}
|
||||
.padding(listStyle == .inset ? 4 : 0)
|
||||
.background(listStyle == .inset ? ListBackgroundStyle.card.color : .clear)
|
||||
#if !os(tvOS)
|
||||
.clipShape(.rect(cornerRadius: 10))
|
||||
#endif
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
@@ -580,6 +598,16 @@ struct SearchView: View {
|
||||
if !searchHistory.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
// Header - tappable to expand/collapse when more than 5 items
|
||||
#if os(tvOS)
|
||||
HStack {
|
||||
Text(String(localized: "search.recentSearches.title"))
|
||||
.font(.headline)
|
||||
.foregroundStyle(.primary)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 8)
|
||||
#else
|
||||
Button {
|
||||
if hasMoreSearchHistory {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
@@ -604,9 +632,10 @@ struct SearchView: View {
|
||||
.disabled(!hasMoreSearchHistory)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 8)
|
||||
#endif
|
||||
|
||||
// Items
|
||||
VStack(spacing: 0) {
|
||||
VStack(spacing: recentItemsSpacing) {
|
||||
ForEach(displayedSearchHistory) { history in
|
||||
Button {
|
||||
executeSearch(history.query)
|
||||
@@ -674,7 +703,7 @@ struct SearchView: View {
|
||||
|
||||
// Horizontal scroll
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack(spacing: 16) {
|
||||
LazyHStack(spacing: horizontalCardSpacing) {
|
||||
ForEach(recentChannels) { recentChannel in
|
||||
NavigationLink(
|
||||
value: NavigationDestination.channel(
|
||||
@@ -689,7 +718,11 @@ struct SearchView: View {
|
||||
channel: channelFromRecent(recentChannel),
|
||||
isCompact: false
|
||||
)
|
||||
#if os(tvOS)
|
||||
.frame(width: 240)
|
||||
#else
|
||||
.frame(width: 160)
|
||||
#endif
|
||||
}
|
||||
.zoomTransitionSource(id: recentChannel.channelID)
|
||||
.buttonStyle(.plain)
|
||||
@@ -704,6 +737,9 @@ struct SearchView: View {
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
#if os(tvOS)
|
||||
.scrollClipDisabled()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,14 +756,18 @@ struct SearchView: View {
|
||||
|
||||
// Horizontal scroll
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack(spacing: 16) {
|
||||
LazyHStack(spacing: horizontalCardSpacing) {
|
||||
ForEach(recentPlaylists) { recentPlaylist in
|
||||
NavigationLink(value: NavigationDestination.playlist(.remote(playlistIDFromRecent(recentPlaylist), instance: nil, title: recentPlaylist.title))) {
|
||||
PlaylistCardView(
|
||||
playlist: playlistFromRecent(recentPlaylist),
|
||||
isCompact: false
|
||||
)
|
||||
#if os(tvOS)
|
||||
.frame(width: 320)
|
||||
#else
|
||||
.frame(width: 200)
|
||||
#endif
|
||||
}
|
||||
.zoomTransitionSource(id: playlistIDFromRecent(recentPlaylist))
|
||||
.buttonStyle(.plain)
|
||||
@@ -742,6 +782,9 @@ struct SearchView: View {
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
#if os(tvOS)
|
||||
.scrollClipDisabled()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,6 +806,9 @@ struct SearchView: View {
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
#if os(tvOS)
|
||||
.scrollClipDisabled()
|
||||
#endif
|
||||
.background(listStyle == .inset ? ListBackgroundStyle.grouped.color : ListBackgroundStyle.plain.color)
|
||||
.accessibilityLabel("search.recents")
|
||||
.confirmationDialog(
|
||||
|
||||
Reference in New Issue
Block a user