From 7d8ea17ff08de194e0bbef5e64179bdef347841e Mon Sep 17 00:00:00 2001 From: JH713 Date: Sun, 21 Apr 2024 16:33:22 +0900 Subject: [PATCH 1/5] build: add SkeletonView library --- Project.swift | 1 + Tuist/Dependencies.swift | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Project.swift b/Project.swift index dabac2a..4fa1bf0 100644 --- a/Project.swift +++ b/Project.swift @@ -19,6 +19,7 @@ class iBoxFactory: ProjectFactory { let dependencies: [TargetDependency] = [ .external(name: "SnapKit"), .external(name: "SwiftSoup"), + .external(name: "SkeletonView"), .target(name: "iBoxShareExtension") ] diff --git a/Tuist/Dependencies.swift b/Tuist/Dependencies.swift index 98b323e..0e66bfc 100644 --- a/Tuist/Dependencies.swift +++ b/Tuist/Dependencies.swift @@ -10,7 +10,8 @@ import ProjectDescription let spm = SwiftPackageManagerDependencies([ .remote(url: "https://github.com/SnapKit/SnapKit.git", requirement: .upToNextMinor(from: "5.0.1")), .remote(url: "https://github.com/scinfu/SwiftSoup.git", requirement: .upToNextMajor(from: "2.7.1")), -], productTypes: ["SnapKit": .framework, "SwiftSoup": .framework] + .remote(url: "https://github.com/Juanpe/SkeletonView.git", requirement: .upToNextMajor(from: "1.0.0")) +], productTypes: ["SnapKit": .framework, "SwiftSoup": .framework, "SkeletonView": .framework] ) let dependencies = Dependencies( From 925af31a7cb6fd13cfbc98195aa54d7177e1ec5d Mon Sep 17 00:00:00 2001 From: JH713 Date: Sun, 21 Apr 2024 16:50:34 +0900 Subject: [PATCH 2/5] feat: skeleton ui --- iBox/Sources/AddBookmark/AddBookmarkView.swift | 10 ++++++++++ .../AddBookmark/AddBookmarkViewController.swift | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/iBox/Sources/AddBookmark/AddBookmarkView.swift b/iBox/Sources/AddBookmark/AddBookmarkView.swift index 085283a..50b2873 100644 --- a/iBox/Sources/AddBookmark/AddBookmarkView.swift +++ b/iBox/Sources/AddBookmark/AddBookmarkView.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import SkeletonView import SnapKit class AddBookmarkView: UIView { @@ -46,6 +47,9 @@ class AddBookmarkView: UIView { $0.isScrollEnabled = true $0.keyboardType = .default $0.autocorrectionType = .no + $0.isSkeletonable = true + $0.skeletonTextLineHeight = .fixed(20) + $0.skeletonPaddingInsets = .init(top: 5, left: 0, bottom: 5, right: 0) } private let clearButton = UIButton().then { @@ -73,6 +77,10 @@ class AddBookmarkView: UIView { $0.isScrollEnabled = true $0.keyboardType = .URL $0.autocorrectionType = .no + $0.isSkeletonable = true + $0.skeletonTextLineHeight = .fixed(20) + $0.skeletonTextNumberOfLines = 2 + $0.skeletonPaddingInsets = .init(top: 5, left: 0, bottom: 5, right: 0) } private let button = UIButton(type: .custom).then { @@ -130,6 +138,8 @@ class AddBookmarkView: UIView { button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) nameTextView.delegate = self urlTextView.delegate = self + + isSkeletonable = true } private func setupHierarchy() { diff --git a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift index 363850a..09588d6 100644 --- a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift +++ b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift @@ -7,6 +7,8 @@ import UIKit +import SkeletonView + protocol AddBookmarkViewControllerProtocol: AnyObject { func addFolderDirect(_ folder: Folder) func addBookmarkDirect(_ bookmark: Bookmark, at folderIndex: Int) @@ -31,6 +33,8 @@ final class AddBookmarkViewController: UIViewController { super.viewWillAppear(animated) updateSelectedFolder() addBookmarkView.updateTextFieldsFilledState() + +// view.showAnimatedGradientSkeleton() } override func viewDidLoad() { @@ -38,6 +42,8 @@ final class AddBookmarkViewController: UIViewController { setupNavigationBar() updateSelectedFolder() addBookmarkView.nameTextView.becomeFirstResponder() + + view.isSkeletonable = true } private func setupNavigationBar() { From 5b58dbe7fdadd96e1a31224027841342980cf4e2 Mon Sep 17 00:00:00 2001 From: JH713 Date: Sun, 21 Apr 2024 21:32:08 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20loading=20=EC=A4=91=20skeletonview?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/AddBookmark/AddBookmarkView.swift | 6 ++++ .../AddBookmarkViewController.swift | 30 +++++++++++++++++-- iBox/Sources/Model/BookmarkError.swift | 14 +++++++++ iBox/Sources/Shared/AddBookmarkManager.swift | 22 +++++++++----- 4 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 iBox/Sources/Model/BookmarkError.swift diff --git a/iBox/Sources/AddBookmark/AddBookmarkView.swift b/iBox/Sources/AddBookmark/AddBookmarkView.swift index 50b2873..e8d7d99 100644 --- a/iBox/Sources/AddBookmark/AddBookmarkView.swift +++ b/iBox/Sources/AddBookmark/AddBookmarkView.swift @@ -36,6 +36,8 @@ class AddBookmarkView: UIView { $0.text = "북마크 이름" $0.font = .cellTitleFont $0.textColor = .systemGray3 + $0.isSkeletonable = true + $0.isHiddenWhenSkeletonIsActive = true } let nameTextView = UITextView().then { @@ -66,6 +68,8 @@ class AddBookmarkView: UIView { $0.text = "URL" $0.font = .cellTitleFont $0.textColor = .systemGray3 + $0.isSkeletonable = true + $0.isHiddenWhenSkeletonIsActive = true } let urlTextView = UITextView().then { @@ -128,6 +132,8 @@ class AddBookmarkView: UIView { deinit { AddBookmarkManager.shared.incomingTitle = nil AddBookmarkManager.shared.incomingData = nil + AddBookmarkManager.shared.incomingFaviconUrl = nil + AddBookmarkManager.shared.incomingError = nil } // MARK: - Setup Methods diff --git a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift index 09588d6..ec81c88 100644 --- a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift +++ b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift @@ -5,6 +5,7 @@ // Created by jiyeon on 1/5/24. // +import Combine import UIKit import SkeletonView @@ -17,6 +18,8 @@ protocol AddBookmarkViewControllerProtocol: AnyObject { final class AddBookmarkViewController: UIViewController { weak var delegate: AddBookmarkViewControllerProtocol? + var cancellables = Set() + var haveValidInput = false var selectedFolder: Folder? var selectedFolderIndex: Int? @@ -33,8 +36,6 @@ final class AddBookmarkViewController: UIViewController { super.viewWillAppear(animated) updateSelectedFolder() addBookmarkView.updateTextFieldsFilledState() - -// view.showAnimatedGradientSkeleton() } override func viewDidLoad() { @@ -42,6 +43,7 @@ final class AddBookmarkViewController: UIViewController { setupNavigationBar() updateSelectedFolder() addBookmarkView.nameTextView.becomeFirstResponder() + setupBindings() view.isSkeletonable = true } @@ -111,6 +113,30 @@ final class AddBookmarkViewController: UIViewController { } } + private func setupBindings() { + AddBookmarkManager.shared.$isFetching + .receive(on: DispatchQueue.main) + .sink { [weak self] isFetching in + if isFetching { + self?.view.showAnimatedGradientSkeleton() + } else { + self?.view.hideSkeleton() + } + } + .store(in: &cancellables) + + AddBookmarkManager.shared.$incomingError + .receive(on: DispatchQueue.main) + .sink { [weak self] error in + guard error != nil else { return } + let alert = UIAlertController(title: "오류", message: "해당 URL을 가져올 수 없습니다", preferredStyle: .alert) + let okAction = UIAlertAction(title: "확인", style: .default) + alert.addAction(okAction) + self?.present(alert, animated: true) + } + .store(in: &cancellables) + } + @objc private func cancelButtonTapped() { let isTextFieldsEmpty = addBookmarkView.nameTextView.text?.isEmpty ?? true && addBookmarkView.urlTextView.text?.isEmpty ?? true diff --git a/iBox/Sources/Model/BookmarkError.swift b/iBox/Sources/Model/BookmarkError.swift new file mode 100644 index 0000000..0128173 --- /dev/null +++ b/iBox/Sources/Model/BookmarkError.swift @@ -0,0 +1,14 @@ +// +// BookmarkError.swift +// iBox +// +// Created by 이지현 on 4/21/24. +// + +import Foundation + +enum BookmarkError { + case htmlError + case decodeError + case parseError +} diff --git a/iBox/Sources/Shared/AddBookmarkManager.swift b/iBox/Sources/Shared/AddBookmarkManager.swift index 1b0962d..7015639 100644 --- a/iBox/Sources/Shared/AddBookmarkManager.swift +++ b/iBox/Sources/Shared/AddBookmarkManager.swift @@ -12,14 +12,17 @@ import SwiftSoup class AddBookmarkManager { static let shared = AddBookmarkManager() + @Published var isFetching: Bool = false @Published var incomingTitle: String? @Published var incomingData: String? @Published var incomingFaviconUrl: String? + @Published var incomingError: BookmarkError? private init() {} private func update(with data: (title: String?, data: String?, faviconUrl: String?)) { DispatchQueue.main.async { + self.isFetching = false self.incomingTitle = data.title?.removingPercentEncoding self.incomingData = data.data?.removingPercentEncoding self.incomingFaviconUrl = data.faviconUrl?.removingPercentEncoding @@ -33,9 +36,9 @@ class AddBookmarkManager { let faviconLink = try doc.select("link[rel='icon']").first()?.attr("href") self.update(with: (title: title, data: url.absoluteString, faviconUrl: faviconLink)) - } catch { - print("Error parsing HTML: \(error)") + self.isFetching = false + self.incomingError = .parseError } } @@ -53,7 +56,8 @@ class AddBookmarkManager { private func fetchWebsiteDetails(from url: URL) { let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let data = data, error == nil else { - print("Error downloading HTML: \(String(describing: error))") + self?.isFetching = false + self?.incomingError = .htmlError return } @@ -61,7 +65,8 @@ class AddBookmarkManager { let encoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString))) guard let html = String(data: data, encoding: encoding) else { - print("Failed to decode data with encoding: \(encodingName)") + self?.isFetching = false + self?.incomingError = .decodeError return } @@ -72,11 +77,12 @@ class AddBookmarkManager { func navigateToAddBookmarkView(from url: URL, in tabBarController: UITabBarController) { guard url.scheme == "iBox", let urlString = extractDataParameter(from: url) else { return } - guard let url = URL(string: urlString) else { - print("Invalid URL \(urlString)") - return - } + guard let url = URL(string: urlString) else { return } + incomingTitle = nil + incomingData = nil + incomingFaviconUrl = nil + isFetching = true fetchWebsiteDetails(from: url) tabBarController.selectedIndex = 0 From 4b90a42e52b958d580e4f87bb5d6961118d7f16c Mon Sep 17 00:00:00 2001 From: JH713 Date: Sun, 21 Apr 2024 22:13:53 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20fetch=20error=20=EC=8B=9C=20skeleto?= =?UTF-8?q?nView=20=EC=9C=A0=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iBox/Sources/AddBookmark/AddBookmarkViewController.swift | 5 ++++- iBox/Sources/BoxList/BoxListViewController.swift | 8 +++++++- iBox/Sources/Extension/UIViewController+Extension.swift | 8 ++++---- iBox/Sources/Shared/AddBookmarkManager.swift | 3 --- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift index ec81c88..671572a 100644 --- a/iBox/Sources/AddBookmark/AddBookmarkViewController.swift +++ b/iBox/Sources/AddBookmark/AddBookmarkViewController.swift @@ -118,6 +118,7 @@ final class AddBookmarkViewController: UIViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isFetching in if isFetching { + self?.view.hideSkeleton() self?.view.showAnimatedGradientSkeleton() } else { self?.view.hideSkeleton() @@ -130,7 +131,9 @@ final class AddBookmarkViewController: UIViewController { .sink { [weak self] error in guard error != nil else { return } let alert = UIAlertController(title: "오류", message: "해당 URL을 가져올 수 없습니다", preferredStyle: .alert) - let okAction = UIAlertAction(title: "확인", style: .default) + let okAction = UIAlertAction(title: "확인", style: .default) { _ in + AddBookmarkManager.shared.isFetching = false + } alert.addAction(okAction) self?.present(alert, animated: true) } diff --git a/iBox/Sources/BoxList/BoxListViewController.swift b/iBox/Sources/BoxList/BoxListViewController.swift index 5acb884..a0665f8 100644 --- a/iBox/Sources/BoxList/BoxListViewController.swift +++ b/iBox/Sources/BoxList/BoxListViewController.swift @@ -7,12 +7,18 @@ import UIKit +import SkeletonView + class BoxListViewController: BaseViewController, BaseViewControllerProtocol { var shouldPresentModalAutomatically: Bool = false { didSet { if shouldPresentModalAutomatically { - if findAddBookmarkViewController() == false { + if let vc = findAddBookmarkViewController() { + if let currentAlert = vc.presentedViewController as? UIAlertController { + vc.dismiss(animated: true) + } + } else { dismiss(animated: false) self.addButtonTapped() } diff --git a/iBox/Sources/Extension/UIViewController+Extension.swift b/iBox/Sources/Extension/UIViewController+Extension.swift index 51b6343..ff81455 100644 --- a/iBox/Sources/Extension/UIViewController+Extension.swift +++ b/iBox/Sources/Extension/UIViewController+Extension.swift @@ -19,11 +19,11 @@ extension UIViewController { return nil } - func findAddBookmarkViewController() -> Bool { + func findAddBookmarkViewController() -> AddBookmarkViewController? { if let navigationController = presentedViewController as? UINavigationController, - let _ = navigationController.topViewController as? AddBookmarkViewController { - return true + let vc = navigationController.topViewController as? AddBookmarkViewController { + return vc } - return false + return nil } } diff --git a/iBox/Sources/Shared/AddBookmarkManager.swift b/iBox/Sources/Shared/AddBookmarkManager.swift index 7015639..e1f8096 100644 --- a/iBox/Sources/Shared/AddBookmarkManager.swift +++ b/iBox/Sources/Shared/AddBookmarkManager.swift @@ -37,7 +37,6 @@ class AddBookmarkManager { self.update(with: (title: title, data: url.absoluteString, faviconUrl: faviconLink)) } catch { - self.isFetching = false self.incomingError = .parseError } } @@ -56,7 +55,6 @@ class AddBookmarkManager { private func fetchWebsiteDetails(from url: URL) { let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let data = data, error == nil else { - self?.isFetching = false self?.incomingError = .htmlError return } @@ -65,7 +63,6 @@ class AddBookmarkManager { let encoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString))) guard let html = String(data: data, encoding: encoding) else { - self?.isFetching = false self?.incomingError = .decodeError return } From 1a2798b616937a95afed9f213e15b8a7749e5c42 Mon Sep 17 00:00:00 2001 From: JH713 Date: Sun, 21 Apr 2024 22:14:34 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iBox/Sources/BoxList/BoxListViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iBox/Sources/BoxList/BoxListViewController.swift b/iBox/Sources/BoxList/BoxListViewController.swift index a0665f8..87ba714 100644 --- a/iBox/Sources/BoxList/BoxListViewController.swift +++ b/iBox/Sources/BoxList/BoxListViewController.swift @@ -15,8 +15,8 @@ class BoxListViewController: BaseViewController, BaseViewController didSet { if shouldPresentModalAutomatically { if let vc = findAddBookmarkViewController() { - if let currentAlert = vc.presentedViewController as? UIAlertController { - vc.dismiss(animated: true) + if vc.presentedViewController is UIAlertController { + vc.dismiss(animated: false) } } else { dismiss(animated: false)