Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions iBox/Sources/Error/ErrorPageView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// ErrorPageView.swift
// iBox
//
// Created by Chan on 4/18/24.
//

import UIKit

import SnapKit

class ErrorPageView: UIView {
private var imageViews: [UIImageView] = []
private let images = ["fox_page0", "fox_page1", "fox_page2", "fox_page3", "fox_page4"]
private var timer: Timer?

let messageLabel = UILabel()

let backButton = UIButton()
let retryButton = UIButton()

override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupLayout()
changeImages()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupViews() {
backgroundColor = .clear

messageLabel.textAlignment = .center
messageLabel.numberOfLines = 0

retryButton.setTitle("무시하기", for: .normal)
retryButton.backgroundColor = .systemBlue
retryButton.setTitleColor(.white, for: .normal)
retryButton.layer.cornerRadius = 10

addSubview(messageLabel)
addSubview(retryButton)

for imageName in images {
let imageView = UIImageView(image: UIImage(named: imageName))
imageView.contentMode = .scaleAspectFit
imageView.isHidden = true
imageView.tintColor = .box2
addSubview(imageView)
imageViews.append(imageView)
}

changeImages()

}

private func setupLayout() {

imageViews.forEach { imageView in
imageView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
make.leading.greaterThanOrEqualToSuperview().offset(20)
make.trailing.lessThanOrEqualToSuperview().offset(-20)
make.width.height.equalTo(32)
}
}

messageLabel.snp.makeConstraints { make in
make.top.equalTo(imageViews[0].snp.bottom).offset(20)
make.centerX.equalToSuperview()
make.leading.greaterThanOrEqualToSuperview().offset(20)
make.trailing.lessThanOrEqualToSuperview().offset(-20)
}

retryButton.snp.makeConstraints { make in
make.top.equalTo(messageLabel.snp.bottom).offset(20)
make.centerX.equalToSuperview()
make.width.equalTo(100)
make.height.equalTo(44)
}
}

func configure(with error: Error, url: String) {
messageLabel.text = "\(url): \n해당 주소를 불러오는데 실패했어요!"
print(error.localizedDescription)
}

private func changeImages() {
var currentIndex = 0

timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] timer in
guard let self = self else { return }

let state = AppStateManager.shared.isVersionCheckCompleted
if state == .success || state == .later || state == .maxRetryReached {
timer.invalidate()
self.timer = nil
return
}

self.imageViews.forEach { $0.isHidden = true }
self.imageViews[currentIndex].isHidden = false

currentIndex = (currentIndex + 1) % self.imageViews.count
}
}
}
67 changes: 67 additions & 0 deletions iBox/Sources/Error/ErrorPageViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// ErrorPageViewController.swift
// iBox
//
// Created by Chan on 4/18/24.
//

import UIKit
import WebKit

protocol ErrorPageControllerDelegate: AnyObject {
func presentErrorPage(_ errorPage: ErrorPageViewController)
}

protocol WebViewErrorDelegate {
func webView(_ webView: WebView, didFailWithError error: Error, url: URL?)
}

class ErrorPageViewController: UIViewController {
weak var delegate: ErrorPageControllerDelegate?
var webView: WebView?

init(webView: WebView) {
super.init(nibName: nil, bundle: nil)
self.webView = webView
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func loadView() {
self.view = ErrorPageView()
}

override func viewDidLoad() {
super.viewDidLoad()
if let errorPageView = view as? ErrorPageView {
errorPageView.retryButton.addTarget(self, action: #selector(retryButtonTapped), for: .touchUpInside)
}
}

func configureWithError(_ error: Error, url: String) {
if let errorPageView = view as? ErrorPageView {
errorPageView.configure(with: error, url: url)
}
}

@objc private func retryButtonTapped() {
webView?.retryLoading()
dismiss(animated: true)
}

func handleError(_ error: Error, _ url: URL?) {
self.modalPresentationStyle = .overFullScreen
self.configureWithError(error, url: url?.absoluteString ?? "")
delegate?.presentErrorPage(self)
}
}

extension ErrorPageViewController: WebViewErrorDelegate {

func webView(_ webView: WebView, didFailWithError error: Error, url: URL?) {
handleError(error, url)
}

}
26 changes: 25 additions & 1 deletion iBox/Sources/Web/WebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import SnapKit
class WebView: UIView {

var delegate: WebViewDelegate?
var errorDelegate: WebViewErrorDelegate?
var lastRequestedURL: URL?

private var progressObserver: NSKeyValueObservation?

Expand All @@ -26,7 +28,7 @@ class WebView: UIView {
private var isActive = false

// MARK: - UI Components


private let webView:WKWebView

Expand Down Expand Up @@ -164,13 +166,35 @@ extension WebView: WKNavigationDelegate {
}

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

// 마지막으로 시도한 navigation url
lastRequestedURL = navigationAction.request.url

// "새 창으로 열기" 링크 WebView 내에서 열기
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
decisionHandler(.allow)
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
// 초기 로드시 에러 발생
errorDelegate?.webView(self, didFailWithError: error, url: selectedWebsite)
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
// 네비게이션 중 에러 발생 시
if let lastURL = lastRequestedURL {
errorDelegate?.webView(self, didFailWithError: error, url: lastURL)
} else {
// lastRequestedURL이 nil인 경우 대비
errorDelegate?.webView(self, didFailWithError: error, url: nil)
}
}

func retryLoading() {
webView.reload()
}
}

extension WebView: UIScrollViewDelegate {
Expand Down
30 changes: 23 additions & 7 deletions iBox/Sources/Web/WebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
//

import UIKit
import WebKit

protocol WebViewDelegate {
func pushAddBookMarkViewController(url: URL)
}

class WebViewController: BaseViewController<WebView>, BaseViewControllerProtocol {

var errorViewController: ErrorPageViewController?
var delegate: AddBookmarkViewControllerProtocol?
var selectedWebsite: URL?

Expand All @@ -22,11 +24,8 @@ class WebViewController: BaseViewController<WebView>, BaseViewControllerProtocol
super.viewDidLoad()

setupNavigationBar()
view.backgroundColor = .backgroundColor

guard let contentView = contentView as? WebView else { return }
contentView.delegate = self
contentView.selectedWebsite = selectedWebsite
setupView()
setupDelegate()
}

override func viewDidLayoutSubviews() {
Expand All @@ -40,7 +39,20 @@ class WebViewController: BaseViewController<WebView>, BaseViewControllerProtocol
func setupNavigationBar() {
setNavigationBarHidden(true)
}

func setupDelegate() {
guard let contentView = contentView as? WebView else { return }
contentView.delegate = self
contentView.selectedWebsite = selectedWebsite

errorViewController = ErrorPageViewController(webView: contentView)
contentView.errorDelegate = errorViewController
errorViewController?.delegate = self
}

func setupView() {
view.backgroundColor = .backgroundColor
}
}

extension WebViewController: WebViewDelegate {
Expand All @@ -53,7 +65,11 @@ extension WebViewController: WebViewDelegate {
AddBookmarkManager.shared.navigateToAddBookmarkView(from: iBoxUrl, in: tabBarController)
}
}

}

}

extension WebViewController: ErrorPageControllerDelegate {
func presentErrorPage(_ errorPage: ErrorPageViewController) {
self.present(errorPage, animated: true, completion: nil)
}
}