diff --git a/Localization/Localizations/Localizable.xcstrings b/Localization/Localizations/Localizable.xcstrings index b359729..7759315 100644 --- a/Localization/Localizations/Localizable.xcstrings +++ b/Localization/Localizations/Localizable.xcstrings @@ -1004,6 +1004,9 @@ } } } + }, + "Edit" : { + }, "Errored" : { "localizations" : { @@ -1991,6 +1994,9 @@ } } } + }, + "SAVE" : { + }, "Save Path" : { "localizations" : { diff --git a/qBitControl.xcodeproj/project.pbxproj b/qBitControl.xcodeproj/project.pbxproj index 9713369..5149979 100644 --- a/qBitControl.xcodeproj/project.pbxproj +++ b/qBitControl.xcodeproj/project.pbxproj @@ -33,7 +33,6 @@ 90AB9B7C2B29D35C005C3612 /* TorrentStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B7B2B29D35C005C3612 /* TorrentStatsView.swift */; }; 90AB9B7E2B29D6AE005C3612 /* ListElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B7D2B29D6AE005C3612 /* ListElement.swift */; }; 90AB9B812B29DC45005C3612 /* ChartElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AB9B802B29DC45005C3612 /* ChartElement.swift */; }; - 90B61A8F2B540A10007ECCAD /* ServerEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90B61A8E2B540A10007ECCAD /* ServerEvents.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 */; }; @@ -41,7 +40,6 @@ 90C6F3982911529100F5A6FD /* TorrentFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90C6F3972911529100F5A6FD /* TorrentFilterView.swift */; }; 90DCA7E52B51C393008A9C1B /* ServersHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90DCA7E42B51C393008A9C1B /* ServersHelper.swift */; }; 90E5DDF82C1213910010DF7A /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E5DDF72C1213910010DF7A /* MainViewModel.swift */; }; - 90E5DDFA2C1218200010DF7A /* ServersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E5DDF92C1218200010DF7A /* ServersViewModel.swift */; }; 90E5DDFC2C1219E10010DF7A /* ServerAddViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E5DDFB2C1219E10010DF7A /* ServerAddViewModel.swift */; }; 90E86FFE2C81C89A00F4EA01 /* qBitDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E86FFD2C81C89A00F4EA01 /* qBitDataClass.swift */; }; 90EF6A492909267A001E9E7F /* AuthClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90EF6A482909267A001E9E7F /* AuthClass.swift */; }; @@ -105,7 +103,6 @@ 90AB9B7B2B29D35C005C3612 /* TorrentStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentStatsView.swift; sourceTree = ""; }; 90AB9B7D2B29D6AE005C3612 /* ListElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListElement.swift; sourceTree = ""; }; 90AB9B802B29DC45005C3612 /* ChartElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartElement.swift; sourceTree = ""; }; - 90B61A8E2B540A10007ECCAD /* ServerEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerEvents.swift; sourceTree = ""; }; 90BA88532B22019900C8A342 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 90BA88542B2206F100C8A342 /* LocalNetworkPermissionClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkPermissionClass.swift; sourceTree = ""; }; 90BCAD18291A7C91009F1FEC /* RSSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSView.swift; sourceTree = ""; }; @@ -114,7 +111,6 @@ 90C6F3972911529100F5A6FD /* TorrentFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TorrentFilterView.swift; sourceTree = ""; }; 90DCA7E42B51C393008A9C1B /* ServersHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersHelper.swift; sourceTree = ""; }; 90E5DDF72C1213910010DF7A /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; }; - 90E5DDF92C1218200010DF7A /* ServersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersViewModel.swift; sourceTree = ""; }; 90E5DDFB2C1219E10010DF7A /* ServerAddViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerAddViewModel.swift; sourceTree = ""; }; 90E86FFD2C81C89A00F4EA01 /* qBitDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = qBitDataClass.swift; sourceTree = ""; }; 90EF6A482909267A001E9E7F /* AuthClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthClass.swift; sourceTree = ""; }; @@ -198,7 +194,6 @@ 90FA253529190D0400DC8F0B /* FileNodeClass.swift */, 90BA88542B2206F100C8A342 /* LocalNetworkPermissionClass.swift */, 90DCA7E42B51C393008A9C1B /* ServersHelper.swift */, - 90B61A8E2B540A10007ECCAD /* ServerEvents.swift */, 90FF93462C8707BF001CDCE4 /* AppInfo.swift */, ); path = Classes; @@ -298,7 +293,6 @@ isa = PBXGroup; children = ( 9082FA2429080E53006C3960 /* ServersView.swift */, - 90E5DDF92C1218200010DF7A /* ServersViewModel.swift */, 903DED3A290E7E7E00FB36D6 /* ServerRowView.swift */, 903DED3C290E8A9000FB36D6 /* ServerAddView.swift */, 90E5DDFB2C1219E10010DF7A /* ServerAddViewModel.swift */, @@ -454,7 +448,6 @@ 90AB9B772B2901D5005C3612 /* TorrentListDefaultToolbar.swift in Sources */, 90EF6A5129095ACC001E9E7F /* TorrentRowView.swift in Sources */, 90C6F3982911529100F5A6FD /* TorrentFilterView.swift in Sources */, - 90E5DDFA2C1218200010DF7A /* ServersViewModel.swift in Sources */, 90AB9B7E2B29D6AE005C3612 /* ListElement.swift in Sources */, 90A4E4C22C175F8D00920968 /* TorrentListModel.swift in Sources */, 90FF93452C8703D0001CDCE4 /* TorrentAboutView.swift in Sources */, @@ -468,7 +461,6 @@ 90EF6A5329098968001E9E7F /* TorrentDetailsView.swift in Sources */, 90BCAD1D291A7EDE009F1FEC /* RSSFeedArticleRowView.swift in Sources */, 903DED3D290E8A9000FB36D6 /* ServerAddView.swift in Sources */, - 90B61A8F2B540A10007ECCAD /* ServerEvents.swift in Sources */, 90DCA7E52B51C393008A9C1B /* ServersHelper.swift in Sources */, 90F7BEE52913D24300F5DEDE /* TorrentDetailsTrackersView.swift in Sources */, 90EF6A492909267A001E9E7F /* AuthClass.swift in Sources */, @@ -647,7 +639,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = qBitControl/qBitControl.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 626XV358Y5; ENABLE_PREVIEWS = YES; @@ -665,7 +657,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = MikeMichael225.qBitControl; PRODUCT_NAME = qBitManager; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -683,7 +675,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = qBitControl/qBitControl.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 626XV358Y5; ENABLE_PREVIEWS = YES; @@ -701,7 +693,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = MikeMichael225.qBitControl; PRODUCT_NAME = qBitManager; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; diff --git a/qBitControl/Classes/AuthClass.swift b/qBitControl/Classes/AuthClass.swift index fe23dc2..31e19b4 100644 --- a/qBitControl/Classes/AuthClass.swift +++ b/qBitControl/Classes/AuthClass.swift @@ -33,7 +33,6 @@ class Auth { return "\(key)=\(value.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")" } let bodyString = parameterArray.joined(separator: "&") - print(bodyString) req.httpBody = bodyString.data(using: .utf8) let sessionConfiguration = URLSessionConfiguration.default diff --git a/qBitControl/Classes/ServerEvents.swift b/qBitControl/Classes/ServerEvents.swift deleted file mode 100644 index 15c4948..0000000 --- a/qBitControl/Classes/ServerEvents.swift +++ /dev/null @@ -1,28 +0,0 @@ -// - -import Foundation - - -class ServerEvents { - static private var onChangeActions: [ServerAction] = [] - - static func addOnChangeAction(action: ServerAction) { - removeOnChangeAction(name: action.name) - - onChangeActions.append(action) - } - - static func removeOnChangeAction(name: String) { - onChangeActions.removeAll { - action in - return action.name == name - } - } - - static func callOnChangeActions() { - onChangeActions.forEach { - action in - action.action() - } - } -} diff --git a/qBitControl/Classes/ServersHelper.swift b/qBitControl/Classes/ServersHelper.swift index ab4ba43..808314a 100644 --- a/qBitControl/Classes/ServersHelper.swift +++ b/qBitControl/Classes/ServersHelper.swift @@ -3,14 +3,31 @@ import Foundation -class ServersHelper { - private var defaults = UserDefaults.standard - private var servers: [Server] = [] +class ServersHelper: ObservableObject { + static public var shared = ServersHelper() + private var defaults = UserDefaults.standard private let serversKey = "servers" private let activeServerKey = "activeServer" - func refreshServerList() { + @Published public var servers: [Server] = [] + @Published public var activeServerId: String? + @Published public var connectingServerId: String? + + @Published public var isLoggedIn = false + + init() { + getServerList() + getActiveServer() + + if let activeServerId = self.activeServerId { + if let activeServer = self.getServer(id: activeServerId) { + self.connect(server: activeServer) + } + } + } + + func getServerList() { let encodedServers = defaults.data(forKey: self.serversKey) if let encodedServers = encodedServers { @@ -24,6 +41,29 @@ class ServersHelper { } } + func getServer(id: String) -> Server? { + return servers.first(where: { + server in + return server.id == id + }) + } + + private func setActiveServer(id: String) { + self.activeServerId = id + defaults.setValue("\(id)", forKey: activeServerKey) + } + + private func getActiveServer() { + let serverId = defaults.string(forKey: activeServerKey) + + if let serverId = serverId { + self.activeServerId = self.servers.first(where: { + server in + server.id == serverId + })?.id + } + } + func saveSeverList() { let encoder = JSONEncoder() @@ -35,27 +75,22 @@ class ServersHelper { } } - func getServers() -> [Server] { - refreshServerList() - return servers - } - func addServer(server: Server) { - refreshServerList() - self.servers.append(server) - saveSeverList() } func removeServer(id: String) { - refreshServerList() - self.servers.removeAll(where: { server in return server.id == id }) + if(id == activeServerId) { + activeServerId = nil + isLoggedIn = false + } + saveSeverList() } @@ -68,40 +103,43 @@ class ServersHelper { } } - func connect(server: Server, isSuccess: @escaping (Bool) -> Void) { + func connect(server: Server, result: ((Bool) -> Void)?) { + connectingServerId = server.id + Task { await Auth.getCookie(url: server.url, username: server.username, password: server.password, isSuccess: { success in - if(success) { - self.setActiveServer(id: server.id) + DispatchQueue.main.async { + if let result = result { + result(success) + } + + if(success) { + self.setActiveServer(id: server.id) + self.isLoggedIn = true + } + + self.connectingServerId = nil } - isSuccess(success) }) } } - func setActiveServer(id: String) { - if let activeServer = getActiveServer() { - if(id != activeServer.id) { - ServerEvents.callOnChangeActions() - } - } - - defaults.setValue("\(id)", forKey: activeServerKey) - } - - func getActiveServer() -> Server? { - let serverId = defaults.string(forKey: activeServerKey) + func connect(server: Server) { + connectingServerId = server.id - if let serverId = serverId { - refreshServerList() - - return self.servers.first(where: { - server in - server.id == serverId + Task { + await Auth.getCookie(url: server.url, username: server.username, password: server.password, isSuccess: { + success in + DispatchQueue.main.async { + if(success) { + self.setActiveServer(id: server.id) + self.isLoggedIn = true + } + + self.connectingServerId = nil + } }) } - - return nil } } diff --git a/qBitControl/MainView.swift b/qBitControl/MainView.swift index c7f7b2b..50e93d3 100644 --- a/qBitControl/MainView.swift +++ b/qBitControl/MainView.swift @@ -2,30 +2,28 @@ import SwiftUI struct MainView: View { @StateObject private var viewModel = MainViewModel() + @ObservedObject var serversHelper = ServersHelper.shared @Environment(\.scenePhase) var scenePhase var body: some View { Group { - if viewModel.shouldAttemptAutoLogIn { + if serversHelper.connectingServerId != nil && !serversHelper.isLoggedIn { Image("logo") .resizable() .scaledToFit() .frame(width: 100, height: 100) .cornerRadius(20) - .onAppear { - viewModel.attemptAutoLogIn() - } Text("qBitControl") .font(.largeTitle) - } else if !viewModel.isLoggedIn { - ServersView(isLoggedIn: $viewModel.isLoggedIn) + } else if !serversHelper.isLoggedIn { + ServersView() .onAppear { LocalNetworkPermissionService().triggerDialog() } .navigationTitle("qBitControl") } else { TabView { - TorrentListView(isLoggedIn: $viewModel.isLoggedIn) + TorrentListView(isLoggedIn: $serversHelper.isLoggedIn) .tabItem { Label("Tasks", systemImage: "square.and.arrow.down.on.square") } @@ -38,7 +36,7 @@ struct MainView: View { Label("Stats", systemImage: "chart.line.uptrend.xyaxis") } - ServersView(isLoggedIn: $viewModel.isLoggedIn) + ServersView() .tabItem { Label("Servers", systemImage: "server.rack") } diff --git a/qBitControl/MainViewModel.swift b/qBitControl/MainViewModel.swift index 7315127..39ee005 100644 --- a/qBitControl/MainViewModel.swift +++ b/qBitControl/MainViewModel.swift @@ -2,37 +2,13 @@ import SwiftUI import Combine class MainViewModel: ObservableObject { - @Published var isLoggedIn: Bool = false - @Published var shouldAttemptAutoLogIn: Bool = true - - private var defaults = UserDefaults.standard - private var cancellables = Set() - private var serversHelper = ServersHelper() - - func attemptAutoLogIn() { - if let activeServer = serversHelper.getActiveServer() { - serversHelper.connect(server: activeServer) { success in - DispatchQueue.main.async { - self.isLoggedIn = success - self.shouldAttemptAutoLogIn = false - } - } - } else { - DispatchQueue.main.async { - self.shouldAttemptAutoLogIn = false - } - } - } - + @ObservedObject var serversHelper = ServersHelper.shared + func reconnectIfNeeded(on scenePhase: ScenePhase) { - if scenePhase == .active && isLoggedIn { - if let activeServer = serversHelper.getActiveServer() { - serversHelper.connect(server: activeServer) { success in - DispatchQueue.main.async { - if !success { - self.isLoggedIn = false - } - } + if scenePhase == .active && serversHelper.isLoggedIn { + if let activeServerId = serversHelper.activeServerId { + if let activeServer = serversHelper.getServer(id: activeServerId) { + serversHelper.connect(server: activeServer) } } } diff --git a/qBitControl/ServersView/ServerAddView.swift b/qBitControl/ServersView/ServerAddView.swift index f990e18..f3dccdb 100644 --- a/qBitControl/ServersView/ServerAddView.swift +++ b/qBitControl/ServersView/ServerAddView.swift @@ -10,8 +10,12 @@ struct ServerAddView: View { @StateObject private var viewModel: ServerAddViewModel - init(serversHelper: ServersHelper) { - _viewModel = StateObject(wrappedValue: ServerAddViewModel(serversHelper: serversHelper)) + init() { + _viewModel = StateObject(wrappedValue: ServerAddViewModel()) + } + + init(editServerId: String) { + _viewModel = StateObject(wrappedValue: ServerAddViewModel(editServerId: editServerId)) } var body: some View { @@ -43,8 +47,13 @@ struct ServerAddView: View { viewModel.addServer(dismiss: dismiss) } label: { Spacer() - Text("ADD") - .fontWeight(.bold) + if(viewModel.editServerId != nil) { + Text("SAVE") + .fontWeight(.bold) + } else { + Text("ADD") + .fontWeight(.bold) + } Spacer() }.buttonStyle(.borderedProminent) }.listRowBackground(Color.blue) diff --git a/qBitControl/ServersView/ServerAddViewModel.swift b/qBitControl/ServersView/ServerAddViewModel.swift index feed8ed..d166315 100644 --- a/qBitControl/ServersView/ServerAddViewModel.swift +++ b/qBitControl/ServersView/ServerAddViewModel.swift @@ -6,7 +6,9 @@ import SwiftUI class ServerAddViewModel: ObservableObject { - var serversHelper: ServersHelper + @ObservedObject var serversHelper = ServersHelper.shared + + var editServerId: String? @Published var friendlyName = "" @Published var url = "" @@ -17,8 +19,16 @@ class ServerAddViewModel: ObservableObject { @Published var isInvalidAlert = false; @Published var invalidAlertMessage = ""; - init(serversHelper: ServersHelper) { - self.serversHelper = serversHelper + init() { } + init(editServerId: String) { + self.editServerId = editServerId + + if let server = serversHelper.getServer(id: editServerId) { + friendlyName = server.name + url = server.url + username = server.username + password = server.password + } } func showAlert(message: String) { @@ -41,6 +51,7 @@ class ServerAddViewModel: ObservableObject { let server = Server(name: friendlyName, url: url, username: username, password: password) if(!isCheckConnection) { + if let editServerId = self.editServerId { serversHelper.removeServer(id: editServerId) } serversHelper.addServer(server: server) dismiss() } @@ -49,6 +60,7 @@ class ServerAddViewModel: ObservableObject { didConnect in DispatchQueue.main.async { if(didConnect) { + if let editServerId = self.editServerId { self.serversHelper.removeServer(id: editServerId) } self.serversHelper.addServer(server: server) dismiss() } else { diff --git a/qBitControl/ServersView/ServerRowView.swift b/qBitControl/ServersView/ServerRowView.swift index e0c41f5..935bad7 100644 --- a/qBitControl/ServersView/ServerRowView.swift +++ b/qBitControl/ServersView/ServerRowView.swift @@ -6,57 +6,36 @@ import SwiftUI struct ServerRowView: View { - @State var id: String - @State var friendlyName: String - @State var url: String - @State var username: String - @State var password: String - @Binding var activeServerId: String - - public var serversHelper: ServersHelper - public var refreshServerList: () -> Void - - @Binding var isConnecting: [String: Bool] - @Binding var isLoggedIn: Bool - - func getServerName() -> String { - if (!friendlyName.isEmpty) { return friendlyName } else { return url } - } - - func isServerConnected() -> Bool { - return (activeServerId == id && isLoggedIn) - } - - func isServerConnecting() -> Bool { - return isConnecting[id] ?? false - } - - func removeServer() -> Void { - serversHelper.removeServer(id: id) - refreshServerList() - } + @ObservedObject var serversHelper = ServersHelper.shared + @State var server: Server + @State var setActiveSheet: (ActiveSheet) -> Void var body: some View { HStack() { - Text(getServerName()) + Text(server.name.isEmpty ? server.url : server.name) Spacer() - if(isServerConnected()) { + if(serversHelper.activeServerId == server.id) { Image(systemName: "checkmark") } - else if(isServerConnecting()) { + else if(serversHelper.connectingServerId == server.id) { ProgressView() .progressViewStyle(.circular) .padding(.leading, 1) } } .contextMenu() { + Button { + setActiveSheet(.edit(serverId: server.id)) + } label: { + Label("Edit", systemImage: "pencil") + } + Button(role: .destructive) { - removeServer() + serversHelper.removeServer(id: server.id) } label: { - Image(systemName: "trash") - Text("Delete") + Label("Delete", systemImage: "trash") } } } diff --git a/qBitControl/ServersView/ServersView.swift b/qBitControl/ServersView/ServersView.swift index fa8a325..437119d 100644 --- a/qBitControl/ServersView/ServersView.swift +++ b/qBitControl/ServersView/ServersView.swift @@ -1,10 +1,34 @@ import SwiftUI -struct ServersView: View { - @StateObject private var viewModel: ServersViewModel +enum ActiveSheet: Identifiable { + case add + case edit(serverId: String) + + var id: String { + switch self { + case .add: + return "add" + case .edit(let serverId): + return serverId + } + } +} - init(isLoggedIn: Binding) { - _viewModel = StateObject(wrappedValue: ServersViewModel(isLoggedIn: isLoggedIn)) +struct ServersView: View { + @ObservedObject var serversHelper = ServersHelper.shared + + @State var activeSheet: ActiveSheet? + @State var isTroubleConnecting = false + + func setActiveSheet(sheet: ActiveSheet) { + activeSheet = sheet + } + + func sortServers(server1: Server, server2: Server) -> Bool { + let name1 = server1.name.isEmpty ? server1.url : server1.name + let name2 = server2.name.isEmpty ? server2.url : server2.name + + return name1 < name2 } var body: some View { @@ -12,7 +36,7 @@ struct ServersView: View { List { Section(header: Text("Manage")) { Button { - viewModel.isServerAddView.toggle() + activeSheet = .add } label: { HStack { Image(systemName: "plus.circle") @@ -20,13 +44,15 @@ struct ServersView: View { } } } - if !viewModel.servers.isEmpty { + if !serversHelper.servers.isEmpty { Section(header: Text("Server List")) { - ForEach(viewModel.servers, id: \.id) { server in + ForEach(serversHelper.servers.sorted(by: sortServers), id: \.id) { server in Button { - viewModel.connectToServer(server: server) + serversHelper.connect(server: server, result: { success in + if(!success) { isTroubleConnecting = true } + }) } label: { - ServerRowView(id: server.id, friendlyName: server.name, url: server.url, username: server.username, password: server.password, activeServerId: $viewModel.activeServerId, serversHelper: viewModel.serversHelper, refreshServerList: viewModel.refreshServerList, isConnecting: $viewModel.isConnecting, isLoggedIn: $viewModel.isLoggedIn) + ServerRowView(server: server, setActiveSheet: setActiveSheet) } } } @@ -34,19 +60,15 @@ struct ServersView: View { } .navigationTitle("Servers") } - .sheet(isPresented: $viewModel.isServerAddView) { - ServerAddView(serversHelper: viewModel.serversHelper) - } - .onChange(of: viewModel.isServerAddView) { isServerAddView in - if !isServerAddView { - viewModel.refreshServerList() + .sheet(item: $activeSheet) { item in + switch item { + case .add: + ServerAddView() + case .edit(let serverId): + ServerAddView(editServerId: serverId) } } - .onAppear { - viewModel.refreshServerList() - viewModel.refreshActiveServer() - } - .alert(isPresented: $viewModel.isTroubleConnecting) { + .alert(isPresented: $isTroubleConnecting) { Alert(title: Text("Couldn't connect to the server."), message: Text("Check if the URL, username and password is correct. Make sure local network access is enabled:\nSettings > Privacy & Security > Local Network > qBitControl")) } } diff --git a/qBitControl/ServersView/ServersViewModel.swift b/qBitControl/ServersView/ServersViewModel.swift deleted file mode 100644 index a3baf0a..0000000 --- a/qBitControl/ServersView/ServersViewModel.swift +++ /dev/null @@ -1,45 +0,0 @@ -import SwiftUI -import Combine - -class ServersViewModel: ObservableObject { - @Published var servers: [Server] = [] - @Published var activeServerId: String = "" - @Published var isConnecting: [String: Bool] = [:] - @Published var isServerAddView = false - @Published var isTroubleConnecting = false - @Binding var isLoggedIn: Bool - - public var serversHelper = ServersHelper() - - init(isLoggedIn: Binding) { - self._isLoggedIn = isLoggedIn - refreshServerList() - refreshActiveServer() - } - - func refreshServerList() { - servers = serversHelper.getServers() - } - - func refreshActiveServer() { - if let activeServer = serversHelper.getActiveServer() { - activeServerId = activeServer.id - } - } - - func connectToServer(server: Server) { - isConnecting[server.id] = true - serversHelper.connect(server: server) { success in - DispatchQueue.main.async { - if !success { - self.isTroubleConnecting = true - } - if success { - self.isLoggedIn = true - } - self.isConnecting[server.id] = false - self.refreshActiveServer() - } - } - } -}