Skip to content
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

fix showing current tab in suggestions #3562

Merged
merged 7 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@
851672D12BED1FC900592F24 /* AutocompleteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D02BED1FC900592F24 /* AutocompleteView.swift */; };
851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */; };
8517D98B221783A0006A8DD0 /* FindInPage.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */; };
851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */; };
8519526C2CE256BC00578553 /* AutocompleteSuggestionsDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */; };
851B1283221FE65E004781BC /* ImproveOnboardingExperiment1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */; };
851B128822200575004781BC /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B128722200575004781BC /* Onboarding.swift */; };
851B12CC22369931004781BC /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850250B220D803F4002199C7 /* AtbAndVariantCleanup.swift */; };
Expand Down Expand Up @@ -1740,6 +1742,8 @@
851672D02BED1FC900592F24 /* AutocompleteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteView.swift; sourceTree = "<group>"; };
851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewModel.swift; sourceTree = "<group>"; };
8517D98A221783A0006A8DD0 /* FindInPage.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FindInPage.xcassets; sourceTree = "<group>"; };
851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteSuggestionsDataSource.swift; sourceTree = "<group>"; };
8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteSuggestionsDataSourceTests.swift; sourceTree = "<group>"; };
851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImproveOnboardingExperiment1Tests.swift; sourceTree = "<group>"; };
851B128722200575004781BC /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
851B128B2220483A004781BC /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4318,10 +4322,19 @@
children = (
851672CE2BED1F9500592F24 /* HistoryMessageManager.swift */,
851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */,
851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */,
);
name = Model;
sourceTree = "<group>";
};
851952692CE2569600578553 /* Autocomplete */ = {
isa = PBXGroup;
children = (
8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */,
);
name = Autocomplete;
sourceTree = "<group>";
};
851DFD88212C5ED600D95F20 /* Main */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -5752,7 +5765,7 @@
F12D98401F266B30003C2EE3 /* DuckDuckGo */ = {
isa = PBXGroup;
children = (
6F03CAFF2C32ED22004179A8 /* NewTabPage */,
851952692CE2569600578553 /* Autocomplete */,
6FF9157F2B88E04F0042AC87 /* AdAttribution */,
F17669A21E411D63003D3222 /* Application */,
981FED7222045FFA008488D7 /* AutoClear */,
Expand All @@ -5765,6 +5778,7 @@
8588026724E4249800C24AB6 /* iPad */,
851DFD88212C5ED600D95F20 /* Main */,
EE56DE3A2A6038F500375C41 /* NetworkProtection */,
6F03CAFF2C32ED22004179A8 /* NewTabPage */,
F1D477C71F2139210031ED49 /* OmniBar */,
9F23B8042C2BE20500950875 /* Onboarding */,
98EA2C3F218BB5140023E1DC /* Settings */,
Expand Down Expand Up @@ -7373,6 +7387,7 @@
8540BD5423D8D5080057FDD2 /* PreserveLoginsAlert.swift in Sources */,
1E87615928A1517200C7C5CE /* PrivacyDashboardViewController.swift in Sources */,
6F03CAFE2C32DD08004179A8 /* HomePageMessagesConfiguration.swift in Sources */,
851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */,
EE9D68D12AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift in Sources */,
319A371028299A850079FBCE /* PasswordHider.swift in Sources */,
982C87C42255559A00919035 /* UITableViewCellExtension.swift in Sources */,
Expand Down Expand Up @@ -8027,6 +8042,7 @@
310E79BD2949CAA5007C49E8 /* FireButtonReferenceTests.swift in Sources */,
4B62C4BA25B930DD008912C6 /* AppConfigurationFetchTests.swift in Sources */,
31C7D71C27515A6300A95D0A /* MockVoiceSearchHelper.swift in Sources */,
8519526C2CE256BC00578553 /* AutocompleteSuggestionsDataSourceTests.swift in Sources */,
6F395BBB2CD2C87D00B92FC3 /* BoolFileMarkerTests.swift in Sources */,
8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */,
98AAF8E4292EB46000DBDF06 /* BookmarksMigrationTests.swift in Sources */,
Expand Down
100 changes: 100 additions & 0 deletions DuckDuckGo/AutocompleteSuggestionsDataSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// AutocompleteSuggestionsDataSource.swift
// DuckDuckGo
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Core
import BrowserServicesKit
import Suggestions
import History
import Persistence
import Networking

final class AutocompleteSuggestionsDataSource: SuggestionLoadingDataSource {

typealias SuggestionsRequestCompletion = (Data?, Error?) -> Void
typealias SuggestionsRequest = (URLRequest, @escaping SuggestionsRequestCompletion) -> Void

private let historyManager: HistoryManaging
private let bookmarksDatabase: CoreDataDatabase
private let featureFlagger: FeatureFlagger
private let tabsModel: TabsModel

private var performSuggestionsRequest: SuggestionsRequest

/// Specifically open tabs that do not have the same URL as the current tab so that we avoid shown them in the results.
private lazy var candidateOpenTabs: [BrowserTab] = {
tabsModel.tabs.compactMap {
guard let url = $0.link?.url,
tabsModel.currentTab?.link?.url != $0.link?.url
else { return nil }

return OpenTab(title: $0.link?.displayTitle ?? "", url: url)
}
}()

private lazy var cachedBookmarks: CachedBookmarks = {
CachedBookmarks(bookmarksDatabase)
}()

var historyCoordinator: HistoryCoordinating {
historyManager.historyCoordinator
}

var platform: Platform {
.mobile
}

init(historyManager: HistoryManaging, bookmarksDatabase: CoreDataDatabase, featureFlagger: FeatureFlagger, tabsModel: TabsModel, performSuggestionsRequest: @escaping SuggestionsRequest) {
self.historyManager = historyManager
self.bookmarksDatabase = bookmarksDatabase
self.featureFlagger = featureFlagger
self.tabsModel = tabsModel
self.performSuggestionsRequest = performSuggestionsRequest
}

func history(for suggestionLoading: Suggestions.SuggestionLoading) -> [HistorySuggestion] {
return historyCoordinator.history ?? []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nip: can remove unnecessary return on line. Same applies to below methods:

  • func bookmarks(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.Bookmark]

  • func internalPages(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.InternalPage]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna leave it. My thinking is that functions should return something (unless they are view builders). I would like to think I'm consistent about that ... but who knows. :) Anyway, since it's just a nit I'm gonna go with what I've got.

}

func bookmarks(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.Bookmark] {
return cachedBookmarks.all
}

func internalPages(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.InternalPage] {
return []
}

func openTabs(for suggestionLoading: any SuggestionLoading) -> [BrowserTab] {
if featureFlagger.isFeatureOn(.autcompleteTabs) {
return candidateOpenTabs
}
return []
}

func suggestionLoading(_ suggestionLoading: Suggestions.SuggestionLoading, suggestionDataFromUrl url: URL, withParameters parameters: [String: String], completion: @escaping (Data?, Error?) -> Void) {
var queryURL = url
parameters.forEach {
queryURL = queryURL.appendingParameter(name: $0.key, value: $0.value)
}
var request = URLRequest.developerInitiated(queryURL)
request.allHTTPHeaderFields = APIRequest.Headers().httpHeaders

performSuggestionsRequest(request, completion)
}

}
82 changes: 20 additions & 62 deletions DuckDuckGo/AutocompleteViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,34 @@ class AutocompleteViewController: UIHostingController<AutocompleteView> {
weak var delegate: AutocompleteViewControllerDelegate?
weak var presentationDelegate: AutocompleteViewControllerPresentationDelegate?

private let historyManager: HistoryManaging
var historyCoordinator: HistoryCoordinating {
historyManager.historyCoordinator
}

private let bookmarksDatabase: CoreDataDatabase
private let appSettings: AppSettings
private let model: AutocompleteViewModel

private var task: URLSessionDataTask?

@Published private var query = ""
private var queryDebounceCancellable: AnyCancellable?

private lazy var cachedBookmarks: CachedBookmarks = {
CachedBookmarks(bookmarksDatabase)
}()

private lazy var openTabs: [BrowserTab] = {
tabsModel.tabs.compactMap {
guard let url = $0.link?.url else { return nil }
return OpenTab(title: $0.link?.displayTitle ?? "", url: url)
}
}()

private var lastResults: SuggestionResult?
private var loader: SuggestionLoader?
private var historyMessageManager: HistoryMessageManager
private var tabsModel: TabsModel
private var featureFlagger: FeatureFlagger
private let historyManager: HistoryManaging
private let bookmarksDatabase: CoreDataDatabase
private let tabsModel: TabsModel

private var task: URLSessionDataTask?

lazy var dataSource: AutocompleteSuggestionsDataSource = {
return AutocompleteSuggestionsDataSource(
historyManager: historyManager,
bookmarksDatabase: bookmarksDatabase,
featureFlagger: featureFlagger,
tabsModel: tabsModel) { [weak self] request, completion in
self?.task = Self.session.dataTask(with: request) { data, _, error in
completion(data, error)
}
self?.task?.resume()
}
}()

init(historyManager: HistoryManaging,
bookmarksDatabase: CoreDataDatabase,
Expand All @@ -81,6 +79,7 @@ class AutocompleteViewController: UIHostingController<AutocompleteView> {
self.tabsModel = tabsModel
self.historyManager = historyManager
self.bookmarksDatabase = bookmarksDatabase

self.appSettings = appSettings
self.historyMessageManager = historyMessageManager
self.featureFlagger = featureFlagger
Expand Down Expand Up @@ -191,7 +190,7 @@ class AutocompleteViewController: UIHostingController<AutocompleteView> {
return url
})

loader?.getSuggestions(query: query, usingDataSource: self) { [weak self] result, error in
loader?.getSuggestions(query: query, usingDataSource: dataSource) { [weak self] result, error in
guard let self, error == nil else { return }
let updatedResults = result ?? .empty
self.lastResults = updatedResults
Expand Down Expand Up @@ -283,47 +282,6 @@ extension AutocompleteViewController: AutocompleteViewModelDelegate {
}
}

extension AutocompleteViewController: SuggestionLoadingDataSource {

var platform: Platform {
.mobile
}

func history(for suggestionLoading: Suggestions.SuggestionLoading) -> [HistorySuggestion] {
return historyCoordinator.history ?? []
}

func bookmarks(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.Bookmark] {
return cachedBookmarks.all
}

func internalPages(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.InternalPage] {
return []
}

func openTabs(for suggestionLoading: any SuggestionLoading) -> [BrowserTab] {
if featureFlagger.isFeatureOn(.autcompleteTabs) {
return openTabs
}
return []
}

func suggestionLoading(_ suggestionLoading: Suggestions.SuggestionLoading, suggestionDataFromUrl url: URL, withParameters parameters: [String: String], completion: @escaping (Data?, Error?) -> Void) {
var queryURL = url
parameters.forEach {
queryURL = queryURL.appendingParameter(name: $0.key, value: $0.value)
}

var request = URLRequest.developerInitiated(queryURL)
request.allHTTPHeaderFields = APIRequest.Headers().httpHeaders
task = Self.session.dataTask(with: request) { data, _, error in
completion(data, error)
}
task?.resume()
}

}

private extension SuggestionResult {
static let empty = SuggestionResult(topHits: [], duckduckgoSuggestions: [], localSuggestions: [])
}
Expand Down
Loading
Loading