Support to upload multiple custom images for NTP background (#15311)

* Support to upload multiple custom images for NTP background

This PR allows users to upload multiple images for NTP background.

* The maximum number of images is 24
* These images are stored in a dedicated directory.
* Users can select one of these or toggle on "Random" button.
* Users also can remove these images.
This commit is contained in:
Sangwoo Ko
2022-10-04 09:53:43 +09:00
committed by GitHub
parent 90d9dd69a6
commit 66a29937d4
32 changed files with 506 additions and 110 deletions
@@ -103,6 +103,14 @@ void CustomBackgroundFileManager::MoveImage(
MakeSureDirExists(std::move(on_check_dir));
}
void CustomBackgroundFileManager::RemoveImage(
const base::FilePath& file_path,
base::OnceCallback<void(bool /*result*/)> callback) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(base::DeleteFile, file_path), std::move(callback));
}
base::FilePath CustomBackgroundFileManager::GetCustomBackgroundDirectory()
const {
return profile_->GetPath().AppendASCII(
@@ -191,7 +199,7 @@ void CustomBackgroundFileManager::SaveImageAsPNG(
base::FilePath modified_path = target_path;
for (int i = 1; base::PathExists(modified_path); ++i) {
modified_path = target_path.InsertBeforeExtensionASCII(
base::StringPrintf("(%d)", i));
base::StringPrintf("-%d", i));
}
if (!base::WriteFile(
@@ -8,10 +8,21 @@
#include <memory>
#include <string>
#include <type_traits>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "brave/components/ntp_background_images/browser/url_constants.h"
#include "url/gurl.h"
#include "url/url_util.h"
#if defined(OS_WIN)
#include "base/strings/sys_string_conversions.h"
#endif
namespace base {
class FilePath;
@@ -32,10 +43,124 @@ class Profile;
// * Manages custom images
// * Have a list of custom images in Prefs.
// * Make it sure that we have local files mapped to entries.
// * Deregisters custom image(TODO)
// * Deregisters custom image
// * remove the local file.
class CustomBackgroundFileManager final {
public:
// |Converter| is a convience class to convert values to and from each layer.
//
// [Web UI] - GURL with percent encoded path.
// || The path value should be same with the value in PrefService
// (path)
// ||
// (value)
// ||
// [PrefService] - std::string. The value is a file name. Encoding is
// || usually UTF8, but on some platforms it might not be
// (value) specified.
// ||
// (file name)
// ||
// [File System] - base::FilePath. On Windows, it uses wide string.
// and on other platforms, uses string but encoding might
// not be specified.
//
// This class is designed to be used for a short time and then destroyed.
// Don't pass this class around code base. Use this just right where you
// need to convert values.
//
// example:
// auto file_path = Converter(url, file_manager).To<base::FilePath>();
// auto url = Converter(prefs_value).To<GURL>();
//
template <class FromT>
class Converter final {
public:
explicit Converter(const FromT& value,
CustomBackgroundFileManager* file_manager = nullptr)
: file_manager_(file_manager) {
if constexpr (std::is_same_v<FromT, std::string>) {
DCHECK(!base::StartsWith(value,
ntp_background_images::kCustomWallpaperURL))
<< "URLs should be passed in as a GURL";
value_ = value;
} else if constexpr (std::is_same_v<FromT, GURL>) {
// GURL(webui data url) -> std::string(prefs value)
// When GURL is given, its path is percent encoded pref name. So
// decode it and create Converter with it.
DCHECK(value.SchemeIs("chrome") &&
value.host() == ntp_background_images::kCustomWallpaperHost)
<< "Not a custom wallpaper URL";
// remove leading slash
const auto path = value.path().substr(1);
DCHECK(!path.empty()) << "URL path is empty " << value;
url::RawCanonOutputT<char16_t> decoded_value;
url::DecodeURLEscapeSequences(path.data(), path.length(),
url::DecodeURLMode::kUTF8OrIsomorphic,
&decoded_value);
value_ = base::UTF16ToUTF8(
std::u16string(decoded_value.data(), decoded_value.length()));
} else {
// FilePath(local file path) -> std::string(prefs value)
static_assert(std::is_same_v<FromT, base::FilePath>,
"FromT must be one of std::string, GURL, base::FilePath");
// When base::FilePath is given, its file name is used as pref value.
// But the file path's underlying type and encoding is platform
// dependent. So, extract file name and convert it to UTF8 if needed.
#if defined(OS_WIN)
auto file_name = base::SysWideToUTF8(value.BaseName().value());
#else
auto file_name = std::string(value.BaseName().value().c_str());
#endif
DCHECK(!file_name.empty())
<< "Couldn't extract file name from the given path " << value;
value_ = file_name;
}
}
Converter(const Converter&) = delete;
Converter& operator=(const Converter&) = delete;
Converter(Converter&&) noexcept = delete;
Converter& operator=(Converter&&) noexcept = delete;
~Converter() = default;
// Converter functions. Not allowing to convert to what it was created from.
template <class ToT>
[[nodiscard]] std::enable_if_t<!std::is_same_v<FromT, ToT>, ToT> To()
const&& {
if constexpr (std::is_same_v<ToT, std::string>) {
return value_;
} else if constexpr (std::is_same_v<ToT, GURL>) {
// std::string(pref_value) -> GURL(webui data url)
// Do percent encoding and compose it with base url so that it can
// be used as webui data url.
url::RawCanonOutputT<char> encoded;
url::EncodeURIComponent(value_.c_str(), value_.length(), &encoded);
return GURL(ntp_background_images::kCustomWallpaperURL +
std::string(encoded.data(), encoded.length()));
} else {
static_assert(std::is_same_v<ToT, base::FilePath>,
"ToT must be one of std::string, GURL, base::FilePath");
// std::string(pref_value) -> base::FilePath(local file path)
DCHECK(file_manager_) << "Converting to local file path requires "
"CustomBackgroundFileManager";
base::FilePath file_path =
file_manager_->GetCustomBackgroundDirectory();
#if defined(OS_WIN)
file_path = file_path.Append(base::SysUTF8ToWide(value_));
#else
file_path = file_path.Append(value_);
#endif
return file_path;
}
}
private:
raw_ptr<CustomBackgroundFileManager> file_manager_ = nullptr;
std::string value_;
};
using SaveFileCallback = base::OnceCallback<void(const base::FilePath&)>;
explicit CustomBackgroundFileManager(Profile* profile);
@@ -48,6 +173,8 @@ class CustomBackgroundFileManager final {
SaveFileCallback callback);
void MoveImage(const base::FilePath& source_file_path,
base::OnceCallback<void(bool /*result*/)> callback);
void RemoveImage(const base::FilePath& file_path,
base::OnceCallback<void(bool /*result*/)> callback);
base::FilePath GetCustomBackgroundDirectory() const;
@@ -115,7 +115,7 @@ IN_PROC_BROWSER_TEST_F(CustomBackgroundFileManagerBrowserTest,
kTestImageName);
if (i > 0) {
expected_path = expected_path.InsertBeforeExtensionASCII(
base::StringPrintf("(%d)", i));
base::StringPrintf("-%d", i));
}
auto check_res =
@@ -9,6 +9,7 @@
#include <utility>
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "brave/components/constants/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
@@ -135,6 +136,13 @@ void NTPBackgroundPrefs::AddCustomImageToList(const std::string& file_name) {
update->GetList().Append(file_name);
}
void NTPBackgroundPrefs::RemoveCustomImageFromList(
const std::string& file_name) {
ListPrefUpdate update(service_, NTPBackgroundPrefs::kCustomImageListPrefName);
auto& list = update->GetList();
list.erase(base::ranges::remove(update->GetList(), file_name), list.end());
}
std::vector<std::string> NTPBackgroundPrefs::GetCustomImageList() const {
const auto* list = service_->GetList(kCustomImageListPrefName);
std::vector<std::string> result;
@@ -85,6 +85,7 @@ class NTPBackgroundPrefs final {
absl::variant<GURL, std::string> GetSelectedValue() const;
void AddCustomImageToList(const std::string& file_name);
void RemoveCustomImageFromList(const std::string& file_name);
std::vector<std::string> GetCustomImageList() const;
private:
@@ -15,6 +15,7 @@
#include "brave/components/constants/pref_names.h"
#include "brave/components/ntp_background_images/browser/ntp_background_images_data.h"
#include "brave/components/ntp_background_images/browser/ntp_background_images_service.h"
#include "brave/components/ntp_background_images/browser/url_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -79,28 +80,20 @@ bool NTPCustomBackgroundImagesServiceDelegate::IsCustomImageBackgroundEnabled()
return NTPBackgroundPrefs(profile_->GetPrefs()).IsCustomImageType();
}
base::FilePath NTPCustomBackgroundImagesServiceDelegate::
GetCustomBackgroundImageLocalFilePath() const {
if (!IsCustomImageBackgroundEnabled())
return base::FilePath();
base::FilePath
NTPCustomBackgroundImagesServiceDelegate::GetCustomBackgroundImageLocalFilePath(
const GURL& url) const {
return CustomBackgroundFileManager::Converter(url, file_manager_.get())
.To<base::FilePath>();
}
auto value = NTPBackgroundPrefs(profile_->GetPrefs()).GetSelectedValue();
if (!absl::holds_alternative<std::string>(value)) {
// This can happen during migration.
return base::FilePath();
}
GURL NTPCustomBackgroundImagesServiceDelegate::GetCustomBackgroundImageURL()
const {
DCHECK(IsCustomImageBackgroundEnabled());
#if defined(OS_WIN)
// On Windows path is wchar type and we should convert it to utf8.
// So we suppose |value| is utf8.
const auto file_name =
base::FilePath::FromUTF8Unsafe(absl::get<std::string>(value)).value();
#else
// On other platform, path's encoding is not specified, and we store value
// as it was given.
const auto file_name = absl::get<std::string>(value);
#endif
return file_manager_->GetCustomBackgroundDirectory().Append(file_name);
auto prefs = NTPBackgroundPrefs(profile_->GetPrefs());
auto name = absl::get<std::string>(prefs.GetSelectedValue());
return CustomBackgroundFileManager::Converter(name).To<GURL>();
}
bool NTPCustomBackgroundImagesServiceDelegate::IsColorBackgroundEnabled()
@@ -40,7 +40,9 @@ class NTPCustomBackgroundImagesServiceDelegate
// NTPCustomBackgroundImagesService::Delegate overrides:
bool IsCustomImageBackgroundEnabled() const override;
base::FilePath GetCustomBackgroundImageLocalFilePath() const override;
base::FilePath GetCustomBackgroundImageLocalFilePath(
const GURL& url) const override;
GURL GetCustomBackgroundImageURL() const override;
bool IsColorBackgroundEnabled() const override;
std::string GetColor() const override;
bool ShouldUseRandomValue() const override;
@@ -6,7 +6,6 @@
#include "brave/browser/ui/webui/new_tab_page/brave_new_tab_page_handler.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/containers/span.h"
@@ -43,10 +42,6 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include "base/strings/sys_string_conversions.h"
#endif
namespace {
bool IsNTPPromotionEnabled(Profile* profile) {
@@ -85,6 +80,7 @@ BraveNewTabPageHandler::BraveNewTabPageHandler(
page_(std::move(pending_page)),
profile_(profile),
web_contents_(web_contents),
file_manager_(std::make_unique<CustomBackgroundFileManager>(profile_)),
weak_factory_(this) {
InitForSearchPromotion();
}
@@ -130,12 +126,56 @@ void BraveNewTabPageHandler::ChooseLocalCustomBackground() {
file_types.extension_description_overrides.push_back(
brave_l10n::GetLocalizedResourceUTF16String(IDS_UPLOAD_IMAGE_FORMAT));
select_file_dialog_->SelectFile(
ui::SelectFileDialog::SELECT_OPEN_FILE, std::u16string(),
ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE, std::u16string(),
profile_->last_selected_directory(), &file_types, 0,
base::FilePath::StringType(), web_contents_->GetTopLevelNativeWindow(),
nullptr);
}
void BraveNewTabPageHandler::UseCustomImageBackground(
const std::string& selected_background) {
auto decoded_background = selected_background;
if (!decoded_background.empty()) {
decoded_background =
CustomBackgroundFileManager::Converter(GURL(decoded_background))
.To<std::string>();
}
auto pref = NTPBackgroundPrefs(profile_->GetPrefs());
pref.SetType(NTPBackgroundPrefs::Type::kCustomImage);
pref.SetSelectedValue(decoded_background);
pref.SetShouldUseRandomValue(decoded_background.empty());
OnBackgroundUpdated();
}
void BraveNewTabPageHandler::GetCustomImageBackgrounds(
GetCustomImageBackgroundsCallback callback) {
std::vector<brave_new_tab_page::mojom::CustomBackgroundPtr> backgrounds;
for (const auto& name :
NTPBackgroundPrefs(profile_->GetPrefs()).GetCustomImageList()) {
auto value = brave_new_tab_page::mojom::CustomBackground::New();
value->url = CustomBackgroundFileManager::Converter(name).To<GURL>();
backgrounds.push_back(std::move(value));
}
std::move(callback).Run(std::move(backgrounds));
}
void BraveNewTabPageHandler::RemoveCustomImageBackground(
const std::string& background) {
if (background.empty())
return;
auto file_path = CustomBackgroundFileManager::Converter(GURL(background),
file_manager_.get())
.To<base::FilePath>();
file_manager_->RemoveImage(
file_path,
base::BindOnce(&BraveNewTabPageHandler::OnRemoveCustomImageBackground,
weak_factory_.GetWeakPtr(), file_path));
}
void BraveNewTabPageHandler::UseBraveBackground(
const std::string& selected_background) {
// Call ntp custom background images service.
@@ -223,11 +263,18 @@ void BraveNewTabPageHandler::OnSavedCustomImage(const base::FilePath& path) {
return;
}
#if defined(OS_WIN)
auto file_name = base::SysWideToUTF8(path.BaseName().value());
#else
auto file_name = std::string(path.BaseName().value().c_str());
#endif
if (brave_new_tab_page::mojom::kMaxCustomImageBackgrounds -
NTPBackgroundPrefs(profile_->GetPrefs())
.GetCustomImageList()
.size() <=
0) {
// We can't save more images.
file_manager_->RemoveImage(path, base::DoNothing());
return;
}
auto file_name =
CustomBackgroundFileManager::Converter(path).To<std::string>();
DCHECK(!file_name.empty());
auto background_pref = NTPBackgroundPrefs(profile_->GetPrefs());
@@ -235,16 +282,51 @@ void BraveNewTabPageHandler::OnSavedCustomImage(const base::FilePath& path) {
background_pref.SetSelectedValue(file_name);
background_pref.AddCustomImageToList(file_name);
OnBackgroundUpdated();
OnCustomImageBackgroundsUpdated();
}
void BraveNewTabPageHandler::OnRemoveCustomImageBackground(
const base::FilePath& path,
bool success) {
if (!success) {
LOG(ERROR) << "Failed to remove custom image " << path;
return;
}
auto file_name =
CustomBackgroundFileManager::Converter(path).To<std::string>();
DCHECK(!file_name.empty());
auto background_pref = NTPBackgroundPrefs(profile_->GetPrefs());
background_pref.RemoveCustomImageFromList(file_name);
if (background_pref.GetType() == NTPBackgroundPrefs::Type::kCustomImage &&
absl::get<std::string>(background_pref.GetSelectedValue()) == file_name) {
if (auto custom_images = background_pref.GetCustomImageList();
!custom_images.empty()) {
background_pref.SetSelectedValue(custom_images.front());
} else {
// Reset to default
background_pref.SetType(NTPBackgroundPrefs::Type::kBrave);
background_pref.SetSelectedValue({});
background_pref.SetShouldUseRandomValue(true);
}
OnBackgroundUpdated();
}
OnCustomImageBackgroundsUpdated();
}
void BraveNewTabPageHandler::OnBackgroundUpdated() {
if (IsCustomBackgroundImageEnabled()) {
auto value = brave_new_tab_page::mojom::CustomBackground::New();
// Add a timestamp to the url to prevent the browser from using a cached
// version when "Upload an image" is used multiple times.
std::string time_string = std::to_string(base::Time::Now().ToTimeT());
std::string local_string(ntp_background_images::kCustomWallpaperURL);
value->url = GURL(local_string + "?ts=" + time_string);
NTPBackgroundPrefs prefs(profile_->GetPrefs());
auto selected_value = prefs.GetSelectedValue();
DCHECK(absl::holds_alternative<std::string>(selected_value));
const std::string file_name = absl::get<std::string>(selected_value);
if (!file_name.empty())
value->url = CustomBackgroundFileManager::Converter(file_name).To<GURL>();
value->use_random_item = prefs.ShouldUseRandomValue();
page_->OnBackgroundUpdated(
brave_new_tab_page::mojom::Background::NewCustom(std::move(value)));
return;
@@ -305,14 +387,23 @@ void BraveNewTabPageHandler::OnBackgroundUpdated() {
brave_new_tab_page::mojom::Background::NewBrave(std::move(value)));
}
void BraveNewTabPageHandler::OnCustomImageBackgroundsUpdated() {
std::vector<brave_new_tab_page::mojom::CustomBackgroundPtr> backgrounds;
for (const auto& name :
NTPBackgroundPrefs(profile_->GetPrefs()).GetCustomImageList()) {
auto value = brave_new_tab_page::mojom::CustomBackground::New();
value->url = CustomBackgroundFileManager::Converter(name).To<GURL>();
backgrounds.push_back(std::move(value));
}
page_->OnCustomImageBackgroundsUpdated(std::move(backgrounds));
}
void BraveNewTabPageHandler::FileSelected(const base::FilePath& path,
int index,
void* params) {
profile_->set_last_selected_directory(path.DirName());
if (!file_manager_)
file_manager_ = std::make_unique<CustomBackgroundFileManager>(profile_);
file_manager_->SaveImage(
path, base::BindOnce(&BraveNewTabPageHandler::OnSavedCustomImage,
weak_factory_.GetWeakPtr()));
@@ -320,6 +411,22 @@ void BraveNewTabPageHandler::FileSelected(const base::FilePath& path,
select_file_dialog_ = nullptr;
}
void BraveNewTabPageHandler::MultiFilesSelected(
const std::vector<base::FilePath>& files,
void* params) {
NTPBackgroundPrefs prefs(profile_->GetPrefs());
auto available_image_count =
brave_new_tab_page::mojom::kMaxCustomImageBackgrounds -
prefs.GetCustomImageList().size();
for (const auto& path : files) {
if (available_image_count == 0)
break;
FileSelected(path, 0, params);
available_image_count--;
}
}
void BraveNewTabPageHandler::FileSelectionCanceled(void* params) {
select_file_dialog_ = nullptr;
}
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
@@ -51,6 +52,12 @@ class BraveNewTabPageHandler : public brave_new_tab_page::mojom::PageHandler,
private:
// brave_new_tab_page::mojom::PageHandler overrides:
void ChooseLocalCustomBackground() override;
void UseCustomImageBackground(
const std::string& selected_background) override;
void GetCustomImageBackgrounds(
GetCustomImageBackgroundsCallback callback) override;
void RemoveCustomImageBackground(const std::string& background) override;
void UseBraveBackground(const std::string& selected_background) override;
void GetBraveBackgrounds(GetBraveBackgroundsCallback callback) override;
void TryBraveSearchPromotion(const std::string& input,
@@ -63,11 +70,14 @@ class BraveNewTabPageHandler : public brave_new_tab_page::mojom::PageHandler,
// Observe NTPCustomBackgroundImagesService.
void OnBackgroundUpdated();
void OnCustomImageBackgroundsUpdated();
// SelectFileDialog::Listener overrides:
void FileSelected(const base::FilePath& path,
int index,
void* params) override;
void MultiFilesSelected(const std::vector<base::FilePath>& files,
void* params) override;
void FileSelectionCanceled(void* params) override;
// TemplateURLServiceObserver overrides:
@@ -77,6 +87,7 @@ class BraveNewTabPageHandler : public brave_new_tab_page::mojom::PageHandler,
bool IsCustomBackgroundImageEnabled() const;
bool IsColorBackgroundEnabled() const;
void OnSavedCustomImage(const base::FilePath& path);
void OnRemoveCustomImageBackground(const base::FilePath& path, bool success);
void OnSearchPromotionDismissed();
void NotifySearchPromotionDisabledIfNeeded() const;
@@ -12,7 +12,7 @@ import { Stats } from '../api/stats'
import { PrivateTabData } from '../api/privateTabData'
import { NewTabAdsData } from '../api/newTabAdsData'
import { InitialData } from '../api/initialData'
import { Background } from '../api/background'
import { Background, CustomBackground } from '../api/background'
export const statsUpdated = (stats: Stats) =>
action(types.NEW_TAB_STATS_UPDATED, {
@@ -54,5 +54,8 @@ export const customizeClicked = () => action(types.CUSTOMIZE_CLICKED, {})
export const customBackgroundUpdated = (background: Background) =>
action(types.BACKGROUND_UPDATED, { background })
export const customImageBackgroundsUpdated = (backgrounds: CustomBackground[]) =>
action(types.CUSTOM_IMAGE_BACKGROUNDS_UPDATED, backgrounds)
export const searchPromotionDisabled = () =>
action(types.SEARCH_PROMOTION_DISABLED, {})
@@ -34,10 +34,12 @@ interface API {
pageCallbackRouter: BraveNewTabPage.PageCallbackRouter
pageHandler: BraveNewTabPage.PageHandlerRemote
addBackgroundUpdatedListener: (listener: BackgroundUpdated) => void
addCustomImageBackgroundsUpdatedListener: (listener: CustomImageBackgroundsUpdated) => void
addSearchPromotionDisabledListener: (listener: () => void) => void
}
type BackgroundUpdated = (background: BraveNewTabPage.Background) => void
type CustomImageBackgroundsUpdated = (backgrounds: BraveNewTabPage.CustomBackground[]) => void
let ntpBrowserAPIInstance: API
@@ -57,6 +59,10 @@ class NTPBrowserAPI implements API {
this.pageCallbackRouter.onBackgroundUpdated.addListener(listener)
}
addCustomImageBackgroundsUpdatedListener (listener: CustomImageBackgroundsUpdated) {
this.pageCallbackRouter.onCustomImageBackgroundsUpdated.addListener(listener)
}
addSearchPromotionDisabledListener (listener: () => void) {
this.pageCallbackRouter.onSearchPromotionDisabled.addListener(listener)
}
@@ -16,6 +16,7 @@ export type InitialData = {
privateTabData: privateTabDataAPI.PrivateTabData
wallpaperData?: NewTab.Wallpaper
braveBackgrounds: NewTab.BraveBackground[]
customImageBackgrounds: NewTab.ImageBackground[]
braveRewardsSupported: boolean
braveTalkSupported: boolean
geminiSupported: boolean
@@ -58,7 +59,8 @@ export async function getInitialData (): Promise<InitialData> {
ftxSupported,
binanceSupported,
searchPromotionEnabled,
braveBackgrounds
braveBackgrounds,
customImageBackgrounds
] = await Promise.all([
preferencesAPI.getPreferences(),
statsAPI.getStats(),
@@ -101,7 +103,10 @@ export async function getInitialData (): Promise<InitialData> {
}),
getNTPBrowserAPI().pageHandler.isSearchPromotionEnabled().then(({ enabled }) => enabled),
getNTPBrowserAPI().pageHandler.getBraveBackgrounds().then(({ backgrounds }) => {
return backgrounds.map(background => { return { type: 'brave', wallpaperImageUrl: background.imageUrl.url, author: background.author, link: background.link.url } })
return backgrounds.map(background => ({ type: 'brave', wallpaperImageUrl: background.imageUrl.url, author: background.author, link: background.link.url }))
}),
getNTPBrowserAPI().pageHandler.getCustomImageBackgrounds().then(({ backgrounds }) => {
return backgrounds.map(background => ({ type: 'image', wallpaperImageUrl: background.url.url }))
})
])
console.timeStamp('Got all initial data.')
@@ -111,6 +116,7 @@ export async function getInitialData (): Promise<InitialData> {
privateTabData,
wallpaperData,
braveBackgrounds,
customImageBackgrounds,
braveRewardsSupported,
braveTalkSupported,
geminiSupported,
@@ -9,7 +9,7 @@ import * as statsAPI from './api/stats'
import * as topSitesAPI from './api/topSites'
import * as privateTabDataAPI from './api/privateTabData'
import * as newTabAdsDataAPI from './api/newTabAdsData'
import getNTPBrowserAPI, { Background } from './api/background'
import getNTPBrowserAPI, { Background, CustomBackground } from './api/background'
import { getInitialData, getRewardsInitialData, getRewardsPreInitialData } from './api/initialData'
import * as backgroundData from './data/backgrounds'
@@ -44,6 +44,10 @@ async function onBackgroundUpdated (background: Background) {
getActions().customBackgroundUpdated(background)
}
async function onCustomImageBackgroundsUpdated (backgrounds: CustomBackground[]) {
getActions().customImageBackgroundsUpdated(backgrounds)
}
// Not marked as async so we don't return a promise
// and confuse callers
export function wireApiEventsToStore () {
@@ -65,6 +69,7 @@ export function wireApiEventsToStore () {
backgroundData.updateImages(initialData.braveBackgrounds)
getNTPBrowserAPI().addBackgroundUpdatedListener(onBackgroundUpdated)
getNTPBrowserAPI().addCustomImageBackgroundsUpdatedListener(onCustomImageBackgroundsUpdated)
getNTPBrowserAPI().addSearchPromotionDisabledListener(() => getActions().searchPromotionDisabled())
})
.catch(e => {
@@ -10,6 +10,8 @@ import "url/mojom/url.mojom";
const string kRandomSolidColorValue = "solid";
const string kRandomGradientColorValue = "gradient";
const int8 kMaxCustomImageBackgrounds = 24;
struct BraveBackground {
string name;
string author;
@@ -48,6 +50,10 @@ interface PageHandlerFactory {
interface PageHandler {
// Choose custom background from local file system.
ChooseLocalCustomBackground();
// When |selectedBackground| is empty, should use random background.
UseCustomImageBackground(string selectedBackground);
GetCustomImageBackgrounds() => (array<CustomBackground> backgrounds);
RemoveCustomImageBackground(string selectedBackground);
// When |seleteceBackground| is empty, should use random background.
UseBraveBackground(string selected_background);
@@ -60,7 +66,6 @@ interface PageHandler {
// |use_random_color| is true
UseColorBackground(string color, bool use_random_color);
TryBraveSearchPromotion(string input, bool open_new_tab);
DismissBraveSearchPromotion();
IsSearchPromotionEnabled() => (bool enabled);
@@ -70,5 +75,7 @@ interface PageHandler {
interface Page {
OnBackgroundUpdated(Background? background);
OnCustomImageBackgroundsUpdated(array<CustomBackground> backgrounds);
OnSearchPromotionDisabled();
};
@@ -321,7 +321,7 @@ function getPageBackground (p: HasImageProps) {
rgba(0, 0, 0, 0) 35%,
rgba(0, 0, 0, 0) 80%,
rgba(0, 0, 0, 0.6) 100%
), url(${p.imageSrc});
), url("${p.imageSrc}");
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
@@ -120,7 +120,7 @@ export const SettingsSidebarSVGContent = styled('div')<SettingsSidebarSVGContent
/* Active version (hidden until item is active).
This is a separate element so that we can:
1. fade it in (no transition for background gradient) */
&:after {
&::after {
position: absolute;
display: block;
content: '';
@@ -169,7 +169,7 @@ export const SettingsSidebarButtonText = styled('span')<{ isActive: boolean }>`
1. fade it in (no transition for background gradient)
2. still show ellipsis for overflowing text (which doesn't show for
background-clip: text) */
&:after {
&::after {
content: attr(data-text);
position: absolute;
opacity: var(--active-opacity, 0);
@@ -600,6 +600,7 @@ export const StyledCustomBackgroundOption = styled('button')<{}>`
interface SelectionProps {
selected: boolean
removable?: boolean
}
interface ColoredBackgroundProps {
@@ -620,15 +621,18 @@ export const StyledSelectionBorder = styled('div')<SelectionProps>`
: 'linear-gradient(122.53deg, #4C54D2 0%, #BF14A2 56.25%, #F73A1C 100%)'};
padding: 2px;
border-radius: 10px;
&:after {
&::after {
content: url(${CheckedCircle});
position:absolute;
top: 10px;
right: 10px;
}
`}
`
${p => p.removable && css`
&:hover::after { display: none; }
`}
`
export const StyledUploadIconContainer = styled('div')<SelectionProps>`
display: flex;
flex-direction: column;
@@ -657,7 +661,7 @@ export const StyledCustomBackgroundOptionImage = styled('div')<SelectionProps &
${p => p.selected
? css`border-radius: 8px;`
: css`border-radius: 10px;`}
background-image: url(${p => p.image});
background-image: url("${p => p.image}");
`
export const StyledCustomBackgroundOptionColor = styled('div')<SelectionProps & ColoredBackgroundProps>`
@@ -23,7 +23,8 @@ export const enum types {
SET_MOST_VISITED_SITES = '@@newtab/SET_MOST_VISITED_SITES',
TOP_SITES_STATE_UPDATED = '@@newtab/TOP_SITES_STATE_UPDATED',
CUSTOMIZE_CLICKED = '@@newtab/CUSTOMIZE_CLICKED',
BACKGROUND_UPDATED = '@@newtab/CUSTOM_BACKGROUND_UPDATED',
BACKGROUND_UPDATED = '@@newtab/_BACKGROUND_UPDATED',
CUSTOM_IMAGE_BACKGROUNDS_UPDATED = '@@newtab/CUSTOM_IMAGE_BACKGROUNDS_UPDATED',
SEARCH_PROMOTION_DISABLED = '@@newtab/SEARCH_PROMOTION_DISABLED',
}
@@ -66,7 +66,9 @@ function DefaultPage (props: Props) {
saveBrandedWallpaperOptIn={PreferencesAPI.saveBrandedWallpaperOptIn}
saveSetAllStackWidgets={PreferencesAPI.saveSetAllStackWidgets}
getBraveNewsDisplayAd={getBraveNewsDisplayAd}
useCustomBackgroundImage={() => getNTPBrowserAPI().pageHandler.chooseLocalCustomBackground() }
chooseNewCustomBackgroundImage={() => getNTPBrowserAPI().pageHandler.chooseLocalCustomBackground() }
setCustomImageBackground={background => getNTPBrowserAPI().pageHandler.useCustomImageBackground(background) }
removeCustomImageBackground={background => getNTPBrowserAPI().pageHandler.removeCustomImageBackground(background) }
setBraveBackground={selectedBackground => getNTPBrowserAPI().pageHandler.useBraveBackground(selectedBackground)}
setColorBackground={(color, useRandomColor) => getNTPBrowserAPI().pageHandler.useColorBackground(color, useRandomColor) }
/>
@@ -75,7 +75,9 @@ interface Props {
saveShowFTX: (value: boolean) => void
saveBrandedWallpaperOptIn: (value: boolean) => void
saveSetAllStackWidgets: (value: boolean) => void
useCustomBackgroundImage: () => void
chooseNewCustomBackgroundImage: () => void
setCustomImageBackground: (selectedBackground: string) => void
removeCustomImageBackground: (background: string) => void
setBraveBackground: (selectedBackground: string) => void
setColorBackground: (color: string, useRandomColor: boolean) => void
}
@@ -1307,7 +1309,9 @@ class NewTabPage extends React.Component<Props, State> {
toggleShowTopSites={this.toggleShowTopSites}
setMostVisitedSettings={this.setMostVisitedSettings}
toggleBrandedWallpaperOptIn={this.toggleShowBrandedWallpaper}
useCustomBackgroundImage={this.props.useCustomBackgroundImage}
chooseNewCustomImageBackground={this.props.chooseNewCustomBackgroundImage}
setCustomImageBackground={this.props.setCustomImageBackground}
removeCustomImageBackground={this.props.removeCustomImageBackground}
setBraveBackground={this.props.setBraveBackground}
setColorBackground={this.props.setColorBackground}
showBackgroundImage={newTabData.showBackgroundImage}
@@ -66,7 +66,9 @@ export interface Props {
toggleShowFTX: () => void
toggleBrandedWallpaperOptIn: () => void
toggleCards: (show: boolean) => void
useCustomBackgroundImage: () => void
chooseNewCustomImageBackground: () => void
setCustomImageBackground: (selectedBackground: string) => void
removeCustomImageBackground: (background: string) => void
setBraveBackground: (selectedBackground: string) => void
setColorBackground: (color: string, useRandomColor: boolean) => void
onEnableRewards: () => void
@@ -184,10 +186,6 @@ export default class Settings extends React.PureComponent<Props, State> {
this.props.toggleShowBackgroundImage()
}
useCustomBackgroundImage = () => {
this.props.useCustomBackgroundImage()
}
setBraveBackground = (selectedBackground: string) => {
this.props.setBraveBackground(selectedBackground)
}
@@ -354,7 +352,9 @@ export default class Settings extends React.PureComponent<Props, State> {
newTabData={this.props.newTabData}
toggleBrandedWallpaperOptIn={toggleBrandedWallpaperOptIn}
toggleShowBackgroundImage={this.toggleShowBackgroundImage}
useCustomBackgroundImage={this.useCustomBackgroundImage}
chooseNewCustomImageBackground={this.props.chooseNewCustomImageBackground}
setCustomImageBackground={this.props.setCustomImageBackground}
removeCustomImageBackground={this.props.removeCustomImageBackground}
setBraveBackground={this.setBraveBackground}
setColorBackground={this.setColorBackground}
brandedWallpaperOptIn={brandedWallpaperOptIn}
@@ -21,12 +21,14 @@ interface Props {
backgrounds: NewTab.BackgroundWallpaper[]
currentValue?: string
usingRandomColor: boolean
renderExtraButton?: () => JSX.Element
onSelectValue: (background: string, useRandomColor: boolean) => void
onBack: () => void
onToggleRandomColor: (on: boolean) => void
onRemoveValue?: (background: string) => void
}
function BackgroundChooser ({ title, backgrounds, onBack, onSelectValue, currentValue, usingRandomColor, onToggleRandomColor }: Props) {
function BackgroundChooser ({ title, backgrounds, onBack, onSelectValue, currentValue, usingRandomColor, onToggleRandomColor, renderExtraButton, onRemoveValue }: Props) {
const containerEl = React.useRef<HTMLDivElement>(null)
React.useEffect(() => {
containerEl.current?.scrollIntoView(true)
@@ -45,8 +47,12 @@ function BackgroundChooser ({ title, backgrounds, onBack, onSelectValue, current
<StyledCustomBackgroundSettings>
{backgrounds.map((background) => {
const value = background.type === 'color' ? background.wallpaperColor : background.wallpaperImageUrl
return <BackgroundOption key={value} background={background} onSelectValue={color => onSelectValue(value, /* useRandomColor= */false)} selected={!usingRandomColor && currentValue === value} />
return <BackgroundOption key={value} background={background}
selected={!usingRandomColor && currentValue === value}
onSelectValue={() => onSelectValue(value, /* useRandomColor= */false)}
onRemoveValue={onRemoveValue ? () => { onRemoveValue(value) } : undefined} />
})}
{ renderExtraButton?.() }
</StyledCustomBackgroundSettings>
</div>
)
@@ -27,11 +27,15 @@ import BackgroundChooser from './backgroundChooser'
import { images, defaultSolidBackgroundColor, solidColorsForBackground, gradientColorsForBackground, defaultGradientColor } from '../../../data/backgrounds'
import SponsoredImageToggle from './sponsoredImagesToggle'
import { RANDOM_SOLID_COLOR_VALUE, RANDOM_GRADIENT_COLOR_VALUE, MAX_CUSTOM_IMAGE_BACKGROUNDS } from 'gen/brave/components/brave_new_tab_ui/brave_new_tab_page.mojom.m.js'
interface Props {
newTabData: NewTab.State
toggleBrandedWallpaperOptIn: () => void
toggleShowBackgroundImage: () => void
useCustomBackgroundImage: () => void
chooseNewCustomImageBackground: () => void
setCustomImageBackground: (selectedBackground: string) => void
removeCustomImageBackground: (background: string) => void
setBraveBackground: (selectedBackground: string) => void
setColorBackground: (color: string, useRandomColor: boolean) => void
brandedWallpaperOptIn: boolean
@@ -42,6 +46,7 @@ interface Props {
enum Location {
LIST,
CUSTOM_IMAGES,
BRAVE_BACKGROUNDS,
SOLID_COLORS,
GRADIENT_COLORS
@@ -64,7 +69,11 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
}
onClickCustomBackground = () => {
this.props.useCustomBackgroundImage()
if (this.props.newTabData.customImageBackgrounds?.length) {
this.setState({ location: Location.CUSTOM_IMAGES })
} else {
this.props.chooseNewCustomImageBackground()
}
}
onClickBraveBackground = () => {
@@ -79,6 +88,26 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
this.setState({ location: Location.GRADIENT_COLORS })
}
renderUploadButton = (onClick: () => void, checked: boolean, showTitle: boolean) => {
return (
<StyledCustomBackgroundOption onClick={onClick}>
<StyledSelectionBorder selected={checked}>
<StyledUploadIconContainer selected={checked}>
<UploadIcon />
<StyledUploadLabel>
{getLocale('customBackgroundImageOptionUploadLabel')}
</StyledUploadLabel>
</StyledUploadIconContainer>
</StyledSelectionBorder>
{showTitle && (
<StyledCustomBackgroundOptionLabel>
{getLocale('customBackgroundImageOptionTitle')}
</StyledCustomBackgroundOptionLabel>
)}
</StyledCustomBackgroundOption>
)
}
render () {
const {
newTabData,
@@ -100,6 +129,9 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
const usingRandomBraveBackground = newTabData.backgroundWallpaper?.type === 'brave' && !!newTabData.backgroundWallpaper.random
const selectedBraveBackground = newTabData.backgroundWallpaper?.type === 'brave' ? newTabData.backgroundWallpaper.wallpaperImageUrl : undefined
const usingRandomCustomImageBackground = newTabData.backgroundWallpaper?.type === 'image' && !!newTabData.backgroundWallpaper.random
const selectedCustomImageBackground = newTabData.backgroundWallpaper?.type === 'image' ? newTabData.backgroundWallpaper.wallpaperImageUrl : undefined
return (
<>
{this.state.location === Location.LIST && (
@@ -114,21 +146,7 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
</SettingsRow>
{showBackgroundImage && featureCustomBackgroundEnabled && (
<StyledCustomBackgroundSettings>
<StyledCustomBackgroundOption
onClick={this.onClickCustomBackground}
>
<StyledSelectionBorder selected={usingCustomImageBackground}>
<StyledUploadIconContainer selected={usingCustomImageBackground}>
<UploadIcon />
<StyledUploadLabel>
{getLocale('customBackgroundImageOptionUploadLabel')}
</StyledUploadLabel>
</StyledUploadIconContainer>
</StyledSelectionBorder>
<StyledCustomBackgroundOptionLabel>
{getLocale('customBackgroundImageOptionTitle')}
</StyledCustomBackgroundOptionLabel>
</StyledCustomBackgroundOption>
{this.renderUploadButton(this.onClickCustomBackground, usingCustomImageBackground, /* showTitle= */ true)}
<StyledCustomBackgroundOption
onClick={this.onClickBraveBackground}
>
@@ -197,7 +215,7 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
backgrounds={solidColorsForBackground}
currentValue={selectedBackgroundColor}
usingRandomColor={usingSolidColorBackground && usingRandomColor}
onToggleRandomColor={on => this.props.setColorBackground(on ? 'solid' : (selectedBackgroundColor ?? defaultSolidBackgroundColor), on)}
onToggleRandomColor={on => this.props.setColorBackground(on ? RANDOM_SOLID_COLOR_VALUE : (selectedBackgroundColor ?? defaultSolidBackgroundColor), on)}
onSelectValue={this.props.setColorBackground}
onBack={() => this.setLocation(Location.LIST)}
/>
@@ -208,11 +226,26 @@ class BackgroundImageSettings extends React.PureComponent<Props, State> {
backgrounds={gradientColorsForBackground}
currentValue={selectedBackgroundColor}
usingRandomColor={usingGradientBackground && usingRandomColor}
onToggleRandomColor={on => this.props.setColorBackground(on ? 'gradient' : (selectedBackgroundColor ?? defaultGradientColor), on)}
onToggleRandomColor={on => this.props.setColorBackground(on ? RANDOM_GRADIENT_COLOR_VALUE : (selectedBackgroundColor ?? defaultGradientColor), on)}
onSelectValue={this.props.setColorBackground}
onBack={() => this.setLocation(Location.LIST)}
/>
}
{this.state.location === Location.CUSTOM_IMAGES &&
<BackgroundChooser
title={getLocale('customBackgroundImageOptionTitle')}
backgrounds={this.props.newTabData.customImageBackgrounds}
currentValue={selectedCustomImageBackground}
usingRandomColor={usingRandomCustomImageBackground}
onToggleRandomColor={on => this.props.setCustomImageBackground(on ? '' : this.props.newTabData.customImageBackgrounds[0].wallpaperImageUrl)}
onSelectValue={this.props.setCustomImageBackground}
onBack={() => this.setLocation(Location.LIST)}
renderExtraButton={ this.props.newTabData.customImageBackgrounds?.length < MAX_CUSTOM_IMAGE_BACKGROUNDS
? () => this.renderUploadButton(this.props.chooseNewCustomImageBackground, /* checked= */false, /* showTitle= */ false)
: undefined}
onRemoveValue={this.props.removeCustomImageBackground}
/>
}
</>
)
}
@@ -4,6 +4,7 @@
// you can obtain one at http://mozilla.org/MPL/2.0/.
import * as React from 'react'
import styled from 'styled-components'
import {
StyledCustomBackgroundOption,
@@ -12,16 +13,44 @@ import {
StyledSelectionBorder
} from '../../../components/default'
import { CloseCircleIcon } from 'brave-ui/components/icons'
interface Props {
background: NewTab.BackgroundWallpaper
selected: boolean
onSelectValue: (value: NewTab.BackgroundWallpaper) => void
onRemoveValue?: (value: NewTab.BackgroundWallpaper) => void
}
export default function BackgroundOption ({ background, selected, onSelectValue }: Props) {
const StyledRemoveButton = styled.div<{hovered: boolean}>`
position: absolute;
top: 10px;
right: 10px;
width: 40px;
height: 40px;
border: unset;
background: transparent;
color: white;
visibility: ${p => p.hovered ? 'visible' : 'hidden'};
& svg {
border-radius: 20px;
filter: drop-shadow( 0 0 5px rgba(0, 0, 0, .7));
}
`
export default function BackgroundOption ({ background, selected, onSelectValue, onRemoveValue }: Props) {
const [hovered, setHovered] = React.useState(false)
return (
<StyledCustomBackgroundOption onClick={_ => onSelectValue(background)}>
<StyledSelectionBorder selected={selected}>
<StyledCustomBackgroundOption onClick={_ => onSelectValue(background) } onMouseOver={() => setHovered(true)} onMouseLeave={() => setHovered(false)}>
<StyledSelectionBorder selected={selected} removable={!!onRemoveValue}>
{ onRemoveValue &&
<StyledRemoveButton hovered={hovered} onClick={(e) => {
onRemoveValue(background)
e.stopPropagation()
}}>
<CloseCircleIcon />
</StyledRemoveButton>
}
{
background.type === 'color'
? <StyledCustomBackgroundOptionColor colorValue={background.wallpaperColor} selected={selected}/>
@@ -22,7 +22,7 @@ import { setMostVisitedSettings } from '../api/topSites'
// Utils
import { handleWidgetPrefsChange } from './stack_widget_reducer'
import { NewTabAdsData } from '../api/newTabAdsData'
import { Background } from '../api/background'
import { Background, CustomBackground } from '../api/background'
let sideEffectState: NewTab.State = storage.load()
@@ -54,13 +54,19 @@ export const newTabReducer: Reducer<NewTab.State | undefined> = (state: NewTab.S
// Auto-dismiss of together prompt only
// takes effect on the next page view and not the
// page view that the action occurred on.
braveTalkPromptDismissed: state.braveTalkPromptDismissed || state.braveTalkPromptAutoDismissed
braveTalkPromptDismissed: state.braveTalkPromptDismissed || state.braveTalkPromptAutoDismissed,
customImageBackgrounds: initialDataPayload.customImageBackgrounds
}
if (initialDataPayload.wallpaperData) {
let backgroundWallpaper = initialDataPayload.wallpaperData.backgroundWallpaper
if (backgroundWallpaper?.type === 'color' && backgroundWallpaper.random) {
backgroundWallpaper = backgroundAPI.randomColorBackground(backgroundWallpaper.wallpaperColor)
} else if (backgroundWallpaper?.type === 'image' && backgroundWallpaper.random) {
const customBackgrounds = state.customImageBackgrounds
if (customBackgrounds.length) {
backgroundWallpaper = { ...customBackgrounds[Math.floor(Math.random() * customBackgrounds.length)], random: true }
}
}
state = {
@@ -133,10 +139,17 @@ export const newTabReducer: Reducer<NewTab.State | undefined> = (state: NewTab.S
const url = background.custom.url.url
const color = background.custom.color
const random = background.custom.useRandomItem
if (url) {
state.backgroundWallpaper = { type: 'image', wallpaperImageUrl: url }
} else if (color) {
if (color) {
state.backgroundWallpaper = random ? backgroundAPI.randomColorBackground(color) : { type: 'color', wallpaperColor: color, random }
} else if (url) {
// Custom Image was specified
state.backgroundWallpaper = { type: 'image', wallpaperImageUrl: url }
} else if (random) {
// Random custom image should be used.
const customBackgrounds = state.customImageBackgrounds
if (customBackgrounds.length) {
state.backgroundWallpaper = { ...customBackgrounds[Math.floor(Math.random() * customBackgrounds.length)], random: true }
}
}
}
@@ -155,6 +168,14 @@ export const newTabReducer: Reducer<NewTab.State | undefined> = (state: NewTab.S
}
break
case types.CUSTOM_IMAGE_BACKGROUNDS_UPDATED:
const customBackgrounds = payload as CustomBackground[]
state = {
...state,
customImageBackgrounds: customBackgrounds.map(background => ({ type: 'image', wallpaperImageUrl: background.url.url }))
}
break
case types.NEW_TAB_PRIVATE_TAB_DATA_UPDATED:
const privateTabData = payload as PrivateTabData
state = {
@@ -145,7 +145,8 @@ export const defaultState: NewTab.State = {
},
ftxState: {
optedIntoMarkets: false
}
},
customImageBackgrounds: []
}
if (chrome.extension.inIncognitoContext) {
@@ -58,7 +58,7 @@ updateImages(images.map((image): NewTab.BraveBackground => {
}))
export const Regular = () => {
const doNothing = (value: boolean) => value
const doNothing = (value?: any) => value
const state = store.getState()
const newTabData = useNewTabData(state.newTabData)
const gridSitesData = getGridSitesData(state.gridSitesData)
@@ -84,7 +84,9 @@ export const Regular = () => {
saveSetAllStackWidgets={doNothing}
getBraveNewsDisplayAd={getBraveNewsDisplayAd}
setBraveBackground={onUseBraveBackground}
useCustomBackgroundImage={() => {}}
chooseNewCustomBackgroundImage={doNothing}
setCustomImageBackground={doNothing}
removeCustomImageBackground={doNothing}
setColorBackground={onChangeColoredBackground}
/>
)
+3 -1
View File
@@ -15,6 +15,7 @@ declare namespace NewTab {
export type ImageBackground = {
type: 'image'
wallpaperImageUrl: string
random?: boolean
}
export type BraveBackground = Omit<ImageBackground, 'type'> & {
@@ -157,7 +158,6 @@ declare namespace NewTab {
torInitProgress: string,
isTor: boolean
isQwant: boolean
backgroundWallpaper?: BackgroundWallpaper
gridLayoutSize?: 'small'
showGridSiteRemovedNotification?: boolean
showBackgroundImage: boolean
@@ -167,6 +167,8 @@ declare namespace NewTab {
stats: Stats,
braveTalkPromptAllowed: boolean
brandedWallpaper?: BrandedWallpaper
backgroundWallpaper?: BackgroundWallpaper
customImageBackgrounds: ImageBackground[]
}
export interface RewardsWidgetState {
@@ -48,9 +48,10 @@ base::Value::Dict NTPCustomBackgroundImagesService::GetBackground() const {
base::Value::Dict data;
data.Set(kIsBackgroundKey, true);
if (delegate_->IsCustomImageBackgroundEnabled()) {
data.Set(kWallpaperImageURLKey, kCustomWallpaperURL);
data.Set(kWallpaperImageURLKey,
delegate_->GetCustomBackgroundImageURL().spec());
data.Set(kWallpaperTypeKey, "image");
data.Set(kWallpaperRandomKey, false);
data.Set(kWallpaperRandomKey, delegate_->ShouldUseRandomValue());
} else if (delegate_->IsColorBackgroundEnabled()) {
data.Set(kWallpaperColorKey, delegate_->GetColor());
data.Set(kWallpaperTypeKey, "color");
@@ -59,8 +60,9 @@ base::Value::Dict NTPCustomBackgroundImagesService::GetBackground() const {
return data;
}
base::FilePath NTPCustomBackgroundImagesService::GetImageFilePath() {
return delegate_->GetCustomBackgroundImageLocalFilePath();
base::FilePath NTPCustomBackgroundImagesService::GetImageFilePath(
const GURL& url) {
return delegate_->GetCustomBackgroundImageLocalFilePath(url);
}
void NTPCustomBackgroundImagesService::Shutdown() {
@@ -28,7 +28,9 @@ class NTPCustomBackgroundImagesService : public KeyedService {
class Delegate {
public:
virtual bool IsCustomImageBackgroundEnabled() const = 0;
virtual base::FilePath GetCustomBackgroundImageLocalFilePath() const = 0;
virtual base::FilePath GetCustomBackgroundImageLocalFilePath(
const GURL& url) const = 0;
virtual GURL GetCustomBackgroundImageURL() const = 0;
virtual bool IsColorBackgroundEnabled() const = 0;
virtual std::string GetColor() const = 0;
@@ -50,7 +52,7 @@ class NTPCustomBackgroundImagesService : public KeyedService {
bool ShouldShowCustomBackground() const;
base::Value::Dict GetBackground() const;
base::FilePath GetImageFilePath();
base::FilePath GetImageFilePath(const GURL& url);
private:
// KeyedService overrides:
@@ -48,7 +48,7 @@ void NTPCustomImagesSource::StartDataRequest(
const content::WebContents::Getter& wc_getter,
GotDataCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
GetImageFile(service_->GetImageFilePath(), std::move(callback));
GetImageFile(service_->GetImageFilePath(url), std::move(callback));
}
std::string NTPCustomImagesSource::GetMimeType(const GURL& url) {
@@ -10,13 +10,11 @@ namespace ntp_background_images {
constexpr char kBackgroundWallpaperHost[] = "background-wallpaper";
constexpr char kBrandedWallpaperHost[] = "branded-wallpaper";
constexpr char kCustomWallpaperHost[] = "custom-wallpaper";
constexpr char kSuperReferralPath[] = "super-referral/";
constexpr char kSponsoredImagesPath[] = "sponsored-images/";
constexpr char kCustomWallpaperFileName[] = "background.jpg";
constexpr char kCustomWallpaperURL[] =
"chrome://custom-wallpaper/background.jpg";
constexpr char kCustomWallpaperHost[] = "custom-wallpaper";
constexpr char kCustomWallpaperURL[] = "chrome://custom-wallpaper/";
constexpr char kCampaignsKey[] = "campaigns";
@@ -122,9 +122,13 @@ class TestDelegate : public NTPCustomBackgroundImagesService::Delegate {
bool IsCustomImageBackgroundEnabled() const override {
return image_enabled_;
}
base::FilePath GetCustomBackgroundImageLocalFilePath() const override {
base::FilePath GetCustomBackgroundImageLocalFilePath(
const GURL& url) const override {
return base::FilePath();
}
GURL GetCustomBackgroundImageURL() const override {
return GURL(std::string(kCustomWallpaperURL) + "foo.jpg");
}
bool IsColorBackgroundEnabled() const override { return color_enabled_; }
std::string GetColor() const override { return "#ff0000"; }
@@ -412,7 +416,8 @@ TEST_F(NTPBackgroundImagesViewCounterTest, GetCurrentWallpaperTest) {
delegate_->image_enabled_ = true;
background = view_counter_->GetCurrentWallpaper();
bg_url = background->FindString(kWallpaperImageURLKey);
EXPECT_EQ("chrome://custom-wallpaper/background.jpg", *bg_url);
EXPECT_TRUE(base::StartsWith(*bg_url, kCustomWallpaperURL))
<< "actual url " << *bg_url;
// Disable custom image background.
delegate_->image_enabled_ = false;