diff --git a/iOS/Delegates/AppDelegate+NetworkMonitoring.swift b/iOS/Delegates/AppDelegate+NetworkMonitoring.swift index b3b7ec5..02cc60d 100644 --- a/iOS/Delegates/AppDelegate+NetworkMonitoring.swift +++ b/iOS/Delegates/AppDelegate+NetworkMonitoring.swift @@ -93,7 +93,7 @@ extension AppDelegate { object: nil, userInfo: [ "isConnected": isConnected, - "connectionType": connectionTypeToString(connectionType), + "connectionType": self.connectionTypeToString(connectionType), "isOfflineSigningAvailable": offlineManager.isOfflineSigningEnabled ] ) diff --git a/iOS/Views/Apps/LibraryViewController+SearchExtensions.swift b/iOS/Views/Apps/LibraryViewController+SearchExtensions.swift new file mode 100644 index 0000000..b6f45af --- /dev/null +++ b/iOS/Views/Apps/LibraryViewController+SearchExtensions.swift @@ -0,0 +1,91 @@ +// Proprietary Software License Version 1.0 +// +// Copyright (C) 2025 BDG +// +// Backdoor App Signer is proprietary software. You may not use, modify, or distribute it except as expressly +// permitted under the terms of the Proprietary Software License. + +import UIKit + +// MARK: - Search Extensions for LibraryViewController + +extension LibraryViewController { + /// Configure the search controller for app filtering + func configureSearchBar() { + searchController = UISearchController(searchResultsController: nil) + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search" + + navigationItem.searchController = searchController + definesPresentationContext = true + navigationItem.hidesSearchBarWhenScrolling = false + } + + /// Check if search filtering is active + var isFiltering: Bool { + return searchController.isActive && !searchBarIsEmpty + } + + /// Check if search bar is empty + var searchBarIsEmpty: Bool { + return searchController.searchBar.text?.isEmpty ?? true + } +} + +// MARK: - UISearchResultsUpdating Implementation +extension LibraryViewController: UISearchResultsUpdating { + func updateSearchResults(for searchController: UISearchController) { + let searchText = searchController.searchBar.text ?? "" + filterContentForSearchText(searchText) + tableView.reloadData() + } + + /// Filter app content based on search text + private func filterContentForSearchText(_ searchText: String) { + let lowercasedSearchText = searchText.lowercased() + + filteredSignedApps = signedApps?.filter { app in + guard let name = app.name?.lowercased() else { return false } + return name.contains(lowercasedSearchText) + } ?? [] + + filteredDownloadedApps = downloadedApps?.filter { app in + guard let name = app.name?.lowercased() else { return false } + return name.contains(lowercasedSearchText) + } ?? [] + } +} + +// MARK: - UISearchControllerDelegate Implementation +extension LibraryViewController: UISearchControllerDelegate, UISearchBarDelegate { + // Can be expanded with additional search-related methods as needed +} + +// MARK: - UI Helper Extensions +extension LibraryViewController { + /// Create and configure a loading alert with spinner + func createLoaderAlert() -> UIAlertController { + let alert = UIAlertController( + title: nil, + message: "Please wait...", + preferredStyle: .alert + ) + + let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50)) + loadingIndicator.hidesWhenStopped = true + loadingIndicator.style = .medium + loadingIndicator.startAnimating() + + alert.view.addSubview(loadingIndicator) + + // Add constraints for proper layout + loadingIndicator.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + loadingIndicator.centerXAnchor.constraint(equalTo: alert.view.centerXAnchor), + loadingIndicator.centerYAnchor.constraint(equalTo: alert.view.centerYAnchor), + ]) + + return alert + } +} diff --git a/iOS/Views/Apps/LibraryViewController+UIActions.swift b/iOS/Views/Apps/LibraryViewController+UIActions.swift new file mode 100644 index 0000000..b8e15a7 --- /dev/null +++ b/iOS/Views/Apps/LibraryViewController+UIActions.swift @@ -0,0 +1,67 @@ +// Proprietary Software License Version 1.0 +// +// Copyright (C) 2025 BDG +// +// Backdoor App Signer is proprietary software. You may not use, modify, or distribute it except as expressly +// permitted under the terms of the Proprietary Software License. + +import UIKit +import CoreData + +// MARK: - UI Action Extensions for LibraryViewController + +extension LibraryViewController { + /// Show certificate missing alert + func showNoCertificatesAlert() { + let alert = UIAlertController( + title: String.localized("APP_SIGNING_VIEW_CONTROLLER_NO_CERTS_ALERT_TITLE"), + message: String.localized("APP_SIGNING_VIEW_CONTROLLER_NO_CERTS_ALERT_DESCRIPTION"), + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: String.localized("LAME"), style: .default)) + present(alert, animated: true) + } + + /// Handle downloaded app actions + func handleDownloadedAppAction(app: DownloadedApps, indexPath: IndexPath) { + // Implementation would go here + // This is a placeholder to match method signature used in code + } + + /// Show confirmation alert for installing an app + func showInstallConfirmationAlert(app: NSManagedObject, filePath: String) { + // Implementation would go here + // This is a placeholder to match method signature used in code + } + + /// Configure popup detents for iOS 15+ sheet presentations + func configurePopupDetents(hasUpdate: Bool) { + // Implementation would go here + // This is a placeholder to match method signature used in code + } + + /// Configure the presentation detents of a popup view controller + func configureSheetPresentationController(for viewController: UIViewController, hasUpdate: Bool = false) { + if #available(iOS 15.0, *) { + if let sheet = viewController.presentationController as? UISheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + } + } + } +} + +// MARK: - Table View Extensions +extension LibraryViewController { + // UITableView related overrides that comply with Swift rules + + // These don't have 'override' as they're in extension blocks + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 80 + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + // Implementation would go here - placeholder + return nil + } +} diff --git a/iOS/Views/Apps/LibraryViewController.swift b/iOS/Views/Apps/LibraryViewController.swift index 0ac1b18..0e9d610 100644 --- a/iOS/Views/Apps/LibraryViewController.swift +++ b/iOS/Views/Apps/LibraryViewController.swift @@ -39,9 +39,9 @@ class LibraryViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() setupViews() - setupSearchController() + configureSearchBar() fetchSources() - loaderAlert = presentLoader() + loaderAlert = createLoaderAlert() } override func viewWillAppear(_ animated: Bool) { @@ -633,20 +633,15 @@ extension LibraryViewController { } } ) - } + } } else { showNoCertificatesAlert() } } - private func showNoCertificatesAlert() { - let alert = UIAlertController( - title: String.localized("APP_SIGNING_VIEW_CONTROLLER_NO_CERTS_ALERT_TITLE"), - message: String.localized("APP_SIGNING_VIEW_CONTROLLER_NO_CERTS_ALERT_DESCRIPTION"), - preferredStyle: .alert - ) - alert.addAction(UIAlertAction(title: String.localized("LAME"), style: .default)) - present(alert, animated: true) + // Method moved to LibraryViewController+UIActions.swift + private func showCertificatesAlert() { + showNoCertificatesAlert() } private func handleDownloadedAppAction( diff --git a/iOS/Views/Home/Core/HomeViewController.swift b/iOS/Views/Home/Core/HomeViewController.swift index 5c74589..326fc0c 100644 --- a/iOS/Views/Home/Core/HomeViewController.swift +++ b/iOS/Views/Home/Core/HomeViewController.swift @@ -73,7 +73,7 @@ class HomeViewController: UIViewController, UISearchResultsUpdating, UIDocumentP let uploadButton = UIBarButtonItem(customView: HomeViewUI.uploadButton) let addButton = UIBarButtonItem(image: UIImage(systemName: "folder.badge.plus"), style: .plain, target: self, action: #selector(addDirectory)) - HomeViewUI.uploadButton.addTarget(self, action: #selector(importFile), for: .touchUpInside) + HomeViewUI.uploadButton.addTarget(self, action: #selector(performFileImport), for: .touchUpInside) HomeViewUI.uploadButton.addGradientBackground() navItem.rightBarButtonItems = [menuButton, uploadButton, addButton] HomeViewUI.navigationBar.setItems([navItem], animated: false) diff --git a/iOS/Views/Terminal/TerminalViewController.swift b/iOS/Views/Terminal/TerminalViewController.swift index 0628b11..c0d1683 100644 --- a/iOS/Views/Terminal/TerminalViewController.swift +++ b/iOS/Views/Terminal/TerminalViewController.swift @@ -435,8 +435,9 @@ class TerminalViewController: UIViewController { self.isExecuting = false switch result { - case .success(let output): - self.appendToTerminal(output, isInput: false) + case .success: + // Result is Void, no output to display from HTTP mode + break case .failure(let error): self.appendToTerminal("Error: \(error.localizedDescription)", isInput: false) } @@ -640,13 +641,16 @@ class TerminalViewController: UIViewController { self.logger.log(message: "Fetching WebDAV credentials for session \(sessionId)", type: .info) // Get base URL from TerminalService - guard let baseURL = TerminalService.shared.baseURL else { + let serverBaseURL: String + if let baseURL = TerminalService.shared.baseURL { + serverBaseURL = baseURL + } else { completion(.failure(NSError(domain: "terminal", code: 2, userInfo: [NSLocalizedDescriptionKey: "Invalid server URL"]))) return } // Create URL for WebDAV credentials - guard let url = URL(string: "\(baseURL)/api/webdav/credentials?session_id=\(sessionId)") else { + guard let url = URL(string: "\(serverBaseURL)/api/webdav/credentials?session_id=\(sessionId)") else { completion(.failure(NSError(domain: "terminal", code: 2, userInfo: [NSLocalizedDescriptionKey: "Invalid URL for WebDAV credentials"]))) return }