mirror of
https://github.com/yattee/yattee.git
synced 2026-05-13 19:05:03 +00:00
Add channels sidebar to Subscriptions on iPad regular width
On iPad in regular horizontal size class, the Subscriptions view now shows a channels column next to the feed (mirroring macOS/tvOS) instead of the floating channel strip. iPhone and compact-width iPad keep the existing strip. - Renames MacSubscriptionsSidebarRow to SubscriptionsSidebarRow and shares it across macOS and iOS. - Uses a custom ScrollView-based sidebar on iPad to avoid iOS 26's sidebar background extension bleeding into the selection highlight. - Forces inline toolbar title on iPad regular so scrolling either column behaves consistently.
This commit is contained in:
77
Yattee/Views/Subscriptions/SubscriptionsSidebarRow.swift
Normal file
77
Yattee/Views/Subscriptions/SubscriptionsSidebarRow.swift
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// SubscriptionsSidebarRow.swift
|
||||
// Yattee
|
||||
//
|
||||
// Compact row used in the Subscriptions sidebar (macOS and iPad) for the
|
||||
// "All Channels" entry and each subscribed channel.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NukeUI
|
||||
|
||||
struct SubscriptionsSidebarRow: View {
|
||||
let name: String
|
||||
let avatarURL: URL?
|
||||
let serverURL: URL?
|
||||
let authHeader: String?
|
||||
let channelID: String?
|
||||
let isAllChannels: Bool
|
||||
var isSelected: Bool = false
|
||||
|
||||
private let avatarSize: CGFloat = 28
|
||||
|
||||
private var effectiveAvatarURL: URL? {
|
||||
guard let channelID else { return nil }
|
||||
return AvatarURLBuilder.avatarURL(
|
||||
channelID: channelID,
|
||||
directURL: avatarURL,
|
||||
serverURL: serverURL,
|
||||
size: Int(avatarSize * 2)
|
||||
)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 8) {
|
||||
avatar
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
|
||||
Text(name)
|
||||
.fontWeight(isSelected ? .semibold : .regular)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var avatar: some View {
|
||||
if isAllChannels {
|
||||
ZStack {
|
||||
Circle().fill(.quaternary)
|
||||
Image(systemName: "rectangle.stack.fill")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(avatarSize * 0.25)
|
||||
}
|
||||
} else {
|
||||
LazyImage(request: AvatarURLBuilder.imageRequest(url: effectiveAvatarURL, authHeader: authHeader)) { state in
|
||||
if let image = state.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
} else {
|
||||
Circle()
|
||||
.fill(.quaternary)
|
||||
.overlay {
|
||||
Text(String(name.prefix(1)))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user