Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

[IP-618] [Search] Onboarding for existing users (#397)

* added onboarding for search

* fixed react button action

* fixed search query

* fixed search onboarding problem

* fixed onboarding showing logic

* fixed onboarding showing logic

* dismissed search onboarding for Cliqz
  • Loading branch information
pavel-cliqz authored and chrmod committed Jul 22, 2019
1 parent 38e2dd4 commit e101a8f6e6474cf50f9c18e3edfcd9e19cee52c5
@@ -890,7 +890,7 @@ class BrowserViewController: UIViewController {
} }
} }


fileprivate func showSearchController() { func showSearchController() {
/* Cliqz: Replace Search Controller /* Cliqz: Replace Search Controller
if searchController != nil { if searchController != nil {
return return
@@ -915,15 +915,20 @@ class BrowserViewController: UIViewController {
searchController!.didMove(toParentViewController: self) searchController!.didMove(toParentViewController: self)
*/ */
if (searchController != nil && SettingsPrefs.shared.getCliqzSearchPref() == false) || let shouldShowCliqzSearch = SettingsPrefs.shared.getCliqzSearchPref() || self.shouldShowSearchOnboarding()
(cliqzSearchController != nil && SettingsPrefs.shared.getCliqzSearchPref() == true){ if (searchController != nil && !shouldShowCliqzSearch) ||
(cliqzSearchController != nil && shouldShowCliqzSearch){
return return
} }


searchLoader = SearchLoader(profile: profile, urlBar: urlBar) searchLoader = SearchLoader(profile: profile, urlBar: urlBar)
searchLoader!.addListener(HistoryListener.shared) searchLoader!.addListener(HistoryListener.shared)


if SettingsPrefs.shared.getCliqzSearchPref() { if shouldShowCliqzSearch {
if self.shouldShowSearchOnboarding() {
LegacyTelemetryHelper.logOnboarding(action: "show", topic: "search")
}

homePanelController?.view?.isHidden = true homePanelController?.view?.isHidden = true


cliqzSearchController = CliqzSearchViewController(profile: self.profile) cliqzSearchController = CliqzSearchViewController(profile: self.profile)
@@ -1000,7 +1005,11 @@ class BrowserViewController: UIViewController {
} }
} }


fileprivate func hideSearchController() { private func shouldShowSearchOnboarding() -> Bool {
return UserPreferences.instance.showSearchOnboarding
}

func hideSearchController() {
/*Cliqz: Hide cliqzSearch or firefoxSearch /*Cliqz: Hide cliqzSearch or firefoxSearch
if let searchController = searchController { if let searchController = searchController {
searchController.willMove(toParentViewController: nil) searchController.willMove(toParentViewController: nil)
@@ -1681,15 +1690,19 @@ extension BrowserViewController: URLBarDelegate {
searchController?.searchQuery = text searchController?.searchQuery = text
searchLoader?.query = text searchLoader?.query = text
*/ */
if !text.isEmpty { self.updateSearchQuery(query: text)
cliqzSearchController?.searchQuery = text
searchController?.searchQuery = text
searchLoader?.query = text
}
// End Cliqz // End Cliqz
} }
} }


func updateSearchQuery(query: String) {
if !query.isEmpty {
cliqzSearchController?.searchQuery = query
searchController?.searchQuery = query
searchLoader?.query = query
}
}

func urlBar(_ urlBar: URLBarView, didSubmitText text: String) { func urlBar(_ urlBar: URLBarView, didSubmitText text: String) {
guard let currentTab = tabManager.selectedTab else { return } guard let currentTab = tabManager.selectedTab else { return }
if let fixupURL = URIFixup.getURL(text) { if let fixupURL = URIFixup.getURL(text) {
@@ -2348,7 +2361,13 @@ extension BrowserViewController: IntroViewControllerDelegate {
#endif #endif
// End Cliqz // End Cliqz
if force || profile.prefs.intForKey(PrefsKeys.IntroSeen) == nil { /* Cliqz: determining the first launch. */
let isFirstLaunch = profile.prefs.intForKey(PrefsKeys.IntroSeen) == nil
if isFirstLaunch {
UserPreferences.instance.showSearchOnboarding = false
}

if force || isFirstLaunch {
#if PAID #if PAID
let introViewController = LumenIntroViewController() let introViewController = LumenIntroViewController()
#else #else
@@ -23,4 +23,21 @@ extension BrowserViewController: SearchViewDelegate {
func dismissKeyboard() { func dismissKeyboard() {
urlBar.hideKeyboard() urlBar.hideKeyboard()
} }

func closeSearchOnboarding() {
let query = cliqzSearchController?.searchQuery
hideSearchController()
showSearchController()
if let query = query {
updateSearchQuery(query: query)
}
}

func makeLumenDefaultSearch() {
let lumenSearchEngine = self.profile.searchEngines.orderedEngines.filter { $0.shortName == LumenSearchEngineDisplayName }.first
if let engine = lumenSearchEngine {
self.profile.searchEngines.defaultEngine = engine
self.urlBar.updatePlaceHolders()
}
}
} }
@@ -52,6 +52,7 @@ extension Notification.Name {


let IsDeveloperModeOnKey = "IsDeveloperModeOnKey" let IsDeveloperModeOnKey = "IsDeveloperModeOnKey"
let ShowPromoCodeKey = "ShowPromoCodeKey" let ShowPromoCodeKey = "ShowPromoCodeKey"
let ShowSearchOnboarding = "showSearchOnboarding"
let ShowNonPrivateSearchWarningKey = "ShowNonPrivateSearchWarningKey" let ShowNonPrivateSearchWarningKey = "ShowNonPrivateSearchWarningKey"


/// If `true`, send a `developer` flag in the telemetry data. /// If `true`, send a `developer` flag in the telemetry data.
@@ -86,6 +87,23 @@ extension Notification.Name {
} }
} }


var showSearchOnboarding: Bool {
get {
#if PAID
if let val = userDefaults().value(forKey: ShowSearchOnboarding) as? Bool {
return val
}

return true
#else
return false
#endif
}
set {
userDefaults().set(newValue, forKey: ShowSearchOnboarding)
}
}

var shouldShowNonPrivateSearchWarningMessage: Bool { var shouldShowNonPrivateSearchWarningMessage: Bool {
get { get {
if let val = userDefaults().value(forKey: ShowNonPrivateSearchWarningKey) as? Bool { if let val = userDefaults().value(forKey: ShowNonPrivateSearchWarningKey) as? Bool {
@@ -30,8 +30,8 @@ open class Engine {
#else #else
let jsCodeLocation = Bundle.main.url(forResource: "jsengine.bundle", withExtension: "js") let jsCodeLocation = Bundle.main.url(forResource: "jsengine.bundle", withExtension: "js")
#endif #endif

rootView = RCTRootView( bundleURL: jsCodeLocation, moduleName: "ExtensionApp", initialProperties: ["showSearchOnboarding": true], launchOptions: nil ) rootView = RCTRootView( bundleURL: jsCodeLocation, moduleName: "ExtensionApp", initialProperties: nil, launchOptions: nil )
bridge = rootView.bridge bridge = rootView.bridge
//ConnectManager.sharedInstance.refresh() //ConnectManager.sharedInstance.refresh()
} }
@@ -93,6 +93,14 @@ class JSBridge : RCTEventEmitter {
} }
} }
} }

@objc(getConfig:reject:)
func getConfig(resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
if SettingsPrefs.shared.isLumenDefaultSearchEngine {
UserPreferences.instance.showSearchOnboarding = false
}
resolve(["onboarding": UserPreferences.instance.showSearchOnboarding])
}


/// Call an action over the JSBridge and execute a callback with the result. Invokation of the callback is /// Call an action over the JSBridge and execute a callback with the result. Invokation of the callback is
/// not guaranteed, for example if the function is never registered. Unlike the synchronous version, this /// not guaranteed, for example if the function is never registered. Unlike the synchronous version, this
@@ -13,5 +13,6 @@ @interface RCT_EXTERN_MODULE(JSBridge, NSObject)
RCT_EXTERN_METHOD(replyToAction:(nonnull NSInteger *)actionId result:(NSDictionary *)result) RCT_EXTERN_METHOD(replyToAction:(nonnull NSInteger *)actionId result:(NSDictionary *)result)
RCT_EXTERN_METHOD(registerAction:) RCT_EXTERN_METHOD(registerAction:)
RCT_EXTERN_METHOD(pushEvent:(nonnull NSString *)eventId data:(NSArray *)data) RCT_EXTERN_METHOD(pushEvent:(nonnull NSString *)eventId data:(NSArray *)data)
RCT_EXTERN_METHOD(getConfig:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)


@end @end
@@ -19,9 +19,13 @@ class Onboarding: RCTEventEmitter {
func tryLumenSearch(accepted: Bool) { func tryLumenSearch(accepted: Bool) {
debugPrint("tryLumenSearch -- \(accepted)") debugPrint("tryLumenSearch -- \(accepted)")
if accepted { if accepted {
// TODO: PK this is try now case. Change Lumen to default search engine. UI will be handled by extenstion DispatchQueue.main.async {
NotificationCenter.default.post(name: MakeLumenDefaultSearchNotification, object: nil, userInfo: nil)
}
} else { } else {
// TODO: PK close cliqz search and open queary with default search engine DispatchQueue.main.async {
NotificationCenter.default.post(name: CloseSearchOnboardingNotification, object: nil, userInfo: nil)
}
} }
} }
} }
@@ -28,6 +28,8 @@ protocol SearchViewDelegate: class {
func didSelectURL(_ url: URL, searchQuery: String?) func didSelectURL(_ url: URL, searchQuery: String?)
func autoCompeleteQuery(_ autoCompleteText: String) func autoCompeleteQuery(_ autoCompleteText: String)
func dismissKeyboard() func dismissKeyboard()
func closeSearchOnboarding()
func makeLumenDefaultSearch()
} }


let OpenURLIsSearchEngineKey = "OpenURLIsSearchEngineKey" let OpenURLIsSearchEngineKey = "OpenURLIsSearchEngineKey"
@@ -37,6 +39,8 @@ let HideKeyboardSearchNotification = NSNotification.Name(rawValue: "mobile-searc
let CallSearchNotification = NSNotification.Name(rawValue: "mobile-search:call") let CallSearchNotification = NSNotification.Name(rawValue: "mobile-search:call")
let MapSearchNotification = NSNotification.Name(rawValue: "mobile-search:map") let MapSearchNotification = NSNotification.Name(rawValue: "mobile-search:map")
let ShareLocationSearchNotification = NSNotification.Name(rawValue: "mobile-search:share-location") let ShareLocationSearchNotification = NSNotification.Name(rawValue: "mobile-search:share-location")
let MakeLumenDefaultSearchNotification = NSNotification.Name(rawValue: "mobile-search:makeLumenDefaultSearchEngine")
let CloseSearchOnboardingNotification = NSNotification.Name(rawValue: "mobile-search:closeSearchOnboarding")


let SearchEngineChangedNotification = Notification.Name(rawValue: "SearchEngineChangedNotification") let SearchEngineChangedNotification = Notification.Name(rawValue: "SearchEngineChangedNotification")


@@ -120,6 +124,8 @@ class CliqzSearchViewController : UIViewController, KeyboardHelperDelegate, UIAl
NotificationCenter.default.addObserver(self, selector: #selector(openMap), name: MapSearchNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(openMap), name: MapSearchNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(shareLocation), name: ShareLocationSearchNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(shareLocation), name: ShareLocationSearchNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(autocomplete(_:)), name: AutoCompleteNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(autocomplete(_:)), name: AutoCompleteNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(closeSearchOnboarding(_:)), name: CloseSearchOnboardingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(makeLumenDefaultSearch(_:)), name: MakeLumenDefaultSearchNotification, object: nil)


//TODO: Send notification when search engine is changed //TODO: Send notification when search engine is changed
NotificationCenter.default.addObserver(self, selector: #selector(searchEngineChanged), name: SearchEngineChangedNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(searchEngineChanged), name: SearchEngineChangedNotification, object: nil)
@@ -286,6 +292,20 @@ extension CliqzSearchViewController {
LocationManager.sharedInstance.shareLocation() LocationManager.sharedInstance.shareLocation()
} }


@objc func closeSearchOnboarding(_ notification: Notification) {
LegacyTelemetryHelper.logOnboarding(action: "click", target: "cancel", topic: "search")
UserPreferences.instance.showSearchOnboarding = false
delegate?.closeSearchOnboarding()
}

@objc func makeLumenDefaultSearch(_ notification: Notification) {
LegacyTelemetryHelper.logOnboarding(action: "click", target: "try", topic: "search")
UserPreferences.instance.showSearchOnboarding = false
if !SettingsPrefs.shared.isLumenDefaultSearchEngine {
delegate?.makeLumenDefaultSearch()
}
}

fileprivate func showLumenSearchLeavingWarning(url: URL) { fileprivate func showLumenSearchLeavingWarning(url: URL) {
LegacyTelemetryHelper.logLumenSearchWarning(action: "show") LegacyTelemetryHelper.logLumenSearchWarning(action: "show")
UserPreferences.instance.shouldShowNonPrivateSearchWarningMessage = false UserPreferences.instance.shouldShowNonPrivateSearchWarningMessage = false
@@ -10,9 +10,11 @@ import UIKit


class LegacyTelemetryHelper: NSObject { class LegacyTelemetryHelper: NSObject {


class func logOnboarding(action: String, page: Int, target: String? = nil) { class func logOnboarding(action: String, page: Int? = nil, target: String? = nil, topic: String? = nil) {
var signal: [String : Any] = ["type": "onboarding", "action": action, "page": page, "version": 1] var signal: [String : Any] = ["type": "onboarding", "action": action, "version": 1]
if let target = target { signal["target"] = target } if let target = target { signal["target"] = target }
if let page = page { signal["page"] = page }
if let topic = topic { signal["topic"] = topic }


sendSignal(signal) sendSignal(signal)
} }
@@ -102,9 +102,9 @@ export default class Onboarding extends React.Component {
</Animated.View> </Animated.View>
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
<TouchableWithoutFeedback disabled={this.state.isClicked} onPress={() => this.onPress(false)}> <TouchableWithoutFeedback disabled={this.state.isClicked} onPress={() => this.onPress(false)}>
<> <View>
<Animated.Text style={{ letterSpacing: -0.2, marginTop: 20, fontSize: 14, lineHeight: 17, fontWeight: '700', color: this.interpolateColor('#3647D0', '#3647D0')}}>{noThanksText}</Animated.Text> <Animated.Text style={{ letterSpacing: -0.2, marginTop: 20, fontSize: 14, lineHeight: 17, fontWeight: '700', color: this.interpolateColor('#3647D0', '#3647D0')}}>{noThanksText}</Animated.Text>
</> </View>
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
</View> </View>
); );
@@ -59,19 +59,29 @@ class MobileCards extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
onboarding: props.showSearchOnboarding, onboarding: false,
results: { results: {
results: [], results: [],
meta: {} meta: {}
}, },
isReady: false,
hasQuery: false, hasQuery: false,
theme: 'lumen-light' theme: 'lumen-light'
} }


this.cliqz = new Cliqz(); this.cliqz = new Cliqz();
this.isDeveloper = prefs.get('developer', false); this.isDeveloper = prefs.get('developer', false);
this.appStart = appStart || Promise.resolve(); this.appStart = appStart || Promise.resolve();
this.init();
}


async init() {
await this.appStart;
const config = await nativeBridge.getConfig();
this.setState({
onboarding: config.onboarding,
isReady: true,
});
events.sub('search:results', this.updateResults); events.sub('search:results', this.updateResults);
events.sub('mobile-browser:notify-preferences', this.updatePreferences); events.sub('mobile-browser:notify-preferences', this.updatePreferences);
events.sub('mobile-browser:set-search-engine', this.setSearchEngine); events.sub('mobile-browser:set-search-engine', this.setSearchEngine);
@@ -138,6 +148,9 @@ class MobileCards extends React.Component {
} }


render() { render() {
if (!this.state.isReady) {
return null;
}
const { results, suggestions, meta, query } = this.state.results; const { results, suggestions, meta, query } = this.state.results;
const appearance = this.state.theme; const appearance = this.state.theme;
const layout = 'vertical'; const layout = 'vertical';

0 comments on commit e101a8f

Please sign in to comment.