-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Rewrite SyllabusWebView * Apply SwiftFormat changes * Fix as reviews --------- Co-authored-by: shp7724 <[email protected]>
- Loading branch information
Showing
7 changed files
with
421 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 0 additions & 19 deletions
19
SNUTT-2022/SNUTT/Views/Components/WebViews/SyllabusWebView.swift
This file was deleted.
Oops, something went wrong.
31 changes: 31 additions & 0 deletions
31
...-2022/SNUTT/Views/Components/WebViews/SyllabusWebView/SyllabusFilePreviewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// SyllabusFilePreviewController.swift | ||
// SNUTT | ||
// | ||
// Created by 박신홍 on 10/19/24. | ||
// | ||
|
||
import QuickLook | ||
|
||
final class SyllabusFilePreviewController: QLPreviewController { | ||
private let item: any QLPreviewItem | ||
init(item: any QLPreviewItem) { | ||
self.item = item | ||
super.init(nibName: nil, bundle: nil) | ||
dataSource = self | ||
} | ||
|
||
@available(*, unavailable) required init?(coder _: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
} | ||
|
||
extension SyllabusFilePreviewController: QLPreviewControllerDataSource { | ||
func numberOfPreviewItems(in _: QLPreviewController) -> Int { | ||
1 | ||
} | ||
|
||
func previewController(_: QLPreviewController, previewItemAt _: Int) -> any QLPreviewItem { | ||
item | ||
} | ||
} |
190 changes: 190 additions & 0 deletions
190
SNUTT-2022/SNUTT/Views/Components/WebViews/SyllabusWebView/SyllabusWebView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// | ||
// SyllabusWebView.swift | ||
// SNUTT | ||
// | ||
// Created by 최유림 on 2022/10/11. | ||
// | ||
|
||
import Combine | ||
import QuickLook | ||
import SwiftUI | ||
import UIKit | ||
import WebKit | ||
|
||
struct SyllabusWebView: UIViewControllerRepresentable { | ||
let lectureTitle: String | ||
@Binding var urlString: String | ||
|
||
func makeUIViewController(context _: UIViewControllerRepresentableContext<Self>) -> UIViewController { | ||
let webViewController = SyllabusWebViewController(entryURL: URL(string: urlString)) | ||
let navigationController = UINavigationController(rootViewController: webViewController) | ||
let appearance = UINavigationBarAppearance() | ||
appearance.configureWithDefaultBackground() | ||
navigationController.navigationBar.standardAppearance = appearance | ||
navigationController.navigationBar.scrollEdgeAppearance = appearance | ||
webViewController.navigationItem.rightBarButtonItem = .init(systemItem: .close, primaryAction: .init(handler: { [weak navigationController] _ in | ||
navigationController?.dismiss(animated: true) | ||
})) | ||
webViewController.title = lectureTitle | ||
return navigationController | ||
} | ||
|
||
func updateUIViewController(_: UIViewController, context _: UIViewControllerRepresentableContext<Self>) {} | ||
} | ||
|
||
final class SyllabusWebViewController: UIViewController { | ||
private enum Constants { | ||
static let homeURL = URL(string: "https://sugang.snu.ac.kr")! | ||
static let referer = "https://sugang.snu.ac.kr/sugang/cc/cc100InterfaceExcel.action" | ||
} | ||
|
||
private enum Design { | ||
static let bottomViewHeight = 50.0 | ||
} | ||
|
||
private let entryURL: URL | ||
private lazy var webView: WKWebView = { | ||
let config = WKWebViewConfiguration() | ||
let webView = WKWebView(frame: .zero, configuration: config) | ||
webView.allowsBackForwardNavigationGestures = true | ||
webView.scrollView.contentInset = .init(top: 0, left: 0, bottom: Design.bottomViewHeight, right: 0) | ||
webView.navigationDelegate = self | ||
return webView | ||
}() | ||
|
||
private var cancellables = Set<AnyCancellable>() | ||
private let bottomView = WebBottomNavigationView() | ||
private var downloadLocalURLs = [WKDownload: URL]() | ||
|
||
init(entryURL: URL?) { | ||
self.entryURL = entryURL ?? Constants.homeURL | ||
super.init(nibName: nil, bundle: nil) | ||
} | ||
|
||
@available(*, unavailable) required init?(coder _: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
setupView() | ||
bindBottomButtons() | ||
initialLoad() | ||
} | ||
|
||
private func setupView() { | ||
view.addSubview(webView) | ||
view.addSubview(bottomView) | ||
webView.translatesAutoresizingMaskIntoConstraints = false | ||
bottomView.translatesAutoresizingMaskIntoConstraints = false | ||
NSLayoutConstraint.activate([ | ||
webView.topAnchor.constraint(equalTo: view.topAnchor), | ||
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | ||
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | ||
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor), | ||
bottomView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | ||
bottomView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | ||
bottomView.bottomAnchor.constraint(equalTo: view.bottomAnchor), | ||
bottomView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -Design.bottomViewHeight), | ||
]) | ||
} | ||
|
||
private func initialLoad() { | ||
var request = URLRequest(url: entryURL) | ||
request.setValue(Constants.referer, forHTTPHeaderField: "Referer") | ||
webView.load(request) | ||
} | ||
|
||
private func bindBottomButtons() { | ||
bottomView.buttonDidPressPublisher | ||
.sink { [weak self] button in | ||
guard let self else { return } | ||
switch button { | ||
case .back: | ||
webView.goBack() | ||
case .forward: | ||
webView.goForward() | ||
case .reload: | ||
webView.reload() | ||
case .safari: | ||
UIApplication.shared.open(entryURL) | ||
} | ||
} | ||
.store(in: &cancellables) | ||
webView.publisher(for: \.canGoBack) | ||
.sink { [weak self] canGoBack in | ||
guard let self else { return } | ||
bottomView.button(for: .back).isEnabled = canGoBack | ||
} | ||
.store(in: &cancellables) | ||
webView.publisher(for: \.canGoForward) | ||
.sink { [weak self] canGoForward in | ||
guard let self else { return } | ||
bottomView.button(for: .forward).isEnabled = canGoForward | ||
} | ||
.store(in: &cancellables) | ||
webView.publisher(for: \.estimatedProgress) | ||
.sink { [weak self] progress in | ||
guard let self else { return } | ||
bottomView.progressView.setProgress(progress) | ||
print("[progress] \(progress)") | ||
} | ||
.store(in: &cancellables) | ||
} | ||
} | ||
|
||
extension SyllabusWebViewController: WKNavigationDelegate { | ||
func webView(_: WKWebView, decidePolicyFor _: WKNavigationAction) async -> WKNavigationActionPolicy { | ||
return .allow | ||
} | ||
|
||
func webView(_: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse) async -> WKNavigationResponsePolicy { | ||
guard let mimeType = navigationResponse.response.mimeType else { return .cancel } | ||
if mimeType == "text/html" { | ||
return .allow | ||
} | ||
return .download | ||
} | ||
|
||
func webView(_: WKWebView, navigationResponse _: WKNavigationResponse, didBecome download: WKDownload) { | ||
download.delegate = self | ||
} | ||
} | ||
|
||
extension SyllabusWebViewController: WKDownloadDelegate { | ||
func download(_ download: WKDownload, decideDestinationUsing _: URLResponse, suggestedFilename: String) async -> URL? { | ||
let percentDecoded = suggestedFilename.removingPercentEncoding ?? suggestedFilename | ||
let fileManager = FileManager.default | ||
let url = fileManager.temporaryDirectory.appendingPathComponent(percentDecoded) | ||
try? fileManager.removeItem(at: url) | ||
downloadLocalURLs[download] = url | ||
return url | ||
} | ||
|
||
func downloadDidFinish(_ download: WKDownload) { | ||
guard let localURL = downloadLocalURLs.removeValue(forKey: download) else { return } | ||
let previewController = SyllabusFilePreviewController(item: localURL as QLPreviewItem) | ||
present(previewController, animated: true) | ||
} | ||
} | ||
|
||
extension UIControl { | ||
func addAction( | ||
for controlEvents: UIControl.Event = .touchUpInside, | ||
_ closure: @MainActor @escaping () -> Void | ||
) { | ||
addAction(UIAction { (_: UIAction) in closure() }, for: controlEvents) | ||
} | ||
} | ||
|
||
@available(iOS 17.0, *) | ||
#Preview { | ||
SyllabusWebView(lectureTitle: "수강스누", urlString: .constant("https://sugang.snu.ac.kr/sugang/cc/cc103.action?openSchyy=2024&openShtmFg=U000200002&openDetaShtmFg=U000300002&sbjtCd=M3500.002000<No=001&sbjtSubhCd=000")) | ||
.ignoresSafeArea(edges: .bottom) | ||
} | ||
|
||
@available(iOS 17.0, *) | ||
#Preview { | ||
SyllabusWebView(lectureTitle: "네이버", urlString: .constant("https://naver.com")) | ||
.ignoresSafeArea(edges: .bottom) | ||
} |
Oops, something went wrong.