From 6006d0ebbff66101fda3e1ea81e2c6f02024ee97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=9F=E3=81=A4=E3=81=9D=E3=82=99=E3=81=86?= Date: Sat, 12 Jun 2021 00:57:05 +0800 Subject: [PATCH] feat: Searchable support & Remove login restriction --- EhPanda/App/Defaults.swift | 19 +- EhPanda/App/EhPandaApp.swift | 4 - EhPanda/App/Extensions.swift | 2 +- EhPanda/App/Tools/Parser.swift | 22 ++- EhPanda/App/Utility.swift | 6 - EhPanda/App/ja.lproj/Localizable.strings | 1 - EhPanda/App/zh-Hans.lproj/Localizable.strings | 1 - EhPanda/App/zh-Hant.lproj/Localizable.strings | 1 - EhPanda/DataFlow/AppAction.swift | 7 +- EhPanda/DataFlow/AppState.swift | 28 +++ EhPanda/DataFlow/Store.swift | 19 +- EhPanda/Models/Filter.swift | 23 ++- EhPanda/Models/Manga.swift | 2 +- EhPanda/Network/Request.swift | 7 +- EhPanda/View/Detail/CommentView.swift | 4 +- EhPanda/View/Detail/DetailView.swift | 108 +++++----- EhPanda/View/Home/FilterView.swift | 99 +++++----- EhPanda/View/Home/HomeView.swift | 184 +++++++----------- EhPanda/View/Home/SlideMenu.swift | 8 +- .../View/Setting/AppearanceSettingView.swift | 5 +- EhPanda/View/Setting/EhPandaView.swift | 10 +- EhPanda/View/Setting/GeneralSettingView.swift | 17 +- EhPanda/View/Setting/SettingView.swift | 12 +- EhPanda/View/Tools/AlertView.swift | 17 -- EhPanda/View/Tools/MangaSummaryRow.swift | 24 ++- 25 files changed, 293 insertions(+), 337 deletions(-) diff --git a/EhPanda/App/Defaults.swift b/EhPanda/App/Defaults.swift index db3c1ca4..44f243b9 100644 --- a/EhPanda/App/Defaults.swift +++ b/EhPanda/App/Defaults.swift @@ -56,18 +56,13 @@ struct Defaults { struct URL { // Domains static var host: String { - if isTokenMatched { - return galleryType == .ehentai ? ehentai : exhentai - } else { - return durarara - } + galleryType == .ehentai ? ehentai : exhentai } static let ehentai = "https://e-hentai.org/" static let exhentai = "https://exhentai.org/" static let forum = "https://forums.e-hentai.org/" static let login = merge([forum + index, loginAct]) static let magnet = "magnet:?xt=urn:btih:" - static let durarara = merge([ehentai, listCompact, nonh, fSearch + "parody:durarara$"]) // Functional Pages static let tag = "tag/" @@ -152,21 +147,13 @@ extension Defaults.URL { ) } static func frontpageList() -> String { - if isTokenMatched { - return merge([host, listCompact]) - } else { - return durarara - } + merge([host, listCompact]) } static func moreFrontpageList(pageNum: String, lastID: String) -> String { merge([host, listCompact, page + pageNum, from + lastID]) } static func popularList() -> String { - if isTokenMatched { - return merge([host + popular, listCompact]) - } else { - return merge([ehentai, listCompact, nonh, fSearch + "parody:gintama$"]) - } + merge([host + popular, listCompact]) } static func watchedList() -> String { merge([host + watched, listCompact]) diff --git a/EhPanda/App/EhPandaApp.swift b/EhPanda/App/EhPandaApp.swift index 13635882..caa135c3 100644 --- a/EhPanda/App/EhPandaApp.swift +++ b/EhPanda/App/EhPandaApp.swift @@ -16,8 +16,6 @@ struct EhPandaApp: App { init() { configureWebImage() clearImageCachesIfNeeded() - UIScrollView.appearance() - .keyboardDismissMode = .onDrag UITableViewCell.appearance() .selectedBackgroundView = UIView() } @@ -46,8 +44,6 @@ private extension EhPandaApp { func onOpenURL(_ url: URL) { switch url.host { - case "token": - setToken(with: url.pathComponents.last) case "debugMode": setDebugMode(with: url.pathComponents.last == "on") default: diff --git a/EhPanda/App/Extensions.swift b/EhPanda/App/Extensions.swift index da7af94a..efbfd332 100644 --- a/EhPanda/App/Extensions.swift +++ b/EhPanda/App/Extensions.swift @@ -126,7 +126,7 @@ extension String { func safeURL() -> URL { isValidURL ? URL(string: self)! - : URL(string: Defaults.URL.durarara)! + : URL(string: Defaults.URL.ehentai)! } var isValidURL: Bool { diff --git a/EhPanda/App/Tools/Parser.swift b/EhPanda/App/Tools/Parser.swift index c101f256..cb3ca89c 100644 --- a/EhPanda/App/Tools/Parser.swift +++ b/EhPanda/App/Tools/Parser.swift @@ -399,16 +399,14 @@ struct Parser { } // MARK: Content - static func parseImagePreContents(_ doc: HTMLDocument, pageCount: Int) throws -> [(Int, URL)] { + static func parseImagePreContents(_ doc: HTMLDocument, previewMode: String, pageCount: Int) throws -> [(Int, URL)] { copyHTMLIfNeeded(doc.toHTML) var imageDetailURLs = [(Int, URL)]() - let className = isTokenMatched ? "gdtl" : "gdtm" guard let gdtNode = doc.at_xpath("//div [@id='gdt']") else { throw AppError.parseFailed } - for (index, element) in gdtNode.xpath("//div [@class='\(className)']").enumerated() { - + for (index, element) in gdtNode.xpath("//div [@class='\(previewMode)']").enumerated() { guard let imageDetailStr = element.at_xpath("//a")?["href"], let imageDetailURL = URL(string: imageDetailStr) else { continue } @@ -428,6 +426,22 @@ struct Parser { return MangaContent(tag: tag, url: imageURL) } + static func parsePreviewMode(_ doc: HTMLDocument) throws -> String { + guard let gdoNode = doc.at_xpath("//div [@id='gdo']"), + let gdo4Node = gdoNode.at_xpath("//div [@id='gdo4']") + else { return "gdtm" } + + for link in gdo4Node.xpath("//div") { + if link.text == "Large", + ["tha nosel", "ths nosel"] + .contains(link["class"]) + { + return "gdtl" + } + } + return "gdtm" + } + // MARK: User static func parseUserInfo(doc: HTMLDocument) throws -> User { var displayName: String? diff --git a/EhPanda/App/Utility.swift b/EhPanda/App/Utility.swift index 920f440c..1ffbfc8a 100644 --- a/EhPanda/App/Utility.swift +++ b/EhPanda/App/Utility.swift @@ -252,16 +252,10 @@ func getStringWithComma(_ value: Int) -> String? { // MARK: UserDefaults let isDebugModeOn = UserDefaults.standard.bool(forKey: "debugModeOn") -let isTokenMatched = UserDefaults.standard.string(forKey: "token") == "r9vG3pcs2mT9MoWj2ZJR" - var pasteboardChangeCount: Int? { UserDefaults.standard.integer(forKey: "PasteboardChangeCount") } -func setToken(with token: String?) { - UserDefaults.standard.set(token, forKey: "token") -} - func setDebugMode(with debugModeOn: Bool) { UserDefaults.standard.set(debugModeOn, forKey: "debugModeOn") } diff --git a/EhPanda/App/ja.lproj/Localizable.strings b/EhPanda/App/ja.lproj/Localizable.strings index bbbaf46c..c85ec26c 100644 --- a/EhPanda/App/ja.lproj/Localizable.strings +++ b/EhPanda/App/ja.lproj/Localizable.strings @@ -31,7 +31,6 @@ // MARK: AlertView "Loading..." = "読み込み中..."; -"You need to login to use this app." = "ご利用にはログインが必要です"; "Login" = "ログイン"; "Your search didn't match any docs." = "お探しの情報が見つかりませんでした"; "Retry" = "やり直す"; diff --git a/EhPanda/App/zh-Hans.lproj/Localizable.strings b/EhPanda/App/zh-Hans.lproj/Localizable.strings index 47fb4ee0..d7a53315 100644 --- a/EhPanda/App/zh-Hans.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hans.lproj/Localizable.strings @@ -31,7 +31,6 @@ // MARK: AlertView "Loading..." = "加载中..."; -"You need to login to use this app." = "请登录以使用这个App"; "Login" = "登录"; "Your search didn't match any docs." = "未能找到你需要的信息"; "Retry" = "重试"; diff --git a/EhPanda/App/zh-Hant.lproj/Localizable.strings b/EhPanda/App/zh-Hant.lproj/Localizable.strings index 3cd6a57d..bacaa5cd 100644 --- a/EhPanda/App/zh-Hant.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hant.lproj/Localizable.strings @@ -31,7 +31,6 @@ // MARK: AlertView "Loading..." = "載入中..."; -"You need to login to use this app." = "你需要登入才能使用這個App"; "Login" = "登入"; "Your search didn't match any docs." = "未能找到你需要的資訊"; "Retry" = "重試"; diff --git a/EhPanda/DataFlow/AppAction.swift b/EhPanda/DataFlow/AppAction.swift index 7e90c403..8e5b615c 100644 --- a/EhPanda/DataFlow/AppAction.swift +++ b/EhPanda/DataFlow/AppAction.swift @@ -16,13 +16,16 @@ enum AppAction { case initializeUser case initializeFilter case initializeSetting - case cleanDetailViewCommentContent - case cleanCommentViewCommentContent + case clearDetailViewCommentContent + case clearCommentViewCommentContent case saveAspectBox(gid: String, box: [Int: CGFloat]) case saveReadingProgress(gid: String, tag: Int) case updateDiskImageCacheSize(size: String) case updateAppIconType(iconType: IconType) case updateHistoryItems(gid: String) + case updateHistoryKeywords(text: String) + case clearHistoryKeywords + case updateSearchKeyword(text: String) case updateViewControllersCount case resetDownloadCommandResponse case replaceMangaCommentJumpID(gid: String?) diff --git a/EhPanda/DataFlow/AppState.swift b/EhPanda/DataFlow/AppState.swift index fb30f76e..a9e69235 100644 --- a/EhPanda/DataFlow/AppState.swift +++ b/EhPanda/DataFlow/AppState.swift @@ -133,6 +133,8 @@ extension AppState { @FileStorage(directory: .cachesDirectory, fileName: "historyList.json") var historyItems: [String: Manga]? + @FileStorage(directory: .cachesDirectory, fileName: "historyKeywords.json") + var historyKeywords: [String]? static func generateBoolDic(_ defaultValue: Bool = false) -> [Int: Bool] { var tmp = [Int: Bool]() @@ -193,6 +195,32 @@ extension AppState { ) } } + mutating func insertHistoryKeyword(text: String) { + guard !text.isEmpty else { return } + guard var historyKeywords = historyKeywords else { + historyKeywords = [text] + return + } + + if let index = historyKeywords.firstIndex(of: text) { + if historyKeywords.last != text { + historyKeywords.remove(at: index) + historyKeywords.append(text) + } + } else { + historyKeywords.append(text) + + let overflow = historyKeywords.count - 10 + + if overflow > 0 { + historyKeywords = Array( + historyKeywords.dropFirst(overflow) + ) + } + } + + self.historyKeywords = historyKeywords + } } // MARK: DetailInfo diff --git a/EhPanda/DataFlow/Store.swift b/EhPanda/DataFlow/Store.swift index 91842498..d8d7a7ef 100644 --- a/EhPanda/DataFlow/Store.swift +++ b/EhPanda/DataFlow/Store.swift @@ -52,6 +52,12 @@ final class Store: ObservableObject { case .updateHistoryItems(let gid): let item = appState.cachedList.items?[gid] appState.homeInfo.insertHistoryItem(manga: item) + case .updateHistoryKeywords(let text): + appState.homeInfo.insertHistoryKeyword(text: text) + case .clearHistoryKeywords: + appState.homeInfo.historyKeywords = nil + case .updateSearchKeyword(let text): + appState.homeInfo.searchKeyword = text case .updateViewControllersCount: appState.environment.viewControllersCount = viewControllersCount case .resetDownloadCommandResponse: @@ -101,14 +107,13 @@ final class Store: ObservableObject { case .toggleCommentViewSheetNil: appState.environment.commentViewSheetState = nil - case .cleanDetailViewCommentContent: + case .clearDetailViewCommentContent: appState.detailInfo.commentContent = "" - case .cleanCommentViewCommentContent: + case .clearCommentViewCommentContent: appState.commentInfo.commentContent = "" // MARK: Fetch Data case .fetchGreeting: - if !didLogin && isTokenMatched { break } if appState.settings.greetingLoading { break } appState.settings.greetingLoading = true @@ -129,7 +134,6 @@ final class Store: ObservableObject { } case .fetchUserInfo(let uid): - if !didLogin && isTokenMatched { break } if appState.settings.userInfoLoading { break } appState.settings.userInfoLoading = true @@ -160,7 +164,6 @@ final class Store: ObservableObject { } case .fetchMangaItemReverse(let detailURL): - if !didLogin || !isTokenMatched { break } appState.environment.mangaItemReverseLoadFailed = false if appState.environment.mangaItemReverseLoading { break } @@ -180,7 +183,6 @@ final class Store: ObservableObject { } case .fetchSearchItems(let keyword): - if !didLogin && isTokenMatched { break } appState.homeInfo.searchNotFound = false appState.homeInfo.searchLoadFailed = false @@ -258,7 +260,6 @@ final class Store: ObservableObject { } case .fetchFrontpageItems: - if !didLogin && isTokenMatched { break } appState.homeInfo.frontpageNotFound = false appState.homeInfo.frontpageLoadFailed = false @@ -294,7 +295,6 @@ final class Store: ObservableObject { case .fetchMoreFrontpageItems: appState.homeInfo.moreFrontpageLoadFailed = false - if !didLogin || !isTokenMatched { break } let currentNum = appState.homeInfo.frontpageCurrentPageNum let maximumNum = appState.homeInfo.frontpagePageNumMaximum if currentNum + 1 > maximumNum { break } @@ -329,7 +329,6 @@ final class Store: ObservableObject { } case .fetchPopularItems: - if !didLogin && isTokenMatched { break } appState.homeInfo.popularNotFound = false appState.homeInfo.popularLoadFailed = false @@ -353,7 +352,6 @@ final class Store: ObservableObject { } case .fetchWatchedItems: - if !didLogin || !isTokenMatched { break } appState.homeInfo.watchedNotFound = false appState.homeInfo.watchedLoadFailed = false @@ -423,7 +421,6 @@ final class Store: ObservableObject { } case .fetchFavoritesItems(let favIndex): - if !didLogin || !isTokenMatched { break } appState.homeInfo.favoritesNotFound[favIndex] = false appState.homeInfo.favoritesLoadFailed[favIndex] = false diff --git a/EhPanda/Models/Filter.swift b/EhPanda/Models/Filter.swift index e5747a97..1eeaef5e 100644 --- a/EhPanda/Models/Filter.swift +++ b/EhPanda/Models/Filter.swift @@ -45,8 +45,8 @@ struct Filter: Codable { var minRating: Int = 2 var pageRangeActivated = false - var pageLowerBound: String = "" - var pageUpperBound: String = "" + @NumString var pageLowerBound: String = "" + @NumString var pageUpperBound: String = "" var disableLanguage = false var disableUploader = false @@ -60,3 +60,22 @@ struct AssociatedCategory: Codable { category.color } } + +@propertyWrapper +struct NumString: Codable { + private var value = "" + var wrappedValue: String { + get { value } + set { + if let num = Int(newValue) { + value = String(num) + } else if newValue.isEmpty { + value = newValue + } + } + } + + init(wrappedValue: String) { + self.wrappedValue = wrappedValue + } +} diff --git a/EhPanda/Models/Manga.swift b/EhPanda/Models/Manga.swift index 4e5dd2ed..765ac5f1 100644 --- a/EhPanda/Models/Manga.swift +++ b/EhPanda/Models/Manga.swift @@ -176,7 +176,7 @@ struct MangaPreview: Identifiable, Codable { } struct MangaAlterData: Identifiable, Codable { - var id: Data { data } + var id = UUID().uuidString let data: Data } diff --git a/EhPanda/Network/Request.swift b/EhPanda/Network/Request.swift index d4b3f1db..01ee4eee 100644 --- a/EhPanda/Network/Request.swift +++ b/EhPanda/Network/Request.swift @@ -465,7 +465,12 @@ struct MangaContentsRequest { .tryMap { try Kanna.HTML(html: $0.data, encoding: .utf8) } .tryMap { try ( Parser.parsePageNum($0), - Parser.parseImagePreContents($0, pageCount: pageCount) + Parser.parseImagePreContents( + $0, + previewMode: + Parser.parsePreviewMode($0), + pageCount: pageCount + ) ) } .mapError(mapAppError) .eraseToAnyPublisher() diff --git a/EhPanda/View/Detail/CommentView.swift b/EhPanda/View/Detail/CommentView.swift index 4b551139..c8e0cf51 100644 --- a/EhPanda/View/Detail/CommentView.swift +++ b/EhPanda/View/Detail/CommentView.swift @@ -120,7 +120,7 @@ private extension CommentView { } } func onLinkTap(_ link: URL) { - if isValidDetailURL(url: link) && isTokenMatched { + if isValidDetailURL(url: link) { let gid = link.pathComponents[2] if cachedList.hasCached(gid: gid) { replaceMangaCommentJumpID(gid: gid) @@ -182,7 +182,7 @@ private extension CommentView { func postComment() { store.dispatch(.comment(gid: gid, content: commentContent)) - store.dispatch(.cleanCommentViewCommentContent) + store.dispatch(.clearCommentViewCommentContent) } func fetchMangaWithDetailURL(_ detailURL: String) { store.dispatch(.fetchMangaItemReverse(detailURL: detailURL)) diff --git a/EhPanda/View/Detail/DetailView.swift b/EhPanda/View/Detail/DetailView.swift index 21a7d81d..3ffb30d4 100644 --- a/EhPanda/View/Detail/DetailView.swift +++ b/EhPanda/View/Detail/DetailView.swift @@ -41,15 +41,13 @@ struct DetailView: View, StoreAccessor { .padding(.bottom, 15) Group { DescScrollView(detail: detail) - if isTokenMatched { - ActionRow( - detail: detail, - ratingAction: onUserRatingChanged - ) { - onSimilarGalleryTap(detail.title) - } + ActionRow( + detail: detail, + ratingAction: onUserRatingChanged + ) { + onSimilarGalleryTap(detail.title) } - if !detail.detailTags.isEmpty && isTokenMatched { + if !detail.detailTags.isEmpty { TagsView( tags: detail.detailTags, onTapAction: onTagsViewTap @@ -59,7 +57,7 @@ struct DetailView: View, StoreAccessor { previews: detail.previews, alterImages: detail.alterImages ) - if !(detail.comments.isEmpty && !isTokenMatched) { + if !detail.comments.isEmpty { CommentScrollView( gid: gid, depth: depth, @@ -136,19 +134,17 @@ private extension DetailView { if mangaDetail != nil { Menu(content: { if !detailInfo.mangaDetailUpdating { - if isTokenMatched { - if mangaDetail?.archiveURL != nil { - Button(action: onArchiveButtonTap) { - Label("Archive", systemImage: "doc.zipper") - } + if mangaDetail?.archiveURL != nil { + Button(action: onArchiveButtonTap) { + Label("Archive", systemImage: "doc.zipper") } - if let count = torrentCount, count > 0 { - Button(action: onTorrentsButtonTap) { - Label( - "Torrents".localized() + " (\(count))", - systemImage: "leaf" - ) - } + } + if let count = torrentCount, count > 0 { + Button(action: onTorrentsButtonTap) { + Label( + "Torrents".localized() + " (\(count))", + systemImage: "leaf" + ) } } Button(action: onShareButtonTap) { @@ -235,7 +231,7 @@ private extension DetailView { func postComment() { store.dispatch(.comment(gid: gid, content: commentContent)) - store.dispatch(.cleanDetailViewCommentContent) + store.dispatch(.clearDetailViewCommentContent) } func fetchMangaDetail() { @@ -305,42 +301,38 @@ private struct HeaderView: View, StoreAccessor { } Spacer() HStack { - if isTokenMatched { - Text(category) - .fontWeight(.bold) - .lineLimit(1) - .font(.headline) - .foregroundColor(.white) - .padding(.vertical, 2) - .padding(.horizontal, 4) - .background( - RoundedRectangle(cornerRadius: 3) - .foregroundColor(manga.color) - ) - } + Text(category) + .fontWeight(.bold) + .lineLimit(1) + .font(.headline) + .foregroundColor(.white) + .padding(.vertical, 2) + .padding(.horizontal, 4) + .background( + RoundedRectangle(cornerRadius: 3) + .foregroundColor(manga.color) + ) Spacer() - if isTokenMatched { - if isFavored { - Button(action: onFavoriteDelete) { - Image(systemName: "heart.fill") - .imageScale(.large) - .foregroundStyle(.tint) - } - } else { - if let user = user, - let names = user.favoriteNames - { - Menu { - ForEach(0.. { $store.appState.environment } + var homeInfoBinding: Binding { + $store.appState.homeInfo + } + + var suggestions: [String] { + homeInfo.historyKeywords?.reversed().filter({ word in + homeInfo.searchKeyword.isEmpty ? true + : word.contains(homeInfo.searchKeyword) + }) ?? [] + } var historyItems: [Manga] { var items = homeInfo.historyItems? .compactMap({ $0.value }) @@ -114,10 +139,23 @@ private extension HomeView { } } var hasJumpPermission: Bool { - viewControllersCount == 1 && isTokenMatched + viewControllersCount == 1 && setting?.detectGalleryFromPasteboard == true } + var suggestionsView: some View { + ForEach(suggestions, id: \.self) { word in + HStack { + Text(word) + .foregroundStyle(.tint) + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + onSuggestionTap(word) + } + } + } var conditionalList: some View { Group { switch environment.homeListType { @@ -129,7 +167,7 @@ private extension HomeView { loadFailedFlag: homeInfo.searchLoadFailed, moreLoadingFlag: homeInfo.moreSearchLoading, moreLoadFailedFlag: homeInfo.moreSearchLoadFailed, - fetchAction: fetchSearchItems, + fetchAction: onSearchRefresh, loadMoreAction: fetchMoreSearchItems ) case .frontpage: @@ -229,7 +267,10 @@ private extension HomeView { } } } +} +// MARK: Private Methods +extension HomeView { func onAppear() { detectPasteboard() fetchGreetingIfNeeded() @@ -241,6 +282,9 @@ private extension HomeView { if setting == nil { store.dispatch(.initializeSetting) } + if settings.filter == nil { + store.dispatch(.initializeFilter) + } if settings.user?.displayName?.isEmpty != false { fetchUserInfo() } @@ -279,6 +323,11 @@ private extension HomeView { toggleNewDawn() } } + func onSearchKeywordChange(_ keyword: String) { + if let archivedKeyword = archivedKeyword, keyword.isEmpty { + store.dispatch(.updateHistoryKeywords(text: archivedKeyword)) + } + } func onFavoritesIndexChange(_ : Int) { fetchFavoritesItemsIfNeeded() } @@ -298,6 +347,21 @@ private extension HomeView { dismissHUD() } } + func onSearchSubmit() { + if environment.homeListType != .search { + store.dispatch(.toggleHomeListType(type: .search)) + } + fetchSearchItems() + archivedKeyword = homeInfo.searchKeyword + } + func onSearchRefresh() { + if let keyword = archivedKeyword { + store.dispatch(.fetchSearchItems(keyword: keyword)) + } + } + func onSuggestionTap(_ word: String) { + store.dispatch(.updateSearchKeyword(text: word)) + } func showHUD() { hudConfig = TTProgressHUDConfig( @@ -400,6 +464,9 @@ private extension HomeView { func toggleNewDawn() { store.dispatch(.toggleHomeViewSheetState(state: .newDawn)) } + func toggleSetting() { + store.dispatch(.toggleHomeViewSheetState(state: .setting)) + } func updateViewControllersCount() { store.dispatch(.updateViewControllersCount) } @@ -455,10 +522,7 @@ private extension HomeView { } // MARK: GenericList -private struct GenericList: View, StoreAccessor { - @EnvironmentObject var store: Store - @FocusState var isTextFieldFocused: Bool - +private struct GenericList: View { private let items: [Manga]? private let loadingFlag: Bool private let notFoundFlag: Bool @@ -489,9 +553,7 @@ private struct GenericList: View, StoreAccessor { } var body: some View { - if !didLogin && isTokenMatched { - NotLoginView(loginAction: toggleSetting) - } else if loadingFlag { + if loadingFlag { LoadingView() } else if loadFailedFlag { NetworkErrorView(retryAction: fetchAction) @@ -499,17 +561,6 @@ private struct GenericList: View, StoreAccessor { NotFoundView(retryAction: fetchAction) } else { List { - if isTokenMatched { - SearchBar( - keyword: homeInfoBinding.searchKeyword, - isTextFieldFocused: _isTextFieldFocused, - commitAction: searchBarCommit, - filterAction: searchBarFilter - ) - .listRowBackground(Color.clear) - .listRowSeparator(.hidden) - .padding(.bottom, 10) - } ForEach(items ?? []) { item in ZStack { NavigationLink( @@ -546,108 +597,19 @@ private struct GenericList: View, StoreAccessor { .listStyle(.plain) } } -} -private extension GenericList { - var homeInfoBinding: Binding { - $store.appState.homeInfo - } - - func onUpdate() { + private func onUpdate() { if let action = fetchAction { action() } } - func onRowAppear(_ item: Manga) { + private func onRowAppear(_ item: Manga) { if let action = loadMoreAction, item == items?.last { action() } } - - func searchBarCommit() { - isTextFieldFocused = false - - if environment.homeListType != .search { - store.dispatch(.toggleHomeListType(type: .search)) - } - fetchSearchItems() - } - func searchBarFilter() { - toggleFilter() - } - - func fetchSearchItems() { - store.dispatch(.fetchSearchItems(keyword: homeInfo.searchKeyword)) - } - - func toggleSetting() { - store.dispatch(.toggleHomeViewSheetState(state: .setting)) - } - func toggleFilter() { - store.dispatch(.toggleHomeViewSheetState(state: .filter)) - } -} - -// MARK: SearchBar -private struct SearchBar: View { - @Binding private var keyword: String - @FocusState private var isTextFieldFocused: Bool - private var commitAction: () -> Void - private var filterAction: () -> Void - - init( - keyword: Binding, - isTextFieldFocused: FocusState, - commitAction: @escaping () -> Void, - filterAction: @escaping () -> Void - ) { - _keyword = keyword - _isTextFieldFocused = isTextFieldFocused - - self.commitAction = commitAction - self.filterAction = filterAction - } - - var body: some View { - HStack { - Image(systemName: "magnifyingglass") - .foregroundColor(.gray) - TextField( - "Search".localized(), - text: $keyword, - onCommit: commitAction - ) - .focused($isTextFieldFocused) - .disableAutocorrection(true) - .autocapitalization(.none) - .submitLabel(.search) - HStack { - Group { - if !keyword.isEmpty { - Button(action: onClearButtonTap) { - Image(systemName: "xmark.circle.fill") - .foregroundColor(.gray) - } - } - Button(action: filterAction) { - Image(systemName: "slider.horizontal.3") - .foregroundColor(.gray) - .padding(.vertical, 13) - .padding(.trailing, 10) - } - } - } - } - .padding(.leading, 10) - .background(Color(.systemGray6)) - .cornerRadius(8) - } - - private func onClearButtonTap() { - keyword = "" - } } // MARK: Definition diff --git a/EhPanda/View/Home/SlideMenu.swift b/EhPanda/View/Home/SlideMenu.swift index 579f5d4e..733b3f3b 100644 --- a/EhPanda/View/Home/SlideMenu.swift +++ b/EhPanda/View/Home/SlideMenu.swift @@ -14,8 +14,6 @@ struct SlideMenu: View, StoreAccessor { @Environment(\.colorScheme) private var colorScheme @Binding private var offset: CGFloat - private var tokenMatchedMenuItems = HomeListType - .allCases.filter({ $0 != .search }) private var edges = keyWindow?.safeAreaInsets init(offset: Binding) { @@ -91,11 +89,7 @@ private extension SlideMenu { colorScheme == .light ? .white : .black } var menuItems: [HomeListType] { - if isTokenMatched { - return tokenMatchedMenuItems - } else { - return Array(tokenMatchedMenuItems.prefix(2)) - } + HomeListType.allCases.filter({ $0 != .search }) } func onMenuRowTap(_ item: HomeListType) { diff --git a/EhPanda/View/Setting/AppearanceSettingView.swift b/EhPanda/View/Setting/AppearanceSettingView.swift index af60a8c2..167387c5 100644 --- a/EhPanda/View/Setting/AppearanceSettingView.swift +++ b/EhPanda/View/Setting/AppearanceSettingView.swift @@ -22,7 +22,8 @@ struct AppearanceSettingView: View, StoreAccessor { NavigationLink( destination: SelectAppIconView(), isActive: $isNavigationLinkActive, - label: {}) + label: {} + ) Form { Section(header: Text("Global")) { HStack { @@ -43,7 +44,7 @@ struct AppearanceSettingView: View, StoreAccessor { Button("App Icon", action: onAppIconButtonTap) .foregroundColor(.primary) .withArrow() - if isTokenMatched || environment.isPreview, Locale.current.languageCode != "en" { + if Locale.current.languageCode != "en" { Toggle(isOn: settingBinding.translateCategory, label: { Text("Translate category") }) diff --git a/EhPanda/View/Setting/EhPandaView.swift b/EhPanda/View/Setting/EhPandaView.swift index 0f98fd9d..4c5b4e4d 100644 --- a/EhPanda/View/Setting/EhPandaView.swift +++ b/EhPanda/View/Setting/EhPandaView.swift @@ -81,12 +81,10 @@ struct EhPandaView: View, StoreAccessor { } .padding(.horizontal) Form { - if isTokenMatched || environment.isPreview { - Section(header: Text("Contacts")) { - ForEach(contacts) { contact in - if let url = URL(string: contact.url) { - LinkRow(url: url, text: contact.text) - } + Section(header: Text("Contacts")) { + ForEach(contacts) { contact in + if let url = URL(string: contact.url) { + LinkRow(url: url, text: contact.text) } } } diff --git a/EhPanda/View/Setting/GeneralSettingView.swift b/EhPanda/View/Setting/GeneralSettingView.swift index 4d6cf24a..08d5370d 100644 --- a/EhPanda/View/Setting/GeneralSettingView.swift +++ b/EhPanda/View/Setting/GeneralSettingView.swift @@ -19,6 +19,9 @@ struct GeneralSettingView: View, StoreAccessor { { Form { Section { + NavigationLink(destination: FilterView()) { + Text("Filters") + } HStack { Text("Language") Spacer() @@ -27,14 +30,12 @@ struct GeneralSettingView: View, StoreAccessor { Toggle(isOn: settingBinding.closeSlideMenuAfterSelection) { Text("Close slide menu after selection") } - if isTokenMatched || environment.isPreview { - Toggle(isOn: settingBinding.detectGalleryFromPasteboard) { - Text("Detect link from the clipboard") - } - if setting.detectGalleryFromPasteboard { - Toggle(isOn: settingBinding.allowsDetectionWhenNoChange) { - Text("Allows detection even when no change") - } + Toggle(isOn: settingBinding.detectGalleryFromPasteboard) { + Text("Detect link from the clipboard") + } + if setting.detectGalleryFromPasteboard { + Toggle(isOn: settingBinding.allowsDetectionWhenNoChange) { + Text("Allows detection even when no change") } } } diff --git a/EhPanda/View/Setting/SettingView.swift b/EhPanda/View/Setting/SettingView.swift index 539188d5..156f0969 100644 --- a/EhPanda/View/Setting/SettingView.swift +++ b/EhPanda/View/Setting/SettingView.swift @@ -17,13 +17,11 @@ struct SettingView: View, StoreAccessor { NavigationView { ScrollView { VStack(spacing: 0) { - if isTokenMatched || environment.isPreview { - SettingRow( - symbolName: "person.fill", - text: "Account", - destination: AccountSettingView() - ) - } + SettingRow( + symbolName: "person.fill", + text: "Account", + destination: AccountSettingView() + ) SettingRow( symbolName: "switch.2", text: "General", diff --git a/EhPanda/View/Tools/AlertView.swift b/EhPanda/View/Tools/AlertView.swift index 9fbd354b..6f8d93a4 100644 --- a/EhPanda/View/Tools/AlertView.swift +++ b/EhPanda/View/Tools/AlertView.swift @@ -13,23 +13,6 @@ struct LoadingView: View { } } -struct NotLoginView: View { - private let loginAction: (() -> Void)? - - init(loginAction: (() -> Void)?) { - self.loginAction = loginAction - } - - var body: some View { - GenericRetryView( - symbolName: "person.crop.circle.badge.questionmark", - message: "You need to login to use this app.", - buttonText: "Login", - retryAction: loginAction - ) - } -} - struct NotFoundView: View { private let retryAction: (() -> Void)? diff --git a/EhPanda/View/Tools/MangaSummaryRow.swift b/EhPanda/View/Tools/MangaSummaryRow.swift index 80161739..52515698 100644 --- a/EhPanda/View/Tools/MangaSummaryRow.swift +++ b/EhPanda/View/Tools/MangaSummaryRow.swift @@ -59,19 +59,17 @@ struct MangaSummaryRow: View, StoreAccessor { } } HStack(alignment: .bottom) { - if isTokenMatched { - Text(category) - .fontWeight(.bold) - .lineLimit(1) - .font(.footnote) - .foregroundColor(.white) - .padding(.vertical, 1) - .padding(.horizontal, 3) - .background( - RoundedRectangle(cornerRadius: 2) - .foregroundColor(manga.color) - ) - } + Text(category) + .fontWeight(.bold) + .lineLimit(1) + .font(.footnote) + .foregroundColor(.white) + .padding(.vertical, 1) + .padding(.horizontal, 3) + .background( + RoundedRectangle(cornerRadius: 2) + .foregroundColor(manga.color) + ) Spacer() Text(manga.formattedDateString) .lineLimit(1)