diff --git a/EhPanda/App/Generated/Strings.swift b/EhPanda/App/Generated/Strings.swift index d72d0fdb..4d8521a9 100644 --- a/EhPanda/App/Generated/Strings.swift +++ b/EhPanda/App/Generated/Strings.swift @@ -484,6 +484,8 @@ internal enum L10n { internal static func browsingCountry(_ p1: Any) -> String { return L10n.tr("Localizable", "eh_setting_view.description.browsing_country", String(describing: p1), fallback: "You appear to be browsing the site from **%@** or use a VPN or proxy in this country, which means the site will try to load images from H@H clients in this general geographic region. If this is incorrect, or if you want to use a different region for any reason (like if you are using a split tunneling VPN), you can select a different country below.") } + /// The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes. + internal static let coverScaleFactor = L10n.tr("Localizable", "eh_setting_view.description.cover_scale_factor", fallback: "The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes.") /// Which display mode would you like to use on the front and search pages? internal static let displayMode = L10n.tr("Localizable", "eh_setting_view.description.display_mode", fallback: "Which display mode would you like to use on the front and search pages?") /// If you wish to hide galleries in certain languages from the gallery list and searches, select them from the list below. Note that matching galleries will never appear regardless of your search query. @@ -511,13 +513,13 @@ internal enum L10n { /// This setting can be used if you have a H@H client running on your local network with the same public IP you browse the site with. Some routers are buggy and cannot route requests back to its own IP; this allows you to work around this problem. /// If you are running the client on the same device you browse from, use the loopback address (127.0.0.1:port). If the client is running on another device on your network, use its local network IP. Some browser configurations prevent external web sites from accessing URLs with local network IPs, the site must then be whitelisted for this to work. internal static let ipAddressPort = L10n.tr("Localizable", "eh_setting_view.description.ip_address_port", fallback: "This setting can be used if you have a H@H client running on your local network with the same public IP you browse the site with. Some routers are buggy and cannot route requests back to its own IP; this allows you to work around this problem.\nIf you are running the client on the same device you browse from, use the loopback address (127.0.0.1:port). If the client is running on another device on your network, use its local network IP. Some browser configurations prevent external web sites from accessing URLs with local network IPs, the site must then be whitelisted for this to work.") + /// Some historic UI elements are now disabled by default. You can enable those here. + internal static let optionalUIElements = L10n.tr("Localizable", "eh_setting_view.description.optional_UI_elements", fallback: "Some historic UI elements are now disabled by default. You can enable those here.") /// By default, galleries that you have rated will appear with red stars for ratings of 2 stars and below, green for ratings between 2.5 and 4 stars, and blue for ratings of 4.5 or 5 stars. You can customize this by entering your desired color combination below. Each letter represents one star. The default RRGGB means R(ed) for the first and second star, G(reen) for the third and fourth, and B(lue) for the fifth. You can also use (Y)ellow for the normal stars. Any five-letter R/G/B/Y combo works. internal static let ratingsColor = L10n.tr("Localizable", "eh_setting_view.description.ratings_color", fallback: "By default, galleries that you have rated will appear with red stars for ratings of 2 stars and below, green for ratings between 2.5 and 4 stars, and blue for ratings of 4.5 or 5 stars. You can customize this by entering your desired color combination below. Each letter represents one star. The default RRGGB means R(ed) for the first and second star, G(reen) for the third and fourth, and B(lue) for the fifth. You can also use (Y)ellow for the normal stars. Any five-letter R/G/B/Y combo works.") /// How many results would you like per page for the index/search page and torrent search pages? /// (Hath Perk: Paging Enlargement Required) internal static let resultCount = L10n.tr("Localizable", "eh_setting_view.description.result_count", fallback: "How many results would you like per page for the index/search page and torrent search pages?\n(Hath Perk: Paging Enlargement Required)") - /// Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%. - internal static let scaleFactor = L10n.tr("Localizable", "eh_setting_view.description.scale_factor", fallback: "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%.") /// You can soft filter tags by adding them to My Tags with a negative weight. If a gallery has tags that add up to weight below this value, it is filtered from view. This threshold can be set between 0 and -9999. internal static let tagFilteringThreshold = L10n.tr("Localizable", "eh_setting_view.description.tag_filtering_threshold", fallback: "You can soft filter tags by adding them to My Tags with a negative weight. If a gallery has tags that add up to weight below this value, it is filtered from view. This threshold can be set between 0 and -9999.") /// Recently uploaded galleries will be included on the watched screen if it has at least one watched tag with positive weight, and the sum of weights on its watched tags add up to this value or higher. This threshold can be set between 0 and 9999. @@ -526,6 +528,8 @@ internal enum L10n { internal static let thumbnailConfiguration = L10n.tr("Localizable", "eh_setting_view.description.thumbnail_configuration", fallback: "You can set a default thumbnail configuration for all galleries you visit.") /// How would you like the mouse-over thumbnails on the front page to load when using List Mode? internal static let thumbnailLoadTiming = L10n.tr("Localizable", "eh_setting_view.description.thumbnail_load_timing", fallback: "How would you like the mouse-over thumbnails on the front page to load when using List Mode?") + /// Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%. + internal static let thumbnailScaleFactor = L10n.tr("Localizable", "eh_setting_view.description.thumbnail_scale_factor", fallback: "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%.") /// Allows you to override the virtual width of the site for mobile devices. This is normally determined automatically by your device based on its DPI. Sensible values at 100%% thumbnail scale are between 640 and 1400. internal static let virtualWidth = L10n.tr("Localizable", "eh_setting_view.description.virtual_width", fallback: "Allows you to override the virtual width of the site for mobile devices. This is normally determined automatically by your device based on its DPI. Sensible values at 100%% thumbnail scale are between 640 and 1400.") } @@ -537,6 +541,8 @@ internal enum L10n { internal enum Title { /// Archiver Settings internal static let archiverSettings = L10n.tr("Localizable", "eh_setting_view.section.title.archiver_settings", fallback: "Archiver Settings") + /// Cover Scaling + internal static let coverScaling = L10n.tr("Localizable", "eh_setting_view.section.title.cover_scaling", fallback: "Cover Scaling") /// Excluded Languages internal static let excludedLanguages = L10n.tr("Localizable", "eh_setting_view.section.title.excluded_languages", fallback: "Excluded Languages") /// Excluded Uploaders @@ -553,6 +559,8 @@ internal enum L10n { internal static let galleryNameDisplay = L10n.tr("Localizable", "eh_setting_view.section.title.gallery_name_display", fallback: "Gallery Name Display") /// Gallery Page Numbering internal static let galleryPageNumbering = L10n.tr("Localizable", "eh_setting_view.section.title.gallery_page_numbering", fallback: "Gallery Page Numbering") + /// Gallery Page Thumbnail Labeling + internal static let galleryPageThumbnailLabeling = L10n.tr("Localizable", "eh_setting_view.section.title.gallery_page_thumbnail_labeling", fallback: "Gallery Page Thumbnail Labeling") /// Gallery Tags internal static let galleryTags = L10n.tr("Localizable", "eh_setting_view.section.title.gallery_tags", fallback: "Gallery Tags") /// Hath Local Network Host @@ -563,8 +571,10 @@ internal enum L10n { internal static let imageSizeSettings = L10n.tr("Localizable", "eh_setting_view.section.title.image_size_settings", fallback: "Image Size Settings") /// Multi-Page Viewer internal static let multiPageViewer = L10n.tr("Localizable", "eh_setting_view.section.title.multi_page_viewer", fallback: "Multi-Page Viewer") - /// Original Images - internal static let originalImages = L10n.tr("Localizable", "eh_setting_view.section.title.original_images", fallback: "Original Images") + /// Optional UI Elements + internal static let optionalUIElements = L10n.tr("Localizable", "eh_setting_view.section.title.optional_UI_elements", fallback: "Optional UI Elements") + /// Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than "Auto" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year). + internal static let originalImages = L10n.tr("Localizable", "eh_setting_view.section.title.original_images", fallback: "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year).") /// Profile Settings internal static let profileSettings = L10n.tr("Localizable", "eh_setting_view.section.title.profile_settings", fallback: "Profile Settings") /// Ratings @@ -598,6 +608,8 @@ internal enum L10n { internal static let displayMode = L10n.tr("Localizable", "eh_setting_view.title.display_mode", fallback: "Display mode") /// Display style internal static let displayStyle = L10n.tr("Localizable", "eh_setting_view.title.display_style", fallback: "Display style") + /// Enable thumbnail selector on gallery screen + internal static let enableGalleryThumbnailSelector = L10n.tr("Localizable", "eh_setting_view.title.enable_gallery_thumbnail_selector", fallback: "Enable thumbnail selector on gallery screen") /// Favorites sort order internal static let favoritesSortOrder = L10n.tr("Localizable", "eh_setting_view.title.favorites_sort_order", fallback: "Favorites sort order") /// Gallery name @@ -628,6 +640,8 @@ internal enum L10n { internal static let showFilteredRemovalCount = L10n.tr("Localizable", "eh_setting_view.title.show_filtered_removal_count", fallback: "Show filtered removal count") /// Show gallery page numbers internal static let showGalleryPageNumbers = L10n.tr("Localizable", "eh_setting_view.title.show_gallery_page_numbers", fallback: "Show gallery page numbers") + /// Show label below gallery thumbnails + internal static let showLabelBelowGalleryThumbnails = L10n.tr("Localizable", "eh_setting_view.title.show_label_below_gallery_thumbnails", fallback: "Show label below gallery thumbnails") /// Show search range indicator internal static let showSearchRangeIndicator = L10n.tr("Localizable", "eh_setting_view.title.show_search_range_indicator", fallback: "Show search range indicator") /// Show thumbnail pane @@ -1313,6 +1327,20 @@ internal enum L10n { internal static let japanese = L10n.tr("Localizable", "enum.eh_setting.gallery_name.value.japanese", fallback: "Japanese Title (if available)") } } + internal enum GalleryPageNumbering { + internal enum Value { + /// No + internal static let no = L10n.tr("Localizable", "enum.eh_setting.gallery_page_numbering.value.no", fallback: "No") + /// None + internal static let `none` = L10n.tr("Localizable", "enum.eh_setting.gallery_page_numbering.value.none", fallback: "None") + /// Page Number + Name + internal static let pageNumberAndName = L10n.tr("Localizable", "enum.eh_setting.gallery_page_numbering.value.page_number_and_name", fallback: "Page Number + Name") + /// Page Number Only + internal static let pageNumberOnly = L10n.tr("Localizable", "enum.eh_setting.gallery_page_numbering.value.page_number_only", fallback: "Page Number Only") + /// Yes + internal static let yes = L10n.tr("Localizable", "enum.eh_setting.gallery_page_numbering.value.yes", fallback: "Yes") + } + } internal enum ImageResolution { internal enum Value { /// Auto @@ -1375,10 +1403,14 @@ internal enum L10n { } internal enum ThumbnailSize { internal enum Value { + /// Auto + internal static let auto = L10n.tr("Localizable", "enum.eh_setting.thumbnail_size.value.auto", fallback: "Auto") /// Large internal static let large = L10n.tr("Localizable", "enum.eh_setting.thumbnail_size.value.large", fallback: "Large") /// Normal internal static let normal = L10n.tr("Localizable", "enum.eh_setting.thumbnail_size.value.normal", fallback: "Normal") + /// Small + internal static let small = L10n.tr("Localizable", "enum.eh_setting.thumbnail_size.value.small", fallback: "Small") } } } diff --git a/EhPanda/App/Tools/Parser.swift b/EhPanda/App/Tools/Parser.swift index 1134d5b7..7e2d367b 100644 --- a/EhPanda/App/Tools/Parser.swift +++ b/EhPanda/App/Tools/Parser.swift @@ -318,7 +318,7 @@ struct Parser { let singlePageCount = Int(gpcText[rangeA.upperBound.. [Int: URL] { + var previewURLs = [Int: URL]() + + for link in node.xpath("//a") { + if let divNode = link.at_xpath("div"), + let style = divNode["style"], + let rangeA = style.range(of: "url("), + let rangeB = style.range(of: ")"), + let urlString = style[rangeA.upperBound.. Int? { + // The probable format of page title is "Page [Number]: filename" + ( + title + .components(separatedBy: ":") + .first? + .replacingOccurrences(of: "Page ", with: "") + .trimmingCharacters(in: .whitespaces) + ) + .flatMap(Int.init) + } + // MARK: ImageURL static func parseThumbnailURLs(doc: HTMLDocument) throws -> [Int: URL] { var thumbnailURLs = [Int: URL]() @@ -730,14 +765,27 @@ struct Parser { let previewMode = try? parsePreviewMode(doc: doc) else { throw AppError.parseFailed } - for link in gdtNode.xpath("//div [@class='\(previewMode)']") { - guard let aLink = link.at_xpath("//a"), - let thumbnailURLString = aLink["href"], - let thumbnailURL = URL(string: thumbnailURLString), - let index = Int(aLink.at_xpath("//img")?["alt"] ?? "") - else { continue } + if previewMode == "gt200" { + for aLink in gdtNode.xpath("a") { + guard let href = aLink["href"], + let thumbnailURL = URL(string: href), + let divNode = aLink.at_xpath("div"), + let title = divNode["title"], + let index = parseGT200IndexFromTitle(from: title) + else { continue } - thumbnailURLs[index] = thumbnailURL + thumbnailURLs[index] = thumbnailURL + } + } else { + for link in gdtNode.xpath("//div [@class='\(previewMode)']") { + guard let aLink = link.at_xpath("//a"), + let thumbnailURLString = aLink["href"], + let thumbnailURL = URL(string: thumbnailURLString), + let index = Int(aLink.at_xpath("//img")?["alt"] ?? "") + else { continue } + + thumbnailURLs[index] = thumbnailURL + } } return thumbnailURLs @@ -769,6 +817,8 @@ struct Parser { return "gdtm" } else if doc.at_xpath("//div [@class='gdtl']") != nil { return "gdtl" + } else if doc.at_xpath("//div [@class='gt200']") != nil { + return "gt200" } else { throw AppError.parseFailed } @@ -1058,7 +1108,7 @@ extension Parser { } // MARK: EhSetting - static func parseEhSetting(doc: HTMLDocument) throws -> EhSetting { + static func parseEhSetting(doc: HTMLDocument, galleryHost: GalleryHost) throws -> EhSetting { func parseInt(node: XMLElement, name: String) -> Int? { var value: Int? for link in node.xpath("//input [@name='\(name)']") @@ -1132,7 +1182,7 @@ extension Parser { let form = tmpForm else { throw AppError.parseFailed } // swiftlint:disable line_length - var ehProfiles = [EhProfile](); var isCapableOfCreatingNewProfile: Bool?; var capableLoadThroughHathSetting: EhSetting.LoadThroughHathSetting?; var capableImageResolution: EhSetting.ImageResolution?; var capableSearchResultCount: EhSetting.SearchResultCount?; var capableThumbnailConfigSize: EhSetting.ThumbnailSize?; var capableThumbnailConfigRowCount: EhSetting.ThumbnailRowCount?; var loadThroughHathSetting: EhSetting.LoadThroughHathSetting?; var browsingCountry: EhSetting.BrowsingCountry?; var imageResolution: EhSetting.ImageResolution?; var imageSizeWidth: Float?; var imageSizeHeight: Float?; var galleryName: EhSetting.GalleryName?; var literalBrowsingCountry: String?; var archiverBehavior: EhSetting.ArchiverBehavior?; var displayMode: EhSetting.DisplayMode?; var showSearchRangeIndicator: Bool?; var disabledCategories = [Bool](); var favoriteCategories = [String](); var favoritesSortOrder: EhSetting.FavoritesSortOrder?; var ratingsColor: String?; var tagFilteringThreshold: Float?; var tagWatchingThreshold: Float?; var showFilteredRemovalCount: Bool?; var excludedLanguages = [Bool](); var excludedUploaders: String?; var searchResultCount: EhSetting.SearchResultCount?; var thumbnailLoadTiming: EhSetting.ThumbnailLoadTiming?; var thumbnailConfigSize: EhSetting.ThumbnailSize?; var thumbnailConfigRows: EhSetting.ThumbnailRowCount?; var thumbnailScaleFactor: Float?; var viewportVirtualWidth: Float?; var commentsSortOrder: EhSetting.CommentsSortOrder?; var commentVotesShowTiming: EhSetting.CommentVotesShowTiming?; var tagsSortOrder: EhSetting.TagsSortOrder?; var galleryShowPageNumbers: Bool?; var useOriginalImages: Bool?; var useMultiplePageViewer: Bool?; var multiplePageViewerStyle: EhSetting.MultiplePageViewerStyle?; var multiplePageViewerShowThumbnailPane: Bool? + var ehProfiles = [EhProfile](); var isCapableOfCreatingNewProfile: Bool?; var capableLoadThroughHathSetting: EhSetting.LoadThroughHathSetting?; var capableImageResolution: EhSetting.ImageResolution?; var capableSearchResultCount: EhSetting.SearchResultCount?; var capableThumbnailConfigSizes = [EhSetting.ThumbnailSize](); var capableThumbnailConfigRowCount: EhSetting.ThumbnailRowCount?; var loadThroughHathSetting: EhSetting.LoadThroughHathSetting?; var browsingCountry: EhSetting.BrowsingCountry?; var imageResolution: EhSetting.ImageResolution?; var imageSizeWidth: Float?; var imageSizeHeight: Float?; var galleryName: EhSetting.GalleryName?; var literalBrowsingCountry: String?; var archiverBehavior: EhSetting.ArchiverBehavior?; var displayMode: EhSetting.DisplayMode?; var showSearchRangeIndicator: Bool?; var enableGalleryThumbnailSelector: Bool?; var disabledCategories = [Bool](); var favoriteCategories = [String](); var favoritesSortOrder: EhSetting.FavoritesSortOrder?; var ratingsColor: String?; var tagFilteringThreshold: Float?; var tagWatchingThreshold: Float?; var showFilteredRemovalCount: Bool?; var excludedLanguages = [Bool](); var excludedUploaders: String?; var searchResultCount: EhSetting.SearchResultCount?; var thumbnailLoadTiming: EhSetting.ThumbnailLoadTiming?; var thumbnailConfigSize: EhSetting.ThumbnailSize?; var thumbnailConfigRows: EhSetting.ThumbnailRowCount?; var thumbnailScaleFactor: Float?; var viewportVirtualWidth: Float?; var commentsSortOrder: EhSetting.CommentsSortOrder?; var commentVotesShowTiming: EhSetting.CommentVotesShowTiming?; var tagsSortOrder: EhSetting.TagsSortOrder?; var galleryPageNumbers: EhSetting.GalleryPageNumbering?; var useOriginalImages: Bool?; var useMultiplePageViewer: Bool?; var multiplePageViewerStyle: EhSetting.MultiplePageViewerStyle?; var multiplePageViewerShowThumbnailPane: Bool? // swiftlint:enable line_length ehProfiles = parseSelections(node: profileOuter, name: "profile_set") @@ -1192,6 +1242,9 @@ extension Parser { if optouter.at_xpath("//input [@name='pp']") != nil { showSearchRangeIndicator = parseInt(node: optouter, name: "pp") == 0 } + if optouter.at_xpath("//input [@name='xn_0']") != nil { + enableGalleryThumbnailSelector = parseCheckBoxBool(node: optouter, name: "xn_0") + } if optouter.at_xpath("//div [@id='catsel']") != nil { disabledCategories = Array(0...9) .map { "ct_\(EhSetting.categoryNames[$0])" } @@ -1234,8 +1287,32 @@ extension Parser { thumbnailLoadTiming = parseEnum(node: optouter, name: "lt") } if optouter.at_xpath("//input [@name='ts']") != nil { - thumbnailConfigSize = parseEnum(node: optouter, name: "ts") - capableThumbnailConfigSize = parseCapability(node: optouter, name: "ts") + var options = [(value: Int, isEnabled: Bool, isSelected: Bool)]() + for link in optouter.xpath("//input [@name='ts']") { + if let valueString = link["value"], let value = Int(valueString) { + let isEnabled = link["disabled"] != "disabled" + let isSelected = link["checked"] == "checked" + options.append((value: value, isEnabled: isEnabled, isSelected: isSelected)) + } + } + let thumbnailSize: (Int) -> EhSetting.ThumbnailSize? = { + switch (galleryHost == .ehentai, $0) { + case (true, 0): .normal + case (true, 1): .large + case (false, 0): .auto + case (false, 1): .normal + case (false, 2): .small + default: nil + } + } + for option in options where option.isEnabled { + if let size = thumbnailSize(option.value) { + capableThumbnailConfigSizes.append(size) + } + } + if let selectedSize = (options.first(where: \.isSelected)?.value).flatMap(thumbnailSize) { + thumbnailConfigSize = selectedSize + } } if optouter.at_xpath("//input [@name='tr']") != nil { thumbnailConfigRows = parseEnum(node: optouter, name: "tr") @@ -1259,7 +1336,7 @@ extension Parser { tagsSortOrder = parseEnum(node: optouter, name: "tb") } if optouter.at_xpath("//input [@name='pn']") != nil { - galleryShowPageNumbers = parseInt(node: optouter, name: "pn") == 1 + galleryPageNumbers = parseEnum(node: optouter, name: "pn") } if optouter.at_xpath("//input [@name='oi']") != nil { useOriginalImages = parseInt(node: optouter, name: "oi") == 1 @@ -1276,10 +1353,10 @@ extension Parser { } // swiftlint:disable line_length - guard !ehProfiles.filter(\.isSelected).isEmpty, let isCapableOfCreatingNewProfile, let capableLoadThroughHathSetting, let capableImageResolution, let capableSearchResultCount, let capableThumbnailConfigSize, let capableThumbnailConfigRowCount, let loadThroughHathSetting, let browsingCountry, let literalBrowsingCountry, let imageResolution, let imageSizeWidth, let imageSizeHeight, let galleryName, let archiverBehavior, let displayMode, let showSearchRangeIndicator, disabledCategories.count == 10, favoriteCategories.count == 10, let favoritesSortOrder, let ratingsColor, let tagFilteringThreshold, let tagWatchingThreshold, let showFilteredRemovalCount, excludedLanguages.count == 50, let excludedUploaders, let searchResultCount, let thumbnailLoadTiming, let thumbnailConfigSize, let thumbnailConfigRows, let thumbnailScaleFactor, let viewportVirtualWidth, let commentsSortOrder, let commentVotesShowTiming, let tagsSortOrder, let galleryShowPageNumbers + guard !ehProfiles.filter(\.isSelected).isEmpty, let isCapableOfCreatingNewProfile, let capableLoadThroughHathSetting, let capableImageResolution, let capableSearchResultCount, !capableThumbnailConfigSizes.isEmpty, let capableThumbnailConfigRowCount, let loadThroughHathSetting, let browsingCountry, let literalBrowsingCountry, let imageResolution, let imageSizeWidth, let imageSizeHeight, let galleryName, let archiverBehavior, let displayMode, let showSearchRangeIndicator, let enableGalleryThumbnailSelector, disabledCategories.count == 10, favoriteCategories.count == 10, let favoritesSortOrder, let ratingsColor, let tagFilteringThreshold, let tagWatchingThreshold, let showFilteredRemovalCount, excludedLanguages.count == 50, let excludedUploaders, let searchResultCount, let thumbnailLoadTiming, let thumbnailConfigSize, let thumbnailConfigRows, let thumbnailScaleFactor, let viewportVirtualWidth, let commentsSortOrder, let commentVotesShowTiming, let tagsSortOrder, let galleryPageNumbers else { throw AppError.parseFailed } - return EhSetting(ehProfiles: ehProfiles.sorted(), isCapableOfCreatingNewProfile: isCapableOfCreatingNewProfile, capableLoadThroughHathSetting: capableLoadThroughHathSetting, capableImageResolution: capableImageResolution, capableSearchResultCount: capableSearchResultCount, capableThumbnailConfigSize: capableThumbnailConfigSize, capableThumbnailConfigRowCount: capableThumbnailConfigRowCount, loadThroughHathSetting: loadThroughHathSetting, browsingCountry: browsingCountry, literalBrowsingCountry: literalBrowsingCountry, imageResolution: imageResolution, imageSizeWidth: imageSizeWidth, imageSizeHeight: imageSizeHeight, galleryName: galleryName, archiverBehavior: archiverBehavior, displayMode: displayMode, showSearchRangeIndicator: showSearchRangeIndicator, disabledCategories: disabledCategories, favoriteCategories: favoriteCategories, favoritesSortOrder: favoritesSortOrder, ratingsColor: ratingsColor, tagFilteringThreshold: tagFilteringThreshold, tagWatchingThreshold: tagWatchingThreshold, showFilteredRemovalCount: showFilteredRemovalCount, excludedLanguages: excludedLanguages, excludedUploaders: excludedUploaders, searchResultCount: searchResultCount, thumbnailLoadTiming: thumbnailLoadTiming, thumbnailConfigSize: thumbnailConfigSize, thumbnailConfigRows: thumbnailConfigRows, thumbnailScaleFactor: thumbnailScaleFactor, viewportVirtualWidth: viewportVirtualWidth, commentsSortOrder: commentsSortOrder, commentVotesShowTiming: commentVotesShowTiming, tagsSortOrder: tagsSortOrder, galleryShowPageNumbers: galleryShowPageNumbers, useOriginalImages: useOriginalImages, useMultiplePageViewer: useMultiplePageViewer, multiplePageViewerStyle: multiplePageViewerStyle, multiplePageViewerShowThumbnailPane: multiplePageViewerShowThumbnailPane + return EhSetting(ehProfiles: ehProfiles.sorted(), isCapableOfCreatingNewProfile: isCapableOfCreatingNewProfile, capableLoadThroughHathSetting: capableLoadThroughHathSetting, capableImageResolution: capableImageResolution, capableSearchResultCount: capableSearchResultCount, capableThumbnailConfigRowCount: capableThumbnailConfigRowCount, capableThumbnailConfigSizes: capableThumbnailConfigSizes, loadThroughHathSetting: loadThroughHathSetting, browsingCountry: browsingCountry, literalBrowsingCountry: literalBrowsingCountry, imageResolution: imageResolution, imageSizeWidth: imageSizeWidth, imageSizeHeight: imageSizeHeight, galleryName: galleryName, archiverBehavior: archiverBehavior, displayMode: displayMode, showSearchRangeIndicator: showSearchRangeIndicator, enableGalleryThumbnailSelector: enableGalleryThumbnailSelector, disabledCategories: disabledCategories, favoriteCategories: favoriteCategories, favoritesSortOrder: favoritesSortOrder, ratingsColor: ratingsColor, tagFilteringThreshold: tagFilteringThreshold, tagWatchingThreshold: tagWatchingThreshold, showFilteredRemovalCount: showFilteredRemovalCount, excludedLanguages: excludedLanguages, excludedUploaders: excludedUploaders, searchResultCount: searchResultCount, thumbnailLoadTiming: thumbnailLoadTiming, thumbnailConfigSize: thumbnailConfigSize, thumbnailConfigRows: thumbnailConfigRows, thumbnailScaleFactor: thumbnailScaleFactor, viewportVirtualWidth: viewportVirtualWidth, commentsSortOrder: commentsSortOrder, commentVotesShowTiming: commentVotesShowTiming, tagsSortOrder: tagsSortOrder, galleryPageNumbering: galleryPageNumbers, useOriginalImages: useOriginalImages, useMultiplePageViewer: useMultiplePageViewer, multiplePageViewerStyle: multiplePageViewerStyle, multiplePageViewerShowThumbnailPane: multiplePageViewerShowThumbnailPane ) // swiftlint:enable line_length } diff --git a/EhPanda/App/de.lproj/Localizable.strings b/EhPanda/App/de.lproj/Localizable.strings index 4d8c07ea..3914fd7e 100644 --- a/EhPanda/App/de.lproj/Localizable.strings +++ b/EhPanda/App/de.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "Minimal"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "Optional UI Elements"; +"eh_setting_view.description.optional_UI_elements" = "Some historic UI elements are now disabled by default. You can enable those here."; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "Enable thumbnail selector on gallery screen"; + "eh_setting_view.section.title.favorites" = "Favorites"; "eh_setting_view.description.favorite_categories" = "Here you can choose and rename your favorite categories."; "eh_setting_view.title.favorites_sort_order" = "Favorites sort order"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "Normal"; "enum.eh_setting.thumbnail_size.value.large" = "Large"; +"enum.eh_setting.thumbnail_size.value.small" = "Small"; +"enum.eh_setting.thumbnail_size.value.auto" = "Auto"; "eh_setting_view.section.title.thumbnail_scaling" = "Thumbnail Scaling"; +"eh_setting_view.section.title.cover_scaling" = "Cover Scaling"; "eh_setting_view.title.scale_factor" = "Scale factor"; -"eh_setting_view.description.scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.thumbnail_scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.cover_scale_factor" = "The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes."; "eh_setting_view.section.title.viewport_override" = "Viewport Override"; "eh_setting_view.title.virtual_width" = "Virtual width"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "By tag power"; "eh_setting_view.section.title.gallery_page_numbering" = "Gallery Page Numbering"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "Gallery Page Thumbnail Labeling"; "eh_setting_view.title.show_gallery_page_numbers" = "Show gallery page numbers"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "Show label below gallery thumbnails"; "eh_setting_view.section.title.hath_local_network_host" = "Hath Local Network Host"; "eh_setting_view.title.ip_address_port" = "IP address:Port"; "eh_setting_view.description.ip_address_port" = "This setting can be used if you have a H@H client running on your local network with the same public IP you browse the site with. Some routers are buggy and cannot route requests back to its own IP; this allows you to work around this problem.\nIf you are running the client on the same device you browse from, use the loopback address (127.0.0.1:port). If the client is running on another device on your network, use its local network IP. Some browser configurations prevent external web sites from accessing URLs with local network IPs, the site must then be whitelisted for this to work."; -"eh_setting_view.section.title.original_images" = "Original Images"; +"eh_setting_view.section.title.original_images" = "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year)."; "eh_setting_view.title.use_original_images" = "Use original images"; "eh_setting_view.section.title.multi_page_viewer" = "Multi-Page Viewer"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "Align left, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "Align center, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "Align center, always scale"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "None"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "Page Number Only"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "Page Number + Name"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "Yes"; +"enum.eh_setting.gallery_page_numbering.value.no" = "No"; // MARK: Category "enum.category.value.doujinshi" = "Doujinshi"; diff --git a/EhPanda/App/en.lproj/Localizable.strings b/EhPanda/App/en.lproj/Localizable.strings index f01943a1..ad45a911 100644 --- a/EhPanda/App/en.lproj/Localizable.strings +++ b/EhPanda/App/en.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "Minimal"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "Optional UI Elements"; +"eh_setting_view.description.optional_UI_elements" = "Some historic UI elements are now disabled by default. You can enable those here."; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "Enable thumbnail selector on gallery screen"; + "eh_setting_view.section.title.favorites" = "Favorites"; "eh_setting_view.description.favorite_categories" = "Here you can choose and rename your favorite categories."; "eh_setting_view.title.favorites_sort_order" = "Favorites sort order"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "Normal"; "enum.eh_setting.thumbnail_size.value.large" = "Large"; +"enum.eh_setting.thumbnail_size.value.small" = "Small"; +"enum.eh_setting.thumbnail_size.value.auto" = "Auto"; "eh_setting_view.section.title.thumbnail_scaling" = "Thumbnail Scaling"; +"eh_setting_view.section.title.cover_scaling" = "Cover Scaling"; "eh_setting_view.title.scale_factor" = "Scale factor"; -"eh_setting_view.description.scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.thumbnail_scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.cover_scale_factor" = "The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes."; "eh_setting_view.section.title.viewport_override" = "Viewport Override"; "eh_setting_view.title.virtual_width" = "Virtual width"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "By tag power"; "eh_setting_view.section.title.gallery_page_numbering" = "Gallery Page Numbering"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "Gallery Page Thumbnail Labeling"; "eh_setting_view.title.show_gallery_page_numbers" = "Show gallery page numbers"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "Show label below gallery thumbnails"; "eh_setting_view.section.title.hath_local_network_host" = "Hath Local Network Host"; "eh_setting_view.title.ip_address_port" = "IP address:Port"; "eh_setting_view.description.ip_address_port" = "This setting can be used if you have a H@H client running on your local network with the same public IP you browse the site with. Some routers are buggy and cannot route requests back to its own IP; this allows you to work around this problem.\nIf you are running the client on the same device you browse from, use the loopback address (127.0.0.1:port). If the client is running on another device on your network, use its local network IP. Some browser configurations prevent external web sites from accessing URLs with local network IPs, the site must then be whitelisted for this to work."; -"eh_setting_view.section.title.original_images" = "Original Images"; +"eh_setting_view.section.title.original_images" = "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year)."; "eh_setting_view.title.use_original_images" = "Use original images"; "eh_setting_view.section.title.multi_page_viewer" = "Multi-Page Viewer"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "Align left, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "Align center, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "Align center, always scale"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "None"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "Page Number Only"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "Page Number + Name"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "Yes"; +"enum.eh_setting.gallery_page_numbering.value.no" = "No"; // MARK: Category "enum.category.value.doujinshi" = "Doujinshi"; diff --git a/EhPanda/App/ja.lproj/Localizable.strings b/EhPanda/App/ja.lproj/Localizable.strings index 6f5dff7e..3df53ff1 100644 --- a/EhPanda/App/ja.lproj/Localizable.strings +++ b/EhPanda/App/ja.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "最小化"; "enum.eh_setting.display_mode.value.minimalPlus" = "最小化+"; +"eh_setting_view.section.title.optional_UI_elements" = "UI の表示制御"; +"eh_setting_view.description.optional_UI_elements" = "一部の従来の UI はデフォルトで無効になっています。ここで有効にすることができます。"; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "ギャラリーのサムネイルセレクタ"; + "eh_setting_view.section.title.favorites" = "お気に入り"; "eh_setting_view.description.favorite_categories" = "ここではお気に入りカテゴリー名の変更ができます。"; "eh_setting_view.title.favorites_sort_order" = "お気に入りの並び替え"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "普通"; "enum.eh_setting.thumbnail_size.value.large" = "大きめ"; +"enum.eh_setting.thumbnail_size.value.small" = "小さめ"; +"enum.eh_setting.thumbnail_size.value.auto" = "自動"; "eh_setting_view.section.title.thumbnail_scaling" = "サムネイルスケーリング"; +"eh_setting_view.section.title.cover_scaling" = "カバースケーリング"; "eh_setting_view.title.scale_factor" = "スケール係数"; -"eh_setting_view.description.scale_factor" = "サムネイル・拡張表示モードでのサムネイルを 75%% ~ 150%% のカスタム値にスケールすることができます。"; +"eh_setting_view.description.thumbnail_scale_factor" = "サムネイル・拡張表示モードでのサムネイルを 75%% ~ 150%% のカスタム値にスケールすることができます。"; +"eh_setting_view.description.cover_scale_factor" = "サムネイル・拡張表示モードでのカバーを 75%% ~ 150%% にスケールすることができます。"; "eh_setting_view.section.title.viewport_override" = "表示領域オーバーライド"; "eh_setting_view.title.virtual_width" = "仮想幅"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "タグパワーの高い順"; "eh_setting_view.section.title.gallery_page_numbering" = "ギャラリーページ数"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "ギャラリーサムネイルのラベル"; "eh_setting_view.title.show_gallery_page_numbers" = "ギャラリーページ数を表示"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "ギャラリーサムネイルの下にラベルを表示"; "eh_setting_view.section.title.hath_local_network_host" = "Hath ローカルネットワークホスト"; "eh_setting_view.title.ip_address_port" = "IP アドレス:ポート"; "eh_setting_view.description.ip_address_port" = "ローカルネットワークで今と同じパブリック IP を使う H@H クライアントがお持ちの場合、この設定が役立ちます。ルーターがバグが多くてリクエストを自分の IP にルートすることができないこともあります、それをこの設定で回避できます。\nH@H クライアントが今と同じデバイスで運行している場合はループバックアドレス(127.0.0.1:ポート)を使ってください。別のデバイスの場合はそのローカル IP を使ってください。かなりのブラウザの構成では外部サイトがローカル IP にアクセスすることをブロックしています、この設定を有効にするには本サイトをホワイトリストに入れてください。"; -"eh_setting_view.section.title.original_images" = "オリジナル画像"; +"eh_setting_view.section.title.original_images" = "オリジナル画像を使いますか?リサンプリングされた画像は、上記の解像度で「自動」以外を選択し、該当する画像の方が幅が広い場合、またはオリジナル画像が 10 MiB(一年以上前のギャラリーの場合は 4 MiB)より大きい場合に使用されます。"; "eh_setting_view.title.use_original_images" = "オリジナル画像を使う"; "eh_setting_view.section.title.multi_page_viewer" = "マルチページビューア"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "左寄せ、幅によってスケール"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "中央揃え、幅によってスケール"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "中央揃え、常時スケール"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "表示しない"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "ページ番号のみ表示"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "ページ番号と名前を表示"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "表示する"; +"enum.eh_setting.gallery_page_numbering.value.no" = "表示しない"; // MARK: Category "enum.category.value.doujinshi" = "同人誌"; diff --git a/EhPanda/App/ko.lproj/Localizable.strings b/EhPanda/App/ko.lproj/Localizable.strings index 6f42c533..76aa3714 100644 --- a/EhPanda/App/ko.lproj/Localizable.strings +++ b/EhPanda/App/ko.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "Minimal"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "Optional UI Elements"; +"eh_setting_view.description.optional_UI_elements" = "Some historic UI elements are now disabled by default. You can enable those here."; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "Enable thumbnail selector on gallery screen"; + "eh_setting_view.section.title.favorites" = "즐겨찾기"; "eh_setting_view.description.favorite_categories" = "여기서 좋아하는 장르들을 선택하고 이름을 바꿀 수 있어요."; "eh_setting_view.title.favorites_sort_order" = "관심 순서를 배열"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "보통"; "enum.eh_setting.thumbnail_size.value.large" = "크게"; +"enum.eh_setting.thumbnail_size.value.small" = "Small"; +"enum.eh_setting.thumbnail_size.value.auto" = "Auto"; "eh_setting_view.section.title.thumbnail_scaling" = "썸네일 크기"; +"eh_setting_view.section.title.cover_scaling" = "Cover Scaling"; "eh_setting_view.title.scale_factor" = "크기 비율"; -"eh_setting_view.description.scale_factor" = "썸네일 그림 및 확장된 갤러리 목록 보기의 미리 보기는 75%에서 150%% 사이의 사용자 지정 값으로 조정할 수 있어요."; +"eh_setting_view.description.thumbnail_scale_factor" = "썸네일 그림 및 확장된 갤러리 목록 보기의 미리 보기는 75%에서 150%% 사이의 사용자 지정 값으로 조정할 수 있어요."; +"eh_setting_view.description.cover_scale_factor" = "The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes."; "eh_setting_view.section.title.viewport_override" = "뷰포트 조정"; "eh_setting_view.title.virtual_width" = "가상 너비"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "태크 가중치로"; "eh_setting_view.section.title.gallery_page_numbering" = "갤러리 페이지 번호 매기기"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "Gallery Page Thumbnail Labeling"; "eh_setting_view.title.show_gallery_page_numbers" = "갤러리 페이지 번호 보이기"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "Show label below gallery thumbnails"; "eh_setting_view.section.title.hath_local_network_host" = "Hath 로컬 네트워크 호스트"; "eh_setting_view.title.ip_address_port" = "IP주소:포트"; "eh_setting_view.description.ip_address_port" = "이 설정은 사이트를 검색하는 것과 동일한 공용 IP로 로컬 네트워크에서 H@H 클라이언트를 실행하는 경우 사용할 수 있습니다. 일부 라우터는 버그가 있어 요청을 자신의 IP로 다시 라우팅할 수 없기에, 아래를 따라서 이 문제를 해결할 수 있습니다.\n찾아보는 동일한 장치에서 클라이언트를 실행하는 경우 루프백 주소(127.0.0.1:port)를 사용할 수 있습니다. 클라이언트가 네트워크의 다른 장치에서 실행 중인 경우 로컬 네트워크 IP를 사용할 수 있습니다. 일부 브라우저 구성에서는 외부 웹 사이트가 로컬 네트워크 IP가 있는 URL에 액세스할 수 없도록 합니다. 그런 다음 사이트가 작동하려면 사이트를 화이트리스트에 추가해야 합니다."; -"eh_setting_view.section.title.original_images" = "원본 이미지"; +"eh_setting_view.section.title.original_images" = "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year)."; "eh_setting_view.title.use_original_images" = "원본 뷰어 적용"; "eh_setting_view.section.title.multi_page_viewer" = "멀티 페이지 뷰어"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "왼쪽 정렬, 너비 초과할 때 크기 맞추기"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "가운데 정렬, 너비 초과할 때 크기 맞추기"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "가운데 정렬, 항상 크기 맞추기"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "None"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "Page Number Only"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "Page Number + Name"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "Yes"; +"enum.eh_setting.gallery_page_numbering.value.no" = "No"; // MARK: Category "enum.category.value.doujinshi" = "동인지"; diff --git a/EhPanda/App/zh-Hans.lproj/Localizable.strings b/EhPanda/App/zh-Hans.lproj/Localizable.strings index 75a7e1b7..79dde9b3 100644 --- a/EhPanda/App/zh-Hans.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hans.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "最小化"; "enum.eh_setting.display_mode.value.minimalPlus" = "最小化 +"; +"eh_setting_view.section.title.optional_UI_elements" = "可选的 UI 组件"; +"eh_setting_view.description.optional_UI_elements" = "一些旧版 UI 组件现已默认禁用。您可以在此启用这些组件。"; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "在画廊页面启用缩图选择器"; + "eh_setting_view.section.title.favorites" = "收藏"; "eh_setting_view.description.favorite_categories" = "在这里你可以重命名你的收藏夹。"; "eh_setting_view.title.favorites_sort_order" = "收藏排序方式"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "普通"; "enum.eh_setting.thumbnail_size.value.large" = "较大"; +"enum.eh_setting.thumbnail_size.value.small" = "较小"; +"enum.eh_setting.thumbnail_size.value.auto" = "自动"; "eh_setting_view.section.title.thumbnail_scaling" = "缩略图缩放"; +"eh_setting_view.section.title.cover_scaling" = "封面缩放"; "eh_setting_view.title.scale_factor" = "缩放比例"; -"eh_setting_view.description.scale_factor" = "缩略图和扩展模式下的画廊列表缩略图可以缩放为 75%% 到 150%% 之间的自定义值。"; +"eh_setting_view.description.thumbnail_scale_factor" = "缩略图和扩展模式下的画廊列表缩略图可以缩放为 75%% 到 150%% 之间的自定义值。"; +"eh_setting_view.description.cover_scale_factor" = "缩略图和扩展模式下的画廊列表封面可以缩放为 75%% 到 150%% 之间的值。"; "eh_setting_view.section.title.viewport_override" = "覆写可视区域"; "eh_setting_view.title.virtual_width" = "虚拟宽度"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "按标签权重"; "eh_setting_view.section.title.gallery_page_numbering" = "画廊页面页码"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "画廊页面缩略图标签"; "eh_setting_view.title.show_gallery_page_numbers" = "显示画廊页码"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "在画廊缩略图下方显示标签"; "eh_setting_view.section.title.hath_local_network_host" = "Hath 本地网络服务器"; "eh_setting_view.title.ip_address_port" = "IP 地址:端口"; "eh_setting_view.description.ip_address_port" = "如果你本地安装了 H@H 客户端,本地 IP 与浏览网站的公共 IP 相同,一些路由器不支持回流导致无法访问到自己,你可以设置这里来解决。\n如果在同一台设备上访问网站和运行客户端,请使用本地回环地址 (127.0.0.1:端口号)。如果客户端在网络上的其它设备运行,请使用那台机器的内网 IP。某些浏览器的配置可能阻止外部网站访问本地网络,你必须将网站列入白名单才能工作。"; -"eh_setting_view.section.title.original_images" = "原始图像"; +"eh_setting_view.section.title.original_images" = "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year)."; "eh_setting_view.title.use_original_images" = "显示原图"; "eh_setting_view.section.title.multi_page_viewer" = "多页查看器"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "左对齐,图像过宽时缩放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "居中对齐,图像过宽时缩放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "居中对齐,图像始终缩放"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "不显示"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "仅显示页码"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "显示页码和名称"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "显示"; +"enum.eh_setting.gallery_page_numbering.value.no" = "不显示"; // MARK: Category "enum.category.value.doujinshi" = "同人志"; diff --git a/EhPanda/App/zh-Hant-HK.lproj/Localizable.strings b/EhPanda/App/zh-Hant-HK.lproj/Localizable.strings index 13fecb7d..17aaac61 100644 --- a/EhPanda/App/zh-Hant-HK.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hant-HK.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "Minimal"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "Optional UI Elements"; +"eh_setting_view.description.optional_UI_elements" = "Some historic UI elements are now disabled by default. You can enable those here."; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "Enable thumbnail selector on gallery screen"; + "eh_setting_view.section.title.favorites" = "Favorites"; "eh_setting_view.description.favorite_categories" = "Here you can choose and rename your favorite categories."; "eh_setting_view.title.favorites_sort_order" = "Favorites sort order"; @@ -480,10 +484,6 @@ "eh_setting_view.section.title.excluded_languages" = "Excluded Languages"; "eh_setting_view.description.excluded_languages" = "If you wish to hide galleries in certain languages from the gallery list and searches, select them from the list below. Note that matching galleries will never appear regardless of your search query."; - -"eh.setting.view.section.title.excludedLanguages" = "Excluded Languages"; -"eh.setting.view.description.excludedLanguages" = "If you wish to hide galleries in certain languages from the gallery list and searches, select them from the list below. Note that matching galleries will never appear regardless of your search query."; ->>>>>>> develop // EhSetting.ExcludedLanguagesCategory "enum.eh_setting.excluded_languages_category.value.original" = "Original"; "enum.eh_setting.excluded_languages_category.value.translated" = "Translated"; @@ -511,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "Normal"; "enum.eh_setting.thumbnail_size.value.large" = "Large"; +"enum.eh_setting.thumbnail_size.value.small" = "Small"; +"enum.eh_setting.thumbnail_size.value.auto" = "Auto"; "eh_setting_view.section.title.thumbnail_scaling" = "Thumbnail Scaling"; +"eh_setting_view.section.title.cover_scaling" = "Cover Scaling"; "eh_setting_view.title.scale_factor" = "Scale factor"; -"eh_setting_view.description.scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.thumbnail_scale_factor" = "Thumbnails on the thumbnail and extended gallery list views can be scaled to a custom value between 75%% and 150%%."; +"eh_setting_view.description.cover_scale_factor" = "The cover size in gallery list views can be scaled to between 75%% and 150%% when using the Thumbnail or Extended display modes."; "eh_setting_view.section.title.viewport_override" = "Viewport Override"; "eh_setting_view.title.virtual_width" = "Virtual width"; @@ -538,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "By tag power"; "eh_setting_view.section.title.gallery_page_numbering" = "Gallery Page Numbering"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "Gallery Page Thumbnail Labeling"; "eh_setting_view.title.show_gallery_page_numbers" = "Show gallery page numbers"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "Show label below gallery thumbnails"; "eh_setting_view.section.title.hath_local_network_host" = "Hath Local Network Host"; "eh_setting_view.title.ip_address_port" = "IP address:Port"; "eh_setting_view.description.ip_address_port" = "This setting can be used if you have a H@H client running on your local network with the same public IP you browse the site with. Some routers are buggy and cannot route requests back to its own IP; this allows you to work around this problem.\nIf you are running the client on the same device you browse from, use the loopback address (127.0.0.1:port). If the client is running on another device on your network, use its local network IP. Some browser configurations prevent external web sites from accessing URLs with local network IPs, the site must then be whitelisted for this to work."; -"eh_setting_view.section.title.original_images" = "Original Images"; +"eh_setting_view.section.title.original_images" = "Use original images instead of the resampled versions? Resampled images will still be used if you select a horizontal resolution different than \"Auto\" above and the image in question is wider, or if the original image is larger than 10 MiB (or 4 MiB for galleries older than one year)."; "eh_setting_view.title.use_original_images" = "Use original images"; "eh_setting_view.section.title.multi_page_viewer" = "Multi-Page Viewer"; @@ -555,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "Align left, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "Align center, scale if overwidth"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "Align center, always scale"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "None"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "Page Number Only"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "Page Number + Name"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "Yes"; +"enum.eh_setting.gallery_page_numbering.value.no" = "No"; // MARK: Category "enum.category.value.doujinshi" = "同人誌"; diff --git a/EhPanda/App/zh-Hant-TW.lproj/Localizable.strings b/EhPanda/App/zh-Hant-TW.lproj/Localizable.strings index 722e382e..5cb5c7f6 100644 --- a/EhPanda/App/zh-Hant-TW.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hant-TW.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "最小(Minimal)"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "可選用的 UI 元件"; +"eh_setting_view.description.optional_UI_elements" = "一些舊版 UI 元件現已預設停用。您可以在此啟用這些元件。"; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "在畫廊頁面啟用縮圖選擇器"; + "eh_setting_view.section.title.favorites" = "收藏匣"; "eh_setting_view.description.favorite_categories" = "在這裡你可以選擇並重新命名收藏匣"; "eh_setting_view.title.favorites_sort_order" = "收藏匣排序"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "正常"; "enum.eh_setting.thumbnail_size.value.large" = "大型"; +"enum.eh_setting.thumbnail_size.value.small" = "小型"; +"enum.eh_setting.thumbnail_size.value.auto" = "自動"; "eh_setting_view.section.title.thumbnail_scaling" = "縮圖縮放"; +"eh_setting_view.section.title.cover_scaling" = "封面縮放"; "eh_setting_view.title.scale_factor" = "縮放比例"; -"eh_setting_view.description.scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,縮圖的重新採樣比率介於 75%% 至 150%%."; +"eh_setting_view.description.thumbnail_scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,縮圖的重新採樣比率介於 75%% 至 150%%."; +"eh_setting_view.description.cover_scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,封面的重新採樣比率介於 75%% 至 150%%."; "eh_setting_view.section.title.viewport_override" = "視窗覆蓋"; "eh_setting_view.title.virtual_width" = "虛擬寬度"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "標籤權重"; "eh_setting_view.section.title.gallery_page_numbering" = "畫廊頁數"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "畫廊頁面縮圖標籤"; "eh_setting_view.title.show_gallery_page_numbers" = "顯示該畫廊的頁數"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "在畫廊縮圖下方顯示標籤"; "eh_setting_view.section.title.hath_local_network_host" = "內網 H@H 服務 (Hath Local Network Host)"; "eh_setting_view.title.ip_address_port" = "IP 位址:連接埠號"; "eh_setting_view.description.ip_address_port" = "如果你在內網上使用與瀏覽站點相同的公共 IP 架設 H@H 用戶端,有些路由器會因此發生問題,無法將請求傳回自己的 IP,透過啟用這項設定可以解決此問題。\n如果您在瀏覽的同一裝置上運行用戶端,請使用回環地址 (127.0.0.1:port)。 如果用戶端在您網路上的另一台裝置上運行,請使用其本地網路 IP。 某些瀏覽器配置會阻止外部網站存取具有本地網路 IP 的 URL,你必須將站點列入白名單才能使其正常工作。"; -"eh_setting_view.section.title.original_images" = "原始圖片"; +"eh_setting_view.section.title.original_images" = "要使用原始圖片而非重新取樣的版本嗎? 若您在上方選擇「自動」以外的水平解析度且圖片較寬,或原始圖片大於 10 MiB(一年以上的圖庫則為 4 MiB),系統仍會使用重新取樣的圖片。"; "eh_setting_view.title.use_original_images" = "使用原始圖片(原解析度)"; "eh_setting_view.section.title.multi_page_viewer" = "多頁瀏覽"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "向左對齊,若寬度超出頁面則進行縮放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "置中對齊,若寬度超出頁面則進行縮放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "置中對齊且總是縮放"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "不顯示"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "只顯示頁碼"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "顯示頁碼和名稱"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "顯示"; +"enum.eh_setting.gallery_page_numbering.value.no" = "不顯示"; // MARK: Category "enum.category.value.doujinshi" = "同人誌"; diff --git a/EhPanda/App/zh-Hant.lproj/Localizable.strings b/EhPanda/App/zh-Hant.lproj/Localizable.strings index e317ade9..a7ceb359 100644 --- a/EhPanda/App/zh-Hant.lproj/Localizable.strings +++ b/EhPanda/App/zh-Hant.lproj/Localizable.strings @@ -453,6 +453,10 @@ "enum.eh_setting.display_mode.value.minimal" = "最小(Minimal)"; "enum.eh_setting.display_mode.value.minimalPlus" = "Minimal+"; +"eh_setting_view.section.title.optional_UI_elements" = "可選用的 UI 元件"; +"eh_setting_view.description.optional_UI_elements" = "一些舊版 UI 元件現已預設停用。您可以在此啟用這些元件。"; +"eh_setting_view.title.enable_gallery_thumbnail_selector" = "在畫廊頁面啟用縮圖選擇器"; + "eh_setting_view.section.title.favorites" = "收藏匣"; "eh_setting_view.description.favorite_categories" = "在這裡你可以選擇並重新命名收藏匣"; "eh_setting_view.title.favorites_sort_order" = "收藏匣排序"; @@ -507,10 +511,14 @@ // EhSetting.ThumbnailSize "enum.eh_setting.thumbnail_size.value.normal" = "正常"; "enum.eh_setting.thumbnail_size.value.large" = "大型"; +"enum.eh_setting.thumbnail_size.value.small" = "小型"; +"enum.eh_setting.thumbnail_size.value.auto" = "自動"; "eh_setting_view.section.title.thumbnail_scaling" = "縮圖縮放"; +"eh_setting_view.section.title.cover_scaling" = "封面縮放"; "eh_setting_view.title.scale_factor" = "縮放比例"; -"eh_setting_view.description.scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,縮圖的重新採樣比率介於 75%% 至 150%%."; +"eh_setting_view.description.thumbnail_scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,縮圖的重新採樣比率介於 75%% 至 150%%."; +"eh_setting_view.description.cover_scale_factor" = "在縮圖與放大檢視這兩種檢視模式下,封面的重新採樣比率介於 75%% 至 150%%."; "eh_setting_view.section.title.viewport_override" = "視窗覆蓋"; "eh_setting_view.title.virtual_width" = "虛擬寬度"; @@ -534,13 +542,15 @@ "enum.eh_setting.tags_sort_order.value.tag_power" = "標籤權重"; "eh_setting_view.section.title.gallery_page_numbering" = "畫廊頁數"; +"eh_setting_view.section.title.gallery_page_thumbnail_labeling" = "畫廊頁面縮圖標籤"; "eh_setting_view.title.show_gallery_page_numbers" = "顯示該畫廊的頁數"; +"eh_setting_view.title.show_label_below_gallery_thumbnails" = "在畫廊縮圖下方顯示標籤"; "eh_setting_view.section.title.hath_local_network_host" = "內網 H@H 服務 (Hath Local Network Host)"; "eh_setting_view.title.ip_address_port" = "IP 位址:連接埠號"; "eh_setting_view.description.ip_address_port" = "如果你在內網上使用與瀏覽站點相同的公共 IP 架設 H@H 用戶端,有些路由器會因此發生問題,無法將請求傳回自己的 IP,透過啟用這項設定可以解決此問題。\n如果您在瀏覽的同一裝置上運行用戶端,請使用回環地址 (127.0.0.1:port)。 如果用戶端在您網路上的另一台裝置上運行,請使用其本地網路 IP。 某些瀏覽器配置會阻止外部網站存取具有本地網路 IP 的 URL,你必須將站點列入白名單才能使其正常工作。"; -"eh_setting_view.section.title.original_images" = "原始圖片"; +"eh_setting_view.section.title.original_images" = "要使用原始圖片而非重新取樣的版本嗎? 若您在上方選擇「自動」以外的水平解析度且圖片較寬,或原始圖片大於 10 MiB(一年以上的圖庫則為 4 MiB),系統仍會使用重新取樣的圖片。"; "eh_setting_view.title.use_original_images" = "使用原始圖片(原解析度)"; "eh_setting_view.section.title.multi_page_viewer" = "多頁瀏覽"; @@ -551,6 +561,12 @@ "enum.eh_setting.multiple_page_viewer_style.value.align_left_scale_if_over_width" = "向左對齊,若寬度超出頁面則進行縮放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_scale_if_over_width" = "置中對齊,若寬度超出頁面則進行縮放"; "enum.eh_setting.multiple_page_viewer_style.value.align_center_always_scale" = "置中對齊且總是縮放"; +// EhSetting.GalleryPageNumbering +"enum.eh_setting.gallery_page_numbering.value.none" = "不顯示"; +"enum.eh_setting.gallery_page_numbering.value.page_number_only" = "只顯示頁碼"; +"enum.eh_setting.gallery_page_numbering.value.page_number_and_name" = "顯示頁碼和名稱"; +"enum.eh_setting.gallery_page_numbering.value.yes" = "顯示"; +"enum.eh_setting.gallery_page_numbering.value.no" = "不顯示"; // MARK: Category "enum.category.value.doujinshi" = "同人誌"; diff --git a/EhPanda/Models/Support/EhSetting.swift b/EhPanda/Models/Support/EhSetting.swift index 75c27730..e1420218 100644 --- a/EhPanda/Models/Support/EhSetting.swift +++ b/EhPanda/Models/Support/EhSetting.swift @@ -8,7 +8,7 @@ // MARK: EhSetting struct EhSetting: Equatable { // swiftlint:disable line_length - static let empty: Self = .init(ehProfiles: [.empty], isCapableOfCreatingNewProfile: true, capableLoadThroughHathSetting: .anyClient, capableImageResolution: .auto, capableSearchResultCount: .fifty, capableThumbnailConfigSize: .normal, capableThumbnailConfigRowCount: .forty, loadThroughHathSetting: .anyClient, browsingCountry: .autoDetect, literalBrowsingCountry: "", imageResolution: .auto, imageSizeWidth: 0, imageSizeHeight: 0, galleryName: .default, archiverBehavior: .autoSelectOriginalAutoStart, displayMode: .compact, showSearchRangeIndicator: true, disabledCategories: Array(repeating: false, count: 10), favoriteCategories: Array(repeating: "", count: 10), favoritesSortOrder: .favoritedTime, ratingsColor: "", tagFilteringThreshold: 0, tagWatchingThreshold: 0, showFilteredRemovalCount: true, excludedLanguages: Array(repeating: false, count: 50), excludedUploaders: "", searchResultCount: .fifty, thumbnailLoadTiming: .onPageLoad, thumbnailConfigSize: .normal, thumbnailConfigRows: .ten, thumbnailScaleFactor: 0, viewportVirtualWidth: 0, commentsSortOrder: .recent, commentVotesShowTiming: .always, tagsSortOrder: .alphabetical, galleryShowPageNumbers: true) + static let empty: Self = .init(ehProfiles: [.empty], isCapableOfCreatingNewProfile: true, capableLoadThroughHathSetting: .anyClient, capableImageResolution: .auto, capableSearchResultCount: .fifty, capableThumbnailConfigRowCount: .forty, capableThumbnailConfigSizes: [], loadThroughHathSetting: .anyClient, browsingCountry: .autoDetect, literalBrowsingCountry: "", imageResolution: .auto, imageSizeWidth: 0, imageSizeHeight: 0, galleryName: .default, archiverBehavior: .autoSelectOriginalAutoStart, displayMode: .compact, showSearchRangeIndicator: true, enableGalleryThumbnailSelector: false, disabledCategories: Array(repeating: false, count: 10), favoriteCategories: Array(repeating: "", count: 10), favoritesSortOrder: .favoritedTime, ratingsColor: "", tagFilteringThreshold: 0, tagWatchingThreshold: 0, showFilteredRemovalCount: true, excludedLanguages: Array(repeating: false, count: 50), excludedUploaders: "", searchResultCount: .fifty, thumbnailLoadTiming: .onPageLoad, thumbnailConfigSize: .normal, thumbnailConfigRows: .ten, thumbnailScaleFactor: 0, viewportVirtualWidth: 0, commentsSortOrder: .recent, commentVotesShowTiming: .always, tagsSortOrder: .alphabetical, galleryPageNumbering: .none) // swiftlint:enable line_length static let categoryNames = Category.allFiltersCases.map(\.rawValue).map { value in @@ -35,8 +35,8 @@ struct EhSetting: Equatable { let capableLoadThroughHathSetting: LoadThroughHathSetting let capableImageResolution: ImageResolution let capableSearchResultCount: SearchResultCount - let capableThumbnailConfigSize: ThumbnailSize let capableThumbnailConfigRowCount: ThumbnailRowCount + let capableThumbnailConfigSizes: [ThumbnailSize] var capableLoadThroughHathSettings: [LoadThroughHathSetting] { LoadThroughHathSetting.allCases.filter { setting in @@ -53,16 +53,14 @@ struct EhSetting: Equatable { count <= capableSearchResultCount } } - var capableThumbnailConfigSizes: [ThumbnailSize] { - ThumbnailSize.allCases.filter { size in - size <= capableThumbnailConfigSize - } - } var capableThumbnailConfigRowCounts: [ThumbnailRowCount] { ThumbnailRowCount.allCases.filter { row in row <= capableThumbnailConfigRowCount } } + func capableGalleryPageNumberingOptions(galleryHost: GalleryHost) -> [GalleryPageNumbering] { + galleryHost == .ehentai ? [.none, .pageNumberOnly] : [.none, .pageNumberOnly, .pageNumberAndName] + } var localizedLiteralBrowsingCountry: String? { BrowsingCountry.allCases.first(where: { $0.englishName == literalBrowsingCountry })?.name } @@ -77,6 +75,7 @@ struct EhSetting: Equatable { var archiverBehavior: ArchiverBehavior var displayMode: DisplayMode var showSearchRangeIndicator: Bool + var enableGalleryThumbnailSelector: Bool var disabledCategories: [Bool] var favoriteCategories: [String] var favoritesSortOrder: FavoritesSortOrder @@ -95,7 +94,7 @@ struct EhSetting: Equatable { var commentsSortOrder: CommentsSortOrder var commentVotesShowTiming: CommentVotesShowTiming var tagsSortOrder: TagsSortOrder - var galleryShowPageNumbers: Bool + var galleryPageNumbering: GalleryPageNumbering var useOriginalImages: Bool? var useMultiplePageViewer: Bool? var multiplePageViewerStyle: MultiplePageViewerStyle? @@ -389,6 +388,8 @@ extension EhSetting.ThumbnailLoadTiming { // MARK: ThumbnailSize extension EhSetting { enum ThumbnailSize: Int, CaseIterable, Identifiable, Comparable { + case auto + case small case normal case large } @@ -405,6 +406,10 @@ extension EhSetting.ThumbnailSize { return L10n.Localizable.Enum.EhSetting.ThumbnailSize.Value.normal case .large: return L10n.Localizable.Enum.EhSetting.ThumbnailSize.Value.large + case .small: + return L10n.Localizable.Enum.EhSetting.ThumbnailSize.Value.small + case .auto: + return L10n.Localizable.Enum.EhSetting.ThumbnailSize.Value.auto } } } @@ -424,16 +429,12 @@ extension EhSetting.ThumbnailRowCount { lhs.rawValue < rhs.rawValue } - var value: String { + func value(galleryHost: GalleryHost) -> String { switch self { - case .four: - return "4" - case .ten: - return "10" - case .twenty: - return "20" - case .forty: - return "40" + case .four: "4" + case .ten: galleryHost == .ehentai ? "10" : "8" + case .twenty: "20" + case .forty: "40" } } } @@ -523,3 +524,32 @@ extension EhSetting.MultiplePageViewerStyle { } } } + +// MARK: GalleryPageNumbering +extension EhSetting { + enum GalleryPageNumbering: Int, CaseIterable, Identifiable { + case none + case pageNumberOnly + case pageNumberAndName + } +} +extension EhSetting.GalleryPageNumbering { + var id: Int { rawValue } + + func value(galleryHost: GalleryHost) -> String { + switch self { + case .none: + return galleryHost == .ehentai + ? L10n.Localizable.Enum.EhSetting.GalleryPageNumbering.Value.no + : L10n.Localizable.Enum.EhSetting.GalleryPageNumbering.Value.none + + case .pageNumberOnly: + return galleryHost == .ehentai + ? L10n.Localizable.Enum.EhSetting.GalleryPageNumbering.Value.yes + : L10n.Localizable.Enum.EhSetting.GalleryPageNumbering.Value.pageNumberOnly + + case .pageNumberAndName: + return L10n.Localizable.Enum.EhSetting.GalleryPageNumbering.Value.pageNumberAndName + } + } +} diff --git a/EhPanda/Network/Request.swift b/EhPanda/Network/Request.swift index 7765e44f..9c0f37cb 100644 --- a/EhPanda/Network/Request.swift +++ b/EhPanda/Network/Request.swift @@ -751,6 +751,7 @@ struct VerifyEhProfileRequest: Request { } struct EhProfileRequest: Request { + let galleryHost: GalleryHost var action: EhProfileAction? var name: String? var set: Int? @@ -776,24 +777,27 @@ struct EhProfileRequest: Request { return URLSession.shared.dataTaskPublisher(for: request) .genericRetry() .tryMap { try Kanna.HTML(html: $0.data, encoding: .utf8) } - .tryMap(Parser.parseEhSetting) + .tryMap({ try Parser.parseEhSetting(doc: $0, galleryHost: galleryHost) }) .mapError(mapAppError) .eraseToAnyPublisher() } } struct EhSettingRequest: Request { + let galleryHost: GalleryHost + var publisher: AnyPublisher { URLSession.shared.dataTaskPublisher(for: Defaults.URL.uConfig) .genericRetry() .tryMap { try Kanna.HTML(html: $0.data, encoding: .utf8) } - .tryMap(Parser.parseEhSetting) + .tryMap({ try Parser.parseEhSetting(doc: $0, galleryHost: galleryHost) }) .mapError(mapAppError) .eraseToAnyPublisher() } } struct SubmitEhSettingChangesRequest: Request { + let galleryHost: GalleryHost let ehSetting: EhSetting var publisher: AnyPublisher { @@ -816,17 +820,29 @@ struct SubmitEhSettingChangesRequest: Request { "xu": ehSetting.excludedUploaders, "rc": String(ehSetting.searchResultCount.rawValue), "lt": String(ehSetting.thumbnailLoadTiming.rawValue), - "ts": String(ehSetting.thumbnailConfigSize.rawValue), "tr": String(ehSetting.thumbnailConfigRows.rawValue), "tp": String(Int(ehSetting.thumbnailScaleFactor)), "vp": String(Int(ehSetting.viewportVirtualWidth)), "cs": String(ehSetting.commentsSortOrder.rawValue), "sc": String(ehSetting.commentVotesShowTiming.rawValue), "tb": String(ehSetting.tagsSortOrder.rawValue), - "pn": ehSetting.galleryShowPageNumbers ? "1" : "0", + "pn": String(ehSetting.galleryPageNumbering.rawValue), "apply": "Apply" ] + if ehSetting.enableGalleryThumbnailSelector { + params["xn_0"] = "on" + } + + switch (galleryHost, ehSetting.thumbnailConfigSize) { + case (.ehentai, .normal): params["ts"] = "0" + case (.ehentai, .large): params["ts"] = "1" + case (.exhentai, .auto): params["ts"] = "0" + case (.exhentai, .normal): params["ts"] = "1" + case (.exhentai, .small): params["ts"] = "2" + default: break + } + EhSetting.categoryNames.enumerated().forEach { index, name in params["ct_\(name)"] = ehSetting.disabledCategories[index] ? "1" : "0" } @@ -860,7 +876,7 @@ struct SubmitEhSettingChangesRequest: Request { return URLSession.shared.dataTaskPublisher(for: request) .genericRetry() .tryMap { try Kanna.HTML(html: $0.data, encoding: .utf8) } - .tryMap(Parser.parseEhSetting) + .tryMap({ try Parser.parseEhSetting(doc: $0, galleryHost: galleryHost) }) .mapError(mapAppError) .eraseToAnyPublisher() } diff --git a/EhPanda/View/Detail/DetailView.swift b/EhPanda/View/Detail/DetailView.swift index e5ec7aa1..901addbd 100644 --- a/EhPanda/View/Detail/DetailView.swift +++ b/EhPanda/View/Detail/DetailView.swift @@ -33,6 +33,7 @@ struct DetailView: View { var body: some View { ZStack { ScrollView(showsIndicators: false) { + let content = VStack(spacing: 30) { HeaderSection( gallery: store.gallery, @@ -106,7 +107,14 @@ struct DetailView: View { ) } .padding(.bottom, 20) - .padding(.top, -25) + + if #available(iOS 18.0, *) { + content + .padding(.top, 25) + } else { + content + .padding(.top, -25) + } } .opacity(store.galleryDetail == nil ? 0 : 1) LoadingView() diff --git a/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift b/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift index 26471655..d403625b 100644 --- a/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift +++ b/EhPanda/View/Setting/EhSetting/EhSettingReducer.swift @@ -45,11 +45,11 @@ struct EhSettingReducer { case setDefaultProfile(Int) case teardown - case fetchEhSetting + case fetchEhSetting(galleryHost: GalleryHost) case fetchEhSettingDone(Result) - case submitChanges + case submitChanges(galleryHost: GalleryHost) case submitChangesDone(Result) - case performAction(EhProfileAction?, String?, Int) + case performAction(galleryHost: GalleryHost, action: EhProfileAction?, name: String?, set: Int) case performActionDone(Result) } @@ -82,11 +82,11 @@ struct EhSettingReducer { case .teardown: return .merge(CancelID.allCases.map(Effect.cancel(id:))) - case .fetchEhSetting: + case .fetchEhSetting(let galleryHost): guard state.loadingState != .loading else { return .none } state.loadingState = .loading return .run { send in - let response = await EhSettingRequest().response() + let response = await EhSettingRequest(galleryHost: galleryHost).response() await send(.fetchEhSettingDone(response)) } .cancellable(id: CancelID.fetchEhSetting) @@ -102,14 +102,17 @@ struct EhSettingReducer { } return .none - case .submitChanges: + case .submitChanges(let galleryHost): guard state.submittingState != .loading, let ehSetting = state.ehSetting else { return .none } state.submittingState = .loading return .run { send in - let response = await SubmitEhSettingChangesRequest(ehSetting: ehSetting).response() + let response = await SubmitEhSettingChangesRequest( + galleryHost: galleryHost, ehSetting: ehSetting + ) + .response() await send(.submitChangesDone(response)) } .cancellable(id: CancelID.submitChanges) @@ -125,11 +128,14 @@ struct EhSettingReducer { } return .none - case .performAction(let action, let name, let set): + case .performAction(let galleryHost, let action, let name, let set): guard state.submittingState != .loading else { return .none } state.submittingState = .loading return .run { send in - let response = await EhProfileRequest(action: action, name: name, set: set).response() + let response = await EhProfileRequest( + galleryHost: galleryHost, action: action, name: name, set: set + ) + .response() await send(.performActionDone(response)) } .cancellable(id: CancelID.performAction) diff --git a/EhPanda/View/Setting/EhSetting/EhSettingView.swift b/EhPanda/View/Setting/EhSetting/EhSettingView.swift index ae9d2fd2..d149199b 100644 --- a/EhPanda/View/Setting/EhSetting/EhSettingView.swift +++ b/EhPanda/View/Setting/EhSetting/EhSettingView.swift @@ -13,6 +13,9 @@ struct EhSettingView: View { private let bypassesSNIFiltering: Bool private let blurRadius: Double + // Should make it an Environment value. + private var galleryHost: GalleryHost { AppUtil.galleryHost } + init(store: StoreOf, bypassesSNIFiltering: Bool, blurRadius: Double) { self.store = store self.bypassesSNIFiltering = bypassesSNIFiltering @@ -27,7 +30,7 @@ struct EhSettingView: View { LoadingView() .tint(nil) } else if case .failed(let error) = store.loadingState { - ErrorView(error: error, action: { store.send(.fetchEhSetting) }) + ErrorView(error: error, action: { store.send(.fetchEhSetting(galleryHost: galleryHost)) }) .tint(nil) } // Using `Binding.init` will crash the app @@ -40,7 +43,7 @@ struct EhSettingView: View { } .onAppear { if store.ehSetting == nil { - store.send(.fetchEhSetting) + store.send(.fetchEhSetting(galleryHost: galleryHost)) } } .onDisappear { @@ -53,7 +56,7 @@ struct EhSettingView: View { .autoBlur(radius: blurRadius) } .toolbar(content: toolbar) - .navigationTitle(L10n.Localizable.EhSettingView.Title.hostSettings(AppUtil.galleryHost.rawValue)) + .navigationTitle(L10n.Localizable.EhSettingView.Title.hostSettings(galleryHost.rawValue)) } // MARK: Form private func form(ehSetting: Binding, ehProfile: Binding) -> some View { @@ -67,12 +70,16 @@ struct EhSettingView: View { deleteAction: { if let value = store.ehProfile?.value { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - store.send(.performAction(.delete, nil, value)) + store.send( + .performAction(galleryHost: galleryHost, action: .delete, name: nil, set: value) + ) } } }, deleteDialogAction: { store.send(.setNavigation(.deleteProfile)) }, - performEhProfileAction: { store.send(.performAction($0, $1, $2)) } + performEhProfileAction: { + store.send(.performAction(galleryHost: galleryHost, action: $0, name: $1, set: $2)) + } ) ImageLoadSettingsSection(ehSetting: ehSetting) @@ -80,25 +87,25 @@ struct EhSettingView: View { GalleryNameDisplaySection(ehSetting: ehSetting) ArchiverSettingsSection(ehSetting: ehSetting) FrontPageSettingsSection(ehSetting: ehSetting) + OptionalUIElementsSection(ehSetting: ehSetting) FavoritesSection(ehSetting: ehSetting) - RatingsSection(ehSetting: ehSetting) - TagFilteringThresholdSection(ehSetting: ehSetting) - TagWatchingThresholdSection(ehSetting: ehSetting) + SearchResultCountSection(ehSetting: ehSetting) + ThumbnailSettingsSection(ehSetting: ehSetting, galleryHost: galleryHost) } Group { + ThumbnailScalingSection(ehSetting: ehSetting, galleryHost: galleryHost) + RatingsSection(ehSetting: ehSetting) + TagWatchingThresholdSection(ehSetting: ehSetting) + TagFilteringThresholdSection(ehSetting: ehSetting) FilteredRemovalCountSection(ehSetting: ehSetting) ExcludedLanguagesSection(ehSetting: ehSetting) ExcludedUploadersSection(ehSetting: ehSetting) - SearchResultCountSection(ehSetting: ehSetting) - ThumbnailSettingsSection(ehSetting: ehSetting) - ThumbnailScalingSection(ehSetting: ehSetting) ViewportOverrideSection(ehSetting: ehSetting) GalleryCommentsSection(ehSetting: ehSetting) GalleryTagsSection(ehSetting: ehSetting) - GalleryPageNumberingSection(ehSetting: ehSetting) } Group { - OriginalImagesSection(ehSetting: ehSetting) + GalleryPageNumberingSection(ehSetting: ehSetting, galleryHost: galleryHost) MultiplePageViewerSection(ehSetting: ehSetting) } } @@ -117,7 +124,7 @@ struct EhSettingView: View { ToolbarItem(placement: .confirmationAction) { Button { - store.send(.submitChanges) + store.send(.submitChanges(galleryHost: galleryHost)) } label: { Image(systemSymbol: .icloudAndArrowUp) } @@ -286,6 +293,16 @@ private struct ImageSizeSettingsSection: View { } .textCase(nil) + if let useOriginalImagesBinding = Binding($ehSetting.useOriginalImages) { + Section(L10n.Localizable.EhSettingView.Section.Title.originalImages) { + Toggle( + L10n.Localizable.EhSettingView.Title.useOriginalImages, + isOn: useOriginalImagesBinding + ) + } + .textCase(nil) + } + Section(L10n.Localizable.EhSettingView.Description.imageSize) { Text(L10n.Localizable.EhSettingView.Title.imageSize) @@ -369,6 +386,15 @@ private struct FrontPageSettingsSection: View { var body: some View { Section { + CategoryView(bindings: categoryBindings) + } header: { + Text(L10n.Localizable.EhSettingView.Section.Title.frontPageSettings) + .newlineBold() + .appending(L10n.Localizable.EhSettingView.Description.galleryCategory) + } + .textCase(nil) + + Section(L10n.Localizable.EhSettingView.Description.displayMode) { Picker(L10n.Localizable.EhSettingView.Title.displayMode, selection: $ehSetting.displayMode) { ForEach(EhSetting.DisplayMode.allCases) { mode in Text(mode.value) @@ -376,25 +402,37 @@ private struct FrontPageSettingsSection: View { } } .pickerStyle(.menu) - } header: { - Text(L10n.Localizable.EhSettingView.Section.Title.frontPageSettings) - .newlineBold() - .appending(L10n.Localizable.EhSettingView.Description.displayMode) } .textCase(nil) - Section { + Section(L10n.Localizable.EhSettingView.Section.Title.showSearchRangeIndicator) { Toggle( - L10n.Localizable.EhSettingView.Section.Title.showSearchRangeIndicator, + L10n.Localizable.EhSettingView.Title.showSearchRangeIndicator, isOn: $ehSetting.showSearchRangeIndicator ) - } header: { - Text(L10n.Localizable.EhSettingView.Section.Title.showSearchRangeIndicator) } .textCase(nil) + } +} - Section(L10n.Localizable.EhSettingView.Description.galleryCategory) { - CategoryView(bindings: categoryBindings) +// MARK: OptionalUIElementsSection +private struct OptionalUIElementsSection: View { + @Binding private var ehSetting: EhSetting + + init(ehSetting: Binding) { + self._ehSetting = ehSetting + } + + var body: some View { + Section { + Toggle( + L10n.Localizable.EhSettingView.Title.enableGalleryThumbnailSelector, + isOn: $ehSetting.enableGalleryThumbnailSelector + ) + } header: { + Text(L10n.Localizable.EhSettingView.Section.Title.optionalUIElements) + .newlineBold() + .appending(L10n.Localizable.EhSettingView.Description.optionalUIElements) } .textCase(nil) } @@ -543,6 +581,7 @@ private struct FilteredRemovalCountSection: View { Text(L10n.Localizable.EhSettingView.Section.Title.filteredRemovalCount).newlineBold() + Text(L10n.Localizable.EhSettingView.Description.filteredRemovalCount) } + .textCase(nil) } } @@ -712,9 +751,11 @@ private struct SearchResultCountSection: View { // MARK: ThumbnailSettingsSection private struct ThumbnailSettingsSection: View { @Binding private var ehSetting: EhSetting + private let galleryHost: GalleryHost - init(ehSetting: Binding) { - _ehSetting = ehSetting + init(ehSetting: Binding, galleryHost: GalleryHost) { + self._ehSetting = ehSetting + self.galleryHost = galleryHost } var body: some View { @@ -755,11 +796,11 @@ private struct ThumbnailSettingsSection: View { LabeledContent(L10n.Localizable.EhSettingView.Title.thumbnailRowCount) { Picker(selection: $ehSetting.thumbnailConfigRows) { ForEach(ehSetting.capableThumbnailConfigRowCounts) { row in - Text(row.value) + Text(row.value(galleryHost: galleryHost)) .tag(row) } } label: { - Text(ehSetting.capableThumbnailConfigRowCount.value) + Text(ehSetting.capableThumbnailConfigRowCount.value(galleryHost: galleryHost)) } .pickerStyle(.segmented) .frame(width: 200) @@ -772,9 +813,23 @@ private struct ThumbnailSettingsSection: View { // MARK: ThumbnailScalingSection private struct ThumbnailScalingSection: View { @Binding private var ehSetting: EhSetting + private let galleryHost: GalleryHost - init(ehSetting: Binding) { - _ehSetting = ehSetting + init(ehSetting: Binding, galleryHost: GalleryHost) { + self._ehSetting = ehSetting + self.galleryHost = galleryHost + } + + var scalingTitle: String { + galleryHost == .ehentai + ? L10n.Localizable.EhSettingView.Section.Title.thumbnailScaling + : L10n.Localizable.EhSettingView.Section.Title.coverScaling + } + + var scalingFactorDescription: String { + galleryHost == .ehentai + ? L10n.Localizable.EhSettingView.Description.thumbnailScaleFactor + : L10n.Localizable.EhSettingView.Description.coverScaleFactor } var body: some View { @@ -786,9 +841,9 @@ private struct ThumbnailScalingSection: View { unit: "%" ) } header: { - Text(L10n.Localizable.EhSettingView.Section.Title.thumbnailScaling) + Text(scalingTitle) .newlineBold() - .appending(L10n.Localizable.EhSettingView.Description.scaleFactor) + .appending(scalingFactorDescription) } .textCase(nil) } @@ -914,40 +969,35 @@ private struct GalleryTagsSection: View { // MARK: GalleryPageNumberingSection private struct GalleryPageNumberingSection: View { @Binding private var ehSetting: EhSetting + private let galleryHost: GalleryHost - init(ehSetting: Binding) { - _ehSetting = ehSetting + init(ehSetting: Binding, galleryHost: GalleryHost) { + self._ehSetting = ehSetting + self.galleryHost = galleryHost } - var body: some View { - Section(L10n.Localizable.EhSettingView.Section.Title.galleryPageNumbering) { - Toggle( - L10n.Localizable.EhSettingView.Title.showGalleryPageNumbers, - isOn: $ehSetting.galleryShowPageNumbers - ) - } - .textCase(nil) + var sectionTitle: String { + galleryHost == .ehentai + ? L10n.Localizable.EhSettingView.Section.Title.galleryPageNumbering + : L10n.Localizable.EhSettingView.Section.Title.galleryPageThumbnailLabeling } -} - -// MARK: OriginalImagesSection -private struct OriginalImagesSection: View { - @Binding private var ehSetting: EhSetting - - init(ehSetting: Binding) { - _ehSetting = ehSetting + var pickerTitle: String { + galleryHost == .ehentai + ? L10n.Localizable.EhSettingView.Title.showGalleryPageNumbers + : L10n.Localizable.EhSettingView.Title.showLabelBelowGalleryThumbnails } var body: some View { - if let useOriginalImagesBinding = Binding($ehSetting.useOriginalImages) { - Section(L10n.Localizable.EhSettingView.Section.Title.originalImages) { - Toggle( - L10n.Localizable.EhSettingView.Title.useOriginalImages, - isOn: useOriginalImagesBinding - ) + Section(sectionTitle) { + Picker(pickerTitle, selection: $ehSetting.galleryPageNumbering) { + ForEach(ehSetting.capableGalleryPageNumberingOptions(galleryHost: galleryHost)) { behavior in + Text(behavior.value(galleryHost: galleryHost)) + .tag(behavior) + } } - .textCase(nil) + .pickerStyle(.menu) } + .textCase(nil) } } diff --git a/EhPanda/View/Setting/SettingReducer.swift b/EhPanda/View/Setting/SettingReducer.swift index 9ed13e49..144a0e02 100644 --- a/EhPanda/View/Setting/SettingReducer.swift +++ b/EhPanda/View/Setting/SettingReducer.swift @@ -296,7 +296,9 @@ struct SettingReducer { return .none case .createDefaultEhProfile: - return .run(operation: { _ in _ = await EhProfileRequest(action: .create, name: "EhPanda").response() }) + return .run { [galleryHost = state.setting.galleryHost] _ in + _ = await EhProfileRequest(galleryHost: galleryHost, action: .create, name: "EhPanda").response() + } case .fetchIgneous: guard cookieClient.didLogin else { return .none }