diff --git a/EhPanda.xcodeproj/project.pbxproj b/EhPanda.xcodeproj/project.pbxproj index 91846dca..0b9ef286 100644 --- a/EhPanda.xcodeproj/project.pbxproj +++ b/EhPanda.xcodeproj/project.pbxproj @@ -7,9 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - AB19224F26727A2500F48E60 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = AB19224E26727A2500F48E60 /* Kingfisher */; }; + AB018DD2268756D000EB0EA9 /* Kanna in Frameworks */ = {isa = PBXBuildFile; productRef = AB018DD1268756D000EB0EA9 /* Kanna */; }; AB19D619266E5C6700BA752A /* TTProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = AB19D618266E5C6700BA752A /* TTProgressHUD */; }; - AB324F66266EFF4200F34A12 /* Kanna in Frameworks */ = {isa = PBXBuildFile; productRef = AB324F65266EFF4200F34A12 /* Kanna */; }; + AB2B0F3B2684228400777944 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = AB2B0F3A2684228400777944 /* SwiftyBeaver */; }; + AB2F72BF2685A8B00088DECA /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = AB2F72BE2685A8B00088DECA /* Kingfisher */; }; AB38A0CB25CA993D00764D64 /* ColorCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB38A0CA25CA993D00764D64 /* ColorCodable.swift */; }; AB40CFDC25983EC200D1DC9A /* FileStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB40CFDB25983EC200D1DC9A /* FileStorage.swift */; }; AB40CFDF25983EDF00D1DC9A /* FileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB40CFDE25983EDF00D1DC9A /* FileHelper.swift */; }; @@ -152,10 +153,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AB19224F26727A2500F48E60 /* Kingfisher in Frameworks */, ABE0FA2F25D4CAEC00E52F18 /* SDWebImageSwiftUI in Frameworks */, - AB324F66266EFF4200F34A12 /* Kanna in Frameworks */, + AB2B0F3B2684228400777944 /* SwiftyBeaver in Frameworks */, AB19D619266E5C6700BA752A /* TTProgressHUD in Frameworks */, + AB2F72BF2685A8B00088DECA /* Kingfisher in Frameworks */, + AB018DD2268756D000EB0EA9 /* Kanna in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -364,8 +366,9 @@ packageProductDependencies = ( ABE0FA2E25D4CAEC00E52F18 /* SDWebImageSwiftUI */, AB19D618266E5C6700BA752A /* TTProgressHUD */, - AB324F65266EFF4200F34A12 /* Kanna */, - AB19224E26727A2500F48E60 /* Kingfisher */, + AB2B0F3A2684228400777944 /* SwiftyBeaver */, + AB2F72BE2685A8B00088DECA /* Kingfisher */, + AB018DD1268756D000EB0EA9 /* Kanna */, ); productName = EhPanda; productReference = ABC3C7542593696C00E0C11B /* EhPanda.app */; @@ -400,8 +403,9 @@ packageReferences = ( ABE0FA2D25D4CAEC00E52F18 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */, AB19D617266E5C6700BA752A /* XCRemoteSwiftPackageReference "TTProgressHUD" */, - AB324F64266EFF4200F34A12 /* XCRemoteSwiftPackageReference "Kanna" */, - AB19224D26727A2500F48E60 /* XCRemoteSwiftPackageReference "Kingfisher" */, + AB2B0F392684228400777944 /* XCRemoteSwiftPackageReference "SwiftyBeaver" */, + AB2F72BD2685A8B00088DECA /* XCRemoteSwiftPackageReference "Kingfisher" */, + AB018DD0268756D000EB0EA9 /* XCRemoteSwiftPackageReference "Kanna" */, ); productRefGroup = ABC3C7552593696C00E0C11B /* Products */; projectDirPath = ""; @@ -666,7 +670,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = EhPanda/EhPanda.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 9SKQ7QTZ74; ENABLE_PREVIEWS = YES; @@ -693,7 +697,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = EhPanda/EhPanda.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 53; + CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 9SKQ7QTZ74; ENABLE_PREVIEWS = YES; @@ -737,12 +741,12 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - AB19224D26727A2500F48E60 /* XCRemoteSwiftPackageReference "Kingfisher" */ = { + AB018DD0268756D000EB0EA9 /* XCRemoteSwiftPackageReference "Kanna" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/tatsuz0u/Kingfisher.git"; + repositoryURL = "https://github.com/tid-kijyun/Kanna.git"; requirement = { - branch = "Remove-Accelerate"; - kind = branch; + kind = revision; + revision = 211beb276b7563eb9bb09474ce2d5f2176976232; }; }; AB19D617266E5C6700BA752A /* XCRemoteSwiftPackageReference "TTProgressHUD" */ = { @@ -753,12 +757,20 @@ kind = branch; }; }; - AB324F64266EFF4200F34A12 /* XCRemoteSwiftPackageReference "Kanna" */ = { + AB2B0F392684228400777944 /* XCRemoteSwiftPackageReference "SwiftyBeaver" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/tid-kijyun/Kanna.git"; + repositoryURL = "https://github.com/SwiftyBeaver/SwiftyBeaver.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 5.0.0; + minimumVersion = 1.9.5; + }; + }; + AB2F72BD2685A8B00088DECA /* XCRemoteSwiftPackageReference "Kingfisher" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/tatsuz0u/Kingfisher"; + requirement = { + branch = "Xcode-13-fix"; + kind = branch; }; }; ABE0FA2D25D4CAEC00E52F18 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = { @@ -772,20 +784,25 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - AB19224E26727A2500F48E60 /* Kingfisher */ = { + AB018DD1268756D000EB0EA9 /* Kanna */ = { isa = XCSwiftPackageProductDependency; - package = AB19224D26727A2500F48E60 /* XCRemoteSwiftPackageReference "Kingfisher" */; - productName = Kingfisher; + package = AB018DD0268756D000EB0EA9 /* XCRemoteSwiftPackageReference "Kanna" */; + productName = Kanna; }; AB19D618266E5C6700BA752A /* TTProgressHUD */ = { isa = XCSwiftPackageProductDependency; package = AB19D617266E5C6700BA752A /* XCRemoteSwiftPackageReference "TTProgressHUD" */; productName = TTProgressHUD; }; - AB324F65266EFF4200F34A12 /* Kanna */ = { + AB2B0F3A2684228400777944 /* SwiftyBeaver */ = { isa = XCSwiftPackageProductDependency; - package = AB324F64266EFF4200F34A12 /* XCRemoteSwiftPackageReference "Kanna" */; - productName = Kanna; + package = AB2B0F392684228400777944 /* XCRemoteSwiftPackageReference "SwiftyBeaver" */; + productName = SwiftyBeaver; + }; + AB2F72BE2685A8B00088DECA /* Kingfisher */ = { + isa = XCSwiftPackageProductDependency; + package = AB2F72BD2685A8B00088DECA /* XCRemoteSwiftPackageReference "Kingfisher" */; + productName = Kingfisher; }; ABE0FA2E25D4CAEC00E52F18 /* SDWebImageSwiftUI */ = { isa = XCSwiftPackageProductDependency; diff --git a/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d55dd0f3..149a9657 100644 --- a/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EhPanda.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,16 +6,16 @@ "repositoryURL": "https://github.com/tid-kijyun/Kanna.git", "state": { "branch": null, - "revision": "c657fb9f5827ef138068215c76ad0bb62bbc92da", - "version": "5.2.4" + "revision": "211beb276b7563eb9bb09474ce2d5f2176976232", + "version": null } }, { "package": "Kingfisher", - "repositoryURL": "https://github.com/tatsuz0u/Kingfisher.git", + "repositoryURL": "https://github.com/tatsuz0u/Kingfisher", "state": { - "branch": "Remove-Accelerate", - "revision": "a057f36f4e4af94a6fe3b3a1e6c70ada5f704050", + "branch": "Xcode-13-fix", + "revision": "ff901f1bbde87c923fb79bb084bb28a75d63b8dc", "version": null } }, @@ -37,6 +37,15 @@ "version": "2.0.2" } }, + { + "package": "SwiftyBeaver", + "repositoryURL": "https://github.com/SwiftyBeaver/SwiftyBeaver.git", + "state": { + "branch": null, + "revision": "2c039501d6eeb4d4cd4aec4a8d884ad28862e044", + "version": "1.9.5" + } + }, { "package": "TTProgressHUD", "repositoryURL": "https://github.com/tatsuz0u/TTProgressHUD.git", diff --git a/EhPanda/App/Defaults.swift b/EhPanda/App/Defaults.swift index c1f5ae82..e09cacc3 100644 --- a/EhPanda/App/Defaults.swift +++ b/EhPanda/App/Defaults.swift @@ -124,7 +124,7 @@ extension Defaults.URL { merge(urls: [ host, listCompact, - fSearch + keyword.URLString() + fSearch + keyword.urlEncoded() ] + applyFilters(filter: filter) ) @@ -139,7 +139,7 @@ extension Defaults.URL { urls: [ host, listCompact, - fSearch + keyword.URLString(), + fSearch + keyword.urlEncoded(), page + pageNum, from + lastID ] @@ -192,7 +192,7 @@ extension Defaults.URL { merge(keyword: keyword, pageNum: nil, lastID: nil) } static func similarGallery(keyword: String) -> String { - merge(urls: [host, listCompact, fSearch + keyword.URLString()]) + merge(urls: [host, listCompact, fSearch + keyword.urlEncoded()]) } static func moreAssociatedItemsRedir(keyword: AssociatedKeyword, lastID: String, pageNum: String) -> String { if let title = keyword.title { @@ -211,7 +211,7 @@ extension Defaults.URL { merge(urls: [ host, listCompact, - fSearch + keyword.URLString(), + fSearch + keyword.urlEncoded(), page + pageNum, from + lastID ]) @@ -334,8 +334,8 @@ private extension Defaults.URL { } static func merge(keyword: (String, String), pageNum: String?, lastID: String?) -> String { guard let pageNum = pageNum, let lastID = lastID else { - return host + tag + "\(keyword.0):\(keyword.1.URLString())" + return host + tag + "\(keyword.0):\(keyword.1.urlEncoded())" } - return merge(urls: [host + tag + "\(keyword.0):\(keyword.1.URLString())/\(pageNum)", from + lastID]) + return merge(urls: [host + tag + "\(keyword.0):\(keyword.1.urlEncoded())/\(pageNum)", from + lastID]) } } diff --git a/EhPanda/App/EhPandaApp.swift b/EhPanda/App/EhPandaApp.swift index db86e016..0addbeed 100644 --- a/EhPanda/App/EhPandaApp.swift +++ b/EhPanda/App/EhPandaApp.swift @@ -7,6 +7,7 @@ import SwiftUI import Kingfisher +import SwiftyBeaver import SDWebImageSwiftUI @main @@ -14,6 +15,7 @@ struct EhPandaApp: App { @StateObject private var store = Store() init() { + configureLogging() configureWebImage() clearImageCachesIfNeeded() } @@ -57,6 +59,42 @@ private extension EhPandaApp { } } + func configureLogging() { + var file = FileDestination() + var console = ConsoleDestination() + let format = [ + "$Dyyyy-MM-dd HH:mm:ss.SSS$d", + "$C$L$c $N.$F:$l - $M $X" + ].joined(separator: " ") + + file.format = format + console.format = format + configure(file: &file) + configure(console: &console) + + SwiftyBeaver.addDestination(file) + #if DEBUG + SwiftyBeaver.addDestination(console) + #endif + } + func configure(file: inout FileDestination) { + file.logFileAmount = 5 + file.logFileURL = try? FileManager.default.url( + for: .documentDirectory, in: .userDomainMask, + appropriateFor: nil, create: true + ).appendingPathComponent("EhPanda.log") + } + func configure(console: inout ConsoleDestination) { + #if DEBUG + console.asynchronously = false + #endif + console.levelColor.verbose = "😪" + console.levelColor.debug = "🐛" + console.levelColor.info = "📖" + console.levelColor.warning = "⚠️" + console.levelColor.error = "‼️" + } + func configureWebImage() { let config = KingfisherManager.shared.downloader.sessionConfiguration config.httpCookieStorage = HTTPCookieStorage.shared diff --git a/EhPanda/App/Extensions.swift b/EhPanda/App/Extensions.swift index 1faa9a21..8c1e9ddb 100644 --- a/EhPanda/App/Extensions.swift +++ b/EhPanda/App/Extensions.swift @@ -11,7 +11,7 @@ import Combine import Foundation extension Dictionary where Key == String, Value == String { - func jsonString() -> String { + func dictString() -> String { var array = [String]() keys.forEach { key in let value = self[key]! @@ -68,8 +68,8 @@ extension String { String(localized: StringLocalizationKey(self)) } - func URLString() -> String { - self.addingPercentEncoding( + func urlEncoded() -> String { + addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed ) ?? "" } diff --git a/EhPanda/App/Info.plist b/EhPanda/App/Info.plist index 2fd3333b..fd3b81c9 100644 --- a/EhPanda/App/Info.plist +++ b/EhPanda/App/Info.plist @@ -77,6 +77,8 @@ LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + NSFaceIDUsageDescription We need this permission to provide Face ID option while unlocking the App. UIApplicationSceneManifest @@ -86,6 +88,8 @@ UIApplicationSupportsIndirectInputEvents + UIFileSharingEnabled + UILaunchScreen UIRequiredDeviceCapabilities diff --git a/EhPanda/App/Tools/Parser.swift b/EhPanda/App/Tools/Parser.swift index 936cb9fd..5c040d9a 100644 --- a/EhPanda/App/Tools/Parser.swift +++ b/EhPanda/App/Tools/Parser.swift @@ -952,19 +952,16 @@ extension Parser { static func parseCommentContent(node: XMLElement) -> [CommentContent] { var contents = [CommentContent]() + for div in node.xpath("//div") { + node.removeChild(div) + } + for span in node.xpath("span") { + node.removeChild(span) + } + guard var rawContent = node.innerHTML? .replacingOccurrences(of: "
", with: "\n") .replacingOccurrences(of: "", with: "") - .replacingOccurrences( - of: ".*?", - with: "", - options: .regularExpression - ) - .replacingOccurrences( - of: "", - with: "", - options: .regularExpression - ) else { return [] } while (node.xpath("//a").count @@ -994,7 +991,9 @@ extension Parser { } guard let link = tmpLink, - let html = link.toHTML, + let html = link.toHTML? + .replacingOccurrences(of: "
", with: "\n") + .replacingOccurrences(of: "", with: ""), let range = rawContent.range(of: html) else { continue } diff --git a/EhPanda/DataFlow/AppAction.swift b/EhPanda/DataFlow/AppAction.swift index 3e8a99cd..b8d97447 100644 --- a/EhPanda/DataFlow/AppAction.swift +++ b/EhPanda/DataFlow/AppAction.swift @@ -30,17 +30,17 @@ enum AppAction { case replaceMangaCommentJumpID(gid: String?) case updateIsSlideMenuClosed(isClosed: Bool) - case toggleAppUnlocked(isUnlocked: Bool) - case toggleBlurEffect(effectOn: Bool) - case toggleHomeListType(type: HomeListType) - case toggleFavoriteIndex(index: Int) - case toggleNavBarHidden(isHidden: Bool) - case toggleHomeViewSheetState(state: HomeViewSheetState?) - case toggleSettingViewSheetState(state: SettingViewSheetState?) - case toggleSettingViewActionSheetState(state: SettingViewActionSheetState) - case toggleFilterViewActionSheetState(state: FilterViewActionSheetState) - case toggleDetailViewSheetState(state: DetailViewSheetState?) - case toggleCommentViewSheetState(state: CommentViewSheetState?) + case toggleApp(unlocked: Bool) + case toggleBlur(effectOn: Bool) + case toggleHomeList(type: HomeListType) + case toggleFavorite(index: Int) + case toggleNavBar(hidden: Bool) + case toggleHomeViewSheet(state: HomeViewSheetState?) + case toggleSettingViewSheet(state: SettingViewSheetState?) + case toggleSettingViewActionSheet(state: SettingViewActionSheetState) + case toggleFilterViewActionSheet(state: FilterViewActionSheetState) + case toggleDetailViewSheet(state: DetailViewSheetState?) + case toggleCommentViewSheet(state: CommentViewSheetState?) case fetchGreeting case fetchGreetingDone(result: Result) diff --git a/EhPanda/DataFlow/AppState.swift b/EhPanda/DataFlow/AppState.swift index 7593c58e..281e9eb2 100644 --- a/EhPanda/DataFlow/AppState.swift +++ b/EhPanda/DataFlow/AppState.swift @@ -287,12 +287,10 @@ extension AppState { pageNum: PageNumber, items: [Manga] ) { - if associatedItems.count >= depth + 1 { + if associatedItems.count > depth { associatedItems[depth].keyword = keyword associatedItems[depth].pageNum = pageNum associatedItems[depth].mangas.append(contentsOf: items) - } else { - print("AssociatedItemsUpdating: Not found") } } } @@ -319,7 +317,6 @@ extension AppState { items?[gid] != nil } mutating func cache(mangas: [Manga]) { - let previousCount = items?.count ?? 0 if items == nil { items = Dictionary(uniqueKeysWithValues: mangas.map { ($0.id, $0) }) return @@ -335,8 +332,6 @@ extension AppState { items?[manga.gid]?.language = manga.language } } - let currentCount = items?.count ?? 0 - print("CachedList updated: \(previousCount) -> \(currentCount)") } mutating func insertDetail(gid: String, detail: MangaDetail) { diff --git a/EhPanda/DataFlow/Store.swift b/EhPanda/DataFlow/Store.swift index 729c6161..bebc4d4e 100644 --- a/EhPanda/DataFlow/Store.swift +++ b/EhPanda/DataFlow/Store.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import SwiftyBeaver final class Store: ObservableObject { @Published var appState = AppState() @@ -14,12 +15,22 @@ final class Store: ObservableObject { func dispatch(_ action: AppAction) { if appState.environment.isPreview { return } - print("[ACTION]: \(action)") + let description = String(describing: action) + if description.contains("error") { + SwiftyBeaver.error("[ACTION]: " + description) + } else { + switch action { + case .saveAspectBox(let gid, _): + SwiftyBeaver.verbose("[ACTION]: saveAspectBox(gid: \(gid))") + default: + SwiftyBeaver.verbose("[ACTION]: " + description) + } + } let result = reduce(state: appState, action: action) appState = result.0 guard let command = result.1 else { return } - print("[COMMAND]: \(command)") + SwiftyBeaver.verbose("[COMMAND]: \(command)") command.execute(in: self) } @@ -79,32 +90,32 @@ final class Store: ObservableObject { appState.environment.isSlideMenuClosed = isClosed // MARK: App Env - case .toggleAppUnlocked(let isUnlocked): - appState.environment.isAppUnlocked = isUnlocked - case .toggleBlurEffect(let effectOn): + case .toggleApp(let unlocked): + appState.environment.isAppUnlocked = unlocked + case .toggleBlur(let effectOn): withAnimation(.linear(duration: 0.1)) { appState.environment.blurRadius = effectOn ? 10 : 0 } - case .toggleHomeListType(let type): + case .toggleHomeList(let type): appState.environment.homeListType = type - case .toggleFavoriteIndex(let index): + case .toggleFavorite(let index): appState.environment.favoritesIndex = index - case .toggleNavBarHidden(let isHidden): - appState.environment.navBarHidden = isHidden - case .toggleHomeViewSheetState(let state): + case .toggleNavBar(let hidden): + appState.environment.navBarHidden = hidden + case .toggleHomeViewSheet(let state): if state != nil { impactFeedback(style: .light) } appState.environment.homeViewSheetState = state - case .toggleSettingViewSheetState(let state): + case .toggleSettingViewSheet(let state): if state != nil { impactFeedback(style: .light) } appState.environment.settingViewSheetState = state - case .toggleSettingViewActionSheetState(let state): + case .toggleSettingViewActionSheet(let state): appState.environment.settingViewActionSheetState = state - case .toggleFilterViewActionSheetState(let state): + case .toggleFilterViewActionSheet(let state): appState.environment.filterViewActionSheetState = state - case .toggleDetailViewSheetState(let state): + case .toggleDetailViewSheet(let state): if state != nil { impactFeedback(style: .light) } appState.environment.detailViewSheetState = state - case .toggleCommentViewSheetState(let state): + case .toggleCommentViewSheet(let state): if state != nil { impactFeedback(style: .light) } appState.environment.commentViewSheetState = state @@ -131,7 +142,6 @@ final class Store: ObservableObject { greeting.updateTime = Date() appState.settings.insert(greeting: greeting) } - print(error) } case .fetchUserInfo: @@ -144,11 +154,8 @@ final class Store: ObservableObject { case .fetchUserInfoDone(let result): appState.settings.userInfoLoading = false - switch result { - case .success(let user): + if case .success(let user) = result { appState.settings.update(user: user) - case .failure(let error): - print(error) } case .fetchFavoriteNames: @@ -159,11 +166,8 @@ final class Store: ObservableObject { case .fetchFavoriteNamesDone(let result): appState.settings.favoriteNamesLoading = false - switch result { - case .success(let names): + if case .success(let names) = result { appState.settings.user?.favoriteNames = names - case .failure(let error): - print(error) } case .fetchMangaItemReverse(let detailURL): @@ -180,9 +184,8 @@ final class Store: ObservableObject { case .success(let manga): appState.cachedList.cache(mangas: [manga]) appState.environment.mangaItemReverseID = manga.gid - case .failure(let error): + case .failure: appState.environment.mangaItemReverseLoadFailed = true - print(error) } case .fetchSearchItems(let keyword): @@ -215,9 +218,8 @@ final class Store: ObservableObject { } else { appState.cachedList.cache(mangas: mangas.2) } - case .failure(let error): + case .failure: appState.homeInfo.searchLoadFailed = true - print(error) } case .fetchMoreSearchItems(let keyword): @@ -257,9 +259,8 @@ final class Store: ObservableObject { } else if appState.homeInfo.searchItems?.isEmpty == true { appState.homeInfo.searchNotFound = true } - case .failure(let error): + case .failure: appState.homeInfo.moreSearchLoadFailed = true - print(error) } case .fetchFrontpageItems: @@ -290,9 +291,8 @@ final class Store: ObservableObject { } else { appState.cachedList.cache(mangas: mangas.1) } - case .failure(let error): + case .failure: appState.homeInfo.frontpageLoadFailed = true - print(error) } case .fetchMoreFrontpageItems: @@ -326,9 +326,8 @@ final class Store: ObservableObject { } else if appState.homeInfo.frontpageItems?.isEmpty == true { appState.homeInfo.frontpageNotFound = true } - case .failure(let error): + case .failure: appState.homeInfo.moreFrontpageLoadFailed = true - print(error) } case .fetchPopularItems: @@ -349,8 +348,7 @@ final class Store: ObservableObject { appState.homeInfo.popularItems = mangas.1 appState.cachedList.cache(mangas: mangas.1) } - case .failure(let error): - print(error) + case .failure: appState.homeInfo.popularLoadFailed = true } @@ -382,8 +380,7 @@ final class Store: ObservableObject { } else { appState.cachedList.cache(mangas: mangas.1) } - case .failure(let error): - print(error) + case .failure: appState.homeInfo.watchedLoadFailed = true } @@ -418,9 +415,8 @@ final class Store: ObservableObject { } else if appState.homeInfo.watchedItems?.isEmpty == true { appState.homeInfo.watchedNotFound = true } - case .failure(let error): + case .failure: appState.homeInfo.moreWatchedLoadFailed = true - print(error) } case .fetchFavoritesItems(let favIndex): @@ -451,9 +447,8 @@ final class Store: ObservableObject { } else { appState.cachedList.cache(mangas: mangas.1) } - case .failure(let error): + case .failure: appState.homeInfo.favoritesLoadFailed[carriedValue] = true - print(error) } case .fetchMoreFavoritesItems(let favIndex): @@ -491,9 +486,8 @@ final class Store: ObservableObject { } else if appState.homeInfo.favoritesItems[carriedValue]?.isEmpty == true { appState.homeInfo.favoritesNotFound[carriedValue] = true } - case .failure(let error): + case .failure: appState.homeInfo.moreFavoritesLoading[carriedValue] = true - print(error) } case .fetchMangaDetail(let gid): @@ -511,8 +505,7 @@ final class Store: ObservableObject { case .success(let detail): appState.settings.user?.apikey = detail.2 appState.cachedList.insertDetail(gid: detail.0, detail: detail.1) - case .failure(let error): - print(error) + case .failure: appState.detailInfo.mangaDetailLoadFailed = true } @@ -541,8 +534,7 @@ final class Store: ObservableObject { ) ) } - case .failure(let error): - print(error) + case .failure: appState.detailInfo.mangaArchiveLoadFailed = true } @@ -555,16 +547,13 @@ final class Store: ObservableObject { case .fetchMangaArchiveFundsDone(let result): appState.detailInfo.mangaArchiveFundsLoading = false - switch result { - case .success(let funds): + if case .success(let funds) = result { appState.settings.update( user: User( currentGP: funds.0, currentCredits: funds.1 ) ) - case .failure(let error): - print(error) } case .fetchMangaTorrents(let gid): @@ -581,8 +570,7 @@ final class Store: ObservableObject { switch result { case .success(let torrents): appState.cachedList.insertTorrents(gid: torrents.0, torrents: torrents.1) - case .failure(let error): - print(error) + case .failure: appState.detailInfo.mangaTorrentsLoadFailed = true } @@ -617,8 +605,7 @@ final class Store: ObservableObject { } else { appState.cachedList.cache(mangas: mangas.3) } - case .failure(let error): - print(error) + case .failure: appState.detailInfo.associatedItemsLoadFailed = true } @@ -661,9 +648,8 @@ final class Store: ObservableObject { } else if appState.detailInfo.associatedItems.isEmpty { appState.detailInfo.associatedItemsNotFound = true } - case .failure(let error): + case .failure: appState.detailInfo.moreAssociatedItemsLoadFailed = true - print(error) } case .fetchAlterImages(let gid): @@ -676,11 +662,8 @@ final class Store: ObservableObject { case .fetchAlterImagesDone(let result): appState.detailInfo.alterImagesLoading = false - switch result { - case .success(let images): + if case .success(let images) = result { appState.cachedList.insertAlterImages(gid: images.0, images: images.1) - case .failure(let error): - print(error) } case .updateMangaDetail(let gid): @@ -692,11 +675,8 @@ final class Store: ObservableObject { case .updateMangaDetailDone(let result): appState.detailInfo.mangaDetailUpdating = false - switch result { - case .success(let detail): + if case .success(let detail) = result { appState.cachedList.updateDetail(gid: detail.0, detail: detail.1) - case .failure(let error): - print(error) } case .updateMangaComments(let gid): @@ -708,11 +688,8 @@ final class Store: ObservableObject { case .updateMangaCommentsDone(result: let result): appState.detailInfo.mangaCommentsUpdating = false - switch result { - case .success(let comments): + if case .success(let comments) = result { appState.cachedList.updateComments(gid: comments.0, comments: comments.1) - case .failure(let error): - print(error) } case .fetchMangaContents(let gid): @@ -735,9 +712,8 @@ final class Store: ObservableObject { pageNum: contents.1, contents: contents.2 ) - case .failure(let error): + case .failure: appState.contentInfo.mangaContentsLoadFailed = true - print(error) } case .fetchMoreMangaContents(let gid): @@ -763,6 +739,17 @@ final class Store: ObservableObject { pageNum: pageNum, pageCount: pageCount ) + + if pageCount >= Int(detail.pageCount) ?? 0 { + SwiftyBeaver.error( + "MangaContents overflow", + context: [ + "detailURL": manga.detailURL, + "pageLimit": detail.pageCount, + "pageCurrentAmount": pageCount + ] + ) + } case .fetchMoreMangaContentsDone(let result): appState.contentInfo.moreMangaContentsLoading = false @@ -773,9 +760,8 @@ final class Store: ObservableObject { pageNum: contents.1, contents: contents.2 ) - case .failure(let error): + case .failure: appState.contentInfo.moreMangaContentsLoadFailed = true - print(error) } // MARK: Account Ops diff --git a/EhPanda/Models/Manga.swift b/EhPanda/Models/Manga.swift index 25750288..0d5d7fc9 100644 --- a/EhPanda/Models/Manga.swift +++ b/EhPanda/Models/Manga.swift @@ -205,7 +205,11 @@ struct MangaTorrent: Identifiable, Codable { } // MARK: Computed Properties -extension Manga: DateFormattable { +extension Manga: DateFormattable, CustomStringConvertible { + var description: String { + "Manga(\(gid))" + } + var filledCount: Int { Int(rating) } var halfFilledCount: Int { Int(rating - 0.5) == filledCount ? 1 : 0 } var notFilledCount: Int { 5 - filledCount - halfFilledCount } @@ -218,7 +222,11 @@ extension Manga: DateFormattable { } } -extension MangaDetail: DateFormattable { +extension MangaDetail: DateFormattable, CustomStringConvertible { + var description: String { + "MangaDetail(\(jpnTitle ?? title))" + } + var languageAbbr: String { language.languageAbbr } @@ -227,13 +235,22 @@ extension MangaDetail: DateFormattable { } } +extension MangaContent: CustomStringConvertible { + var description: String { + "MangaContent(\(tag))" + } +} + extension MangaComment: DateFormattable { var originalDate: Date { commentDate } } -extension MangaTorrent: DateFormattable { +extension MangaTorrent: DateFormattable, CustomStringConvertible { + var description: String { + "MangaTorrent(\(fileName))" + } var originalDate: Date { postedDate } diff --git a/EhPanda/Network/Request.swift b/EhPanda/Network/Request.swift index dd077ee7..90ddd1d6 100644 --- a/EhPanda/Network/Request.swift +++ b/EhPanda/Network/Request.swift @@ -8,8 +8,10 @@ import Kanna import Combine import Foundation +import SwiftyBeaver private func mapAppError(error: Error) -> AppError { + SwiftyBeaver.error(error) switch error { case is ParseError: return .parseFailed @@ -512,7 +514,7 @@ struct AddFavoriteRequest { var request = URLRequest(url: url.safeURL()) request.httpMethod = "POST" - request.httpBody = parameters.jsonString().data(using: .utf8) + request.httpBody = parameters.dictString().urlEncoded().data(using: .utf8) return URLSession.shared.dataTaskPublisher(for: request) .map { $0 } @@ -535,7 +537,7 @@ struct DeleteFavoriteRequest { var request = URLRequest(url: url.safeURL()) request.httpMethod = "POST" - request.httpBody = parameters.jsonString().data(using: .utf8) + request.httpBody = parameters.dictString().urlEncoded().data(using: .utf8) return URLSession.shared.dataTaskPublisher(for: request) .map { $0 } @@ -556,7 +558,7 @@ struct SendDownloadCommandRequest { var request = URLRequest(url: archiveURL.safeURL()) request.httpMethod = "POST" - request.httpBody = parameters.jsonString().data(using: .utf8) + request.httpBody = parameters.dictString().urlEncoded().data(using: .utf8) return URLSession.shared.dataTaskPublisher(for: request) .tryMap { try Kanna.HTML(html: $0.data, encoding: .utf8) } @@ -608,7 +610,7 @@ struct CommentRequest { var request = URLRequest(url: detailURL.safeURL()) request.httpMethod = "POST" - request.httpBody = parameters.jsonString().data(using: .utf8) + request.httpBody = parameters.dictString().urlEncoded().data(using: .utf8) return URLSession.shared.dataTaskPublisher(for: request) .map { $0 } @@ -632,7 +634,7 @@ struct EditCommentRequest { var request = URLRequest(url: detailURL.safeURL()) request.httpMethod = "POST" - request.httpBody = parameters.jsonString().data(using: .utf8) + request.httpBody = parameters.dictString().urlEncoded().data(using: .utf8) return URLSession.shared.dataTaskPublisher(for: request) .map { $0 } diff --git a/EhPanda/View/Content/ContentView.swift b/EhPanda/View/Content/ContentView.swift index c47d49e2..1a7d9723 100644 --- a/EhPanda/View/Content/ContentView.swift +++ b/EhPanda/View/Content/ContentView.swift @@ -73,6 +73,8 @@ struct ContentView: View, StoreAccessor { .onAppear { onWebImageAppear(item: item) } + Text("\(item.tag + 1)/\(mangaDetail?.pageCount ?? "")") + .bold().font(.largeTitle).foregroundColor(.gray) } } LoadMoreFooter( @@ -206,7 +208,7 @@ private extension ContentView { } func toggleNavBarHiddenIfNeeded() { if !environment.navBarHidden { - store.dispatch(.toggleNavBarHidden(isHidden: true)) + store.dispatch(.toggleNavBar(hidden: true)) } } @@ -335,7 +337,6 @@ private extension ContentView { withAnimation { scale = newScale - print("debugMark: \(newScale)") } } } diff --git a/EhPanda/View/Detail/ArchiveView.swift b/EhPanda/View/Detail/ArchiveView.swift index 80a716e7..37f071a6 100644 --- a/EhPanda/View/Detail/ArchiveView.swift +++ b/EhPanda/View/Detail/ArchiveView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import SwiftyBeaver import TTProgressHUD struct ArchiveView: View, StoreAccessor { @@ -135,7 +136,7 @@ private extension ArchiveView { case .error: notificFeedback(style: .error) default: - print(type) + SwiftyBeaver.verbose(type) } hudConfig = TTProgressHUDConfig( diff --git a/EhPanda/View/Detail/CommentView.swift b/EhPanda/View/Detail/CommentView.swift index 3c7ad37b..70989bbe 100644 --- a/EhPanda/View/Detail/CommentView.swift +++ b/EhPanda/View/Detail/CommentView.swift @@ -81,7 +81,6 @@ struct CommentView: View, StoreAccessor { ToolbarItem(placement: .navigationBarTrailing) { Button(action: toggleNewComment, label: { Image(systemName: "square.and.pencil") - Text("Post Comment") }) } } @@ -220,7 +219,7 @@ private extension CommentView { func edit(comment: MangaComment) { editCommentID = comment.commentID editCommentContent = trim(contents: comment.contents) - store.dispatch(.toggleCommentViewSheetState(state: .editComment)) + store.dispatch(.toggleCommentViewSheet(state: .editComment)) } func postNewComment() { store.dispatch(.comment(gid: gid, content: commentContent)) @@ -244,10 +243,10 @@ private extension CommentView { } func toggleNewComment() { - store.dispatch(.toggleCommentViewSheetState(state: .newComment)) + store.dispatch(.toggleCommentViewSheet(state: .newComment)) } func toggleCommentViewSheetNil() { - store.dispatch(.toggleCommentViewSheetState(state: nil)) + store.dispatch(.toggleCommentViewSheet(state: nil)) } } diff --git a/EhPanda/View/Detail/DetailView.swift b/EhPanda/View/Detail/DetailView.swift index f51e8984..b06ac143 100644 --- a/EhPanda/View/Detail/DetailView.swift +++ b/EhPanda/View/Detail/DetailView.swift @@ -164,7 +164,7 @@ private extension DetailView { private extension DetailView { func onAppear() { if environment.navBarHidden { - store.dispatch(.toggleNavBarHidden(isHidden: false)) + store.dispatch(.toggleNavBar(hidden: false)) } if mangaDetail == nil { @@ -227,7 +227,7 @@ private extension DetailView { toggleSheetStateNil() } func toggleSheet(state: DetailViewSheetState?) { - store.dispatch(.toggleDetailViewSheetState(state: state)) + store.dispatch(.toggleDetailViewSheet(state: state)) } func toggleSheetStateNil() { toggleSheet(state: nil) diff --git a/EhPanda/View/Home/AuthView.swift b/EhPanda/View/Home/AuthView.swift index 6ba0a0f9..021b3cbc 100644 --- a/EhPanda/View/Home/AuthView.swift +++ b/EhPanda/View/Home/AuthView.swift @@ -92,11 +92,11 @@ private extension AuthView { withAnimation(.linear(duration: 0.1)) { blurRadius = effectOn ? 10 : 0 } - store.dispatch(.toggleBlurEffect(effectOn: effectOn)) + store.dispatch(.toggleBlur(effectOn: effectOn)) } func set(isUnlocked: Bool) { - store.dispatch(.toggleAppUnlocked(isUnlocked: isUnlocked)) + store.dispatch(.toggleApp(unlocked: isUnlocked)) } func lockIfExpired() { diff --git a/EhPanda/View/Home/FilterView.swift b/EhPanda/View/Home/FilterView.swift index 7554a6db..9d30c2ff 100644 --- a/EhPanda/View/Home/FilterView.swift +++ b/EhPanda/View/Home/FilterView.swift @@ -76,7 +76,7 @@ private extension FilterView { } func onResetButtonTap() { - store.dispatch(.toggleFilterViewActionSheetState(state: .resetFilters)) + store.dispatch(.toggleFilterViewActionSheet(state: .resetFilters)) } func resetFilters() { store.dispatch(.initializeFilter) diff --git a/EhPanda/View/Home/HomeView.swift b/EhPanda/View/Home/HomeView.swift index c54f1e76..dd30e91e 100644 --- a/EhPanda/View/Home/HomeView.swift +++ b/EhPanda/View/Home/HomeView.swift @@ -35,11 +35,11 @@ struct HomeView: View, StoreAccessor { TTProgressHUD($hudVisible, config: hudConfig) } .searchable( - "Search", text: homeInfoBinding.searchKeyword, placement: .navigationBarDrawer( displayMode: .always ), + prompt: "Search", suggestions: { ForEach(suggestions, id: \.self) { word in HStack { @@ -291,7 +291,7 @@ private extension HomeView { !greeting.gainedNothing { self.greeting = greeting - store.dispatch(.toggleHomeViewSheetState(state: .newDawn)) + store.dispatch(.toggleHomeViewSheet(state: .newDawn)) } } func onSearchKeywordChange(keyword: String) { @@ -303,7 +303,7 @@ private extension HomeView { fetchFavoritesItemsIfNeeded() } func onFavMenuSelect(index: Int) { - store.dispatch(.toggleFavoriteIndex(index: index)) + store.dispatch(.toggleFavorite(index: index)) } func onJumpIDChange(value: String?) { if value != nil, hasJumpPermission { @@ -320,7 +320,7 @@ private extension HomeView { } func onSearchSubmit() { if environment.homeListType != .search { - store.dispatch(.toggleHomeListType(type: .search)) + store.dispatch(.toggleHomeList(type: .search)) } if !homeInfo.searchKeyword.isEmpty { archivedKeyword = homeInfo.searchKeyword @@ -387,7 +387,7 @@ private extension HomeView { } func clearObstruction() { if environment.homeViewSheetState != nil { - store.dispatch(.toggleHomeViewSheetState(state: nil)) + store.dispatch(.toggleHomeViewSheet(state: nil)) } if environment.isSlideMenuClosed != true { postSlideMenuShouldCloseNotification() @@ -523,6 +523,7 @@ private struct GenericList: View { gid: item.gid, depth: 0 ) ) {} + .opacity(0) MangaSummaryRow( manga: item, setting: setting diff --git a/EhPanda/View/Home/SlideMenu.swift b/EhPanda/View/Home/SlideMenu.swift index c663db12..0d779dc9 100644 --- a/EhPanda/View/Home/SlideMenu.swift +++ b/EhPanda/View/Home/SlideMenu.swift @@ -80,7 +80,7 @@ private extension SlideMenu { func onMenuRowTap(item: HomeListType) { if homeListType != item { - store.dispatch(.toggleHomeListType(type: item)) + store.dispatch(.toggleHomeList(type: item)) impactFeedback(style: .soft) if setting?.closeSlideMenuAfterSelection == true { @@ -89,7 +89,7 @@ private extension SlideMenu { } } func onSettingMenuRowTap() { - store.dispatch(.toggleHomeViewSheetState(state: .setting)) + store.dispatch(.toggleHomeViewSheet(state: .setting)) } func onFavoritesIndexChange(_ : Int) { if setting?.closeSlideMenuAfterSelection == true { diff --git a/EhPanda/View/Setting/AccountSettingView.swift b/EhPanda/View/Setting/AccountSettingView.swift index 57400612..e5e0b9c2 100644 --- a/EhPanda/View/Setting/AccountSettingView.swift +++ b/EhPanda/View/Setting/AccountSettingView.swift @@ -152,16 +152,16 @@ private extension AccountSettingView { // MARK: Dispatch Methods func toggleWebViewLogin() { - store.dispatch(.toggleSettingViewSheetState(state: .webviewLogin)) + store.dispatch(.toggleSettingViewSheet(state: .webviewLogin)) } func toggleWebViewConfig() { - store.dispatch(.toggleSettingViewSheetState(state: .webviewConfig)) + store.dispatch(.toggleSettingViewSheet(state: .webviewConfig)) } func toggleWebViewMyTags() { - store.dispatch(.toggleSettingViewSheetState(state: .webviewMyTags)) + store.dispatch(.toggleSettingViewSheet(state: .webviewMyTags)) } func toggleLogout() { - store.dispatch(.toggleSettingViewActionSheetState(state: .logout)) + store.dispatch(.toggleSettingViewActionSheet(state: .logout)) } } diff --git a/EhPanda/View/Setting/AppearanceSettingView.swift b/EhPanda/View/Setting/AppearanceSettingView.swift index 85215693..e83abde0 100644 --- a/EhPanda/View/Setting/AppearanceSettingView.swift +++ b/EhPanda/View/Setting/AppearanceSettingView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import SwiftyBeaver struct AppearanceSettingView: View, StoreAccessor { @EnvironmentObject var store: Store @@ -138,7 +139,7 @@ private struct SelectAppIconView: View { UIApplication.shared.setAlternateIconName(icon.fileName) { error in if let error = error { notificFeedback(style: .error) - print(error) + SwiftyBeaver.error(error) } selectAction() } diff --git a/EhPanda/View/Setting/EhPandaView.swift b/EhPanda/View/Setting/EhPandaView.swift index 69b29e8d..ace79d93 100644 --- a/EhPanda/View/Setting/EhPandaView.swift +++ b/EhPanda/View/Setting/EhPandaView.swift @@ -49,6 +49,10 @@ struct EhPandaView: View, StoreAccessor { url: "https://github.com/onevcat/Kingfisher", text: "Kingfisher" ), + Info( + url: "https://github.com/SwiftyBeaver/SwiftyBeaver", + text: "SwiftyBeaver" + ), Info( url: "https://github.com/honkmaster/TTProgressHUD", text: "TTProgressHUD" diff --git a/EhPanda/View/Setting/GeneralSettingView.swift b/EhPanda/View/Setting/GeneralSettingView.swift index f82fd751..1201ee3c 100644 --- a/EhPanda/View/Setting/GeneralSettingView.swift +++ b/EhPanda/View/Setting/GeneralSettingView.swift @@ -122,9 +122,9 @@ private extension GeneralSettingView { } func toggleClearImgCaches() { - store.dispatch(.toggleSettingViewActionSheetState(state: .clearImgCaches)) + store.dispatch(.toggleSettingViewActionSheet(state: .clearImgCaches)) } func toggleClearWebCaches() { - store.dispatch(.toggleSettingViewActionSheetState(state: .clearWebCaches)) + store.dispatch(.toggleSettingViewActionSheet(state: .clearWebCaches)) } } diff --git a/EhPanda/View/Setting/SettingView.swift b/EhPanda/View/Setting/SettingView.swift index 52cc9c75..775bb36e 100644 --- a/EhPanda/View/Setting/SettingView.swift +++ b/EhPanda/View/Setting/SettingView.swift @@ -7,6 +7,7 @@ import SwiftUI import Kingfisher +import SwiftyBeaver import SDWebImageSwiftUI struct SettingView: View, StoreAccessor { @@ -113,7 +114,7 @@ private extension SettingView { ) ) case .failure(let error): - print(error) + SwiftyBeaver.error(error) } } } diff --git a/EhPanda/View/Setting/WebView.swift b/EhPanda/View/Setting/WebView.swift index 497f0c15..66252d1e 100644 --- a/EhPanda/View/Setting/WebView.swift +++ b/EhPanda/View/Setting/WebView.swift @@ -5,8 +5,9 @@ // Created by 荒木辰造 on R 2/12/27. // -import SwiftUI import WebKit +import SwiftUI +import SwiftyBeaver struct WebView: UIViewControllerRepresentable { @EnvironmentObject private var store: Store @@ -37,7 +38,7 @@ struct WebView: UIViewControllerRepresentable { Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { [weak self] _ in if didLogin { let store = self?.parent.store - store?.dispatch(.toggleSettingViewSheetState(state: nil)) + store?.dispatch(.toggleSettingViewSheet(state: nil)) store?.dispatch(.fetchFrontpageItems) store?.dispatch(.fetchUserInfo) } @@ -47,7 +48,7 @@ struct WebView: UIViewControllerRepresentable { } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - print(error) + SwiftyBeaver.error(error) } }