mirror of
https://github.com/yattee/yattee.git
synced 2025-08-05 02:04:07 +00:00
Home Settings
This commit is contained in:
@@ -9,19 +9,13 @@ struct BrowsingSettings: View {
|
||||
@Default(.accountPickerDisplaysAnonymousAccounts) private var accountPickerDisplaysAnonymousAccounts
|
||||
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
||||
#if os(iOS)
|
||||
@Default(.homeRecentDocumentsItems) private var homeRecentDocumentsItems
|
||||
@Default(.lockPortraitWhenBrowsing) private var lockPortraitWhenBrowsing
|
||||
@Default(.showDocuments) private var showDocuments
|
||||
#endif
|
||||
@Default(.thumbnailsQuality) private var thumbnailsQuality
|
||||
@Default(.channelOnThumbnail) private var channelOnThumbnail
|
||||
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
||||
@Default(.showHome) private var showHome
|
||||
@Default(.showFavoritesInHome) private var showFavoritesInHome
|
||||
@Default(.showQueueInHome) private var showQueueInHome
|
||||
@Default(.showOpenActionsInHome) private var showOpenActionsInHome
|
||||
@Default(.showOpenActionsToolbarItem) private var showOpenActionsToolbarItem
|
||||
@Default(.homeHistoryItems) private var homeHistoryItems
|
||||
@Default(.visibleSections) private var visibleSections
|
||||
@Default(.playerButtonSingleTapGesture) private var playerButtonSingleTapGesture
|
||||
@Default(.playerButtonDoubleTapGesture) private var playerButtonDoubleTapGesture
|
||||
@@ -32,12 +26,11 @@ struct BrowsingSettings: View {
|
||||
|
||||
@ObservedObject private var accounts = AccountsModel.shared
|
||||
|
||||
@State private var homeHistoryItemsText = ""
|
||||
#if os(iOS)
|
||||
@State private var homeRecentDocumentsItemsText = ""
|
||||
#endif
|
||||
#if os(macOS)
|
||||
@State private var presentingEditFavoritesSheet = false
|
||||
@State private var presentingHomeSettingsSheet = false
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
@@ -83,79 +76,32 @@ struct BrowsingSettings: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var homeSettings: some View {
|
||||
Section(header: SettingsHeader(text: "Home".localized())) {
|
||||
#if !os(tvOS)
|
||||
if !accounts.isEmpty {
|
||||
Toggle("Show Home", isOn: $showHome)
|
||||
}
|
||||
#endif
|
||||
Toggle("Show Open Videos quick actions", isOn: $showOpenActionsInHome)
|
||||
Toggle("Show Next in Queue", isOn: $showQueueInHome)
|
||||
|
||||
#if os(iOS)
|
||||
HStack {
|
||||
Text("Recent Documents")
|
||||
TextField("Recent Documents", text: $homeRecentDocumentsItemsText)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.labelsHidden()
|
||||
#if !os(macOS)
|
||||
.keyboardType(.numberPad)
|
||||
#endif
|
||||
.onAppear {
|
||||
homeRecentDocumentsItemsText = String(homeRecentDocumentsItems)
|
||||
}
|
||||
.onChange(of: homeRecentDocumentsItemsText) { newValue in
|
||||
homeRecentDocumentsItems = Int(newValue) ?? 3
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HStack {
|
||||
Text("Recent History")
|
||||
TextField("Recent History", text: $homeHistoryItemsText)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.labelsHidden()
|
||||
#if !os(macOS)
|
||||
.keyboardType(.numberPad)
|
||||
#endif
|
||||
.onAppear {
|
||||
homeHistoryItemsText = String(homeHistoryItems)
|
||||
@ViewBuilder private var homeSettings: some View {
|
||||
if !accounts.isEmpty {
|
||||
Section(header: SettingsHeader(text: "Home".localized())) {
|
||||
#if os(macOS)
|
||||
Button {
|
||||
presentingHomeSettingsSheet = true
|
||||
} label: {
|
||||
Text("Home Settings")
|
||||
}
|
||||
.onChange(of: homeHistoryItemsText) { newValue in
|
||||
homeHistoryItems = Int(newValue) ?? 10
|
||||
}
|
||||
}
|
||||
|
||||
if !accounts.isEmpty {
|
||||
Toggle("Show Favorites", isOn: $showFavoritesInHome)
|
||||
|
||||
Group {
|
||||
#if os(macOS)
|
||||
Button {
|
||||
presentingEditFavoritesSheet = true
|
||||
} label: {
|
||||
Text("Edit Favorites…")
|
||||
}
|
||||
.sheet(isPresented: $presentingEditFavoritesSheet) {
|
||||
VStack(alignment: .leading) {
|
||||
Button("Done") {
|
||||
presentingEditFavoritesSheet = false
|
||||
}
|
||||
.padding()
|
||||
.keyboardShortcut(.cancelAction)
|
||||
|
||||
EditFavorites()
|
||||
.sheet(isPresented: $presentingHomeSettingsSheet) {
|
||||
VStack(alignment: .leading) {
|
||||
Button("Done") {
|
||||
presentingHomeSettingsSheet = false
|
||||
}
|
||||
.frame(width: 500, height: 300)
|
||||
.padding()
|
||||
.keyboardShortcut(.cancelAction)
|
||||
|
||||
HomeSettings()
|
||||
}
|
||||
#else
|
||||
NavigationLink(destination: LazyView(EditFavorites())) {
|
||||
Text("Edit Favorites…")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.disabled(!showFavoritesInHome)
|
||||
.frame(width: 500, height: 800)
|
||||
}
|
||||
#else
|
||||
NavigationLink(destination: LazyView(HomeSettings())) {
|
||||
Text("Home Settings")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,119 +0,0 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct EditFavorites: View {
|
||||
private var playlistsModel = PlaylistsModel.shared
|
||||
private var model = FavoritesModel.shared
|
||||
|
||||
@Default(.favorites) private var favorites
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
#if os(tvOS)
|
||||
ScrollView {
|
||||
VStack {
|
||||
editor
|
||||
}
|
||||
}
|
||||
.frame(width: 1000)
|
||||
#else
|
||||
List {
|
||||
editor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.navigationTitle("Favorites")
|
||||
}
|
||||
|
||||
var editor: some View {
|
||||
Group {
|
||||
Section(header: Text("Favorites")) {
|
||||
if favorites.isEmpty {
|
||||
Text("Favorites is empty")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
ForEach(favorites) { item in
|
||||
HStack {
|
||||
Text(label(item))
|
||||
|
||||
Spacer()
|
||||
HStack(spacing: 30) {
|
||||
Button {
|
||||
model.moveUp(item)
|
||||
} label: {
|
||||
Label("Move Up", systemImage: "arrow.up")
|
||||
}
|
||||
|
||||
Button {
|
||||
model.moveDown(item)
|
||||
} label: {
|
||||
Label("Move Down", systemImage: "arrow.down")
|
||||
}
|
||||
|
||||
Button {
|
||||
model.remove(item)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.borderless)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.padding(.trailing, 40)
|
||||
#endif
|
||||
|
||||
#if os(tvOS)
|
||||
Divider()
|
||||
.padding(20)
|
||||
#endif
|
||||
|
||||
if !model.addableItems().isEmpty {
|
||||
Section(header: Text("Available")) {
|
||||
ForEach(model.addableItems()) { item in
|
||||
HStack {
|
||||
Text(label(item))
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
model.add(item)
|
||||
} label: {
|
||||
Label("Add to Favorites", systemImage: "heart")
|
||||
#if os(tvOS)
|
||||
.font(.system(size: 30))
|
||||
#endif
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.borderless)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.padding(.trailing, 40)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
|
||||
func label(_ item: FavoriteItem) -> String {
|
||||
switch item.section {
|
||||
case let .playlist(_, id):
|
||||
return playlistsModel.find(id: id)?.title ?? "Playlist".localized()
|
||||
default:
|
||||
return item.section.label.localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EditFavorites_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
EditFavorites()
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
302
Shared/Settings/HomeSettings.swift
Normal file
302
Shared/Settings/HomeSettings.swift
Normal file
@@ -0,0 +1,302 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct HomeSettings: View {
|
||||
private var model = FavoritesModel.shared
|
||||
|
||||
@Default(.favorites) private var favorites
|
||||
@Default(.showHome) private var showHome
|
||||
@Default(.showFavoritesInHome) private var showFavoritesInHome
|
||||
@Default(.showQueueInHome) private var showQueueInHome
|
||||
@Default(.showOpenActionsInHome) private var showOpenActionsInHome
|
||||
@Default(.showOpenActionsToolbarItem) private var showOpenActionsToolbarItem
|
||||
|
||||
@ObservedObject private var accounts = AccountsModel.shared
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
#if os(tvOS)
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
homeSettings
|
||||
.padding(.horizontal)
|
||||
editor
|
||||
}
|
||||
}
|
||||
.frame(width: 1000)
|
||||
#else
|
||||
List {
|
||||
homeSettings
|
||||
editor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.navigationTitle("Home Settings")
|
||||
}
|
||||
|
||||
var editor: some View {
|
||||
Group {
|
||||
Section(header: SettingsHeader(text: "Favorites")) {
|
||||
if favorites.isEmpty {
|
||||
Text("Favorites is empty")
|
||||
.padding(.vertical)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
ForEach(favorites) { item in
|
||||
FavoriteItemEditor(item: item)
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.padding(.trailing, 40)
|
||||
#endif
|
||||
|
||||
if !model.addableItems().isEmpty {
|
||||
Section(header: SettingsHeader(text: "Available")) {
|
||||
ForEach(model.addableItems()) { item in
|
||||
HStack {
|
||||
FavoriteItemLabel(item: item)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
model.add(item)
|
||||
} label: {
|
||||
Label("Add to Favorites", systemImage: "heart")
|
||||
#if os(tvOS)
|
||||
.font(.system(size: 30))
|
||||
#endif
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.borderless)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.padding(.trailing, 40)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
|
||||
private var homeSettings: some View {
|
||||
Section(header: SettingsHeader(text: "Home".localized())) {
|
||||
#if !os(tvOS)
|
||||
if !accounts.isEmpty {
|
||||
Toggle("Show Home", isOn: $showHome)
|
||||
}
|
||||
#endif
|
||||
Toggle("Show Open Videos quick actions", isOn: $showOpenActionsInHome)
|
||||
Toggle("Show Next in Queue", isOn: $showQueueInHome)
|
||||
|
||||
if !accounts.isEmpty {
|
||||
Toggle("Show Favorites", isOn: $showFavoritesInHome)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FavoriteItemLabel: View {
|
||||
var item: FavoriteItem
|
||||
var body: some View {
|
||||
Text(label)
|
||||
.fontWeight(.bold)
|
||||
}
|
||||
|
||||
var label: String {
|
||||
switch item.section {
|
||||
case let .playlist(_, id):
|
||||
return PlaylistsModel.shared.find(id: id)?.title ?? "Playlist".localized()
|
||||
default:
|
||||
return item.section.label.localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FavoriteItemEditor: View {
|
||||
var item: FavoriteItem
|
||||
|
||||
private var model: FavoritesModel { .shared }
|
||||
|
||||
@State private var listingStyle = WidgetListingStyle.horizontalCells
|
||||
@State private var limit = 3
|
||||
|
||||
@State private var presentingRemoveAlert = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
FavoriteItemLabel(item: item)
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 10) {
|
||||
FavoriteItemEditorButton {
|
||||
Label("Move Up", systemImage: "arrow.up")
|
||||
} onTapGesture: {
|
||||
model.moveUp(item)
|
||||
}
|
||||
|
||||
FavoriteItemEditorButton {
|
||||
Label("Move Down", systemImage: "arrow.down")
|
||||
} onTapGesture: {
|
||||
model.moveDown(item)
|
||||
}
|
||||
|
||||
FavoriteItemEditorButton(color: .init("AppRedColor")) {
|
||||
Label("Remove", systemImage: "trash")
|
||||
} onTapGesture: {
|
||||
presentingRemoveAlert = true
|
||||
}
|
||||
.alert(isPresented: $presentingRemoveAlert) {
|
||||
Alert(
|
||||
title: Text(
|
||||
String(
|
||||
format: "Are you sure you want to remove %@ from Favorites?".localized(),
|
||||
item.section.label.localized()
|
||||
)
|
||||
),
|
||||
message: Text("This cannot be reverted"),
|
||||
primaryButton: .destructive(Text("Remove")) {
|
||||
model.remove(item)
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listingStylePicker
|
||||
.padding(.vertical, 5)
|
||||
|
||||
limitInput
|
||||
|
||||
#if !os(iOS)
|
||||
Divider()
|
||||
#endif
|
||||
}
|
||||
.onAppear(perform: setupEditor)
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.borderless)
|
||||
#endif
|
||||
}
|
||||
|
||||
var listingStylePicker: some View {
|
||||
Picker("Listing Style", selection: $listingStyle) {
|
||||
Text("Cells").tag(WidgetListingStyle.horizontalCells)
|
||||
Text("List").tag(WidgetListingStyle.list)
|
||||
}
|
||||
.onChange(of: listingStyle) { newValue in
|
||||
model.setListingStyle(newValue, item)
|
||||
limit = min(limit, WidgetSettings.maxLimit(newValue))
|
||||
}
|
||||
.labelsHidden()
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
|
||||
var limitInput: some View {
|
||||
HStack {
|
||||
Text("Limit")
|
||||
Spacer()
|
||||
|
||||
#if !os(tvOS)
|
||||
limitMinusButton
|
||||
.disabled(limit == 1)
|
||||
#endif
|
||||
|
||||
#if os(tvOS)
|
||||
let textFieldWidth = 100.00
|
||||
#else
|
||||
let textFieldWidth = 30.00
|
||||
#endif
|
||||
|
||||
TextField("Limit", value: $limit, formatter: NumberFormatter())
|
||||
#if !os(macOS)
|
||||
.keyboardType(.numberPad)
|
||||
#endif
|
||||
.labelsHidden()
|
||||
.frame(width: textFieldWidth, alignment: .trailing)
|
||||
.multilineTextAlignment(.center)
|
||||
.onChange(of: limit) { newValue in
|
||||
let value = min(limit, WidgetSettings.maxLimit(listingStyle))
|
||||
if newValue <= 0 || newValue != value {
|
||||
limit = value
|
||||
} else {
|
||||
model.setLimit(value, item)
|
||||
}
|
||||
}
|
||||
#if !os(tvOS)
|
||||
limitPlusButton
|
||||
.disabled(limit == WidgetSettings.maxLimit(listingStyle))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
var limitMinusButton: some View {
|
||||
FavoriteItemEditorButton {
|
||||
Label("Minus", systemImage: "minus")
|
||||
} onTapGesture: {
|
||||
limit = max(1, limit - 1)
|
||||
}
|
||||
}
|
||||
|
||||
var limitPlusButton: some View {
|
||||
FavoriteItemEditorButton {
|
||||
Label("Plus", systemImage: "plus")
|
||||
} onTapGesture: {
|
||||
limit = max(1, limit + 1)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func setupEditor() {
|
||||
listingStyle = model.listingStyle(item)
|
||||
limit = model.limit(item)
|
||||
}
|
||||
}
|
||||
|
||||
struct FavoriteItemEditorButton<LabelView: View>: View {
|
||||
var color = Color.accentColor
|
||||
var label: LabelView
|
||||
var onTapGesture: () -> Void = {}
|
||||
|
||||
init(
|
||||
color: Color = .accentColor,
|
||||
@ViewBuilder label: () -> LabelView,
|
||||
onTapGesture: @escaping () -> Void = {}
|
||||
) {
|
||||
self.color = color
|
||||
self.label = label()
|
||||
self.onTapGesture = onTapGesture
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
#if os(tvOS)
|
||||
Button(action: onTapGesture) {
|
||||
label
|
||||
}
|
||||
#else
|
||||
label
|
||||
.imageScale(.medium)
|
||||
.labelStyle(.iconOnly)
|
||||
.padding(7)
|
||||
.frame(minWidth: 40, minHeight: 40)
|
||||
.foregroundColor(color)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(color))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture(perform: onTapGesture)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct HomeSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HomeSettings()
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user