Skip to content

Commit

Permalink
Added 'Select Torrents' Feature & Cleaned Up Code
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-128 committed Dec 12, 2023
1 parent 37b8b83 commit ce01376
Show file tree
Hide file tree
Showing 8 changed files with 482 additions and 130 deletions.
12 changes: 12 additions & 0 deletions qBitControl.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
90A280132B1B9A0E00A8396C /* TorrentFilterDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A280122B1B9A0E00A8396C /* TorrentFilterDemo.swift */; };
90A280152B1B9AE400A8396C /* TorrentAddFileViewDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A280142B1B9AE400A8396C /* TorrentAddFileViewDemo.swift */; };
90A280172B1B9AFD00A8396C /* TorrentAddOptionsViewDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A280162B1B9AFD00A8396C /* TorrentAddOptionsViewDemo.swift */; };
90AB9B752B2900F4005C3612 /* TorrentListToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B742B2900F4005C3612 /* TorrentListToolbar.swift */; };
90AB9B772B2901D5005C3612 /* TorrentListDefaultToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B762B2901D5005C3612 /* TorrentListDefaultToolbar.swift */; };
90AB9B792B29051B005C3612 /* TorrentListSelectionToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B782B29051B005C3612 /* TorrentListSelectionToolbar.swift */; };
90BA88552B2206F100C8A342 /* LocalNetworkPermissionClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90BA88542B2206F100C8A342 /* LocalNetworkPermissionClass.swift */; };
90BCAD19291A7C91009F1FEC /* RSSView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90BCAD18291A7C91009F1FEC /* RSSView.swift */; };
90BCAD1B291A7EC9009F1FEC /* RSSFeedArticlesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90BCAD1A291A7EC9009F1FEC /* RSSFeedArticlesView.swift */; };
Expand Down Expand Up @@ -91,6 +94,9 @@
90A280122B1B9A0E00A8396C /* TorrentFilterDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentFilterDemo.swift; sourceTree = "<group>"; };
90A280142B1B9AE400A8396C /* TorrentAddFileViewDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentAddFileViewDemo.swift; sourceTree = "<group>"; };
90A280162B1B9AFD00A8396C /* TorrentAddOptionsViewDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentAddOptionsViewDemo.swift; sourceTree = "<group>"; };
90AB9B742B2900F4005C3612 /* TorrentListToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentListToolbar.swift; sourceTree = "<group>"; };
90AB9B762B2901D5005C3612 /* TorrentListDefaultToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentListDefaultToolbar.swift; sourceTree = "<group>"; };
90AB9B782B29051B005C3612 /* TorrentListSelectionToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentListSelectionToolbar.swift; sourceTree = "<group>"; };
90BA88532B22019900C8A342 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
90BA88542B2206F100C8A342 /* LocalNetworkPermissionClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkPermissionClass.swift; sourceTree = "<group>"; };
90BCAD18291A7C91009F1FEC /* RSSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -227,6 +233,9 @@
children = (
9082FA4E2908248B006C3960 /* TorrentListView.swift */,
908315022B272FB7005B6953 /* TorrentList.swift */,
90AB9B742B2900F4005C3612 /* TorrentListToolbar.swift */,
90AB9B762B2901D5005C3612 /* TorrentListDefaultToolbar.swift */,
90AB9B782B29051B005C3612 /* TorrentListSelectionToolbar.swift */,
);
path = TorrentListView;
sourceTree = "<group>";
Expand Down Expand Up @@ -392,6 +401,7 @@
9082FA2529080E53006C3960 /* ServersView.swift in Sources */,
903DED2E290AABA800FB36D6 /* TorrentAddView.swift in Sources */,
90A2800E2B1B910E00A8396C /* TorrentListViewDemo.swift in Sources */,
90AB9B772B2901D5005C3612 /* TorrentListDefaultToolbar.swift in Sources */,
90EF6A5129095ACC001E9E7F /* TorrentRowView.swift in Sources */,
90C6F3982911529100F5A6FD /* TorrentFilterView.swift in Sources */,
909F850E290FFB73003FC051 /* TorrentAddOptionsView.swift in Sources */,
Expand All @@ -409,8 +419,10 @@
90EF6A492909267A001E9E7F /* AuthClass.swift in Sources */,
903DED30290AADB300FB36D6 /* TorrentAddMagnetView.swift in Sources */,
9082FA4F2908248B006C3960 /* TorrentListView.swift in Sources */,
90AB9B792B29051B005C3612 /* TorrentListSelectionToolbar.swift in Sources */,
90A280172B1B9AFD00A8396C /* TorrentAddOptionsViewDemo.swift in Sources */,
90FA253629190D0400DC8F0B /* FileNodeClass.swift in Sources */,
90AB9B752B2900F4005C3612 /* TorrentListToolbar.swift in Sources */,
9082FA4D29082208006C3960 /* qBittorrentClass.swift in Sources */,
90FA253829190D3100DC8F0B /* TorrentDetailsFilesView.swift in Sources */,
90896E452B13FD26001B3322 /* LoginView.swift in Sources */,
Expand Down
16 changes: 16 additions & 0 deletions qBitControl/Classes/qBittorrentClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ class qBittorrent {
qBitRequest.requestTorrentManagement(request: request)
}

static func recheckTorrents(hashes: [String]) {
let path = "/api/v2/torrents/recheck"

let request = qBitRequest.prepareURLRequest(path: path, queryItems: [URLQueryItem(name: "hashes", value: hashes.joined(separator: "|"))])

qBitRequest.requestTorrentManagement(request: request)
}

static func reannounceTorrent(hash: String) {
let path = "/api/v2/torrents/reannounce"

Expand All @@ -263,6 +271,14 @@ class qBittorrent {
qBitRequest.requestTorrentManagement(request: request)
}

static func reannounceTorrents(hashes: [String]) {
let path = "/api/v2/torrents/reannounce"

let request = qBitRequest.prepareURLRequest(path: path, queryItems: [URLQueryItem(name: "hashes", value: hashes.joined(separator: "|"))])

qBitRequest.requestTorrentManagement(request: request)
}

static func deleteTorrent(hash: String, deleteFiles: Bool) {
let path = "/api/v2/torrents/delete"

Expand Down
4 changes: 2 additions & 2 deletions qBitControl/Structures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import Foundation

struct Torrent: Decodable {
struct Torrent: Decodable, Hashable {
let added_on: Int
let amount_left: Int
let auto_tmm: Bool
Expand Down Expand Up @@ -41,7 +41,7 @@ struct Torrent: Decodable {
let seen_complete: Int
let seq_dl: Bool
let size: Int64
let state: String
var state: String
let super_seeding: Bool
let tags: String
let time_active: Int
Expand Down
35 changes: 28 additions & 7 deletions qBitControl/TorrentView/TorrentListView/TorrentList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,39 @@ struct TorrentList: View {

@State private var hash = ""

@Binding public var isSelectionMode: Bool
@Binding public var selectedTorrents: Set<Torrent>

var body: some View {
Section(header: torrentListHeader()) {
ForEach(torrents, id: \.hash) {
torrent in
if searchQuery == "" || torrent.name.lowercased().contains(searchQuery.lowercased()) {
NavigationLink {
TorrentDetailsView(torrent: torrent)
} label: {
TorrentRowView(name: torrent.name, progress: torrent.progress, state: torrent.state, dlspeed: torrent.dlspeed, upspeed: torrent.upspeed, ratio: torrent.ratio)
.contextMenu() {
torrentRowContextMenu(torrent: torrent)
if(!isSelectionMode) {
NavigationLink {
TorrentDetailsView(torrent: torrent)
} label: {
TorrentRowView(name: torrent.name, progress: torrent.progress, state: torrent.state, dlspeed: torrent.dlspeed, upspeed: torrent.upspeed, ratio: torrent.ratio)
.contextMenu() {
torrentRowContextMenu(torrent: torrent)
}
}
} else {
if(selectedTorrents.contains(torrent)) {
HStack {
Image(systemName: "checkmark.circle.fill").scaleEffect(1.25).foregroundStyle(Color(.blue))
TorrentRowView(name: torrent.name, progress: torrent.progress, state: torrent.state, dlspeed: torrent.dlspeed, upspeed: torrent.upspeed, ratio: torrent.ratio)
}.onTapGesture {
selectedTorrents.remove(torrent)
}
} else {
HStack {
Image(systemName: "circle").scaleEffect(1.25).foregroundStyle(Color(.gray))
TorrentRowView(name: torrent.name, progress: torrent.progress, state: torrent.state, dlspeed: torrent.dlspeed, upspeed: torrent.upspeed, ratio: torrent.ratio)
}.onTapGesture {
selectedTorrents.insert(torrent)
}
}
}
}
}
Expand Down Expand Up @@ -140,7 +161,7 @@ struct TorrentList: View {


func getTorrents() {
if(scenePhase != .active || isTorrentAddView) {
if(scenePhase != .active || isTorrentAddView || isSelectionMode) {
return
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//

import SwiftUI

struct TorrentListDefaultToolbar: ToolbarContent {
@Binding public var torrents: [Torrent]

@Binding public var category: String

@Binding public var isSelectionMode: Bool
@Binding public var isLoggedIn: Bool
@Binding public var isFilterView: Bool

@State private var alertIdentifier: AlertIdentifier?
@State private var isAlertClearCompleted: Bool = false

var body: some ToolbarContent {
ToolbarItem(placement: .topBarLeading) {
Menu {
Section {
Button {
isSelectionMode = true
} label: {
Image(systemName: "checkmark.circle")
Text("Select")
}
}

if(category != "None") {
Section {
Button {
let torrentsInCategory = torrents.filter {
torrent in
return torrent.category == category
}

qBittorrent.resumeTorrents(hashes: torrentsInCategory.compactMap { torrent in torrent.hash })
} label: {
Image(systemName: "play")
.rotationEffect(.degrees(180))
Text("Resume \(category.capitalized)")
}

Button {
let torrentsInCategory = torrents.filter {
torrent in
return torrent.category == category
}

qBittorrent.pauseTorrents(hashes: torrentsInCategory.compactMap { torrent in torrent.hash })
} label: {
Image(systemName: "pause")
.rotationEffect(.degrees(180))
Text("Pause \(category.capitalized)")
}
}
}

Section {
Button {
alertIdentifier = AlertIdentifier(id: .resumeAll)
} label: {
Image(systemName: "play")
.rotationEffect(.degrees(180))
Text("Resume All Tasks")
}

Button {
alertIdentifier = AlertIdentifier(id: .pauseAll)
} label: {
Image(systemName: "pause")
.rotationEffect(.degrees(180))
Text("Pause All Tasks")
}
}

Section {
Button(role: .destructive) {
isAlertClearCompleted = true
} label: {
Image(systemName: "trash")
.rotationEffect(.degrees(180))
Text("Clear Completed")
}
}

Section {
Button(role: .destructive) {
alertIdentifier = AlertIdentifier(id: .logOut)
} label: {
Image(systemName: "rectangle.portrait.and.arrow.forward")
.rotationEffect(.degrees(180))
Text("Log out")
}
}
} label: {
Image(systemName: "ellipsis.circle")
}.alert(item: $alertIdentifier) { alert in
switch(alert.id) {
case .resumeAll:
return Alert(title: Text("Confirm Resume All"), message: Text("Are you sure you want to resume all tasks?"), primaryButton: .default(Text("Resume")) {
qBittorrent.resumeAllTorrents()
}, secondaryButton: .cancel())
case .pauseAll:
return Alert(title: Text("Confirm Pause All"), message: Text("Are you sure you want to pause all tasks?"), primaryButton: .default(Text("Pause")) {
qBittorrent.pauseAllTorrents()
}, secondaryButton: .cancel())
case .logOut:
return Alert(title: Text("Confirm Logout"), message: Text("Are you sure you want to log out?"), primaryButton: .destructive(Text("Log Out")) {
qBittorrent.setCookie(cookie: "")
isLoggedIn = false
}, secondaryButton: .cancel())
}
}.alert("Confirm Deletion", isPresented: $isAlertClearCompleted, actions: {
Button("Delete Completed Tasks", role: .destructive) {
let completedTorrents = torrents.filter {torrent in torrent.progress == 1}
let completedHashes = completedTorrents.compactMap {torrent in torrent.hash}

qBittorrent.deleteTorrents(hashes: completedHashes)
}
Button("Delete Completed Tasks with Files", role: .destructive) {
let completedTorrents = torrents.filter {torrent in torrent.progress == 1}
let completedHashes = completedTorrents.compactMap {torrent in torrent.hash}


qBittorrent.deleteTorrents(hashes: completedHashes, deleteFiles: true)
}
})
}

ToolbarItem(placement: .topBarTrailing) {
Button {
isFilterView.toggle()
} label: {
Image(systemName: "line.3.horizontal.decrease.circle")
}
}
}
}
Loading

0 comments on commit ce01376

Please sign in to comment.