Actions: Fix default action settings

Since actions use a new API, update default actions to use the
same API rather than the legacy models. If an action is removed,
a prompt will tell the user to change their default debrid/magnet
action and default to the choice sheet.

Also add extra UI fixes and cleanup.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2023-03-01 18:31:29 -05:00
parent 0661ed66f3
commit f622b7af05
19 changed files with 301 additions and 299 deletions

View file

@ -81,8 +81,7 @@
0C84F4842895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47C2895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift */; };
0C84F4852895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47D2895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift */; };
0C871BDF29994D9D005279AC /* FilterLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C871BDE29994D9D005279AC /* FilterLabelView.swift */; };
0C95D8D828A55B03005E22B3 /* DefaultActionsPickerViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C95D8D728A55B03005E22B3 /* DefaultActionsPickerViews.swift */; };
0C95D8DA28A55BB6005E22B3 /* SettingsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C95D8D928A55BB6005E22B3 /* SettingsModels.swift */; };
0C95D8D828A55B03005E22B3 /* DefaultActionPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C95D8D728A55B03005E22B3 /* DefaultActionPickerView.swift */; };
0CA05457288EE58200850554 /* SettingsPluginListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA05456288EE58200850554 /* SettingsPluginListView.swift */; };
0CA05459288EE9E600850554 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA05458288EE9E600850554 /* PluginManager.swift */; };
0CA0545B288EEA4E00850554 /* PluginListEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA0545A288EEA4E00850554 /* PluginListEditorView.swift */; };
@ -204,8 +203,7 @@
0C84F47C2895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceHtmlParser+CoreDataClass.swift"; sourceTree = "<group>"; };
0C84F47D2895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceHtmlParser+CoreDataProperties.swift"; sourceTree = "<group>"; };
0C871BDE29994D9D005279AC /* FilterLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterLabelView.swift; sourceTree = "<group>"; };
0C95D8D728A55B03005E22B3 /* DefaultActionsPickerViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultActionsPickerViews.swift; sourceTree = "<group>"; };
0C95D8D928A55BB6005E22B3 /* SettingsModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModels.swift; sourceTree = "<group>"; };
0C95D8D728A55B03005E22B3 /* DefaultActionPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultActionPickerView.swift; sourceTree = "<group>"; };
0CA05456288EE58200850554 /* SettingsPluginListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPluginListView.swift; sourceTree = "<group>"; };
0CA05458288EE9E600850554 /* PluginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginManager.swift; sourceTree = "<group>"; };
0CA0545A288EEA4E00850554 /* PluginListEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginListEditorView.swift; sourceTree = "<group>"; };
@ -346,7 +344,6 @@
0C422E7F293542F300486D65 /* PremiumizeModels.swift */,
0C0167DB29293FA900B65783 /* RealDebridModels.swift */,
0C41BC6428C2AEB900B47DD6 /* SearchModels.swift */,
0C95D8D928A55BB6005E22B3 /* SettingsModels.swift */,
0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */,
0C3E00D7296F5B9A00ECECB2 /* PluginModels.swift */,
);
@ -438,7 +435,7 @@
0C44E2AE28D52E8A007711AE /* BackupsView.swift */,
0CA05456288EE58200850554 /* SettingsPluginListView.swift */,
0CA0545A288EEA4E00850554 /* PluginListEditorView.swift */,
0C95D8D728A55B03005E22B3 /* DefaultActionsPickerViews.swift */,
0C95D8D728A55B03005E22B3 /* DefaultActionPickerView.swift */,
0C10848A28BD9A38008F0BA6 /* SettingsAppVersionView.swift */,
);
path = Settings;
@ -763,7 +760,7 @@
0CC389532970AD900066D06F /* Action+CoreDataClass.swift in Sources */,
0C03EB72296F619900162E9A /* PluginList+CoreDataProperties.swift in Sources */,
0C572D4C2993FC2A003EEC05 /* ViewDidAppearHandler.swift in Sources */,
0C95D8D828A55B03005E22B3 /* DefaultActionsPickerViews.swift in Sources */,
0C95D8D828A55B03005E22B3 /* DefaultActionPickerView.swift in Sources */,
0C44E2AF28D52E8A007711AE /* BackupsView.swift in Sources */,
0CA148E1288903F000DE2211 /* Collection.swift in Sources */,
0C750744289B003E004B3906 /* SourceRssParser+CoreDataClass.swift in Sources */,
@ -778,7 +775,6 @@
0CA148D8288903F000DE2211 /* ActionChoiceView.swift in Sources */,
0C41BC6528C2AEB900B47DD6 /* SearchModels.swift in Sources */,
0C68135028BC1A2D00FAD890 /* GithubWrapper.swift in Sources */,
0C95D8DA28A55BB6005E22B3 /* SettingsModels.swift in Sources */,
0CA148E3288903F000DE2211 /* Task.swift in Sources */,
0CA148E7288903F000DE2211 /* ToastViewModel.swift in Sources */,
0C6C7C9D29315292002DF910 /* AllDebridModels.swift in Sources */,

View file

@ -1,32 +0,0 @@
//
// SettingsModels.swift
// Ferrite
//
// Created by Brian Dashore on 8/11/22.
//
import Foundation
public enum DefaultMagnetActionType: Int, CaseIterable {
// Let the user choose
case none = 0
// Open in actions come first
case webtor = 1
// Sharing actions come last
case shareMagnet = 2
}
public enum DefaultDebridActionType: Int, CaseIterable {
// Let the user choose
case none = 0
// Open in actions come first
case outplayer = 1
case vlc = 2
case infuse = 3
// Sharing actions come last
case shareDownload = 4
}

View file

@ -8,16 +8,16 @@
import SwiftUI
@MainActor
class NavigationViewModel: ObservableObject {
public class NavigationViewModel: ObservableObject {
var toastModel: ToastViewModel?
// Used between SearchResultsView and MagnetChoiceView
enum ChoiceSheetType: Identifiable {
var id: Int {
public enum ChoiceSheetType: Identifiable {
public var id: Int {
hashValue
}
case magnet
case action
case batch
case activity
}
@ -66,82 +66,4 @@ class NavigationViewModel: ObservableObject {
@Published var libraryPickerSelection: LibraryPickerSegment = .bookmarks
@Published var pluginPickerSelection: PluginPickerSegment = .sources
@AppStorage("Actions.DefaultDebrid") var defaultDebridAction: DefaultDebridActionType = .none
@AppStorage("Actions.DefaultMagnet") var defaultMagnetAction: DefaultMagnetActionType = .none
// TODO: Fix for new Actions API
public func runDebridAction(urlString: String, _ action: DefaultDebridActionType? = nil) {
currentChoiceSheet = .magnet
/*
let selectedAction = action ?? defaultDebridAction
switch selectedAction {
case .none:
currentChoiceSheet = .magnet
case .outplayer:
if let downloadUrl = URL(string: "outplayer://\(urlString)") {
UIApplication.shared.open(downloadUrl)
} else {
toastModel?.updateToastDescription("Could not create an Outplayer URL")
}
case .vlc:
if let downloadUrl = URL(string: "vlc://\(urlString)") {
UIApplication.shared.open(downloadUrl)
} else {
toastModel?.updateToastDescription("Could not create a VLC URL")
}
case .infuse:
if let downloadUrl = URL(string: "infuse://x-callback-url/play?url=\(urlString)") {
UIApplication.shared.open(downloadUrl)
} else {
toastModel?.updateToastDescription("Could not create a Infuse URL")
}
case .shareDownload:
if let downloadUrl = URL(string: urlString), currentChoiceSheet == nil {
activityItems = [downloadUrl]
currentChoiceSheet = .activity
} else {
toastModel?.updateToastDescription("Could not create object for sharing")
}
}
*/
}
// TODO: Fix for new Actions API
public func runMagnetAction(magnet: Magnet?, _ action: DefaultMagnetActionType? = nil) {
currentChoiceSheet = .magnet
// Fall back to selected magnet if the provided magnet is nil
/*
let magnet = magnet ?? selectedMagnet
guard let magnetLink = magnet?.link else {
toastModel?.updateToastDescription("Could not run your action because the magnet link is invalid.")
print("Magnet action error: The magnet link is invalid.")
return
}
let selectedAction = action ?? defaultMagnetAction
switch selectedAction {
case .none:
currentChoiceSheet = .magnet
case .webtor:
if let url = URL(string: "https://webtor.io/#/show?magnet=\(magnetLink)") {
UIApplication.shared.open(url)
} else {
toastModel?.updateToastDescription("Could not create a WebTor URL")
}
case .shareMagnet:
if let magnetUrl = URL(string: magnetLink),
currentChoiceSheet == nil
{
activityItems = [magnetUrl]
currentChoiceSheet = .activity
} else {
toastModel?.updateToastDescription("Could not create object for sharing")
}
}
*/
}
}

View file

@ -14,6 +14,8 @@ public class PluginManager: ObservableObject {
@Published var availableSources: [SourceJson] = []
@Published var availableActions: [ActionJson] = []
@Published var showBrokenDefaultActionAlert = false
@MainActor
public func fetchPluginsFromUrl() async {
let pluginListRequest = PluginList.fetchRequest()
@ -162,6 +164,58 @@ public class PluginManager: ObservableObject {
}
}
@MainActor
public func runDebridAction(urlString: String?, currentChoiceSheet: inout NavigationViewModel.ChoiceSheetType?) {
let context = PersistenceController.shared.backgroundContext
if
let defaultDebridActionName = UserDefaults.standard.string(forKey: "Actions.DefaultDebridName"),
let defaultDebridActionList = UserDefaults.standard.string(forKey: "Actions.DefaultDebridList")
{
let actionFetchRequest = Action.fetchRequest()
actionFetchRequest.fetchLimit = 1
actionFetchRequest.predicate = NSPredicate(format: "name == %@ AND listId == %@", defaultDebridActionName, defaultDebridActionList)
if let fetchedAction = try? context.fetch(actionFetchRequest).first {
runDeeplinkAction(fetchedAction, urlString: urlString)
} else {
currentChoiceSheet = .action
UserDefaults.standard.set(nil, forKey: "Actions.DefaultDebridName")
UserDefaults.standard.set(nil, forKey: "Action.DefaultDebridList")
showBrokenDefaultActionAlert.toggle()
}
} else {
currentChoiceSheet = .action
}
}
@MainActor
public func runMagnetAction(urlString: String?, currentChoiceSheet: inout NavigationViewModel.ChoiceSheetType?) {
let context = PersistenceController.shared.backgroundContext
if
let defaultMagnetActionName = UserDefaults.standard.string(forKey: "Actions.DefaultMagnetName"),
let defaultMagnetActionList = UserDefaults.standard.string(forKey: "Actions.DefaultMagnetList")
{
let actionFetchRequest = Action.fetchRequest()
actionFetchRequest.fetchLimit = 1
actionFetchRequest.predicate = NSPredicate(format: "name == %@ AND listId == %@", defaultMagnetActionName, defaultMagnetActionList)
if let fetchedAction = try? context.fetch(actionFetchRequest).first {
runDeeplinkAction(fetchedAction, urlString: urlString)
} else {
currentChoiceSheet = .action
UserDefaults.standard.set(nil, forKey: "Actions.DefaultMagnetName")
UserDefaults.standard.set(nil, forKey: "Actions.DefaultMagnetList")
showBrokenDefaultActionAlert.toggle()
}
} else {
currentChoiceSheet = .action
}
}
// The iOS version of Ferrite only runs deeplink actions
@MainActor
public func runDeeplinkAction(_ action: Action, urlString: String?) {

View file

@ -10,6 +10,7 @@ import SwiftUI
struct AllDebridCloudView: View {
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var pluginManager: PluginManager
@Binding var searchText: String
@ -38,7 +39,10 @@ struct AllDebridCloudView: View {
if !debridManager.downloadUrl.isEmpty {
historyInfo.url = debridManager.downloadUrl
PersistenceController.shared.createHistory(historyInfo, performSave: true)
navModel.runDebridAction(urlString: debridManager.downloadUrl)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
}
} else {

View file

@ -11,6 +11,7 @@ import SwiftUIX
struct PremiumizeCloudView: View {
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var pluginManager: PluginManager
@Binding var searchText: String
@ -38,7 +39,10 @@ struct PremiumizeCloudView: View {
performSave: true
)
navModel.runDebridAction(urlString: debridManager.downloadUrl)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
}
}

View file

@ -10,6 +10,7 @@ import SwiftUI
struct RealDebridCloudView: View {
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var pluginManager: PluginManager
@Binding var searchText: String
@ -35,7 +36,10 @@ struct RealDebridCloudView: View {
performSave: true
)
navModel.runDebridAction(urlString: debridManager.downloadUrl)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
.backport.tint(.primary)
}
@ -72,7 +76,10 @@ struct RealDebridCloudView: View {
historyInfo.url = debridManager.downloadUrl
PersistenceController.shared.createHistory(historyInfo, performSave: true)
navModel.runDebridAction(urlString: debridManager.downloadUrl)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
}
} else {

View file

@ -11,6 +11,7 @@ struct HistoryButtonView: View {
@EnvironmentObject var toastModel: ToastViewModel
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var pluginManager: PluginManager
let entry: HistoryEntry
@ -23,14 +24,20 @@ struct HistoryButtonView: View {
if url.starts(with: "https://") {
Task {
debridManager.downloadUrl = url
navModel.runDebridAction(urlString: url)
pluginManager.runDebridAction(
urlString: url,
currentChoiceSheet: &navModel.currentChoiceSheet
)
if navModel.currentChoiceSheet != .magnet {
if navModel.currentChoiceSheet != .action {
debridManager.downloadUrl = ""
}
}
} else {
navModel.runMagnetAction(magnet: Magnet(hash: nil, link: url))
pluginManager.runMagnetAction(
urlString: url,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
} else {
toastModel.updateToastDescription("URL invalid. Cannot load this history entry. Please delete it.")

View file

@ -12,6 +12,11 @@ struct SourceSettingsView: View {
@EnvironmentObject var navModel: NavigationViewModel
@FetchRequest(
entity: PluginList.entity(),
sortDescriptors: []
) var pluginLists: FetchedResults<PluginList>
var body: some View {
NavView {
List {
@ -32,10 +37,12 @@ struct SourceSettingsView: View {
Group {
Text("ID: \(selectedSource.id)")
if let listId = selectedSource.listId {
Text("List ID: \(listId)")
if let pluginList = pluginLists.first(where: { $0.id == selectedSource.listId })
{
Text("List: \(pluginList.name)")
Text("List ID: \(pluginList.id.uuidString)")
} else {
Text("No list ID found. This source should be removed.")
Text("No plugin list found. This source should be removed.")
}
}
.foregroundColor(.secondary)

View file

@ -12,6 +12,7 @@ struct SearchResultButtonView: View {
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var pluginManager: PluginManager
var result: SearchResult
@ -42,9 +43,12 @@ struct SearchResultButtonView: View {
performSave: true
)
navModel.runDebridAction(urlString: debridManager.downloadUrl)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
if navModel.currentChoiceSheet != .magnet {
if navModel.currentChoiceSheet != .action {
debridManager.downloadUrl = ""
}
}
@ -68,7 +72,10 @@ struct SearchResultButtonView: View {
performSave: true
)
navModel.runMagnetAction(magnet: result.magnet)
pluginManager.runMagnetAction(
urlString: result.magnet.link,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
}
} label: {

View file

@ -0,0 +1,109 @@
//
// DefaultActionsPickerViews.swift
// Ferrite
//
// Created by Brian Dashore on 8/11/22.
//
import SwiftUI
struct DefaultActionPickerView: View {
@EnvironmentObject var toastModel: ToastViewModel
let actionRequirement: ActionRequirement
@Binding var defaultActionName: String?
@Binding var defaultActionList: String?
@FetchRequest(
entity: Action.entity(),
sortDescriptors: []
) var actions: FetchedResults<Action>
@FetchRequest(
entity: PluginList.entity(),
sortDescriptors: []
) var pluginLists: FetchedResults<PluginList>
var body: some View {
List {
UserChoiceButton(
defaultActionName: $defaultActionName,
defaultActionList: $defaultActionList,
pluginLists: pluginLists
)
ForEach(actions.filter { $0.requires.contains(actionRequirement.rawValue) }, id: \.id) { action in
Button {
if let actionListId = action.listId?.uuidString {
defaultActionName = action.name
defaultActionList = actionListId
} else {
toastModel.updateToastDescription(
"Default action error: This action doesn't have a corresponding plugin list! Please uninstall the action"
)
}
} label: {
HStack {
VStack(alignment: .leading, spacing: 5) {
Text(action.name)
Group {
if let pluginList = pluginLists.first(where: { $0.id == action.listId }) {
Text("List: \(pluginList.name)")
Text(pluginList.id.uuidString)
.font(.caption)
} else {
Text("No plugin list found")
.font(.caption)
}
}
.foregroundColor(.secondary)
}
Spacer()
if
let defaultActionList,
action.listId?.uuidString == defaultActionList,
action.name == defaultActionName
{
Image(systemName: "checkmark")
.foregroundColor(.blue)
}
}
}
.backport.tint(.primary)
}
}
.listStyle(.insetGrouped)
.inlinedList(inset: -20)
.navigationTitle("Default \(actionRequirement == .debrid ? "debrid" : "magnet") action")
.navigationBarTitleDisplayMode(.inline)
}
}
private struct UserChoiceButton: View {
@Binding var defaultActionName: String?
@Binding var defaultActionList: String?
var pluginLists: FetchedResults<PluginList>
var body: some View {
Button {
defaultActionName = nil
defaultActionList = nil
} label: {
HStack {
Text("Let me choose")
Spacer()
// Force "Let me choose" if the name OR list ID is nil
// Prevents any mismatches
if defaultActionName == nil || pluginLists.contains(where: { $0.id.uuidString == defaultActionList }) {
Image(systemName: "checkmark")
.foregroundColor(.blue)
}
}
}
.backport.tint(.primary)
}
}

View file

@ -1,90 +0,0 @@
//
// DefaultActionsPickerViews.swift
// Ferrite
//
// Created by Brian Dashore on 8/11/22.
//
import SwiftUI
struct MagnetActionPickerView: View {
@AppStorage("Actions.DefaultMagnet") var defaultMagnetAction: DefaultMagnetActionType = .none
var body: some View {
List {
ForEach(DefaultMagnetActionType.allCases, id: \.self) { action in
Button {
defaultMagnetAction = action
} label: {
HStack {
Text(fetchPickerChoiceName(choice: action))
Spacer()
if action == defaultMagnetAction {
Image(systemName: "checkmark")
.foregroundColor(.blue)
}
}
}
.backport.tint(.primary)
}
}
.listStyle(.insetGrouped)
.inlinedList(inset: -20)
.navigationTitle("Default magnet action")
.navigationBarTitleDisplayMode(.inline)
}
func fetchPickerChoiceName(choice: DefaultMagnetActionType) -> String {
switch choice {
case .none:
return "Let me choose"
case .webtor:
return "Open in Webtor"
case .shareMagnet:
return "Share magnet link"
}
}
}
struct DebridActionPickerView: View {
@AppStorage("Actions.DefaultDebrid") var defaultDebridAction: DefaultDebridActionType = .none
var body: some View {
List {
ForEach(DefaultDebridActionType.allCases, id: \.self) { action in
Button {
defaultDebridAction = action
} label: {
HStack {
Text(fetchPickerChoiceName(choice: action))
Spacer()
if action == defaultDebridAction {
Image(systemName: "checkmark")
.foregroundColor(.blue)
}
}
}
.backport.tint(.primary)
}
}
.listStyle(.insetGrouped)
.inlinedList(inset: -20)
.navigationTitle("Default debrid action")
.navigationBarTitleDisplayMode(.inline)
}
func fetchPickerChoiceName(choice: DefaultDebridActionType) -> String {
switch choice {
case .none:
return "Let me choose"
case .outplayer:
return "Open in Outplayer"
case .vlc:
return "Open in VLC"
case .infuse:
return "Open in Infuse"
case .shareDownload:
return "Share download link"
}
}
}

View file

@ -30,12 +30,13 @@ struct SettingsPluginListView: View {
VStack(alignment: .leading, spacing: 5) {
Text(pluginList.name)
Text(pluginList.author)
.foregroundColor(.gray)
Group {
Text(pluginList.author)
Text("ID: \(pluginList.id)")
.font(.caption)
.foregroundColor(.gray)
Text("ID: \(pluginList.id)")
.font(.caption)
}
.foregroundColor(.secondary)
}
.padding(.vertical, 2)
.contextMenu {

View file

@ -44,6 +44,22 @@ struct LibraryView: View {
DebridCloudView(searchText: $searchText)
}
}
.overlay {
switch navModel.libraryPickerSelection {
case .bookmarks:
if bookmarks.isEmpty {
EmptyInstructionView(title: "No Bookmarks", message: "Add a bookmark from search results")
}
case .history:
if history.isEmpty {
EmptyInstructionView(title: "No History", message: "Start watching to build history")
}
case .debridCloud:
if debridManager.selectedDebridType == nil {
EmptyInstructionView(title: "Cloud Unavailable", message: "Listing is not available for this service")
}
}
}
.navigationTitle("Library")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
@ -83,22 +99,6 @@ struct LibraryView: View {
}
.environment(\.editMode, $editMode)
}
.overlay {
switch navModel.libraryPickerSelection {
case .bookmarks:
if bookmarks.isEmpty {
EmptyInstructionView(title: "No Bookmarks", message: "Add a bookmark from search results")
}
case .history:
if history.isEmpty {
EmptyInstructionView(title: "No History", message: "Start watching to build history")
}
case .debridCloud:
if debridManager.selectedDebridType == nil {
EmptyInstructionView(title: "Cloud Unavailable", message: "Listing is not available for this service")
}
}
}
.onChange(of: navModel.libraryPickerSelection) { _ in
editMode = .inactive
}

View file

@ -51,7 +51,7 @@ struct MainView: View {
}
.sheet(item: $navModel.currentChoiceSheet) { item in
switch item {
case .magnet:
case .action:
ActionChoiceView()
.environmentObject(debridManager)
.environmentObject(scrapingModel)
@ -139,7 +139,9 @@ struct MainView: View {
.backport.alert(
isPresented: $showUpdateAlert,
title: "Update available",
message: "Ferrite \(releaseVersionString) can be downloaded. \n\nThis alert can be disabled in Settings.",
message:
"Ferrite \(releaseVersionString) can be downloaded. \n\n" +
"This alert can be disabled in Settings.",
buttons: [
.init("Download") {
guard let releaseUrl = URL(string: releaseUrlString) else {

View file

@ -44,6 +44,22 @@ struct PluginsView: View {
}
}
}
.overlay {
if checkedForPlugins {
switch navModel.pluginPickerSelection {
case .sources:
if sources.isEmpty && pluginManager.availableSources.isEmpty {
EmptyInstructionView(title: "No Sources", message: "Add a plugin list in Settings")
}
case .actions:
if actions.isEmpty && pluginManager.availableActions.isEmpty {
EmptyInstructionView(title: "No Actions", message: "Add a plugin list in Settings")
}
}
} else {
ProgressView()
}
}
.backport.onAppear {
viewTask = Task {
await pluginManager.fetchPluginsFromUrl()
@ -71,22 +87,6 @@ struct PluginsView: View {
.environmentObject(navModel)
}
}
.overlay {
if checkedForPlugins {
switch navModel.pluginPickerSelection {
case .sources:
if sources.isEmpty && pluginManager.availableSources.isEmpty {
EmptyInstructionView(title: "No Sources", message: "Add a plugin list in Settings")
}
case .actions:
if actions.isEmpty && pluginManager.availableActions.isEmpty {
EmptyInstructionView(title: "No Actions", message: "Add a plugin list in Settings")
}
}
} else {
ProgressView()
}
}
}
}

View file

@ -20,8 +20,11 @@ struct SettingsView: View {
@AppStorage("Updates.AutomaticNotifs") var autoUpdateNotifs = true
@AppStorage("Actions.DefaultDebrid") var defaultDebridAction: DefaultDebridActionType = .none
@AppStorage("Actions.DefaultMagnet") var defaultMagnetAction: DefaultMagnetActionType = .none
@AppStorage("Actions.DefaultDebridName") var defaultDebridActionName: String?
@AppStorage("Actions.DefaultDebridList") var defaultDebridActionList: String?
@AppStorage("Actions.DefaultMagnetName") var defaultMagnetActionName: String?
@AppStorage("Actions.DefaultMagnetList") var defaultMagnetActionList: String?
var body: some View {
NavView {
@ -94,50 +97,40 @@ struct SettingsView: View {
}
Section(header: InlineHeader("Default actions")) {
if debridManager.enabledDebrids.count > 0 {
//if debridManager.enabledDebrids.count > 0 {
NavigationLink(
destination: DebridActionPickerView(),
destination: DefaultActionPickerView(
actionRequirement: .debrid,
defaultActionName: $defaultDebridActionName,
defaultActionList: $defaultDebridActionList
),
label: {
HStack {
Text("Default debrid action")
Text("Debrid action")
Spacer()
Group {
switch defaultDebridAction {
case .none:
Text("User choice")
case .outplayer:
Text("Outplayer")
case .vlc:
Text("VLC")
case .infuse:
Text("Infuse")
case .shareDownload:
Text("Share")
}
}
.foregroundColor(.gray)
// TODO: Maybe make this check for nil list as well?
Text(defaultDebridActionName.map { $0 } ?? "User choice")
.foregroundColor(.secondary)
}
}
)
}
//}
NavigationLink(
destination: MagnetActionPickerView(),
destination: DefaultActionPickerView(
actionRequirement: .magnet,
defaultActionName: $defaultMagnetActionName,
defaultActionList: $defaultMagnetActionList
),
label: {
HStack {
Text("Default magnet action")
Text("Magnet action")
Spacer()
Group {
switch defaultMagnetAction {
case .none:
Text("User choice")
case .webtor:
Text("Webtor")
case .shareMagnet:
Text("Share")
}
}
.foregroundColor(.gray)
// TODO: Maybe make this check for nil list as well?
Text(defaultMagnetActionName.map { $0 } ?? "User choice")
.foregroundColor(.secondary)
}
}
)

View file

@ -112,6 +112,13 @@ struct ActionChoiceView: View {
AppActivityView(activityItems: navModel.activityItems)
}
}
.backport.alert(
isPresented: $pluginManager.showBrokenDefaultActionAlert,
title: "Action not found",
message:
"The default action could not be run. The action choice sheet has been opened. \n\n" +
"Please check your default actions in Settings"
)
.onDisappear {
debridManager.downloadUrl = ""
navModel.selectedTitle = ""

View file

@ -11,6 +11,7 @@ struct BatchChoiceView: View {
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var scrapingModel: ScrapingViewModel
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var pluginManager: PluginManager
let backgroundContext = PersistenceController.shared.backgroundContext
@ -83,7 +84,10 @@ struct BatchChoiceView: View {
PersistenceController.shared.createHistory(selectedHistoryInfo, performSave: true)
}
navModel.runDebridAction(urlString: debridManager.downloadUrl, nil)
pluginManager.runDebridAction(
urlString: debridManager.downloadUrl,
currentChoiceSheet: &navModel.currentChoiceSheet
)
}
debridManager.clearSelectedDebridItems()