mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Redesigned settings (fixes #47)
This commit is contained in:
parent
520d69f37a
commit
3baa7a6893
@ -15,10 +15,10 @@ struct AccountsNavigationLink: View {
|
||||
}
|
||||
|
||||
private func removeInstanceButton(_ instance: Instance) -> some View {
|
||||
if #available(iOS 15.0, *) {
|
||||
return Button("Remove", role: .destructive) { removeAction(instance) }
|
||||
} else {
|
||||
return Button("Remove") { removeAction(instance) }
|
||||
Button {
|
||||
removeAction(instance)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
|
||||
|
124
Shared/Settings/Help.swift
Normal file
124
Shared/Settings/Help.swift
Normal file
@ -0,0 +1,124 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct Help: View {
|
||||
static let wikiURL = URL(string: "https://github.com/yattee/yattee/wiki")!
|
||||
static let matrixURL = URL(string: "https://tinyurl.com/yattee-matrix")!
|
||||
static let issuesURL = URL(string: "https://github.com/yattee/yattee/issues")!
|
||||
static let milestonesURL = URL(string: "https://github.com/yattee/yattee/milestones")!
|
||||
static let donationsURL = URL(string: "https://github.com/yattee/yattee/wiki/Donations")!
|
||||
static let contributingURL = URL(string: "https://github.com/yattee/yattee/wiki/Contributing")!
|
||||
|
||||
@Environment(\.openURL) private var openURL
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Section {
|
||||
header("I am lost")
|
||||
|
||||
Text("You can find information about using Yattee in the Wiki pages.")
|
||||
.padding(.bottom, 8)
|
||||
|
||||
helpItemLink("Wiki", url: Self.wikiURL, systemImage: "questionmark.circle")
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Section {
|
||||
header("I want to ask a question")
|
||||
|
||||
Text("Discussions take place in Matrix chat channel. It's a good spot for general questions.")
|
||||
.padding(.bottom, 8)
|
||||
|
||||
helpItemLink("Matrix Channel", url: Self.matrixURL, systemImage: "message")
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Section {
|
||||
header("I found a bug /")
|
||||
header("I have a feature request")
|
||||
|
||||
Text("Bugs and great feature ideas can be sent to the GitHub issues tracker. ")
|
||||
Text("If you are reporting a bug, include all relevant details (especially: app\u{00a0}version, used device and system version, steps to reproduce).")
|
||||
Text("If you are interested what's coming in future updates, you can track project Milestones.")
|
||||
.padding(.bottom, 8)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
helpItemLink("Issues Tracker", url: Self.issuesURL, systemImage: "ladybug")
|
||||
helpItemLink("Milestones", url: Self.milestonesURL, systemImage: "list.star")
|
||||
}
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Section {
|
||||
header("I like this app!")
|
||||
|
||||
Text("That's nice to hear. It is fun to deliver apps other people want to use. " +
|
||||
"You can consider donating to the project or help by contributing to new features development.")
|
||||
.padding(.bottom, 8)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
helpItemLink("Donations", url: Self.donationsURL, systemImage: "dollarsign.circle")
|
||||
helpItemLink("Contributing", url: Self.contributingURL, systemImage: "hammer")
|
||||
}
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
}
|
||||
#if os(iOS)
|
||||
.padding(.horizontal)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
#else
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
#endif
|
||||
.navigationTitle("Help")
|
||||
}
|
||||
|
||||
func header(_ text: String) -> some View {
|
||||
Text(text)
|
||||
.fontWeight(.bold)
|
||||
.font(.title3)
|
||||
.padding(.bottom, 6)
|
||||
}
|
||||
|
||||
func helpItemLink(_ label: String, url: URL, systemImage: String) -> some View {
|
||||
Group {
|
||||
#if os(tvOS)
|
||||
VStack {
|
||||
Button {} label: {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: systemImage)
|
||||
Text(label)
|
||||
}
|
||||
.font(.system(size: 25).bold())
|
||||
}
|
||||
|
||||
Text(url.absoluteString)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
#else
|
||||
Button {
|
||||
openURL(url)
|
||||
} label: {
|
||||
Label(label, systemImage: systemImage)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Help_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Help()
|
||||
}
|
||||
}
|
@ -19,31 +19,66 @@ struct HistorySettings: View {
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
Section(header: SettingsHeader(text: "History")) {
|
||||
Toggle("Save recent queries and channels", isOn: $saveRecents)
|
||||
Toggle("Save history of played videos", isOn: $saveHistory)
|
||||
Toggle("Show progress of watching on thumbnails", isOn: $showWatchingProgress)
|
||||
.disabled(!saveHistory)
|
||||
#if os(macOS)
|
||||
sections
|
||||
#else
|
||||
List {
|
||||
sections
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
#elseif os(iOS)
|
||||
.listStyle(.insetGrouped)
|
||||
#endif
|
||||
.navigationTitle("History")
|
||||
}
|
||||
|
||||
private var sections: some View {
|
||||
Group {
|
||||
#if os(tvOS)
|
||||
Section(header: SettingsHeader(text: "History")) {
|
||||
Toggle("Save history of searches, channels and playlists", isOn: $saveRecents)
|
||||
Toggle("Save history of played videos", isOn: $saveHistory)
|
||||
Toggle("Show progress of watching on thumbnails", isOn: $showWatchingProgress)
|
||||
.disabled(!saveHistory)
|
||||
|
||||
watchedVideoPlayNowBehaviorPicker
|
||||
|
||||
#if !os(tvOS)
|
||||
watchedThresholdPicker
|
||||
resetWatchedStatusOnPlayingToggle
|
||||
watchedVideoStylePicker
|
||||
watchedVideoBadgeColorPicker
|
||||
}
|
||||
#else
|
||||
Section(header: SettingsHeader(text: "History")) {
|
||||
Toggle("Save history of searches, channels and playlists", isOn: $saveRecents)
|
||||
Toggle("Save history of played videos", isOn: $saveHistory)
|
||||
Toggle("Show progress of watching on thumbnails", isOn: $showWatchingProgress)
|
||||
.disabled(!saveHistory)
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Watched")) {
|
||||
watchedVideoPlayNowBehaviorPicker
|
||||
#if os(macOS)
|
||||
.padding(.top, 1)
|
||||
#endif
|
||||
watchedThresholdPicker
|
||||
resetWatchedStatusOnPlayingToggle
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Interface")) {
|
||||
watchedVideoStylePicker
|
||||
#if os(macOS)
|
||||
.padding(.top, 1)
|
||||
#endif
|
||||
watchedVideoBadgeColorPicker
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
Spacer()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(tvOS)
|
||||
watchedThresholdPicker
|
||||
watchedVideoStylePicker
|
||||
watchedVideoBadgeColorPicker
|
||||
watchedVideoPlayNowBehaviorPicker
|
||||
resetWatchedStatusOnPlayingToggle
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
Spacer()
|
||||
#endif
|
||||
|
||||
clearHistoryButton
|
||||
@ -51,7 +86,7 @@ struct HistorySettings: View {
|
||||
}
|
||||
|
||||
private var watchedThresholdPicker: some View {
|
||||
Section(header: header("Mark video as watched after playing")) {
|
||||
Section(header: SettingsHeader(text: "Mark video as watched after playing", secondary: true)) {
|
||||
Picker("Mark video as watched after playing", selection: $watchedThreshold) {
|
||||
ForEach(Self.watchedThresholds, id: \.self) { threshold in
|
||||
Text("\(threshold)%").tag(threshold)
|
||||
@ -69,7 +104,7 @@ struct HistorySettings: View {
|
||||
}
|
||||
|
||||
private var watchedVideoStylePicker: some View {
|
||||
Section(header: header("Mark watched videos with")) {
|
||||
Section(header: SettingsHeader(text: "Mark watched videos with", secondary: true)) {
|
||||
Picker("Mark watched videos with", selection: $watchedVideoStyle) {
|
||||
Text("Nothing").tag(WatchedVideoStyle.nothing)
|
||||
Text("Badge").tag(WatchedVideoStyle.badge)
|
||||
@ -88,7 +123,7 @@ struct HistorySettings: View {
|
||||
}
|
||||
|
||||
private var watchedVideoBadgeColorPicker: some View {
|
||||
Section(header: header("Badge color")) {
|
||||
Section(header: SettingsHeader(text: "Badge color", secondary: true)) {
|
||||
Picker("Badge color", selection: $watchedVideoBadgeColor) {
|
||||
Text("Based on system color scheme").tag(WatchedVideoBadgeColor.colorSchemeBased)
|
||||
Text("Blue").tag(WatchedVideoBadgeColor.blue)
|
||||
@ -96,6 +131,7 @@ struct HistorySettings: View {
|
||||
}
|
||||
.disabled(!saveHistory)
|
||||
.disabled(watchedVideoStyle == .decreasedOpacity)
|
||||
.disabled(watchedVideoStyle == .nothing)
|
||||
.labelsHidden()
|
||||
|
||||
#if os(iOS)
|
||||
@ -107,7 +143,7 @@ struct HistorySettings: View {
|
||||
}
|
||||
|
||||
private var watchedVideoPlayNowBehaviorPicker: some View {
|
||||
Section(header: header("When partially watched video is played")) {
|
||||
Section(header: SettingsHeader(text: "When partially watched video is played", secondary: true)) {
|
||||
Picker("When partially watched video is played", selection: $watchedVideoPlayNowBehavior) {
|
||||
Text("Continue").tag(WatchedVideoPlayNowBehavior.continue)
|
||||
Text("Restart").tag(WatchedVideoPlayNowBehavior.restart)
|
||||
@ -125,6 +161,7 @@ struct HistorySettings: View {
|
||||
|
||||
private var resetWatchedStatusOnPlayingToggle: some View {
|
||||
Toggle("Reset watched status when playing again", isOn: $resetWatchedStatusOnPlaying)
|
||||
.disabled(!saveHistory)
|
||||
}
|
||||
|
||||
private var clearHistoryButton: some View {
|
||||
@ -149,19 +186,6 @@ struct HistorySettings: View {
|
||||
.foregroundColor(.red)
|
||||
.disabled(!saveHistory)
|
||||
}
|
||||
|
||||
private func header(_ text: String) -> some View {
|
||||
#if os(iOS)
|
||||
return EmptyView()
|
||||
#elseif os(macOS)
|
||||
return Text(text)
|
||||
.opacity(saveHistory ? 1 : 0.3)
|
||||
#else
|
||||
return Text(text)
|
||||
.foregroundColor(.secondary)
|
||||
.opacity(saveHistory ? 1 : 0.2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct HistorySettings_Previews: PreviewProvider {
|
||||
|
@ -14,25 +14,7 @@ struct InstanceSettings: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
if instance.app.hasFrontendURL {
|
||||
Section(header: Text("Frontend URL")) {
|
||||
TextField(
|
||||
"Frontend URL",
|
||||
text: $frontendURL
|
||||
)
|
||||
.onAppear {
|
||||
frontendURL = instance.frontendURL ?? ""
|
||||
}
|
||||
.onChange(of: frontendURL) { newValue in
|
||||
InstancesModel.setFrontendURL(instance, newValue)
|
||||
}
|
||||
.labelsHidden()
|
||||
.autocapitalization(.none)
|
||||
.keyboardType(.URL)
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Accounts"), footer: sectionFooter) {
|
||||
Section(header: Text("Accounts")) {
|
||||
if instance.app.supportsAccounts {
|
||||
ForEach(InstancesModel.accounts(instanceID), id: \.self) { account in
|
||||
#if os(tvOS)
|
||||
@ -54,15 +36,21 @@ struct InstanceSettings: View {
|
||||
Spacer()
|
||||
}
|
||||
.contextMenu {
|
||||
Button("Remove") { removeAccount(account) }
|
||||
Button {
|
||||
removeAccount(account)
|
||||
} label: {
|
||||
Label("Remove", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.redrawOn(change: accountsChanged)
|
||||
|
||||
Button("Add account...") {
|
||||
Button {
|
||||
presentingAccountForm = true
|
||||
} label: {
|
||||
Label("Add Account...", systemImage: "plus")
|
||||
}
|
||||
.sheet(isPresented: $presentingAccountForm, onDismiss: { accountsChanged.toggle() }) {
|
||||
AccountForm(instance: instance)
|
||||
@ -75,6 +63,23 @@ struct InstanceSettings: View {
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
if instance.app.hasFrontendURL {
|
||||
Section(header: Text("Frontend URL")) {
|
||||
TextField(
|
||||
"Frontend URL",
|
||||
text: $frontendURL
|
||||
)
|
||||
.onAppear {
|
||||
frontendURL = instance.frontendURL ?? ""
|
||||
}
|
||||
.onChange(of: frontendURL) { newValue in
|
||||
InstancesModel.setFrontendURL(instance, newValue)
|
||||
}
|
||||
.labelsHidden()
|
||||
.autocapitalization(.none)
|
||||
.keyboardType(.URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
@ -85,15 +90,6 @@ struct InstanceSettings: View {
|
||||
.navigationTitle(instance.description)
|
||||
}
|
||||
|
||||
private var sectionFooter: some View {
|
||||
if !instance.app.supportsAccounts {
|
||||
return Text("")
|
||||
}
|
||||
|
||||
return Text("Tap and hold to remove account")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
private func removeAccount(_ account: Account) {
|
||||
AccountsModel.remove(account)
|
||||
accountsChanged.toggle()
|
||||
|
@ -1,10 +1,16 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct PlaybackSettings: View {
|
||||
struct PlayerSettings: View {
|
||||
@Default(.instances) private var instances
|
||||
@Default(.playerInstanceID) private var playerInstanceID
|
||||
@Default(.quality) private var quality
|
||||
@Default(.commentsInstanceID) private var commentsInstanceID
|
||||
|
||||
#if !os(tvOS)
|
||||
@Default(.commentsPlacement) private var commentsPlacement
|
||||
#endif
|
||||
|
||||
@Default(.playerSidebar) private var playerSidebar
|
||||
@Default(.showHistoryInPlayer) private var showHistory
|
||||
@Default(.showKeywords) private var showKeywords
|
||||
@ -29,66 +35,74 @@ struct PlaybackSettings: View {
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
#if os(iOS)
|
||||
Section(header: SettingsHeader(text: "Player")) {
|
||||
sourcePicker
|
||||
qualityPicker
|
||||
#if os(macOS)
|
||||
sections
|
||||
|
||||
Spacer()
|
||||
#else
|
||||
List {
|
||||
sections
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
#elseif os(iOS)
|
||||
.listStyle(.insetGrouped)
|
||||
#endif
|
||||
.navigationTitle("Player")
|
||||
}
|
||||
|
||||
private var sections: some View {
|
||||
Group {
|
||||
Section(header: SettingsHeader(text: "Playback")) {
|
||||
sourcePicker
|
||||
qualityPicker
|
||||
pauseOnHidingPlayerToggle
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Comments")) {
|
||||
commentsInstancePicker
|
||||
#if !os(tvOS)
|
||||
commentsPlacementPicker
|
||||
.disabled(!CommentsModel.enabled)
|
||||
#endif
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Interface")) {
|
||||
#if os(iOS)
|
||||
if idiom == .pad {
|
||||
sidebarPicker
|
||||
}
|
||||
|
||||
keywordsToggle
|
||||
showHistoryToggle
|
||||
channelSubscribersToggle
|
||||
pauseOnHidingPlayerToggle
|
||||
|
||||
if idiom == .pad {
|
||||
enterFullscreenInLandscapeToggle
|
||||
}
|
||||
|
||||
honorSystemOrientationLockToggle
|
||||
lockLandscapeWhenEnteringFullscreenToggle
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Picture in Picture")) {
|
||||
closePiPOnNavigationToggle
|
||||
closePiPOnOpeningPlayerToggle
|
||||
closePiPAndOpenPlayerOnEnteringForegroundToggle
|
||||
}
|
||||
#else
|
||||
Section(header: SettingsHeader(text: "Source")) {
|
||||
sourcePicker
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Quality")) {
|
||||
qualityPicker
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
Section(header: SettingsHeader(text: "Sidebar")) {
|
||||
sidebarPicker
|
||||
}
|
||||
sidebarPicker
|
||||
#endif
|
||||
|
||||
keywordsToggle
|
||||
showHistoryToggle
|
||||
channelSubscribersToggle
|
||||
pauseOnHidingPlayerToggle
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Picture in Picture")) {
|
||||
closePiPOnNavigationToggle
|
||||
closePiPOnOpeningPlayerToggle
|
||||
#if !os(macOS)
|
||||
closePiPAndOpenPlayerOnEnteringForegroundToggle
|
||||
#endif
|
||||
#if os(iOS)
|
||||
Section(header: SettingsHeader(text: "Orientation")) {
|
||||
if idiom == .pad {
|
||||
enterFullscreenInLandscapeToggle
|
||||
}
|
||||
honorSystemOrientationLockToggle
|
||||
lockLandscapeWhenEnteringFullscreenToggle
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
Spacer()
|
||||
#endif
|
||||
Section(header: SettingsHeader(text: "Picture in Picture")) {
|
||||
closePiPOnNavigationToggle
|
||||
closePiPOnOpeningPlayerToggle
|
||||
#if !os(macOS)
|
||||
closePiPAndOpenPlayerOnEnteringForegroundToggle
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var sourcePicker: some View {
|
||||
@ -122,17 +136,46 @@ struct PlaybackSettings: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
private var commentsInstancePicker: some View {
|
||||
Picker("Source", selection: $commentsInstanceID) {
|
||||
Text("Disabled").tag(Optional(""))
|
||||
|
||||
ForEach(InstancesModel.all.filter { $0.app.supportsComments }) { instance in
|
||||
Text(instance.description).tag(Optional(instance.id))
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
#if os(iOS)
|
||||
.pickerStyle(.automatic)
|
||||
#elseif os(tvOS)
|
||||
.pickerStyle(.inline)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
private var commentsPlacementPicker: some View {
|
||||
Picker("Placement", selection: $commentsPlacement) {
|
||||
Text("Below video description").tag(CommentsPlacement.info)
|
||||
Text("Separate tab").tag(CommentsPlacement.separate)
|
||||
}
|
||||
.labelsHidden()
|
||||
#if os(iOS)
|
||||
.pickerStyle(.automatic)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
private var sidebarPicker: some View {
|
||||
Picker("Sidebar", selection: $playerSidebar) {
|
||||
#if os(macOS)
|
||||
Text("Show").tag(PlayerSidebarSetting.always)
|
||||
Text("Show sidebar").tag(PlayerSidebarSetting.always)
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
Text("Show sidebar when space permits").tag(PlayerSidebarSetting.whenFits)
|
||||
#endif
|
||||
|
||||
Text("Hide").tag(PlayerSidebarSetting.never)
|
||||
Text("Hide sidebar").tag(PlayerSidebarSetting.never)
|
||||
}
|
||||
.labelsHidden()
|
||||
|
||||
@ -144,15 +187,15 @@ struct PlaybackSettings: View {
|
||||
}
|
||||
|
||||
private var keywordsToggle: some View {
|
||||
Toggle("Show video keywords", isOn: $showKeywords)
|
||||
Toggle("Show keywords", isOn: $showKeywords)
|
||||
}
|
||||
|
||||
private var showHistoryToggle: some View {
|
||||
Toggle("Show history of videos", isOn: $showHistory)
|
||||
Toggle("Show history", isOn: $showHistory)
|
||||
}
|
||||
|
||||
private var channelSubscribersToggle: some View {
|
||||
Toggle("Show channel subscribers count", isOn: $channelSubscribers)
|
||||
Toggle("Show subscribers count", isOn: $channelSubscribers)
|
||||
}
|
||||
|
||||
private var pauseOnHidingPlayerToggle: some View {
|
||||
@ -161,7 +204,7 @@ struct PlaybackSettings: View {
|
||||
|
||||
#if os(iOS)
|
||||
private var honorSystemOrientationLockToggle: some View {
|
||||
Toggle("Honor system orientation lock", isOn: $honorSystemOrientationLock)
|
||||
Toggle("Honor orientation lock", isOn: $honorSystemOrientationLock)
|
||||
.disabled(!enterFullscreenInLandscape)
|
||||
}
|
||||
|
||||
@ -170,7 +213,7 @@ struct PlaybackSettings: View {
|
||||
}
|
||||
|
||||
private var lockLandscapeWhenEnteringFullscreenToggle: some View {
|
||||
Toggle("Lock landscape orientation when entering fullscreen", isOn: $lockLandscapeWhenEnteringFullscreen)
|
||||
Toggle("Lock landscape on rotation", isOn: $lockLandscapeWhenEnteringFullscreen)
|
||||
.disabled(!enterFullscreenInLandscape)
|
||||
}
|
||||
#endif
|
||||
@ -192,7 +235,7 @@ struct PlaybackSettings: View {
|
||||
|
||||
struct PlaybackSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PlaybackSettings()
|
||||
PlayerSettings()
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct ServicesSettings: View {
|
||||
@Default(.sponsorBlockInstance) private var sponsorBlockInstance
|
||||
@Default(.sponsorBlockCategories) private var sponsorBlockCategories
|
||||
@Default(.commentsInstanceID) private var commentsInstanceID
|
||||
|
||||
#if !os(tvOS)
|
||||
@Default(.commentsPlacement) private var commentsPlacement
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
Section(header: SettingsHeader(text: "Comments")) {
|
||||
commentsInstancePicker
|
||||
#if !os(tvOS)
|
||||
commentsPlacementPicker
|
||||
.disabled(!CommentsModel.enabled)
|
||||
#endif
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "SponsorBlock API")) {
|
||||
TextField(
|
||||
"SponsorBlock API Instance",
|
||||
text: $sponsorBlockInstance
|
||||
)
|
||||
.labelsHidden()
|
||||
#if !os(macOS)
|
||||
.autocapitalization(.none)
|
||||
.keyboardType(.URL)
|
||||
#endif
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Categories to Skip")) {
|
||||
#if os(macOS)
|
||||
let list = ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||
SponsorBlockCategorySelectionRow(
|
||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||
selected: sponsorBlockCategories.contains(category)
|
||||
) { value in
|
||||
toggleCategory(category, value: value)
|
||||
}
|
||||
}
|
||||
|
||||
Group {
|
||||
if #available(macOS 12.0, *) {
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
} else {
|
||||
list
|
||||
.listStyle(.inset)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
#else
|
||||
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||
SponsorBlockCategorySelectionRow(
|
||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||
selected: sponsorBlockCategories.contains(category)
|
||||
) { value in
|
||||
toggleCategory(category, value: value)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private var commentsInstancePicker: some View {
|
||||
Picker("Source", selection: $commentsInstanceID) {
|
||||
Text("Disabled").tag(Optional(""))
|
||||
|
||||
ForEach(InstancesModel.all.filter { $0.app.supportsComments }) { instance in
|
||||
Text(instance.description).tag(Optional(instance.id))
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
#if os(iOS)
|
||||
.pickerStyle(.automatic)
|
||||
#elseif os(tvOS)
|
||||
.pickerStyle(.inline)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
private var commentsPlacementPicker: some View {
|
||||
Picker("Placement", selection: $commentsPlacement) {
|
||||
Text("Below video description").tag(CommentsPlacement.info)
|
||||
Text("Separate tab").tag(CommentsPlacement.separate)
|
||||
}
|
||||
.labelsHidden()
|
||||
#if os(iOS)
|
||||
.pickerStyle(.automatic)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
func toggleCategory(_ category: String, value: Bool) {
|
||||
if let index = sponsorBlockCategories.firstIndex(where: { $0 == category }), !value {
|
||||
sponsorBlockCategories.remove(at: index)
|
||||
} else if value {
|
||||
sponsorBlockCategories.insert(category)
|
||||
}
|
||||
}
|
||||
|
||||
struct SponsorBlockCategorySelectionRow: View {
|
||||
let title: String
|
||||
let selected: Bool
|
||||
var action: (Bool) -> Void
|
||||
|
||||
@State private var toggleChecked = false
|
||||
|
||||
var body: some View {
|
||||
Button(action: { action(!selected) }) {
|
||||
HStack {
|
||||
#if os(macOS)
|
||||
Toggle(isOn: $toggleChecked) {
|
||||
Text(self.title)
|
||||
Spacer()
|
||||
}
|
||||
.onAppear {
|
||||
toggleChecked = selected
|
||||
}
|
||||
.onChange(of: toggleChecked) { new in
|
||||
action(new)
|
||||
}
|
||||
#else
|
||||
Text(self.title)
|
||||
Spacer()
|
||||
if selected {
|
||||
Image(systemName: "checkmark")
|
||||
#if os(iOS)
|
||||
.foregroundColor(.accentColor)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ServicesSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
ServicesSettings()
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,28 @@ import SwiftUI
|
||||
|
||||
struct SettingsHeader: View {
|
||||
var text: String
|
||||
var secondary = false
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
#if os(macOS) || os(tvOS)
|
||||
.font(.title3)
|
||||
.foregroundColor(.secondary)
|
||||
.focusable(false)
|
||||
Group {
|
||||
#if os(iOS)
|
||||
if secondary {
|
||||
EmptyView()
|
||||
} else {
|
||||
Text(text)
|
||||
}
|
||||
#else
|
||||
Text(text)
|
||||
#endif
|
||||
}
|
||||
#if os(tvOS)
|
||||
.font(secondary ? .footnote : .title3)
|
||||
.foregroundColor(.secondary)
|
||||
.focusable(false)
|
||||
#endif
|
||||
#if os(macOS)
|
||||
.font(secondary ? .system(size: 13) : .system(size: 15))
|
||||
.foregroundColor(secondary ? Color.primary : .secondary)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,10 @@ import SwiftUI
|
||||
struct SettingsView: View {
|
||||
#if os(macOS)
|
||||
private enum Tabs: Hashable {
|
||||
case instances, browsing, history, playback, services, updates
|
||||
case instances, browsing, player, history, sponsorBlock, updates, help
|
||||
}
|
||||
|
||||
@State private var selection = Tabs.instances
|
||||
#endif
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@ -24,7 +26,7 @@ struct SettingsView: View {
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
TabView {
|
||||
TabView(selection: $selection) {
|
||||
Form {
|
||||
InstancesSettings()
|
||||
.environmentObject(accounts)
|
||||
@ -42,6 +44,14 @@ struct SettingsView: View {
|
||||
}
|
||||
.tag(Tabs.browsing)
|
||||
|
||||
Form {
|
||||
PlayerSettings()
|
||||
}
|
||||
.tabItem {
|
||||
Label("Player", systemImage: "play.rectangle")
|
||||
}
|
||||
.tag(Tabs.player)
|
||||
|
||||
Form {
|
||||
HistorySettings()
|
||||
}
|
||||
@ -51,20 +61,12 @@ struct SettingsView: View {
|
||||
.tag(Tabs.history)
|
||||
|
||||
Form {
|
||||
PlaybackSettings()
|
||||
SponsorBlockSettings()
|
||||
}
|
||||
.tabItem {
|
||||
Label("Playback", systemImage: "play.rectangle")
|
||||
Label("SponsorBlock", systemImage: "dollarsign.circle")
|
||||
}
|
||||
.tag(Tabs.playback)
|
||||
|
||||
Form {
|
||||
ServicesSettings()
|
||||
}
|
||||
.tabItem {
|
||||
Label("Services", systemImage: "puzzlepiece")
|
||||
}
|
||||
.tag(Tabs.services)
|
||||
.tag(Tabs.sponsorBlock)
|
||||
|
||||
Form {
|
||||
UpdatesSettings()
|
||||
@ -73,20 +75,22 @@ struct SettingsView: View {
|
||||
Label("Updates", systemImage: "gearshape.2")
|
||||
}
|
||||
.tag(Tabs.updates)
|
||||
|
||||
Form {
|
||||
Help()
|
||||
}
|
||||
.tabItem {
|
||||
Label("Help", systemImage: "questionmark.circle")
|
||||
}
|
||||
.tag(Tabs.help)
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 400, height: 400)
|
||||
.frame(width: 480, height: windowHeight)
|
||||
#else
|
||||
NavigationView {
|
||||
List {
|
||||
#if os(tvOS)
|
||||
AccountSelectionView()
|
||||
|
||||
Section(header: SettingsHeader(text: "Favorites")) {
|
||||
NavigationLink("Edit favorites...") {
|
||||
EditFavorites()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Section(header: Text("Instances")) {
|
||||
@ -96,14 +100,55 @@ struct SettingsView: View {
|
||||
addInstanceButton
|
||||
}
|
||||
|
||||
BrowsingSettings()
|
||||
HistorySettings()
|
||||
PlaybackSettings()
|
||||
ServicesSettings()
|
||||
#if os(tvOS)
|
||||
Divider()
|
||||
#endif
|
||||
|
||||
Section {
|
||||
#if os(tvOS)
|
||||
NavigationLink {
|
||||
EditFavorites()
|
||||
} label: {
|
||||
Label("Favorites", systemImage: "heart.fill")
|
||||
}
|
||||
#endif
|
||||
|
||||
NavigationLink {
|
||||
BrowsingSettings()
|
||||
} label: {
|
||||
Label("Browsing", systemImage: "list.and.film")
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
PlayerSettings()
|
||||
} label: {
|
||||
Label("Player", systemImage: "play.rectangle")
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
HistorySettings()
|
||||
} label: {
|
||||
Label("History", systemImage: "clock.arrow.circlepath")
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
SponsorBlockSettings()
|
||||
} label: {
|
||||
Label("SponsorBlock", systemImage: "dollarsign.circle")
|
||||
}
|
||||
}
|
||||
|
||||
Section(footer: versionString) {
|
||||
NavigationLink {
|
||||
Help()
|
||||
} label: {
|
||||
Label("Help", systemImage: "questionmark.circle")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Settings")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
#if !os(tvOS)
|
||||
Button("Done") {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
@ -126,9 +171,39 @@ struct SettingsView: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private var windowHeight: Double {
|
||||
switch selection {
|
||||
case .instances:
|
||||
return 390
|
||||
case .browsing:
|
||||
return 350
|
||||
case .player:
|
||||
return 450
|
||||
case .history:
|
||||
return 480
|
||||
case .sponsorBlock:
|
||||
return 290
|
||||
case .updates:
|
||||
return 200
|
||||
case .help:
|
||||
return 570
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private var versionString: some View {
|
||||
Text("Yattee \(YatteeApp.version) (build \(YatteeApp.build))")
|
||||
#if os(tvOS)
|
||||
.foregroundColor(.secondary)
|
||||
#endif
|
||||
}
|
||||
|
||||
private var addInstanceButton: some View {
|
||||
Button("Add Instance...") {
|
||||
Button {
|
||||
presentingInstanceForm = true
|
||||
} label: {
|
||||
Label("Add Instance...", systemImage: "plus")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
132
Shared/Settings/SponsorBlockSettings.swift
Normal file
132
Shared/Settings/SponsorBlockSettings.swift
Normal file
@ -0,0 +1,132 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct SponsorBlockSettings: View {
|
||||
@Default(.sponsorBlockInstance) private var sponsorBlockInstance
|
||||
@Default(.sponsorBlockCategories) private var sponsorBlockCategories
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
#if os(macOS)
|
||||
sections
|
||||
|
||||
Spacer()
|
||||
#else
|
||||
List {
|
||||
sections
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
#elseif os(iOS)
|
||||
.listStyle(.insetGrouped)
|
||||
#endif
|
||||
.navigationTitle("SponsorBlock")
|
||||
}
|
||||
|
||||
private var sections: some View {
|
||||
Group {
|
||||
Section(header: SettingsHeader(text: "SponsorBlock API")) {
|
||||
TextField(
|
||||
"SponsorBlock API Instance",
|
||||
text: $sponsorBlockInstance
|
||||
)
|
||||
.labelsHidden()
|
||||
#if !os(macOS)
|
||||
.autocapitalization(.none)
|
||||
.keyboardType(.URL)
|
||||
#endif
|
||||
}
|
||||
|
||||
Section(header: SettingsHeader(text: "Categories to Skip")) {
|
||||
#if os(macOS)
|
||||
let list = ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||
SponsorBlockCategorySelectionRow(
|
||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||
selected: sponsorBlockCategories.contains(category)
|
||||
) { value in
|
||||
toggleCategory(category, value: value)
|
||||
}
|
||||
}
|
||||
|
||||
Group {
|
||||
if #available(macOS 12.0, *) {
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
} else {
|
||||
list
|
||||
.listStyle(.inset)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
#else
|
||||
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||
SponsorBlockCategorySelectionRow(
|
||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||
selected: sponsorBlockCategories.contains(category)
|
||||
) { value in
|
||||
toggleCategory(category, value: value)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toggleCategory(_ category: String, value: Bool) {
|
||||
if let index = sponsorBlockCategories.firstIndex(where: { $0 == category }), !value {
|
||||
sponsorBlockCategories.remove(at: index)
|
||||
} else if value {
|
||||
sponsorBlockCategories.insert(category)
|
||||
}
|
||||
}
|
||||
|
||||
struct SponsorBlockCategorySelectionRow: View {
|
||||
let title: String
|
||||
let selected: Bool
|
||||
var action: (Bool) -> Void
|
||||
|
||||
@State private var toggleChecked = false
|
||||
|
||||
var body: some View {
|
||||
Button(action: { action(!selected) }) {
|
||||
HStack {
|
||||
#if os(macOS)
|
||||
Toggle(isOn: $toggleChecked) {
|
||||
Text(self.title)
|
||||
Spacer()
|
||||
}
|
||||
.onAppear {
|
||||
toggleChecked = selected
|
||||
}
|
||||
.onChange(of: toggleChecked) { new in
|
||||
action(new)
|
||||
}
|
||||
#else
|
||||
Text(self.title)
|
||||
Spacer()
|
||||
if selected {
|
||||
Image(systemName: "checkmark")
|
||||
#if os(iOS)
|
||||
.foregroundColor(.accentColor)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ServicesSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
SponsorBlockSettings()
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,14 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct YatteeApp: App {
|
||||
static var version: String {
|
||||
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
|
||||
}
|
||||
|
||||
static var build: String {
|
||||
Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||
@StateObject private var updater = UpdaterModel()
|
||||
|
@ -99,6 +99,8 @@
|
||||
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
||||
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||
3727B74A27872A920021C15E /* VisualEffectBlur-iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */; };
|
||||
3727B74B27872B880021C15E /* VisualEffectBlur-macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */; };
|
||||
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
||||
3729037F2739E47400EA99F6 /* MenuCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3729037D2739E47400EA99F6 /* MenuCommands.swift */; };
|
||||
372915E42687E33E00F5A35B /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 372915E32687E33E00F5A35B /* Defaults */; };
|
||||
@ -147,9 +149,9 @@
|
||||
3748186E26A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
|
||||
3748186F26A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
|
||||
3748187026A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
|
||||
37484C1926FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||
37484C1B26FC837400287258 /* PlaybackSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlaybackSettings.swift */; };
|
||||
37484C1926FC837400287258 /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlayerSettings.swift */; };
|
||||
37484C1A26FC837400287258 /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlayerSettings.swift */; };
|
||||
37484C1B26FC837400287258 /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C1826FC837400287258 /* PlayerSettings.swift */; };
|
||||
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||
37484C2626FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||
37484C2726FC83E000287258 /* InstanceForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C2426FC83E000287258 /* InstanceForm.swift */; };
|
||||
@ -161,9 +163,9 @@
|
||||
37484C3126FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||
37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37484C3026FCB8F900287258 /* AccountValidator.swift */; };
|
||||
374C053527242D9F009BDDBE /* ServicesSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* ServicesSettings.swift */; };
|
||||
374C053627242D9F009BDDBE /* ServicesSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* ServicesSettings.swift */; };
|
||||
374C053727242D9F009BDDBE /* ServicesSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* ServicesSettings.swift */; };
|
||||
374C053527242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* SponsorBlockSettings.swift */; };
|
||||
374C053627242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* SponsorBlockSettings.swift */; };
|
||||
374C053727242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053427242D9F009BDDBE /* SponsorBlockSettings.swift */; };
|
||||
374C053B2724614F009BDDBE /* PlayerTVMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053A2724614F009BDDBE /* PlayerTVMenu.swift */; };
|
||||
374C053C2724614F009BDDBE /* PlayerTVMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053A2724614F009BDDBE /* PlayerTVMenu.swift */; };
|
||||
374C053D2724614F009BDDBE /* PlayerTVMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374C053A2724614F009BDDBE /* PlayerTVMenu.swift */; };
|
||||
@ -177,6 +179,9 @@
|
||||
3751B4B227836902000B7DF4 /* SearchPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3751B4B127836902000B7DF4 /* SearchPage.swift */; };
|
||||
3751B4B327836902000B7DF4 /* SearchPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3751B4B127836902000B7DF4 /* SearchPage.swift */; };
|
||||
3751B4B427836902000B7DF4 /* SearchPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3751B4B127836902000B7DF4 /* SearchPage.swift */; };
|
||||
37579D5D27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
||||
37579D5E27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
||||
37579D5F27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
||||
3758638A2721B0A9000CB14E /* ChannelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743B86727216D3600261544 /* ChannelCell.swift */; };
|
||||
37599F30272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
||||
37599F31272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
||||
@ -633,6 +638,8 @@
|
||||
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Badge+Backport.swift"; sourceTree = "<group>"; };
|
||||
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
||||
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tint+Backport.swift"; sourceTree = "<group>"; };
|
||||
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-macOS.swift"; sourceTree = "<group>"; };
|
||||
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-iOS.swift"; sourceTree = "<group>"; };
|
||||
3729037D2739E47400EA99F6 /* MenuCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuCommands.swift; sourceTree = "<group>"; };
|
||||
372915E52687E3B900F5A35B /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
|
||||
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingView.swift; sourceTree = "<group>"; };
|
||||
@ -651,18 +658,19 @@
|
||||
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
|
||||
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
|
||||
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
|
||||
37484C1826FC837400287258 /* PlaybackSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSettings.swift; sourceTree = "<group>"; };
|
||||
37484C1826FC837400287258 /* PlayerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSettings.swift; sourceTree = "<group>"; };
|
||||
37484C2426FC83E000287258 /* InstanceForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceForm.swift; sourceTree = "<group>"; };
|
||||
37484C2826FC83FF00287258 /* AccountForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountForm.swift; sourceTree = "<group>"; };
|
||||
37484C2C26FC844700287258 /* InstanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceSettings.swift; sourceTree = "<group>"; };
|
||||
37484C3026FCB8F900287258 /* AccountValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidator.swift; sourceTree = "<group>"; };
|
||||
374C053427242D9F009BDDBE /* ServicesSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesSettings.swift; sourceTree = "<group>"; };
|
||||
374C053427242D9F009BDDBE /* SponsorBlockSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SponsorBlockSettings.swift; sourceTree = "<group>"; };
|
||||
374C053A2724614F009BDDBE /* PlayerTVMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTVMenu.swift; sourceTree = "<group>"; };
|
||||
374C053E272472C0009BDDBE /* PlayerSponsorBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSponsorBlock.swift; sourceTree = "<group>"; };
|
||||
374C0542272496E4009BDDBE /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = macOS/AppDelegate.swift; sourceTree = SOURCE_ROOT; };
|
||||
374C0544272496FD009BDDBE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
375168D52700FAFF008F96A6 /* Debounce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debounce.swift; sourceTree = "<group>"; };
|
||||
3751B4B127836902000B7DF4 /* SearchPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchPage.swift; sourceTree = "<group>"; };
|
||||
37579D5C27864F5F00FD0B98 /* Help.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Help.swift; sourceTree = "<group>"; };
|
||||
37599F2F272B42810087F250 /* FavoriteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItem.swift; sourceTree = "<group>"; };
|
||||
37599F33272B44000087F250 /* FavoritesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesModel.swift; sourceTree = "<group>"; };
|
||||
37599F37272B4D740087F250 /* FavoriteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButton.swift; sourceTree = "<group>"; };
|
||||
@ -1003,6 +1011,8 @@
|
||||
3722AEBD274DA401005EA4D6 /* Backport.swift */,
|
||||
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */,
|
||||
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */,
|
||||
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */,
|
||||
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */,
|
||||
);
|
||||
path = Backports;
|
||||
sourceTree = "<group>";
|
||||
@ -1068,11 +1078,12 @@
|
||||
37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */,
|
||||
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */,
|
||||
376BE50A27349108009AD608 /* BrowsingSettings.swift */,
|
||||
37579D5C27864F5F00FD0B98 /* Help.swift */,
|
||||
37BC50A72778A84700510953 /* HistorySettings.swift */,
|
||||
37484C2426FC83E000287258 /* InstanceForm.swift */,
|
||||
37484C2C26FC844700287258 /* InstanceSettings.swift */,
|
||||
37484C1826FC837400287258 /* PlaybackSettings.swift */,
|
||||
374C053427242D9F009BDDBE /* ServicesSettings.swift */,
|
||||
37484C1826FC837400287258 /* PlayerSettings.swift */,
|
||||
374C053427242D9F009BDDBE /* SponsorBlockSettings.swift */,
|
||||
376BE50627347B57009AD608 /* SettingsHeader.swift */,
|
||||
37B044B626F7AB9000E1419D /* SettingsView.swift */,
|
||||
);
|
||||
@ -1903,13 +1914,14 @@
|
||||
378E50FF26FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
|
||||
37169AA62729E2CC0011DE61 /* AccountsBridge.swift in Sources */,
|
||||
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
|
||||
3727B74A27872A920021C15E /* VisualEffectBlur-iOS.swift in Sources */,
|
||||
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||
37130A5F277657300033018A /* PersistenceController.swift in Sources */,
|
||||
37FD43E32704847C0073EE42 /* View+Fixtures.swift in Sources */,
|
||||
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||
37BA793F26DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
||||
37C194C726F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
||||
37484C1926FC837400287258 /* PlaybackSettings.swift in Sources */,
|
||||
37484C1926FC837400287258 /* PlayerSettings.swift in Sources */,
|
||||
3711403F26B206A6005B3555 /* SearchModel.swift in Sources */,
|
||||
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */,
|
||||
37F64FE426FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
||||
@ -1958,7 +1970,7 @@
|
||||
377FC7E3267A084A00A6BBAF /* VideoCell.swift in Sources */,
|
||||
37C3A251272366440087A57A /* ChannelPlaylistView.swift in Sources */,
|
||||
37E2EEAB270656EC00170416 /* PlayerControlsView.swift in Sources */,
|
||||
374C053527242D9F009BDDBE /* ServicesSettings.swift in Sources */,
|
||||
374C053527242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */,
|
||||
37BF661C27308859008CCFB0 /* DropFavorite.swift in Sources */,
|
||||
376A33E42720CB35000C1D6B /* Account.swift in Sources */,
|
||||
37BA794326DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
||||
@ -2022,6 +2034,7 @@
|
||||
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
||||
37BE0BCF26A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
||||
3769C02E2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */,
|
||||
37579D5D27864F5F00FD0B98 /* Help.swift in Sources */,
|
||||
3758638A2721B0A9000CB14E /* ChannelCell.swift in Sources */,
|
||||
37001563271B1F250049C794 /* AccountsModel.swift in Sources */,
|
||||
37CC3F50270D010D00608308 /* VideoBanner.swift in Sources */,
|
||||
@ -2043,6 +2056,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3727B74B27872B880021C15E /* VisualEffectBlur-macOS.swift in Sources */,
|
||||
374710062755291C00CE0F87 /* SearchField.swift in Sources */,
|
||||
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
||||
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
||||
@ -2053,7 +2067,7 @@
|
||||
37C3A24627235DA70087A57A /* ChannelPlaylist.swift in Sources */,
|
||||
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||
374C0540272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */,
|
||||
374C053627242D9F009BDDBE /* ServicesSettings.swift in Sources */,
|
||||
374C053627242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */,
|
||||
37BA794826DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
|
||||
37E70928271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */,
|
||||
37DD9DA42785BBC900539416 /* NoCommentsView.swift in Sources */,
|
||||
@ -2080,7 +2094,7 @@
|
||||
376B2E0826F920D600B1D64D /* SignInRequiredView.swift in Sources */,
|
||||
37CC3F4D270CFE1700608308 /* PlayerQueueView.swift in Sources */,
|
||||
37B81B0026D2CA3700675966 /* VideoDetails.swift in Sources */,
|
||||
37484C1A26FC837400287258 /* PlaybackSettings.swift in Sources */,
|
||||
37484C1A26FC837400287258 /* PlayerSettings.swift in Sources */,
|
||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
||||
37484C3226FCB8F900287258 /* AccountValidator.swift in Sources */,
|
||||
378AE944274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
||||
@ -2117,6 +2131,7 @@
|
||||
37AAF29126740715007FC770 /* Channel.swift in Sources */,
|
||||
376A33E12720CAD6000C1D6B /* VideosApp.swift in Sources */,
|
||||
37BD07BC2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */,
|
||||
37579D5E27864F5F00FD0B98 /* Help.swift in Sources */,
|
||||
37EF9A77275BEB8E0043B585 /* CommentView.swift in Sources */,
|
||||
37BF661D27308859008CCFB0 /* DropFavorite.swift in Sources */,
|
||||
3748186F26A769D60084E870 /* DetailBadge.swift in Sources */,
|
||||
@ -2273,6 +2288,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37579D5F27864F5F00FD0B98 /* Help.swift in Sources */,
|
||||
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||
373C8FE6275B955100CB5936 /* CommentsPage.swift in Sources */,
|
||||
37DD9DBC2785D60300539416 /* FramePreferenceKey.swift in Sources */,
|
||||
@ -2365,7 +2381,7 @@
|
||||
37B2631C2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
|
||||
37484C2B26FC83FF00287258 /* AccountForm.swift in Sources */,
|
||||
37FB2860272225E800A57617 /* ContentItemView.swift in Sources */,
|
||||
374C053727242D9F009BDDBE /* ServicesSettings.swift in Sources */,
|
||||
374C053727242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */,
|
||||
37C069802725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
|
||||
3711404126B206A6005B3555 /* SearchModel.swift in Sources */,
|
||||
37FD43F02704A9C00073EE42 /* RecentsModel.swift in Sources */,
|
||||
@ -2398,7 +2414,7 @@
|
||||
37C3A24F272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
||||
37FB28432721B22200A57617 /* ContentItem.swift in Sources */,
|
||||
37AAF2A226741C97007FC770 /* SubscriptionsView.swift in Sources */,
|
||||
37484C1B26FC837400287258 /* PlaybackSettings.swift in Sources */,
|
||||
37484C1B26FC837400287258 /* PlayerSettings.swift in Sources */,
|
||||
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
|
||||
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,
|
||||
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
||||
|
@ -22,6 +22,9 @@ struct UpdatesSettings: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Yattee \(YatteeApp.version) (build \(YatteeApp.build))")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
CheckForUpdatesView()
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ struct AccountSelectionView: View {
|
||||
@Default(.instances) private var instances
|
||||
|
||||
var body: some View {
|
||||
Section(header: SettingsHeader(text: showHeader ? "Current Account" : "")) {
|
||||
Section(header: Text(showHeader ? "Current Account" : "")) {
|
||||
Button(accountButtonTitle(account: accountsModel.current, long: true)) {
|
||||
if let account = nextAccount {
|
||||
accountsModel.setCurrent(account)
|
||||
|
@ -71,7 +71,7 @@ struct EditFavorites: View {
|
||||
}
|
||||
.frame(width: 1000, alignment: .leading)
|
||||
}
|
||||
.navigationTitle("Edit Favorites")
|
||||
.navigationTitle("Favorites")
|
||||
}
|
||||
|
||||
func label(_ item: FavoriteItem) -> String {
|
||||
|
Loading…
Reference in New Issue
Block a user