From 046901b6fe6a53f1ff5cbbef432967c68d869be6 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 11:07:26 +0100 Subject: [PATCH 01/12] Add search parameter to getThemesForBlog method --- WordPress/Classes/Services/ThemeService.h | 2 ++ WordPress/Classes/Services/ThemeService.m | 4 ++++ WordPress/WordPressTest/ThemeServiceTests.m | 1 + 3 files changed, 7 insertions(+) diff --git a/WordPress/Classes/Services/ThemeService.h b/WordPress/Classes/Services/ThemeService.h index bb004f0867b9..1edb75ccf92f 100644 --- a/WordPress/Classes/Services/ThemeService.h +++ b/WordPress/Classes/Services/ThemeService.h @@ -48,6 +48,7 @@ typedef void(^ThemeServiceFailureBlock)(NSError *error); * * @param blogId The blog to get the themes for. Cannot be nil. * @param page Results page to return. + * @param search Search string to filter themes. Cannot be nil. * @param sync Whether to remove unsynced results. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. @@ -56,6 +57,7 @@ typedef void(^ThemeServiceFailureBlock)(NSError *error); */ - (NSProgress *)getThemesForBlog:(Blog *)blog page:(NSInteger)page + search:(NSString *)search sync:(BOOL)sync success:(ThemeServiceThemesRequestSuccessBlock)success failure:(ThemeServiceFailureBlock)failure; diff --git a/WordPress/Classes/Services/ThemeService.m b/WordPress/Classes/Services/ThemeService.m index 8f4908299743..bcc1346c1bfa 100644 --- a/WordPress/Classes/Services/ThemeService.m +++ b/WordPress/Classes/Services/ThemeService.m @@ -149,11 +149,13 @@ - (NSProgress *)getActiveThemeForBlog:(Blog *)blog - (NSProgress *)getThemesForBlog:(Blog *)blog page:(NSInteger)page + search:(NSString *)search sync:(BOOL)sync success:(ThemeServiceThemesRequestSuccessBlock)success failure:(ThemeServiceFailureBlock)failure { NSParameterAssert([blog isKindOfClass:[Blog class]]); + NSParameterAssert([search isKindOfClass:[NSString class]]); NSAssert([self blogSupportsThemeServices:blog], @"Do not call this method on unsupported blogs, check with blogSupportsThemeServices first."); @@ -166,6 +168,7 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog if ([blog supports:BlogFeatureCustomThemes]) { return [remote getWPThemesPage:page freeOnly:![blog supports:BlogFeaturePremiumThemes] + search:search success:^(NSArray *remoteThemes, BOOL hasMore, NSInteger totalThemeCount) { NSArray * __block themeObjectIDs = nil; [self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) { @@ -205,6 +208,7 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog } else { return [remote getThemesForBlogId:[blog dotComID] page:page + search:search success:^(NSArray *remoteThemes, BOOL hasMore, NSInteger totalThemeCount) { NSArray * __block themeObjectIDs = nil; [self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) { diff --git a/WordPress/WordPressTest/ThemeServiceTests.m b/WordPress/WordPressTest/ThemeServiceTests.m index c3edd9c4dd7e..5668bc9242ca 100644 --- a/WordPress/WordPressTest/ThemeServiceTests.m +++ b/WordPress/WordPressTest/ThemeServiceTests.m @@ -116,6 +116,7 @@ - (void)testThatGetThemesForBlogWorks XCTAssertNoThrow(service = [[ThemeService alloc] initWithCoreDataStack:self.manager]); XCTAssertNoThrow([service getThemesForBlog:blog page:1 + search:@"" sync:NO success:nil failure:nil]); From 2a5b67e2a8c36367dc860a89ddd3966f2db37e57 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 11:52:46 +0100 Subject: [PATCH 02/12] Add remote search functionality to theme synchronization --- .../Themes/ThemeBrowserViewController.swift | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index e92fe3d5c1ba..423337ac4865 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -451,11 +451,12 @@ public protocol ThemePresenter: AnyObject { } } - fileprivate func syncThemePage(_ page: NSInteger, success: ((_ hasMore: Bool) -> Void)?, failure: ((_ error: NSError) -> Void)?) { + fileprivate 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,36 @@ public protocol ThemePresenter: AnyObject { // MARK: - Search support + fileprivate var searchDebounceTimer: Timer? + fileprivate let searchDebounceInterval: TimeInterval = 0.5 + fileprivate func beginSearchFor(_ pattern: String) { searchController.isActive = true searchController.searchBar.text = pattern - searchName = pattern + updateSearchName(pattern) + } + + fileprivate func updateSearchName(_ searchText: String) { + // Cancel any existing timer + searchDebounceTimer?.invalidate() + + // If search text is empty, update immediately + if searchText.isEmpty { + self.searchName = searchText + self.fetchThemes() + self.reloadThemes() + return + } + + // Create a new timer for debounce + searchDebounceTimer = Timer.scheduledTimer(withTimeInterval: searchDebounceInterval, repeats: false) { [weak self] _ in + guard let self = self else { return } + self.searchName = searchText + // Reset to first page when searching + self.themesSyncingPage = 0 + self.themesSyncHelper.syncContent() + } } // MARK: - UISearchControllerDelegate @@ -708,19 +734,11 @@ 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) } @@ -732,7 +750,7 @@ public protocol ThemePresenter: AnyObject { 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 } switch subpredicates.count { case 1: return subpredicates[0] From e8f6e13e655c85f2eaad9f67507c708d7c493ae4 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 18:41:59 +0100 Subject: [PATCH 03/12] Update WordPressKit-iOS dependency to use branch for search parameter integration --- Modules/Package.swift | 2 +- WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/Package.swift b/Modules/Package.swift index 7850155872c8..0d1441c77a43 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -46,7 +46,7 @@ let package = Package( .package(url: "https://github.com/wordpress-mobile/MediaEditor-iOS", branch: "task/spm-support"), .package(url: "https://github.com/wordpress-mobile/NSObject-SafeExpectations", from: "0.0.6"), .package(url: "https://github.com/wordpress-mobile/NSURL-IDN", branch: "trunk"), - .package(url: "https://github.com/wordpress-mobile/WordPressKit-iOS", branch: "wpios-edition"), + .package(url: "https://github.com/wordpress-mobile/WordPressKit-iOS", branch: "add-search-param-in-theme-service-remote"), .package(url: "https://github.com/zendesk/support_sdk_ios", from: "8.0.3"), // We can't use wordpress-rs branches nor commits here. Only tags work. .package(url: "https://github.com/Automattic/wordpress-rs", revision: "alpha-20250127"), diff --git a/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9b9551386cf0..90ab5b00e97a 100644 --- a/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "b048f2348f14b6f12b4a4b8588355abe499af3f8f4e91cacc054e98187a7746c", + "originHash" : "8117dae8b3d06437bc38067b5c732e1508045719f050cca08922ff947919bda4", "pins" : [ { "identity" : "alamofire", @@ -391,8 +391,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/wordpress-mobile/WordPressKit-iOS", "state" : { - "branch" : "wpios-edition", - "revision" : "ba542bae62a1d9b80b0baee44d610bfac55936ea" + "branch" : "add-search-param-in-theme-service-remote", + "revision" : "4fbd973b499f1312103311ff5c883fba19c44dc6" } }, { From e2b137cf46f10be1c8c80b875ac28af8c895a92b Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 18:42:24 +0100 Subject: [PATCH 04/12] Clear search parameter if empty in getThemesForBlog method --- WordPress/Classes/Services/ThemeService.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/Services/ThemeService.m b/WordPress/Classes/Services/ThemeService.m index bcc1346c1bfa..3cb26ec0ec72 100644 --- a/WordPress/Classes/Services/ThemeService.m +++ b/WordPress/Classes/Services/ThemeService.m @@ -159,6 +159,11 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog NSAssert([self blogSupportsThemeServices:blog], @"Do not call this method on unsupported blogs, check with blogSupportsThemeServices first."); + // Set search to nil if it's empty to clear search results + if (search.length == 0) { + search = nil; + } + if (blog.wordPressComRestApi == nil) { return nil; } @@ -167,8 +172,8 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog if ([blog supports:BlogFeatureCustomThemes]) { return [remote getWPThemesPage:page + search:search freeOnly:![blog supports:BlogFeaturePremiumThemes] - search:search success:^(NSArray *remoteThemes, BOOL hasMore, NSInteger totalThemeCount) { NSArray * __block themeObjectIDs = nil; [self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) { @@ -208,7 +213,6 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog } else { return [remote getThemesForBlogId:[blog dotComID] page:page - search:search success:^(NSArray *remoteThemes, BOOL hasMore, NSInteger totalThemeCount) { NSArray * __block themeObjectIDs = nil; [self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) { From 4951d37b8f81d0e96a6768571670040f6fc3175e Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 18:48:24 +0100 Subject: [PATCH 05/12] Enhance local and remote search logic in ThemeBrowserViewController.swift - Apply immediate local search when search text changes - Perform remote search for WordPress.com themes with 3+ characters - Update predicates to include local search conditions for custom themes - Refactor comments for clarity on search behavior and conditions --- .../Themes/ThemeBrowserViewController.swift | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index 423337ac4865..f0ef4e7279f9 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -683,9 +683,25 @@ public protocol ThemePresenter: AnyObject { searchDebounceTimer = Timer.scheduledTimer(withTimeInterval: searchDebounceInterval, repeats: false) { [weak self] _ in guard let self = self else { return } self.searchName = searchText - // Reset to first page when searching - self.themesSyncingPage = 0 - self.themesSyncHelper.syncContent() + + // 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 { + // Just reload with local results for shorter queries + self.reloadThemes() + } + } else { + // For blogs without custom themes support, we already fetched locally + self.reloadThemes() + } } } @@ -744,13 +760,34 @@ public protocol ThemePresenter: AnyObject { } fileprivate func customThemesBrowsePredicate() -> NSPredicate? { - return browsePredicateThemesWithCustomValue(true) + let browsePredicate = browsePredicateThemesWithCustomValue(true) + + // Add 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, 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) + 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] From 163b4b7ab81642dce246866327787819816f9d65 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 19:01:57 +0100 Subject: [PATCH 06/12] Add remote search reset functionality - Modify `ThemeBrowserViewController.swift` to include `resetRemoteSearch` method - Integrate `resetRemoteSearch` in search logic to reset search state upon search text changes - Adjust logic to handle shorter search queries that follow longer ones by resetting remote search - Ensure local results reload consistently after search operations --- .../Themes/ThemeBrowserViewController.swift | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index f0ef4e7279f9..f60e06f0ba76 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -659,6 +659,14 @@ public protocol ThemePresenter: AnyObject { fileprivate var searchDebounceTimer: Timer? fileprivate let searchDebounceInterval: TimeInterval = 0.5 + + fileprivate func resetRemoteSearch() { + themesSyncingPage = 0 + + if blog.supports(BlogFeature.customThemes) { + themesSyncHelper.syncContent() + } + } fileprivate func beginSearchFor(_ pattern: String) { searchController.isActive = true @@ -671,14 +679,18 @@ public protocol ThemePresenter: AnyObject { // Cancel any existing timer searchDebounceTimer?.invalidate() - // If search text is empty, update immediately + // 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 = self else { return } @@ -694,14 +706,15 @@ public protocol ThemePresenter: AnyObject { // Reset to first page when searching self.themesSyncingPage = 0 self.themesSyncHelper.syncContent() - } else { - // Just reload with local results for shorter queries - self.reloadThemes() + } else if previouslyHadRemoteSearch { + // If we previously had 3+ characters but now have less, + // we need to reset the remote search results + self.resetRemoteSearch() } - } else { - // For blogs without custom themes support, we already fetched locally - self.reloadThemes() } + + // Always reload with local results + self.reloadThemes() } } @@ -723,6 +736,7 @@ public protocol ThemePresenter: AnyObject { hideSectionHeaders = false searchName = "" searchController.searchBar.text = "" + resetRemoteSearch() } open func didDismissSearchController(_ searchController: UISearchController) { From 90c32a4d6b8f5f4c5cdd24229c8647f90e6dc842 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 19:08:05 +0100 Subject: [PATCH 07/12] fix: comment --- WordPress/Classes/Services/ThemeService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/Services/ThemeService.h b/WordPress/Classes/Services/ThemeService.h index 1edb75ccf92f..9e44b48aa638 100644 --- a/WordPress/Classes/Services/ThemeService.h +++ b/WordPress/Classes/Services/ThemeService.h @@ -48,7 +48,7 @@ typedef void(^ThemeServiceFailureBlock)(NSError *error); * * @param blogId The blog to get the themes for. Cannot be nil. * @param page Results page to return. - * @param search Search string to filter themes. Cannot be nil. + * @param search Search string to filter themes. * @param sync Whether to remove unsynced results. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. From d768d1d0839a1d22d45117b9688291da82b6fa1f Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 23:29:21 +0100 Subject: [PATCH 08/12] - Remove redundant NSParameterAssert for search in ThemeService.m - Update test to use nil instead of empty string for search in ThemeServiceTests.m --- WordPress/Classes/Services/ThemeService.m | 2 -- WordPress/WordPressTest/ThemeServiceTests.m | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/Classes/Services/ThemeService.m b/WordPress/Classes/Services/ThemeService.m index 3cb26ec0ec72..5613a0f3c163 100644 --- a/WordPress/Classes/Services/ThemeService.m +++ b/WordPress/Classes/Services/ThemeService.m @@ -155,11 +155,9 @@ - (NSProgress *)getThemesForBlog:(Blog *)blog failure:(ThemeServiceFailureBlock)failure { NSParameterAssert([blog isKindOfClass:[Blog class]]); - NSParameterAssert([search isKindOfClass:[NSString class]]); NSAssert([self blogSupportsThemeServices:blog], @"Do not call this method on unsupported blogs, check with blogSupportsThemeServices first."); - // Set search to nil if it's empty to clear search results if (search.length == 0) { search = nil; } diff --git a/WordPress/WordPressTest/ThemeServiceTests.m b/WordPress/WordPressTest/ThemeServiceTests.m index 5668bc9242ca..1bb3b992f512 100644 --- a/WordPress/WordPressTest/ThemeServiceTests.m +++ b/WordPress/WordPressTest/ThemeServiceTests.m @@ -116,7 +116,7 @@ - (void)testThatGetThemesForBlogWorks XCTAssertNoThrow(service = [[ThemeService alloc] initWithCoreDataStack:self.manager]); XCTAssertNoThrow([service getThemesForBlog:blog page:1 - search:@"" + search:nil sync:NO success:nil failure:nil]); From 25a0f8e7f451e94b5b4059b65127ac896e9a3f3f Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 23:30:08 +0100 Subject: [PATCH 09/12] Refactor ThemeBrowserViewController access modifiers and simplify code - Change `fileprivate` to `private` for several functions and variables in ThemeBrowserViewController.swift - Simplify guard statement in `updateSearchName` function - Update comment in `customThemesBrowsePredicate` function --- .../Themes/ThemeBrowserViewController.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index f60e06f0ba76..76f5ccd88c5a 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -451,7 +451,7 @@ public protocol ThemePresenter: AnyObject { } } - fileprivate func syncThemePage(_ page: NSInteger, search: String, 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, @@ -657,12 +657,12 @@ public protocol ThemePresenter: AnyObject { // MARK: - Search support - fileprivate var searchDebounceTimer: Timer? - fileprivate let searchDebounceInterval: TimeInterval = 0.5 - - fileprivate func resetRemoteSearch() { + private var searchDebounceTimer: Timer? + private let searchDebounceInterval: TimeInterval = 0.5 + + private func resetRemoteSearch() { themesSyncingPage = 0 - + if blog.supports(BlogFeature.customThemes) { themesSyncHelper.syncContent() } @@ -675,7 +675,7 @@ public protocol ThemePresenter: AnyObject { updateSearchName(pattern) } - fileprivate func updateSearchName(_ searchText: String) { + private func updateSearchName(_ searchText: String) { // Cancel any existing timer searchDebounceTimer?.invalidate() @@ -693,7 +693,7 @@ public protocol ThemePresenter: AnyObject { // Create a new timer for debounce searchDebounceTimer = Timer.scheduledTimer(withTimeInterval: searchDebounceInterval, repeats: false) { [weak self] _ in - guard let self = self else { return } + guard let self else { return } self.searchName = searchText // Apply local search immediately @@ -776,7 +776,7 @@ public protocol ThemePresenter: AnyObject { fileprivate func customThemesBrowsePredicate() -> NSPredicate? { let browsePredicate = browsePredicateThemesWithCustomValue(true) - // Add search predicate for custom themes (local search only) + // Search predicate for custom themes (local search only) if !searchName.isEmpty { let searchPredicate = NSPredicate(format: "name CONTAINS[cd] %@", searchName) if let existingPredicate = browsePredicate { From 69c5b90a74d1511731c9092685f1f65ea0b2ebdb Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Thu, 20 Mar 2025 13:20:50 +0100 Subject: [PATCH 10/12] fix: Trailing Whitespace Violation --- .../Themes/ThemeBrowserViewController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift index 76f5ccd88c5a..c75bb12d06bd 100644 --- a/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift +++ b/WordPress/Classes/ViewRelated/Themes/ThemeBrowserViewController.swift @@ -662,7 +662,7 @@ public protocol ThemePresenter: AnyObject { private func resetRemoteSearch() { themesSyncingPage = 0 - + if blog.supports(BlogFeature.customThemes) { themesSyncHelper.syncContent() } @@ -690,7 +690,7 @@ public protocol ThemePresenter: AnyObject { // 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 } @@ -712,7 +712,7 @@ public protocol ThemePresenter: AnyObject { self.resetRemoteSearch() } } - + // Always reload with local results self.reloadThemes() } @@ -768,7 +768,7 @@ public protocol ThemePresenter: AnyObject { } // MARK: - NSFetchedResultsController helpers - + fileprivate func browsePredicate() -> NSPredicate? { return browsePredicateThemesWithCustomValue(false) } @@ -793,7 +793,7 @@ public protocol ThemePresenter: AnyObject { let blogPredicate = NSPredicate(format: "blog == %@ AND custom == %d", self.blog, custom ? 1 : 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) @@ -801,7 +801,7 @@ public protocol ThemePresenter: AnyObject { let searchPredicate = NSPredicate(format: "name CONTAINS[cd] %@", searchName) return NSCompoundPredicate(andPredicateWithSubpredicates: subpredicates + [searchPredicate]) } - + switch subpredicates.count { case 1: return subpredicates[0] From 2f809cccdefa1ccc2712a40f770635bfabdb2cd7 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Fri, 28 Mar 2025 15:30:23 +0100 Subject: [PATCH 11/12] update: point back to wpios-edition for WordPressKit-iOS --- Modules/Package.swift | 2 +- WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/Package.swift b/Modules/Package.swift index 0d1441c77a43..7850155872c8 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -46,7 +46,7 @@ let package = Package( .package(url: "https://github.com/wordpress-mobile/MediaEditor-iOS", branch: "task/spm-support"), .package(url: "https://github.com/wordpress-mobile/NSObject-SafeExpectations", from: "0.0.6"), .package(url: "https://github.com/wordpress-mobile/NSURL-IDN", branch: "trunk"), - .package(url: "https://github.com/wordpress-mobile/WordPressKit-iOS", branch: "add-search-param-in-theme-service-remote"), + .package(url: "https://github.com/wordpress-mobile/WordPressKit-iOS", branch: "wpios-edition"), .package(url: "https://github.com/zendesk/support_sdk_ios", from: "8.0.3"), // We can't use wordpress-rs branches nor commits here. Only tags work. .package(url: "https://github.com/Automattic/wordpress-rs", revision: "alpha-20250127"), diff --git a/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved index 90ab5b00e97a..d4b7d8a6ab5f 100644 --- a/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/WordPress.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "8117dae8b3d06437bc38067b5c732e1508045719f050cca08922ff947919bda4", + "originHash" : "b637515cdb9c1c25894b401b59b20ad56c195cd52aa6bee2ada1b56cd753ece8", "pins" : [ { "identity" : "alamofire", @@ -391,8 +391,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/wordpress-mobile/WordPressKit-iOS", "state" : { - "branch" : "add-search-param-in-theme-service-remote", - "revision" : "4fbd973b499f1312103311ff5c883fba19c44dc6" + "branch" : "wpios-edition", + "revision" : "7dc4ed37223be387e95a5d68e23f1dc956db318b" } }, { From 39a46f1dcc301a3b626581c41c6c6f00a5084787 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Mon, 31 Mar 2025 11:59:31 +0200 Subject: [PATCH 12/12] fix: ThemeServiceTests --- WordPress/WordPressTest/ThemeServiceTests.m | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/WordPressTest/ThemeServiceTests.m b/WordPress/WordPressTest/ThemeServiceTests.m index c4813e7c1078..2d8ed1ab928c 100644 --- a/WordPress/WordPressTest/ThemeServiceTests.m +++ b/WordPress/WordPressTest/ThemeServiceTests.m @@ -125,6 +125,7 @@ - (void)testThatGetThemesForBlogThrowsExceptionWithoutBlog XCTAssertNoThrow(service = [[ThemeService alloc] initWithCoreDataStack:self.manager]); XCTAssertThrows([service getThemesForBlog:nil page:1 + search:nil sync:NO success:nil failure:nil]);