-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Enable remote search in Themes if custom themes are supported #24262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
kean
merged 14 commits into
trunk
from
issue/23153-cannot-search-for-themes-if-not-already-downloaded
Mar 31, 2025
Merged
Changes from 10 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
046901b
Add search parameter to getThemesForBlog method
pmusolino 2a5b67e
Add remote search functionality to theme synchronization
pmusolino e8f6e13
Update WordPressKit-iOS dependency to use branch for search parameter…
pmusolino e2b137c
Clear search parameter if empty in getThemesForBlog method
pmusolino 4951d37
Enhance local and remote search logic in ThemeBrowserViewController.s…
pmusolino 163b4b7
Add remote search reset functionality
pmusolino 90c32a4
fix: comment
pmusolino d768d1d
- Remove redundant NSParameterAssert for search in ThemeService.m
pmusolino 25a0f8e
Refactor ThemeBrowserViewController access modifiers and simplify code
pmusolino 69c5b90
fix: Trailing Whitespace Violation
pmusolino 2f809cc
update: point back to wpios-edition for WordPressKit-iOS
pmusolino 41d0f61
Merge commit '58f73c0d7d91f5cfc75c26a5dcf08eae8d3e2030' into issue/23…
pmusolino 39a46f1
fix: ThemeServiceTests
pmusolino 1d552f7
Merge branch 'trunk' into issue/23153-cannot-search-for-themes-if-not…
pmusolino File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -451,11 +451,12 @@ public protocol ThemePresenter: AnyObject { | |
| } | ||
| } | ||
|
|
||
| fileprivate func syncThemePage(_ page: NSInteger, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { | ||
| private func syncThemePage(_ page: NSInteger, search: String, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { | ||
| assert(page > 0) | ||
| themesSyncingPage = page | ||
| _ = themeService.getThemesFor(blog, | ||
| page: themesSyncingPage, | ||
| search: search, | ||
| sync: page == 1, | ||
| success: {[weak self](themes: [Theme]?, hasMore: Bool, themeCount: NSInteger) in | ||
| if let success { | ||
|
|
@@ -508,7 +509,7 @@ public protocol ThemePresenter: AnyObject { | |
|
|
||
| func syncHelper(_ syncHelper: WPContentSyncHelper, syncContentWithUserInteraction userInteraction: Bool, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { | ||
| if syncHelper == themesSyncHelper { | ||
| syncThemePage(1, success: success, failure: failure) | ||
| syncThemePage(1, search: searchName, success: success, failure: failure) | ||
| } else if syncHelper == customThemesSyncHelper { | ||
| syncCustomThemes(success: success, failure: failure) | ||
| } | ||
|
|
@@ -517,7 +518,7 @@ public protocol ThemePresenter: AnyObject { | |
| func syncHelper(_ syncHelper: WPContentSyncHelper, syncMoreWithSuccess success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { | ||
| if syncHelper == themesSyncHelper { | ||
| let nextPage = themesSyncingPage + 1 | ||
| syncThemePage(nextPage, success: success, failure: failure) | ||
| syncThemePage(nextPage, search: searchName, success: success, failure: failure) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -656,11 +657,65 @@ public protocol ThemePresenter: AnyObject { | |
|
|
||
| // MARK: - Search support | ||
|
|
||
| private var searchDebounceTimer: Timer? | ||
| private let searchDebounceInterval: TimeInterval = 0.5 | ||
|
|
||
| private func resetRemoteSearch() { | ||
| themesSyncingPage = 0 | ||
|
|
||
| if blog.supports(BlogFeature.customThemes) { | ||
| themesSyncHelper.syncContent() | ||
| } | ||
| } | ||
|
|
||
| fileprivate func beginSearchFor(_ pattern: String) { | ||
| searchController.isActive = true | ||
| searchController.searchBar.text = pattern | ||
|
|
||
| searchName = pattern | ||
| updateSearchName(pattern) | ||
| } | ||
|
|
||
| private func updateSearchName(_ searchText: String) { | ||
| // Cancel any existing timer | ||
| searchDebounceTimer?.invalidate() | ||
|
|
||
| // If search text is empty, update immediately and reset remote search | ||
| if searchText.isEmpty { | ||
| self.searchName = searchText | ||
| self.fetchThemes() | ||
| self.resetRemoteSearch() | ||
| self.reloadThemes() | ||
| return | ||
| } | ||
|
|
||
| // Check if we have a previously longer search that is now under 3 characters | ||
| let previouslyHadRemoteSearch = self.searchName.count >= 3 | ||
|
|
||
| // Create a new timer for debounce | ||
| searchDebounceTimer = Timer.scheduledTimer(withTimeInterval: searchDebounceInterval, repeats: false) { [weak self] _ in | ||
| guard let self else { return } | ||
| self.searchName = searchText | ||
|
|
||
| // Apply local search immediately | ||
| self.fetchThemes() | ||
|
|
||
| // Remote search only applies to WordPress.com themes and only if customThemes are supported. | ||
| // The remote endpoint support search just for 3+ characters | ||
| if self.blog.supports(BlogFeature.customThemes) { | ||
| if searchText.count >= 3 { | ||
| // Reset to first page when searching | ||
| self.themesSyncingPage = 0 | ||
| self.themesSyncHelper.syncContent() | ||
| } else if previouslyHadRemoteSearch { | ||
| // If we previously had 3+ characters but now have less, | ||
| // we need to reset the remote search results | ||
| self.resetRemoteSearch() | ||
| } | ||
| } | ||
|
|
||
| // Always reload with local results | ||
| self.reloadThemes() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - UISearchControllerDelegate | ||
|
|
@@ -681,6 +736,7 @@ public protocol ThemePresenter: AnyObject { | |
| hideSectionHeaders = false | ||
| searchName = "" | ||
| searchController.searchBar.text = "" | ||
| resetRemoteSearch() | ||
| } | ||
|
|
||
| open func didDismissSearchController(_ searchController: UISearchController) { | ||
|
|
@@ -708,31 +764,44 @@ public protocol ThemePresenter: AnyObject { | |
| // MARK: - UISearchResultsUpdating | ||
|
|
||
| open func updateSearchResults(for searchController: UISearchController) { | ||
| searchName = searchController.searchBar.text ?? "" | ||
| updateSearchName(searchController.searchBar.text ?? "") | ||
| } | ||
|
|
||
| // MARK: - NSFetchedResultsController helpers | ||
|
|
||
| fileprivate func searchNamePredicate() -> NSPredicate? { | ||
| guard !searchName.isEmpty else { | ||
| return nil | ||
| } | ||
|
|
||
| return NSPredicate(format: "name contains[c] %@", searchName) | ||
| } | ||
|
|
||
| fileprivate func browsePredicate() -> NSPredicate? { | ||
| return browsePredicateThemesWithCustomValue(false) | ||
| } | ||
|
|
||
| fileprivate func customThemesBrowsePredicate() -> NSPredicate? { | ||
| return browsePredicateThemesWithCustomValue(true) | ||
| let browsePredicate = browsePredicateThemesWithCustomValue(true) | ||
|
|
||
| // Search predicate for custom themes (local search only) | ||
| if !searchName.isEmpty { | ||
| let searchPredicate = NSPredicate(format: "name CONTAINS[cd] %@", searchName) | ||
| if let existingPredicate = browsePredicate { | ||
| return NSCompoundPredicate(andPredicateWithSubpredicates: [existingPredicate, searchPredicate]) | ||
| } else { | ||
| return searchPredicate | ||
| } | ||
| } | ||
|
|
||
| return browsePredicate | ||
| } | ||
|
|
||
| fileprivate func browsePredicateThemesWithCustomValue(_ custom: Bool) -> NSPredicate? { | ||
| let blogPredicate = NSPredicate(format: "blog == %@ AND custom == %d", self.blog, custom ? 1 : 0) | ||
|
|
||
| let subpredicates = [blogPredicate, searchNamePredicate(), filterType.predicate].compactMap { $0 } | ||
| let subpredicates = [blogPredicate, filterType.predicate].compactMap { $0 } | ||
|
|
||
| // For regular themes, add local search predicate if: | ||
| // 1. Not using custom themes feature, or | ||
| // 2. Search term is less than 3 characters (we'll only search locally for short terms) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just noting that it's an unfortunate limitation. |
||
| if !searchName.isEmpty && !custom && (!blog.supports(BlogFeature.customThemes) || searchName.count < 3) { | ||
| let searchPredicate = NSPredicate(format: "name CONTAINS[cd] %@", searchName) | ||
| return NSCompoundPredicate(andPredicateWithSubpredicates: subpredicates + [searchPredicate]) | ||
| } | ||
|
|
||
| switch subpredicates.count { | ||
| case 1: | ||
| return subpredicates[0] | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure to update it to point to
wpios-editionbefore merging.