mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
SponsorBlock set colors for each category
Default colors are defined in alignment to upstream. These can be changed by the user. The colors are also used in the Timeline and the seek view.
This commit is contained in:
parent
321eaecd21
commit
b5ac760af2
@ -243,6 +243,7 @@ extension Defaults.Keys {
|
|||||||
|
|
||||||
static let sponsorBlockInstance = Key<String>("sponsorBlockInstance", default: "https://sponsor.ajay.app")
|
static let sponsorBlockInstance = Key<String>("sponsorBlockInstance", default: "https://sponsor.ajay.app")
|
||||||
static let sponsorBlockCategories = Key<Set<String>>("sponsorBlockCategories", default: Set(SponsorBlockAPI.categories))
|
static let sponsorBlockCategories = Key<Set<String>>("sponsorBlockCategories", default: Set(SponsorBlockAPI.categories))
|
||||||
|
static let sponsorBlockColors = Key<[String: String]>("sponsorBlockColors", default: SponsorBlockColors.dictionary)
|
||||||
|
|
||||||
// MARK: GROUP - Locations
|
// MARK: GROUP - Locations
|
||||||
|
|
||||||
@ -580,3 +581,26 @@ enum WidgetListingStyle: String, CaseIterable, Defaults.Serializable {
|
|||||||
case horizontalCells
|
case horizontalCells
|
||||||
case list
|
case list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SponsorBlockColors: String {
|
||||||
|
case sponsor = "#00D400" // Green
|
||||||
|
case selfpromo = "#FFFF00" // Yellow
|
||||||
|
case interaction = "#CC00FF" // Purple
|
||||||
|
case intro = "#00FFFF" // Cyan
|
||||||
|
case outro = "#0202ED" // Dark Blue
|
||||||
|
case preview = "#008FD6" // Light Blue
|
||||||
|
case filler = "#7300FF" // Violet
|
||||||
|
case music_offtopic = "#FF9900" // Orange
|
||||||
|
|
||||||
|
// Define all cases, can be used to iterate over the colors
|
||||||
|
static let allCases: [SponsorBlockColors] = [.sponsor, .selfpromo, .interaction, .intro, .outro, .preview, .filler, .music_offtopic]
|
||||||
|
|
||||||
|
// Create a dictionary with the category names as keys and colors as values
|
||||||
|
static let dictionary: [String: String] = {
|
||||||
|
var dict = [String: String]()
|
||||||
|
for item in allCases {
|
||||||
|
dict[String(describing: item)] = item.rawValue
|
||||||
|
}
|
||||||
|
return dict
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
@ -13,6 +13,17 @@ struct Seek: View {
|
|||||||
|
|
||||||
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
||||||
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
||||||
|
@Default(.sponsorBlockColors) private var sponsorBlockColors
|
||||||
|
|
||||||
|
private func getColor(for category: String) -> Color {
|
||||||
|
if let hexString = sponsorBlockColors[category], let rgbValue = Int(hexString.dropFirst(), radix: 16) {
|
||||||
|
let r = Double((rgbValue >> 16) & 0xFF) / 255.0
|
||||||
|
let g = Double((rgbValue >> 8) & 0xFF) / 255.0
|
||||||
|
let b = Double(rgbValue & 0xFF) / 255.0
|
||||||
|
return Color(red: r, green: g, blue: b)
|
||||||
|
}
|
||||||
|
return Color("AppRedColor") // Fallback color if no match found
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
@ -51,7 +62,8 @@ struct Seek: View {
|
|||||||
if let segment = projectedSegment {
|
if let segment = projectedSegment {
|
||||||
Text(SponsorBlockAPI.categoryDescription(segment.category) ?? "Sponsor")
|
Text(SponsorBlockAPI.categoryDescription(segment.category) ?? "Sponsor")
|
||||||
.font(.system(size: playerControlsLayout.segmentFontSize))
|
.font(.system(size: playerControlsLayout.segmentFontSize))
|
||||||
.foregroundColor(Color("AppRedColor"))
|
.foregroundColor(getColor(for: segment.category))
|
||||||
|
.padding(.bottom, 3)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ -69,7 +81,8 @@ struct Seek: View {
|
|||||||
Divider()
|
Divider()
|
||||||
Text(SponsorBlockAPI.categoryDescription(category) ?? "Sponsor")
|
Text(SponsorBlockAPI.categoryDescription(category) ?? "Sponsor")
|
||||||
.font(.system(size: playerControlsLayout.segmentFontSize))
|
.font(.system(size: playerControlsLayout.segmentFontSize))
|
||||||
.foregroundColor(Color("AppRedColor"))
|
.foregroundColor(getColor(for: category))
|
||||||
|
.padding(.bottom, 3)
|
||||||
default:
|
default:
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,22 @@ struct TimelineView: View {
|
|||||||
|
|
||||||
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
||||||
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
||||||
|
@Default(.sponsorBlockColors) private var sponsorBlockColors
|
||||||
|
|
||||||
var playerControlsLayout: PlayerControlsLayout {
|
var playerControlsLayout: PlayerControlsLayout {
|
||||||
player.playingFullScreen ? fullScreenPlayerControlsLayout : regularPlayerControlsLayout
|
player.playingFullScreen ? fullScreenPlayerControlsLayout : regularPlayerControlsLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func getColor(for category: String) -> Color {
|
||||||
|
if let hexString = sponsorBlockColors[category], let rgbValue = Int(hexString.dropFirst(), radix: 16) {
|
||||||
|
let r = Double((rgbValue >> 16) & 0xFF) / 255.0
|
||||||
|
let g = Double((rgbValue >> 8) & 0xFF) / 255.0
|
||||||
|
let b = Double(rgbValue & 0xFF) / 255.0
|
||||||
|
return Color(red: r, green: g, blue: b)
|
||||||
|
}
|
||||||
|
return Color("AppRedColor") // Fallback color if no match found
|
||||||
|
}
|
||||||
|
|
||||||
var chapters: [Chapter] {
|
var chapters: [Chapter] {
|
||||||
player.currentVideo?.chapters ?? []
|
player.currentVideo?.chapters ?? []
|
||||||
}
|
}
|
||||||
@ -79,7 +90,7 @@ struct TimelineView: View {
|
|||||||
Text(description)
|
Text(description)
|
||||||
.font(.system(size: playerControlsLayout.segmentFontSize))
|
.font(.system(size: playerControlsLayout.segmentFontSize))
|
||||||
.fixedSize()
|
.fixedSize()
|
||||||
.foregroundColor(Color("AppRedColor"))
|
.foregroundColor(getColor(for: segment.category))
|
||||||
}
|
}
|
||||||
if let chapter = projectedChapter {
|
if let chapter = projectedChapter {
|
||||||
Text(chapter.title)
|
Text(chapter.title)
|
||||||
@ -299,7 +310,7 @@ struct TimelineView: View {
|
|||||||
ForEach(segments, id: \.uuid) { segment in
|
ForEach(segments, id: \.uuid) { segment in
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.offset(x: segmentLayerHorizontalOffset(segment))
|
.offset(x: segmentLayerHorizontalOffset(segment))
|
||||||
.foregroundColor(Color("AppRedColor"))
|
.foregroundColor(getColor(for: segment.category))
|
||||||
.frame(maxHeight: height)
|
.frame(maxHeight: height)
|
||||||
.frame(width: segmentLayerWidth(segment))
|
.frame(width: segmentLayerWidth(segment))
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import Defaults
|
import Defaults
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
struct SponsorBlockSettings: View {
|
struct SponsorBlockSettings: View {
|
||||||
|
@ObservedObject private var settings = SettingsModel.shared
|
||||||
|
|
||||||
@Default(.sponsorBlockInstance) private var sponsorBlockInstance
|
@Default(.sponsorBlockInstance) private var sponsorBlockInstance
|
||||||
@Default(.sponsorBlockCategories) private var sponsorBlockCategories
|
@Default(.sponsorBlockCategories) private var sponsorBlockCategories
|
||||||
|
@Default(.sponsorBlockColors) private var sponsorBlockColors
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
sections
|
sections
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
#else
|
#else
|
||||||
List {
|
List {
|
||||||
@ -35,41 +38,63 @@ struct SponsorBlockSettings: View {
|
|||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
|
.disableAutocorrection(true)
|
||||||
.keyboardType(.URL)
|
.keyboardType(.URL)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Section(header: SettingsHeader(text: "Categories to Skip".localized())) {
|
||||||
|
categoryRows
|
||||||
|
}
|
||||||
|
colorSection
|
||||||
|
|
||||||
Section(header: SettingsHeader(text: "Categories to Skip".localized()), footer: categoriesDetails) {
|
Button {
|
||||||
#if os(macOS)
|
settings.presentAlert(
|
||||||
let list = ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
Alert(
|
||||||
MultiselectRow(
|
title: Text("Restore Default Colors?"),
|
||||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
message: Text("This action will reset all custom colors back to their original defaults. " +
|
||||||
selected: sponsorBlockCategories.contains(category)
|
"Any custom color changes you've made will be lost."),
|
||||||
) { value in
|
primaryButton: .destructive(Text("Restore")) {
|
||||||
toggleCategory(category, value: value)
|
resetColors()
|
||||||
}
|
},
|
||||||
}
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} label: {
|
||||||
|
Text("Restore Default Colors …")
|
||||||
|
.foregroundColor(.red)
|
||||||
|
}
|
||||||
|
|
||||||
Group {
|
Section(footer: categoriesDetails) {
|
||||||
if #available(macOS 12.0, *) {
|
EmptyView()
|
||||||
list
|
}
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
}
|
||||||
} else {
|
}
|
||||||
list
|
|
||||||
.listStyle(.inset)
|
private var colorSection: some View {
|
||||||
}
|
Section(header: SettingsHeader(text: "Colors for Categories")) {
|
||||||
}
|
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||||
Spacer()
|
LazyVStack(alignment: .leading) {
|
||||||
#else
|
ColorPicker(
|
||||||
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||||
MultiselectRow(
|
selection: Binding(
|
||||||
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
get: { getColor(for: category) },
|
||||||
selected: sponsorBlockCategories.contains(category)
|
set: { setColor($0, for: category) }
|
||||||
) { value in
|
)
|
||||||
toggleCategory(category, value: value)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var categoryRows: some View {
|
||||||
|
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||||
|
LazyVStack(alignment: .leading) {
|
||||||
|
MultiselectRow(
|
||||||
|
title: SponsorBlockAPI.categoryDescription(category) ?? "Unknown",
|
||||||
|
selected: sponsorBlockCategories.contains(category)
|
||||||
|
) { value in
|
||||||
|
toggleCategory(category, value: value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +115,6 @@ struct SponsorBlockSettings: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.padding(.top, 10)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleCategory(_ category: String, value: Bool) {
|
func toggleCategory(_ category: String, value: Bool) {
|
||||||
@ -100,6 +124,40 @@ struct SponsorBlockSettings: View {
|
|||||||
sponsorBlockCategories.insert(category)
|
sponsorBlockCategories.insert(category)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func getColor(for category: String) -> Color {
|
||||||
|
if let hexString = sponsorBlockColors[category], let rgbValue = Int(hexString.dropFirst(), radix: 16) {
|
||||||
|
let r = Double((rgbValue >> 16) & 0xFF) / 255.0
|
||||||
|
let g = Double((rgbValue >> 8) & 0xFF) / 255.0
|
||||||
|
let b = Double(rgbValue & 0xFF) / 255.0
|
||||||
|
return Color(red: r, green: g, blue: b)
|
||||||
|
}
|
||||||
|
return Color("AppRedColor") // Fallback color if no match found
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setColor(_ color: Color, for category: String) {
|
||||||
|
let uiColor = UIColor(color)
|
||||||
|
|
||||||
|
// swiftlint:disable no_cgfloat
|
||||||
|
var red: CGFloat = 0
|
||||||
|
var green: CGFloat = 0
|
||||||
|
var blue: CGFloat = 0
|
||||||
|
var alpha: CGFloat = 0
|
||||||
|
// swiftlint:enable no_cgfloat
|
||||||
|
|
||||||
|
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
||||||
|
|
||||||
|
let r = Int(red * 255.0)
|
||||||
|
let g = Int(green * 255.0)
|
||||||
|
let b = Int(blue * 255.0)
|
||||||
|
|
||||||
|
let rgbValue = (r << 16) | (g << 8) | b
|
||||||
|
sponsorBlockColors[category] = String(format: "#%06x", rgbValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func resetColors() {
|
||||||
|
sponsorBlockColors = SponsorBlockColors.dictionary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SponsorBlockSettings_Previews: PreviewProvider {
|
struct SponsorBlockSettings_Previews: PreviewProvider {
|
||||||
|
Loading…
Reference in New Issue
Block a user