mirror of
https://github.com/whoeevee/EeveeSpotifyReborn.git
synced 2026-01-09 00:23:20 +01:00
experiments
This commit is contained in:
1 parent
92e6cc7900
commit
a994490604
36 files changed
+264
-64
No files matched your search
+5
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTSharingSDKDestination {
|
||||
func destinationID() -> String
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
struct InstgramDestinationGroup: HookGroup { }
|
||||
|
||||
class SPTSharingSDKHook: ClassHook<NSObject> {
|
||||
typealias Group = InstgramDestinationGroup
|
||||
static let targetName = "SPTSharingSDK"
|
||||
|
||||
func canHandleShareDestination(_ destination: SPTSharingSDKDestination) -> Bool {
|
||||
if destination.destinationID().contains("instagram") {
|
||||
return true
|
||||
}
|
||||
|
||||
return orig.canHandleShareDestination(destination)
|
||||
}
|
||||
}
|
||||
|
||||
class FoundationImplPropertiesHook: ClassHook<NSObject> {
|
||||
typealias Group = InstgramDestinationGroup
|
||||
static let targetName = "SPTShare_FoundationImplProperties"
|
||||
|
||||
func isInstagramStoriesCanvasSharingEnabled() -> Bool { return true }
|
||||
func isInstagramDirectMessageSharingEnabled() -> Bool { return true }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
class UIApplicationLiveContainerSharingHook: ClassHook<UIApplication> {
|
||||
func openURL(
|
||||
_ url: URL,
|
||||
options: [String: Any],
|
||||
completionHandler: (@MainActor (ObjCBool) -> Void)?
|
||||
) {
|
||||
if UserDefaults.experimentsOptions.liveContainerSharing, !target.canOpenURL(url) {
|
||||
UIPasteboard.general.addItems([[UTType.url.identifier: url]])
|
||||
|
||||
let data = url.dataRepresentation
|
||||
let liveContainerUrl = URL(string: "livecontainer://open-web-page?url=\(data.base64EncodedString())")!
|
||||
|
||||
orig.openURL(
|
||||
liveContainerUrl,
|
||||
options: options,
|
||||
completionHandler: { success in
|
||||
completionHandler?(true)
|
||||
|
||||
if !success.boolValue {
|
||||
PopUpHelper.showPopUp(
|
||||
delayed: false,
|
||||
message: "could_not_share_popup".localized,
|
||||
buttonText: "OK".uiKitLocalized
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
orig.openURL(url, options: options, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
@UserDefault(
|
||||
key: "experimentsOptions",
|
||||
defaultValue: ExperimentsOptions(
|
||||
showInstagramDestination: false,
|
||||
liveContainerSharing: true
|
||||
)
|
||||
)
|
||||
static var experimentsOptions
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
struct ExperimentsOptions: Codable, Equatable {
|
||||
var showInstagramDestination: Bool
|
||||
var liveContainerSharing: Bool
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@objc protocol NowPlayingScrollViewController {
|
||||
func collectionView() -> UICollectionView
|
||||
func nowPlayingScrollViewModelDidChangeScrollEnabledValue()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTPlayerTrack {
|
||||
func setMetadata(_ metadata: [String:String])
|
||||
func metadata() -> [String:String]
|
||||
func extractedColorHex() -> String?
|
||||
func trackTitle() -> String
|
||||
func artistTitle() -> String
|
||||
func artistName() -> String
|
||||
func URI() -> SPTURL
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
@UserDefault(
|
||||
key: "lyricsColors",
|
||||
defaultValue: LyricsColorOptions(
|
||||
displayOriginalColors: true,
|
||||
useStaticColor: false,
|
||||
staticColor: "",
|
||||
normalizationFactor: 0.5
|
||||
)
|
||||
)
|
||||
static var lyricsColors
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
struct LyricsColorsSettings: Codable, Equatable {
|
||||
struct LyricsColorOptions: Codable, Equatable {
|
||||
var displayOriginalColors: Bool
|
||||
var useStaticColor: Bool
|
||||
var staticColor: String
|
||||
@@ -0,0 +1,15 @@
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
@UserDefault(
|
||||
key: "lyricsOptions",
|
||||
defaultValue: LyricsOptions(
|
||||
romanization: false,
|
||||
musixmatchLanguage: Locale.current.languageCode ?? "",
|
||||
lrclibUrl: LrclibLyricsRepository.originalApiUrl,
|
||||
geniusFallback: true,
|
||||
showFallbackReasons: true
|
||||
)
|
||||
)
|
||||
static var lyricsOptions
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
private static let lyricsSourceKey = "lyricsSource"
|
||||
|
||||
static var lyricsSource: LyricsSource {
|
||||
get {
|
||||
if let rawValue = container.object(forKey: lyricsSourceKey) as? Int {
|
||||
return LyricsSource(rawValue: rawValue)!
|
||||
}
|
||||
|
||||
return LyricsSource.defaultSource
|
||||
}
|
||||
set (newSource) {
|
||||
container.set(newSource.rawValue, forKey: lyricsSourceKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct EeveeExperimentsSettingsView: View {
|
||||
@State var experimentsOptions = UserDefaults.experimentsOptions
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(footer: Text("livecontainer_sharing_description".localized)) {
|
||||
Toggle(
|
||||
"livecontainer_sharing".localized,
|
||||
isOn: $experimentsOptions.liveContainerSharing
|
||||
)
|
||||
}
|
||||
|
||||
Section(
|
||||
footer: Text("show_instagram_destination_description"
|
||||
.localizeWithFormat("restart_is_required_description".localized))
|
||||
) {
|
||||
Toggle(
|
||||
"show_instagram_destination".localized,
|
||||
isOn: $experimentsOptions.showInstagramDestination
|
||||
)
|
||||
}
|
||||
}
|
||||
.onChange(of: experimentsOptions) { options in
|
||||
UserDefaults.experimentsOptions = options
|
||||
|
||||
if options.showInstagramDestination {
|
||||
OfflineHelper.resetData()
|
||||
}
|
||||
}
|
||||
|
||||
.listStyle(GroupedListStyle())
|
||||
.animation(.default, value: experimentsOptions)
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,23 @@
|
||||
import Foundation
|
||||
|
||||
@propertyWrapper
|
||||
struct UserDefault<T: Codable> {
|
||||
let key: String
|
||||
let defaultValue: T
|
||||
var container: UserDefaults = .standard
|
||||
|
||||
var wrappedValue: T {
|
||||
get {
|
||||
if let data = container.data(forKey: key),
|
||||
let value = try? JSONDecoder().decode(T.self, from: data) {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
set {
|
||||
if let data = try? JSONEncoder().encode(newValue) {
|
||||
container.set(data, forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,19 @@ struct EeveeSettingsView: View {
|
||||
)
|
||||
}
|
||||
|
||||
Button {
|
||||
pushSettingsController(
|
||||
with: EeveeExperimentsSettingsView(),
|
||||
title: "experiments".localized
|
||||
)
|
||||
} label: {
|
||||
NavigationSectionView(
|
||||
color: .purple,
|
||||
title: "experiments".localized,
|
||||
imageSystemName: "sparkle"
|
||||
)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Section(footer: Text("reset_data_description".localized)) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
extension UserDefaults {
|
||||
private static let defaults = UserDefaults.standard
|
||||
static var container: UserDefaults = .standard
|
||||
|
||||
private static let lyricsSourceKey = "lyricsSource"
|
||||
private static let musixmatchTokenKey = "musixmatchToken"
|
||||
private static let darkPopUpsKey = "darkPopUps"
|
||||
private static let patchTypeKey = "patchType"
|
||||
@@ -12,103 +11,52 @@ extension UserDefaults {
|
||||
private static let lyricsOptionsKey = "lyricsOptions"
|
||||
private static let hasShownCommonIssuesTipKey = "hasShownCommonIssuesTip"
|
||||
|
||||
static var lyricsSource: LyricsSource {
|
||||
get {
|
||||
if let rawValue = defaults.object(forKey: lyricsSourceKey) as? Int {
|
||||
return LyricsSource(rawValue: rawValue)!
|
||||
}
|
||||
|
||||
return LyricsSource.defaultSource
|
||||
}
|
||||
set (newSource) {
|
||||
defaults.set(newSource.rawValue, forKey: lyricsSourceKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var musixmatchToken: String {
|
||||
get {
|
||||
defaults.string(forKey: musixmatchTokenKey) ?? ""
|
||||
container.string(forKey: musixmatchTokenKey) ?? ""
|
||||
}
|
||||
set (token) {
|
||||
defaults.set(token, forKey: musixmatchTokenKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var lyricsOptions: LyricsOptions {
|
||||
get {
|
||||
if let data = defaults.object(forKey: lyricsOptionsKey) as? Data,
|
||||
let lyricsOptions = try? JSONDecoder().decode(LyricsOptions.self, from: data) {
|
||||
return lyricsOptions
|
||||
}
|
||||
|
||||
return LyricsOptions(
|
||||
romanization: false,
|
||||
musixmatchLanguage: Locale.current.languageCode ?? "",
|
||||
lrclibUrl: LrclibLyricsRepository.originalApiUrl,
|
||||
geniusFallback: true,
|
||||
showFallbackReasons: true
|
||||
)
|
||||
}
|
||||
set (lyricsOptions) {
|
||||
defaults.set(try! JSONEncoder().encode(lyricsOptions), forKey: lyricsOptionsKey)
|
||||
container.set(token, forKey: musixmatchTokenKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var darkPopUps: Bool {
|
||||
get {
|
||||
defaults.object(forKey: darkPopUpsKey) as? Bool ?? true
|
||||
container.object(forKey: darkPopUpsKey) as? Bool ?? true
|
||||
}
|
||||
set (darkPopUps) {
|
||||
defaults.set(darkPopUps, forKey: darkPopUpsKey)
|
||||
container.set(darkPopUps, forKey: darkPopUpsKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var patchType: PatchType {
|
||||
get {
|
||||
if let rawValue = defaults.object(forKey: patchTypeKey) as? Int {
|
||||
if let rawValue = container.object(forKey: patchTypeKey) as? Int {
|
||||
return PatchType(rawValue: rawValue) ?? .requests
|
||||
}
|
||||
|
||||
return .notSet
|
||||
}
|
||||
set (patchType) {
|
||||
defaults.set(patchType.rawValue, forKey: patchTypeKey)
|
||||
container.set(patchType.rawValue, forKey: patchTypeKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var overwriteConfiguration: Bool {
|
||||
get {
|
||||
defaults.bool(forKey: overwriteConfigurationKey)
|
||||
container.bool(forKey: overwriteConfigurationKey)
|
||||
}
|
||||
set (overwriteConfiguration) {
|
||||
defaults.set(overwriteConfiguration, forKey: overwriteConfigurationKey)
|
||||
container.set(overwriteConfiguration, forKey: overwriteConfigurationKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var hasShownCommonIssuesTip: Bool {
|
||||
get {
|
||||
defaults.bool(forKey: hasShownCommonIssuesTipKey)
|
||||
container.bool(forKey: hasShownCommonIssuesTipKey)
|
||||
}
|
||||
set (hasShownCommonIssuesTip) {
|
||||
defaults.set(hasShownCommonIssuesTip, forKey: hasShownCommonIssuesTipKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var lyricsColors: LyricsColorsSettings {
|
||||
get {
|
||||
if let data = defaults.object(forKey: lyricsColorsKey) as? Data {
|
||||
return try! JSONDecoder().decode(LyricsColorsSettings.self, from: data)
|
||||
}
|
||||
|
||||
return LyricsColorsSettings(
|
||||
displayOriginalColors: true,
|
||||
useStaticColor: false,
|
||||
staticColor: "",
|
||||
normalizationFactor: 0.5
|
||||
)
|
||||
}
|
||||
set (lyricsColors) {
|
||||
defaults.set(try! JSONEncoder().encode(lyricsColors), forKey: lyricsColorsKey)
|
||||
container.set(hasShownCommonIssuesTip, forKey: hasShownCommonIssuesTipKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,10 @@ struct EeveeSpotify: Tweak {
|
||||
}
|
||||
|
||||
init() {
|
||||
if UserDefaults.experimentsOptions.showInstagramDestination {
|
||||
InstgramDestinationGroup().activate()
|
||||
}
|
||||
|
||||
if UserDefaults.darkPopUps {
|
||||
DarkPopUps().activate()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user