mirror of
https://github.com/yattee/yattee.git
synced 2026-07-20 14:22:02 +00:00
Move Home shortcut style picker to its own page with live preview
Replace the inline Plain/Accent/Colorful picker in Home customization with a navigation row that opens a dedicated page. The new page keeps the style selector and renders a non-interactive preview of every shortcut type so the chosen style is visible before committing. - Add an optional styleOverride to HomeShortcutCardView so the preview can reflect the not-yet-saved selection. - On macOS, navigate via navigationDestination(isPresented:) instead of a List-embedded NavigationLink, which otherwise stays stuck in its selected state after popping back and can't be reopened.
This commit is contained in:
@@ -4214,6 +4214,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"home.settings.shortcuts.style.preview" : {
|
||||
"comment" : "Header for the shortcut style preview section",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preview"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"home.shortcuts.style.accent" : {
|
||||
"comment" : "Accent card style option",
|
||||
"localizations" : {
|
||||
|
||||
@@ -29,6 +29,13 @@ struct HomeSettingsView: View {
|
||||
// Edit mode for delete functionality
|
||||
@State private var isEditMode = false
|
||||
|
||||
#if os(macOS)
|
||||
// macOS: drive the style page programmatically. A List-embedded NavigationLink
|
||||
// gets stuck in the selected (blue) state after popping back and can't be
|
||||
// re-activated, so navigate via navigationDestination(isPresented:) instead.
|
||||
@State private var showingStyleSettings = false
|
||||
#endif
|
||||
|
||||
private var settingsManager: SettingsManager? { appEnvironment?.settingsManager }
|
||||
|
||||
var body: some View {
|
||||
@@ -46,6 +53,9 @@ struct HomeSettingsView: View {
|
||||
#endif
|
||||
#if os(macOS)
|
||||
.listStyle(.inset)
|
||||
.navigationDestination(isPresented: $showingStyleSettings) {
|
||||
HomeShortcutStyleView(style: $shortcutCardStyle)
|
||||
}
|
||||
#endif
|
||||
#if !os(tvOS)
|
||||
.navigationTitle(String(localized: "home.settings.title"))
|
||||
@@ -75,13 +85,35 @@ struct HomeSettingsView: View {
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
|
||||
// Card style picker (Plain / Accent / Colorful) — only for cards layout
|
||||
// Card style (Plain / Accent / Colorful) — navigates to a page with
|
||||
// a selector and a live preview. Only for cards layout.
|
||||
if shortcutLayout == .cards {
|
||||
Picker(String(localized: "home.settings.shortcuts.style"), selection: $shortcutCardStyle) {
|
||||
ForEach(HomeShortcutCardStyle.allCases, id: \.self) { style in
|
||||
Text(style.displayName).tag(style)
|
||||
#if os(macOS)
|
||||
Button {
|
||||
showingStyleSettings = true
|
||||
} label: {
|
||||
HStack(spacing: 8) {
|
||||
Label(String(localized: "home.settings.shortcuts.style"), systemImage: "paintpalette")
|
||||
Spacer()
|
||||
Text(shortcutCardStyle.displayName)
|
||||
.foregroundStyle(.secondary)
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.tertiary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
#else
|
||||
SettingsNavigationRow(
|
||||
"home.settings.shortcuts.style",
|
||||
systemImage: "paintpalette",
|
||||
trailing: { Text(shortcutCardStyle.displayName) }
|
||||
) {
|
||||
HomeShortcutStyleView(style: $shortcutCardStyle)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ struct HomeShortcutCardView<StatusIndicator: View>: View {
|
||||
var showsCount: Bool
|
||||
/// Fixed color used when the "colorful" card style is active.
|
||||
var colorfulColor: Color
|
||||
/// Explicit style override. When set, takes precedence over the global
|
||||
/// setting — used to render live previews of a not-yet-saved style.
|
||||
var styleOverride: HomeShortcutCardStyle?
|
||||
var statusIndicator: StatusIndicator?
|
||||
|
||||
init(
|
||||
@@ -36,6 +39,7 @@ struct HomeShortcutCardView<StatusIndicator: View>: View {
|
||||
subtitle: String,
|
||||
showsCount: Bool = true,
|
||||
colorfulColor: Color = .accentColor,
|
||||
styleOverride: HomeShortcutCardStyle? = nil,
|
||||
statusIndicator: StatusIndicator?
|
||||
) {
|
||||
self.icon = icon
|
||||
@@ -44,6 +48,7 @@ struct HomeShortcutCardView<StatusIndicator: View>: View {
|
||||
self.subtitle = subtitle
|
||||
self.showsCount = showsCount
|
||||
self.colorfulColor = colorfulColor
|
||||
self.styleOverride = styleOverride
|
||||
self.statusIndicator = statusIndicator
|
||||
}
|
||||
|
||||
@@ -53,7 +58,7 @@ struct HomeShortcutCardView<StatusIndicator: View>: View {
|
||||
#if os(tvOS)
|
||||
return .plain
|
||||
#else
|
||||
return appEnvironment?.settingsManager.homeShortcutCardStyle ?? .plain
|
||||
return styleOverride ?? (appEnvironment?.settingsManager.homeShortcutCardStyle ?? .plain)
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -296,7 +301,8 @@ extension HomeShortcutCardView where StatusIndicator == EmptyView {
|
||||
count: Int,
|
||||
subtitle: String,
|
||||
showsCount: Bool = true,
|
||||
colorfulColor: Color = .accentColor
|
||||
colorfulColor: Color = .accentColor,
|
||||
styleOverride: HomeShortcutCardStyle? = nil
|
||||
) {
|
||||
self.icon = icon
|
||||
self.title = title
|
||||
@@ -304,6 +310,7 @@ extension HomeShortcutCardView where StatusIndicator == EmptyView {
|
||||
self.subtitle = subtitle
|
||||
self.showsCount = showsCount
|
||||
self.colorfulColor = colorfulColor
|
||||
self.styleOverride = styleOverride
|
||||
self.statusIndicator = nil
|
||||
}
|
||||
}
|
||||
|
||||
96
Yattee/Views/Home/HomeShortcutStyleView.swift
Normal file
96
Yattee/Views/Home/HomeShortcutStyleView.swift
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// HomeShortcutStyleView.swift
|
||||
// Yattee
|
||||
//
|
||||
// Dedicated page for choosing the Home shortcut card style, with a live
|
||||
// non-interactive preview of every shortcut type in the selected style.
|
||||
//
|
||||
|
||||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
struct HomeShortcutStyleView: View {
|
||||
@Binding var style: HomeShortcutCardStyle
|
||||
|
||||
private let previewColumns = [GridItem(.adaptive(minimum: 150), spacing: 16)]
|
||||
|
||||
/// All static shortcut types, previewed regardless of the user's current
|
||||
/// Home configuration so every style variation is visible.
|
||||
private let previewItems = HomeShortcutItem.defaultOrder
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section {
|
||||
Picker(String(localized: "home.settings.shortcuts.style"), selection: $style) {
|
||||
ForEach(HomeShortcutCardStyle.allCases, id: \.self) { style in
|
||||
Text(style.displayName).tag(style)
|
||||
}
|
||||
}
|
||||
#if os(iOS)
|
||||
.pickerStyle(.segmented)
|
||||
#endif
|
||||
}
|
||||
|
||||
Section {
|
||||
LazyVGrid(columns: previewColumns, spacing: 16) {
|
||||
ForEach(previewItems) { item in
|
||||
HomeShortcutCardView(
|
||||
icon: item.icon,
|
||||
title: item.localizedTitle,
|
||||
count: sampleCount(for: item),
|
||||
subtitle: "",
|
||||
showsCount: showsCount(for: item),
|
||||
colorfulColor: item.cardColor,
|
||||
styleOverride: style
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
.allowsHitTesting(false)
|
||||
} header: {
|
||||
Text(String(localized: "home.settings.shortcuts.style.preview"))
|
||||
}
|
||||
}
|
||||
#if os(macOS)
|
||||
.listStyle(.inset)
|
||||
#endif
|
||||
.navigationTitle(String(localized: "home.settings.shortcuts.style"))
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Shortcuts without a meaningful count hide it in the filled layout,
|
||||
/// mirroring `HomeView`'s real card configuration.
|
||||
private func showsCount(for item: HomeShortcutItem) -> Bool {
|
||||
switch item {
|
||||
case .openURL, .remoteControl, .subscriptions:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/// Representative count so the accent/colorful (Reminders-style) layout
|
||||
/// looks realistic in the preview.
|
||||
private func sampleCount(for item: HomeShortcutItem) -> Int {
|
||||
switch item {
|
||||
case .playlists: return 8
|
||||
case .bookmarks: return 12
|
||||
case .continueWatching: return 3
|
||||
case .history: return 42
|
||||
case .downloads: return 5
|
||||
case .channels: return 24
|
||||
case .mediaSources: return 2
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
HomeShortcutStyleView(style: .constant(.colorful))
|
||||
.appEnvironment(.preview)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user