blob: c112534ae49e2fced9a6a307ee2cbe2534771c1e [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
#define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
#include <memory>
#include <vector>
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
class PrefRegistrySimple;
class PrefService;
namespace ntp_snippets {
// An implementation of a CategoryRanker based on a number of clicks per
// category. Initial order is hardcoded, but sections with more clicks are moved
// to the top. The new remote categories must be registered using
// AppendCategoryIfNecessary. All other categories must be hardcoded in the
// initial order. The order and category usage data are persisted in prefs and
// reloaded on startup.
// TODO(crbug.com/675929): Remove unused categories from prefs.
class ClickBasedCategoryRanker : public CategoryRanker {
public:
explicit ClickBasedCategoryRanker(PrefService* pref_service,
base::Clock* clock);
~ClickBasedCategoryRanker() override;
// CategoryRanker implementation.
bool Compare(Category left, Category right) const override;
void ClearHistory(base::Time begin, base::Time end) override;
void AppendCategoryIfNecessary(Category category) override;
void InsertCategoryBeforeIfNecessary(Category category_to_insert,
Category anchor) override;
void InsertCategoryAfterIfNecessary(Category category_to_insert,
Category anchor) override;
std::vector<CategoryRanker::DebugDataItem> GetDebugData() override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
// Returns time when last decay occured. For testing only.
base::Time GetLastDecayTime() const;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// Returns passing margin, i.e. a number of extra clicks required to move a
// category upwards. For testing only.
static int GetPassingMargin();
// Returns number of top categories with extra margin (i.e. with increased
// passing margin). For testing only.
static int GetNumTopCategoriesWithExtraMargin();
// Returns number of positions by which a dismissed category is downgraded.
// For testing only.
static int GetDismissedCategoryPenalty();
private:
struct RankedCategory {
Category category;
int clicks;
base::Time last_dismissed;
RankedCategory(Category category,
int clicks,
const base::Time& last_dismissed);
};
int GetPositionPassingMargin(
std::vector<RankedCategory>::const_iterator category_position) const;
void RestoreDefaultOrder();
void AppendKnownCategory(KnownCategories known_category);
bool ReadOrderFromPrefs(std::vector<RankedCategory>* result_categories) const;
void StoreOrderToPrefs(const std::vector<RankedCategory>& ordered_categories);
std::vector<RankedCategory>::iterator FindCategory(Category category);
bool ContainsCategory(Category category) const;
void InsertCategoryRelativeToIfNecessary(Category category_to_insert,
Category anchor,
bool after);
base::Time ReadLastDecayTimeFromPrefs() const;
void StoreLastDecayTimeToPrefs(base::Time last_decay_time);
bool IsEnoughClicksToDecay() const;
bool DecayClicksIfNeeded();
std::vector<RankedCategory> ordered_categories_;
PrefService* pref_service_;
base::Clock* clock_;
DISALLOW_COPY_AND_ASSIGN(ClickBasedCategoryRanker);
};
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_