1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_ 6 #define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_ 7 8 #include <memory> 9 #include <vector> 10 11 #include "base/macros.h" 12 #include "base/time/clock.h" 13 #include "base/time/time.h" 14 #include "components/ntp_snippets/category.h" 15 #include "components/ntp_snippets/category_rankers/category_ranker.h" 16 17 class PrefRegistrySimple; 18 class PrefService; 19 20 namespace ntp_snippets { 21 22 // An implementation of a CategoryRanker based on a number of clicks per 23 // category. Initial order is hardcoded, but sections with more clicks are moved 24 // to the top. The new remote categories must be registered using 25 // AppendCategoryIfNecessary. All other categories must be hardcoded in the 26 // initial order. The order and category usage data are persisted in prefs and 27 // reloaded on startup. 28 // TODO(crbug.com/675929): Remove unused categories from prefs. 29 class ClickBasedCategoryRanker : public CategoryRanker { 30 public: 31 explicit ClickBasedCategoryRanker(PrefService* pref_service, 32 base::Clock* clock); 33 ~ClickBasedCategoryRanker() override; 34 35 // CategoryRanker implementation. 36 bool Compare(Category left, Category right) const override; 37 void ClearHistory(base::Time begin, base::Time end) override; 38 void AppendCategoryIfNecessary(Category category) override; 39 void InsertCategoryBeforeIfNecessary(Category category_to_insert, 40 Category anchor) override; 41 void InsertCategoryAfterIfNecessary(Category category_to_insert, 42 Category anchor) override; 43 std::vector<CategoryRanker::DebugDataItem> GetDebugData() override; 44 void OnSuggestionOpened(Category category) override; 45 void OnCategoryDismissed(Category category) override; 46 47 // Returns time when last decay occured. For testing only. 48 base::Time GetLastDecayTime() const; 49 50 static void RegisterProfilePrefs(PrefRegistrySimple* registry); 51 52 // Returns passing margin, i.e. a number of extra clicks required to move a 53 // category upwards. For testing only. 54 static int GetPassingMargin(); 55 56 // Returns number of top categories with extra margin (i.e. with increased 57 // passing margin). For testing only. 58 static int GetNumTopCategoriesWithExtraMargin(); 59 60 // Returns number of positions by which a dismissed category is downgraded. 61 // For testing only. 62 static int GetDismissedCategoryPenalty(); 63 64 private: 65 struct RankedCategory { 66 Category category; 67 int clicks; 68 base::Time last_dismissed; 69 70 RankedCategory(Category category, 71 int clicks, 72 const base::Time& last_dismissed); 73 }; 74 75 int GetPositionPassingMargin( 76 std::vector<RankedCategory>::const_iterator category_position) const; 77 void RestoreDefaultOrder(); 78 void AppendKnownCategory(KnownCategories known_category); 79 bool ReadOrderFromPrefs(std::vector<RankedCategory>* result_categories) const; 80 void StoreOrderToPrefs(const std::vector<RankedCategory>& ordered_categories); 81 std::vector<RankedCategory>::iterator FindCategory(Category category); 82 bool ContainsCategory(Category category) const; 83 void InsertCategoryRelativeToIfNecessary(Category category_to_insert, 84 Category anchor, 85 bool after); 86 87 base::Time ReadLastDecayTimeFromPrefs() const; 88 void StoreLastDecayTimeToPrefs(base::Time last_decay_time); 89 bool IsEnoughClicksToDecay() const; 90 bool DecayClicksIfNeeded(); 91 92 std::vector<RankedCategory> ordered_categories_; 93 PrefService* pref_service_; 94 base::Clock* clock_; 95 96 DISALLOW_COPY_AND_ASSIGN(ClickBasedCategoryRanker); 97 }; 98 99 } // namespace ntp_snippets 100 101 #endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_ 102