diff --git a/browser/brave_rewards/tip_dialog.cc b/browser/brave_rewards/tip_dialog.cc index 91c1397e5376..82d31db0670d 100644 --- a/browser/brave_rewards/tip_dialog.cc +++ b/browser/brave_rewards/tip_dialog.cc @@ -7,12 +7,13 @@ #include #include +#include #include -#include "base/values.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/strings/utf_string_conversions.h" +#include "base/values.h" #include "brave/common/webui_url_constants.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -37,7 +38,7 @@ constexpr int kDialogMaxHeight = 700; class TipDialogDelegate : public ui::WebDialogDelegate { public: explicit TipDialogDelegate(WebContents* initiator, - std::string publisher_key); + std::unique_ptr params); ~TipDialogDelegate() override; ui::ModalType GetDialogModalType() const override; @@ -53,15 +54,14 @@ class TipDialogDelegate : public ui::WebDialogDelegate { private: WebContents* initiator_; - const std::string publisher_key_; + std::unique_ptr params_; DISALLOW_COPY_AND_ASSIGN(TipDialogDelegate); }; TipDialogDelegate::TipDialogDelegate(WebContents* initiator, - std::string publisher_key) - : initiator_(initiator), - publisher_key_(publisher_key) { + std::unique_ptr params) + : initiator_(initiator), params_(std::move(params)) { } TipDialogDelegate::~TipDialogDelegate() { @@ -111,11 +111,9 @@ void TipDialogDelegate::GetDialogSize(gfx::Size* size) const { } std::string TipDialogDelegate::GetDialogArgs() const { - std::string data; - base::DictionaryValue dialog_args; - dialog_args.SetString("publisherKey", publisher_key_); - base::JSONWriter::Write(dialog_args, &data); - return data; + std::string json; + base::JSONWriter::Write(*params_, &json); + return json; } void TipDialogDelegate::OnDialogClosed( @@ -136,7 +134,7 @@ bool TipDialogDelegate::ShouldShowDialogTitle() const { namespace brave_rewards { void OpenTipDialog(WebContents* initiator, - const std::string& publisher_key) { + std::unique_ptr params) { content::WebContents* outermost_web_contents = guest_view::GuestViewBase::GetTopLevelWebContents(initiator); gfx::Size host_size = outermost_web_contents->GetContainerBounds().size(); @@ -147,7 +145,7 @@ void OpenTipDialog(WebContents* initiator, // resize) ShowConstrainedWebDialogWithAutoResize( initiator->GetBrowserContext(), - std::make_unique(initiator, publisher_key), + std::make_unique(initiator, std::move(params)), initiator, min_size, max_size); } diff --git a/browser/brave_rewards/tip_dialog.h b/browser/brave_rewards/tip_dialog.h index 324691fc39a7..facd4843a3e7 100644 --- a/browser/brave_rewards/tip_dialog.h +++ b/browser/brave_rewards/tip_dialog.h @@ -6,8 +6,13 @@ #ifndef BRAVE_BROWSER_BRAVE_REWARDS_TIP_DIALOG_H_ #define BRAVE_BROWSER_BRAVE_REWARDS_TIP_DIALOG_H_ +#include #include +namespace base { +class DictionaryValue; +} + namespace content { class WebContents; } @@ -15,7 +20,7 @@ class WebContents; namespace brave_rewards { void OpenTipDialog(content::WebContents* initiator, - const std::string& publisher_key); + std::unique_ptr params); } diff --git a/browser/extensions/api/brave_rewards_api.cc b/browser/extensions/api/brave_rewards_api.cc index 94fb60aeee3e..f1273c9774aa 100644 --- a/browser/extensions/api/brave_rewards_api.cc +++ b/browser/extensions/api/brave_rewards_api.cc @@ -5,6 +5,7 @@ #include "brave/browser/extensions/api/brave_rewards_api.h" +#include #include #include #include @@ -13,19 +14,19 @@ #include "base/strings/string_number_conversions.h" #include "brave/browser/brave_rewards/tip_dialog.h" #include "brave/common/extensions/api/brave_rewards.h" -#include "brave/components/brave_rewards/browser/rewards_service.h" -#include "brave/components/brave_rewards/browser/rewards_service_factory.h" #include "brave/components/brave_ads/browser/ads_service.h" #include "brave/components/brave_ads/browser/ads_service_factory.h" -#include "content/public/browser/web_contents.h" +#include "brave/components/brave_rewards/browser/rewards_service.h" +#include "brave/components/brave_rewards/browser/rewards_service_factory.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" +#include "content/public/browser/web_contents.h" -using brave_rewards::RewardsService; -using brave_rewards::RewardsServiceFactory; using brave_ads::AdsService; using brave_ads::AdsServiceFactory; +using brave_rewards::RewardsService; +using brave_rewards::RewardsServiceFactory; namespace extensions { namespace api { @@ -62,7 +63,7 @@ ExtensionFunction::ResponseAction BraveRewardsTipSiteFunction::Run() { if (!ExtensionTabUtil::GetTabById( params->tab_id, profile, - include_incognito_information(), + false, nullptr, nullptr, &contents, @@ -70,11 +71,96 @@ ExtensionFunction::ResponseAction BraveRewardsTipSiteFunction::Run() { return RespondNow(Error(tabs_constants::kTabNotFoundError, base::NumberToString(params->tab_id))); } - ::brave_rewards::OpenTipDialog(contents, params->publisher_key); + + auto params_dict = std::make_unique(); + params_dict->SetString("publisherKey", params->publisher_key); + ::brave_rewards::OpenTipDialog(contents, std::move(params_dict)); return RespondNow(NoArguments()); } +BraveRewardsTipTwitterUserFunction::BraveRewardsTipTwitterUserFunction() + : weak_factory_(this) { +} + +BraveRewardsTipTwitterUserFunction::~BraveRewardsTipTwitterUserFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsTipTwitterUserFunction::Run() { + std::unique_ptr params( + brave_rewards::TipTwitterUser::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + // Sanity check: don't allow tips in private / tor contexts, + // although the command should not have been enabled in the first place. + Profile* profile = Profile::FromBrowserContext(browser_context()); + if (profile->IsOffTheRecord()) { + return RespondNow( + Error("Cannot tip Twitter user in a private context")); + } + + auto* rewards_service = RewardsServiceFactory::GetForProfile(profile); + if (rewards_service) { + AddRef(); + std::map args; + args["user_id"] = params->tweet_meta_data.user_id; + args["name"] = params->tweet_meta_data.name; + args["screen_name"] = params->tweet_meta_data.screen_name; + rewards_service->SaveTwitterPublisherInfo( + args, + base::Bind(&BraveRewardsTipTwitterUserFunction:: + OnTwitterPublisherInfoSaved, + weak_factory_.GetWeakPtr())); + } + + return RespondNow(NoArguments()); +} + +void BraveRewardsTipTwitterUserFunction::OnTwitterPublisherInfoSaved( + std::unique_ptr<::brave_rewards::ContentSite> publisher_info) { + std::unique_ptr params( + brave_rewards::TipTwitterUser::Params::Create(*args_)); + + if (!publisher_info) { + // TODO(nejczdovc): what should we do in this case? + Release(); + return; + } + + // Get web contents for this tab + content::WebContents* contents = nullptr; + if (!ExtensionTabUtil::GetTabById( + params->tab_id, + Profile::FromBrowserContext(browser_context()), + false, + nullptr, + nullptr, + &contents, + nullptr)) { + return; + } + + auto params_dict = std::make_unique(); + params_dict->SetString("publisherKey", publisher_info->id); + + auto tweet_meta_data_dict = std::make_unique(); + tweet_meta_data_dict->SetString("name", publisher_info->name); + tweet_meta_data_dict->SetString("screenName", + params->tweet_meta_data.screen_name); + tweet_meta_data_dict->SetString("userId", params->tweet_meta_data.user_id); + tweet_meta_data_dict->SetString("tweetId", params->tweet_meta_data.tweet_id); + tweet_meta_data_dict->SetInteger("tweetTimestamp", + params->tweet_meta_data.tweet_timestamp); + tweet_meta_data_dict->SetString("tweetText", + params->tweet_meta_data.tweet_text); + params_dict->SetDictionary("tweetMetaData", std::move(tweet_meta_data_dict)); + + ::brave_rewards::OpenTipDialog(contents, std::move(params_dict)); + + Release(); +} + BraveRewardsGetPublisherDataFunction::~BraveRewardsGetPublisherDataFunction() { } @@ -492,5 +578,33 @@ BraveRewardsGetAllNotificationsFunction::Run() { return RespondNow(OneArgument(std::move(list))); } +BraveRewardsGetInlineTipSettingFunction:: +~BraveRewardsGetInlineTipSettingFunction() { +} + +ExtensionFunction::ResponseAction +BraveRewardsGetInlineTipSettingFunction::Run() { + std::unique_ptr params( + brave_rewards::GetInlineTipSetting::Params::Create(*args_)); + + Profile* profile = Profile::FromBrowserContext(browser_context()); + RewardsService* rewards_service = + RewardsServiceFactory::GetForProfile(profile); + if (!rewards_service) { + return RespondNow(OneArgument(std::make_unique(false))); + } + + rewards_service->GetInlineTipSetting( + params->key, + base::BindOnce( + &BraveRewardsGetInlineTipSettingFunction::OnInlineTipSetting, + this)); + return RespondLater(); +} + +void BraveRewardsGetInlineTipSettingFunction::OnInlineTipSetting(bool value) { + Respond(OneArgument(std::make_unique(value))); +} + } // namespace api } // namespace extensions diff --git a/browser/extensions/api/brave_rewards_api.h b/browser/extensions/api/brave_rewards_api.h index b3468df2e98a..f31e3ed54191 100644 --- a/browser/extensions/api/brave_rewards_api.h +++ b/browser/extensions/api/brave_rewards_api.h @@ -9,9 +9,10 @@ #include #include -#include "extensions/browser/extension_function.h" +#include "base/memory/weak_ptr.h" #include "brave/components/brave_rewards/browser/content_site.h" #include "brave/components/brave_rewards/browser/publisher_banner.h" +#include "extensions/browser/extension_function.h" namespace extensions { namespace api { @@ -36,6 +37,23 @@ class BraveRewardsTipSiteFunction : public UIThreadExtensionFunction { ResponseAction Run() override; }; +class BraveRewardsTipTwitterUserFunction + : public UIThreadExtensionFunction { + public: + BraveRewardsTipTwitterUserFunction(); + DECLARE_EXTENSION_FUNCTION("braveRewards.tipTwitterUser", UNKNOWN) + + protected: + ~BraveRewardsTipTwitterUserFunction() override; + + ResponseAction Run() override; + + private: + base::WeakPtrFactory weak_factory_; + void OnTwitterPublisherInfoSaved( + std::unique_ptr publisher_info); +}; + class BraveRewardsGetPublisherDataFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("braveRewards.getPublisherData", UNKNOWN) @@ -247,6 +265,20 @@ class BraveRewardsGetAllNotificationsFunction : ResponseAction Run() override; }; +class BraveRewardsGetInlineTipSettingFunction : + public UIThreadExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("braveRewards.getInlineTipSetting", UNKNOWN) + + protected: + ~BraveRewardsGetInlineTipSettingFunction() override; + + ResponseAction Run() override; + + private: + void OnInlineTipSetting(bool value); +}; + } // namespace api } // namespace extensions diff --git a/browser/ui/webui/brave_rewards_ui.cc b/browser/ui/webui/brave_rewards_ui.cc index b4b213a8963d..06bdfde6dea1 100644 --- a/browser/ui/webui/brave_rewards_ui.cc +++ b/browser/ui/webui/brave_rewards_ui.cc @@ -115,6 +115,8 @@ class RewardsDOMHandler : public WebUIMessageHandler, void OnGetOneTimeTips( std::unique_ptr list); + void SetInlineTipSetting(const base::ListValue* args); + // RewardsServiceObserver implementation void OnWalletInitialized(brave_rewards::RewardsService* rewards_service, uint32_t result) override; @@ -292,6 +294,9 @@ void RewardsDOMHandler::RegisterMessages() { web_ui()->RegisterMessageCallback("brave_rewards.getExcludedPublishersNumber", base::BindRepeating(&RewardsDOMHandler::GetExcludedPublishersNumber, base::Unretained(this))); + web_ui()->RegisterMessageCallback("brave_rewards.setInlineTipSetting", + base::BindRepeating(&RewardsDOMHandler::SetInlineTipSetting, + base::Unretained(this))); } void RewardsDOMHandler::Init() { @@ -1079,6 +1084,18 @@ void RewardsDOMHandler::OnContributionSaved( "brave_rewards.onContributionSaved", result); } +void RewardsDOMHandler::SetInlineTipSetting(const base::ListValue* args) { + std::string key; + args->GetString(0, &key); + + std::string value; + args->GetString(1, &value); + + if (rewards_service_) { + rewards_service_->SetInlineTipSetting(key, value == "true"); + } +} + } // namespace BraveRewardsUI::BraveRewardsUI(content::WebUI* web_ui, const std::string& name) diff --git a/browser/ui/webui/brave_tip_ui.cc b/browser/ui/webui/brave_tip_ui.cc index 032ae04f772f..fe00015a7260 100644 --- a/browser/ui/webui/brave_tip_ui.cc +++ b/browser/ui/webui/brave_tip_ui.cc @@ -5,31 +5,36 @@ #include "brave/browser/ui/webui/brave_tip_ui.h" +#include #include #include #include #include "base/memory/weak_ptr.h" +#include "base/strings/utf_string_conversions.h" #include "brave/browser/brave_browser_process_impl.h" #include "brave/browser/ui/webui/basic_ui.h" #include "brave/common/pref_names.h" #include "brave/common/webui_url_constants.h" +#include "brave/components/brave_rewards/browser/publisher_banner.h" +#include "brave/components/brave_rewards/browser/rewards_service.h" +#include "brave/components/brave_rewards/browser/rewards_service_factory.h" +#include "brave/components/brave_rewards/browser/rewards_service_observer.h" #include "brave/components/brave_rewards/resources/grit/brave_rewards_resources.h" #include "brave/components/brave_rewards/resources/grit/brave_tip_generated_map.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_pages.h" +#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h" #include "chrome/common/pref_names.h" #include "chrome/common/webui_url_constants.h" +#include "components/grit/brave_components_strings.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_message_handler.h" -#include "brave/components/brave_rewards/browser/rewards_service.h" -#include "brave/components/brave_rewards/browser/rewards_service_factory.h" -#include "brave/components/brave_rewards/browser/rewards_service_observer.h" -#include "brave/components/brave_rewards/browser/publisher_banner.h" +#include "ui/base/l10n/l10n_util.h" using content::WebUIMessageHandler; @@ -56,10 +61,13 @@ class RewardsTipDOMHandler : public WebUIMessageHandler, void OnReconcileStamp(uint64_t reconcile_stamp); void OnGetRecurringTips( std::unique_ptr list); + void TweetTip(const base::ListValue *args); void OnPublisherBanner( std::unique_ptr banner); + void OnTwitterShareURL(const std::string& url); + // RewardsServiceObserver implementation void OnWalletProperties( brave_rewards::RewardsService* rewards_service, @@ -115,6 +123,10 @@ void RewardsTipDOMHandler::RegisterMessages() { "brave_rewards_tip.getReconcileStamp", base::BindRepeating(&RewardsTipDOMHandler::GetReconcileStamp, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "brave_rewards_tip.tweetTip", + base::BindRepeating(&RewardsTipDOMHandler::TweetTip, + base::Unretained(this))); } void RewardsTipDOMHandler::GetPublisherTipData( @@ -291,6 +303,9 @@ BraveTipUI::BraveTipUI(content::WebUI* web_ui, const std::string& name) handler->Init(); } +BraveTipUI::~BraveTipUI() { +} + void RewardsTipDOMHandler::GetReconcileStamp(const base::ListValue *args) { if (rewards_service_) { rewards_service_->GetReconcileStamp(base::Bind( @@ -331,5 +346,43 @@ void RewardsTipDOMHandler::OnRecurringTipSaved( "brave_rewards_tip.recurringTipSaved", base::Value(success)); } -BraveTipUI::~BraveTipUI() { +void RewardsTipDOMHandler::TweetTip(const base::ListValue *args) { + DCHECK_EQ(args->GetSize(), 2U); + + if (!rewards_service_) + return; + + // Retrieve the relevant metadata from arguments. + std::string name; + if (!args->GetString(0, &name)) + return; + std::string tweet_id; + if (!args->GetString(1, &tweet_id)) + return; + + // Share the tip comment/compliment on Twitter. + std::string comment = l10n_util::GetStringFUTF8( + IDS_BRAVE_REWARDS_LOCAL_COMPLIMENT_TWEET, base::UTF8ToUTF16(name)); + std::map share_url_args; + share_url_args["comment"] = comment; + share_url_args["name"] = name.erase(0, 1); + share_url_args["tweet_id"] = tweet_id; + rewards_service_->GetShareURL( + "twitter", share_url_args, + base::BindOnce(&RewardsTipDOMHandler::OnTwitterShareURL, + base::Unretained(this))); +} + +void RewardsTipDOMHandler::OnTwitterShareURL(const std::string& url) { + GURL gurl(url); + if (!gurl.is_valid()) + return; + + // Open a new tab with the prepopulated tweet ready to share. + chrome::ScopedTabbedBrowserDisplayer browser_displayer( + Profile::FromWebUI(web_ui())); + content::OpenURLParams open_url_params( + gurl, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false); + browser_displayer.browser()->OpenURL(open_url_params); } diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index 156c7bb40481..fbca93ab1f10 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -569,9 +569,12 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "sendDonation", IDS_BRAVE_UI_SEND_DONATION }, { "siteBannerNoticeNote", IDS_BRAVE_UI_SITE_BANNER_NOTICE_NOTE }, { "siteBannerNoticeText", IDS_BRAVE_UI_SITE_BANNER_NOTICE_TEXT }, + { "tellOthers", IDS_BRAVE_UI_TELL_OTHERS }, { "thankYou", IDS_BRAVE_UI_THANK_YOU }, { "tipText", IDS_BRAVE_UI_TIP_TEXT }, { "tokens", IDS_BRAVE_UI_TOKENS }, + { "tweetNow", IDS_BRAVE_UI_TWEET_NOW }, + { "tweetTipTitle", IDS_BRAVE_UI_TWEET_TIP_TITLE }, { "unVerifiedTextMore", IDS_BRAVE_UI_SITE_UNVERIFIED_TEXT_MORE }, { "walletBalance", IDS_BRAVE_UI_WALLET_BALANCE }, { "welcome", IDS_BRAVE_UI_WELCOME }, diff --git a/common/extensions/api/brave_rewards.json b/common/extensions/api/brave_rewards.json index 51e260dc07b8..d795328f7c64 100644 --- a/common/extensions/api/brave_rewards.json +++ b/common/extensions/api/brave_rewards.json @@ -354,6 +354,47 @@ } ] }, + { + "name": "tipTwitterUser", + "type": "function", + "description": "Allow the user to perform a donation to a Twitter user", + "parameters": [ + { + "name": "tabID", + "type": "integer" + }, + { + "name": "tweetMetaData", + "type": "object", + "properties": { + "userId": { + "type": "string", + "description": "User ID of tweet author" + }, + "name": { + "type": "string", + "description": "Name of tweet author" + }, + "screenName": { + "type": "string", + "description": "Twitter handle of tweet author" + }, + "tweetId": { + "type": "string", + "description": "Unique tweet ID" + }, + "tweetTimestamp": { + "type": "number", + "description": "Timestamp (in milliseconds) of tweet" + }, + "tweetText": { + "type": "string", + "description": "Textual contents of tweet" + } + } + } + ] + }, { "name": "getPublisherData", "type": "function", @@ -650,6 +691,27 @@ ] } ] + }, + { + "name": "getInlineTipSetting", + "type": "function", + "description": "Gets setting for inline tip for provided key", + "parameters": [ + { + "name": "key", + "value": "string" + }, + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "enabled", + "type": "boolean" + } + ] + } + ] } ] } diff --git a/components/brave_ads/browser/ads_service_impl_unittest.cc b/components/brave_ads/browser/ads_service_impl_unittest.cc index f86fb7553a03..95a0a6859ed2 100644 --- a/components/brave_ads/browser/ads_service_impl_unittest.cc +++ b/components/brave_ads/browser/ads_service_impl_unittest.cc @@ -143,6 +143,18 @@ class MockRewardsService : public RewardsService { brave_rewards::RefreshPublisherCallback)); MOCK_METHOD0(GetAllNotifications, const brave_rewards::RewardsNotificationService::RewardsNotificationsMap&()); + MOCK_METHOD2(SaveTwitterPublisherInfo, + void(const std::map&, + brave_rewards::SaveMediaInfoCallback)); + MOCK_METHOD2(SetInlineTipSetting, + void(const std::string& key, bool enabled)); + MOCK_METHOD2(GetInlineTipSetting, + void(const std::string& key, + brave_rewards::GetInlineTipSettingCallback callback)); + MOCK_METHOD3(GetShareURL, + void(const std::string& type, + const std::map& args, + brave_rewards::GetShareURLCallback callback)); }; class AdsServiceTest : public testing::Test { diff --git a/components/brave_rewards/browser/rewards_service.h b/components/brave_rewards/browser/rewards_service.h index 0547ffd02318..0744c17050e5 100644 --- a/components/brave_rewards/browser/rewards_service.h +++ b/components/brave_rewards/browser/rewards_service.h @@ -77,6 +77,10 @@ using GetPublisherBannerCallback = base::OnceCallback)>; using RefreshPublisherCallback = base::OnceCallback; +using SaveMediaInfoCallback = + base::OnceCallback)>; +using GetInlineTipSettingCallback = base::OnceCallback; +using GetShareURLCallback = base::OnceCallback; class RewardsService : public KeyedService { public: @@ -206,6 +210,21 @@ class RewardsService : public KeyedService { virtual const RewardsNotificationService::RewardsNotificationsMap& GetAllNotifications() = 0; + virtual void SaveTwitterPublisherInfo( + const std::map& args, + SaveMediaInfoCallback callback) = 0; + + virtual void SetInlineTipSetting(const std::string& key, bool enabled) = 0; + + virtual void GetInlineTipSetting( + const std::string& key, + GetInlineTipSettingCallback callback) = 0; + + virtual void GetShareURL( + const std::string& type, + const std::map& args, + GetShareURLCallback callback) = 0; + protected: base::ObserverList observers_; diff --git a/components/brave_rewards/browser/rewards_service_browsertest.cc b/components/brave_rewards/browser/rewards_service_browsertest.cc index dc4c537e5be8..b2325ece17ff 100644 --- a/components/brave_rewards/browser/rewards_service_browsertest.cc +++ b/components/brave_rewards/browser/rewards_service_browsertest.cc @@ -21,10 +21,13 @@ #include "chrome/common/chrome_paths.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/network_session_configurator/common/network_switches.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/test/browser_test_utils.h" #include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,8 +44,25 @@ std::unique_ptr HandleRequest( new net::test_server::BasicHttpResponse()); http_response->set_code(net::HTTP_OK); http_response->set_content_type("text/html"); - http_response->set_content( - "
Hello, world!
"); + if (request.relative_url == "/twitter") { + http_response->set_content( + "" + " " + " " + "
" + "
Hello, Twitter!
" + "
" + " " + ""); + } else { + http_response->set_content( + "" + " " + " " + "
Hello, world!
" + " " + ""); + } return std::move(http_response); } @@ -79,9 +99,22 @@ class BraveRewardsBrowserTest : public InProcessBrowserTest, public: void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); content::SetupCrossSiteRedirector(embedded_test_server()); - InitEmbeddedTestServer(); + + // Setup up embedded test server for HTTP requests + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&HandleRequest)); + ASSERT_TRUE(embedded_test_server()->Start()); + + // Setup up embedded test server for HTTPS requests + https_server_.reset(new net::EmbeddedTestServer( + net::test_server::EmbeddedTestServer::TYPE_HTTPS)); + https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK); + https_server_->RegisterRequestHandler(base::BindRepeating(&HandleRequest)); + ASSERT_TRUE(https_server_->Start()); + brave::RegisterPathProvider(); ReadTestData(); rewards_service_ = static_cast( @@ -97,11 +130,14 @@ class BraveRewardsBrowserTest : public InProcessBrowserTest, InProcessBrowserTest::TearDown(); } - void InitEmbeddedTestServer() { - embedded_test_server()->RegisterRequestHandler(base::Bind(&HandleRequest)); - ASSERT_TRUE(embedded_test_server()->Start()); + void SetUpCommandLine(base::CommandLine* command_line) override { + // HTTPS server only serves a valid cert for localhost, so this is needed + // to load pages from other hosts without an error + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); } + net::EmbeddedTestServer* https_server() { return https_server_.get(); } + void RunUntilIdle() { base::RunLoop loop; loop.RunUntilIdle(); @@ -531,7 +567,7 @@ class BraveRewardsBrowserTest : public InProcessBrowserTest, content::NotificationService::AllSources()); // Click button to initiate sending a tip - content::EvalJsResult js_result = EvalJs( + content::EvalJsResult js_result = EvalJs( popup_contents, "new Promise((resolve) => {" "let count = 10;" @@ -730,6 +766,30 @@ class BraveRewardsBrowserTest : public InProcessBrowserTest, } } + bool IsTwitterTipsInjected() { + content::EvalJsResult js_result = + EvalJs(contents(), + "new Promise((resolve) => {" + "let count = 10;" + "var interval = setInterval(function() {" + " if (count === 0) {" + " clearInterval(interval);" + " resolve(false);" + " } else {" + " count -= 1;" + " }" + " const braveTipActions" + " = document.querySelectorAll(\".action-brave-tip\");" + " if (braveTipActions && braveTipActions.length === 1) {" + " clearInterval(interval);" + " resolve(true);" + " }" + "}, 500);});", + content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, + content::ISOLATED_WORLD_ID_CONTENT_END); + return js_result.ExtractBool(); + } + void OnWalletInitialized(brave_rewards::RewardsService* rewards_service, uint32_t result) { ASSERT_TRUE(result == ledger::Result::WALLET_CREATED || @@ -796,6 +856,8 @@ class BraveRewardsBrowserTest : public InProcessBrowserTest, MOCK_METHOD1(OnGetReconcileTime, void(int32_t)); MOCK_METHOD1(OnGetShortRetries, void(bool)); + std::unique_ptr https_server_; + brave_rewards::RewardsServiceImpl* rewards_service_; brave_rewards::Grant grant_; @@ -1409,3 +1471,48 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, // Stop observing the Rewards service rewards_service_->RemoveObserver(this); } + +// Brave tip icon is injected when visiting Twitter +IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, TwitterTipsInjectedOnTwitter) { + // Enable Rewards + EnableRewards(); + + // Navigate to Twitter in a new tab + GURL url = https_server()->GetURL("twitter.com", "/twitter"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + // Ensure that Twitter tips injection is active + EXPECT_TRUE(IsTwitterTipsInjected()); +} + +// Brave tip icon is not injected when visiting Twitter while Brave +// Rewards is disabled +IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, + TwitterTipsNotInjectedWhenRewardsDisabled) { + // Navigate to Twitter in a new tab + GURL url = https_server()->GetURL("twitter.com", "/twitter"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + // Ensure that Twitter tips injection is not active + EXPECT_FALSE(IsTwitterTipsInjected()); +} + +// Brave tip icon is not injected into non-Twitter sites +IN_PROC_BROWSER_TEST_F(BraveRewardsBrowserTest, + TwitterTipsNotInjectedOnNonTwitter) { + // Enable Rewards + EnableRewards(); + + // Navigate to a non-Twitter site in a new tab + GURL url = embedded_test_server()->GetURL("google.com", "/twitter"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + // Ensure that Twitter tips injection is not active + EXPECT_FALSE(IsTwitterTipsInjected()); +} diff --git a/components/brave_rewards/browser/rewards_service_impl.cc b/components/brave_rewards/browser/rewards_service_impl.cc index 2355b8dd35ca..d4267c1de9f8 100644 --- a/components/brave_rewards/browser/rewards_service_impl.cc +++ b/components/brave_rewards/browser/rewards_service_impl.cc @@ -2241,6 +2241,38 @@ void RewardsServiceImpl::SaveRecurringTip( AsWeakPtr())); } +void RewardsServiceImpl::OnTwitterPublisherInfoSaved( + SaveMediaInfoCallback callback, + int32_t result, + ledger::PublisherInfoPtr publisher) { + if (!Connected()) { + std::move(callback).Run(nullptr); + return; + } + if (Connected()) { + ledger::Result result_converted = static_cast(result); + std::unique_ptr site; + + if (result_converted == ledger::Result::LEDGER_OK) { + site = std::make_unique( + PublisherInfoToContentSite(*publisher)); + } + + std::move(callback).Run(std::move(site)); + } +} + +void RewardsServiceImpl::SaveTwitterPublisherInfo( + const std::map& args, + SaveMediaInfoCallback callback) { + bat_ledger_->SaveMediaInfo( + "twitter", + mojo::MapToFlatMap(args), + base::BindOnce(&RewardsServiceImpl::OnTwitterPublisherInfoSaved, + AsWeakPtr(), + std::move(callback))); +} + ledger::PublisherInfoList GetRecurringTipsOnFileTaskRunner( PublisherInfoDatabase* backend) { ledger::PublisherInfoList list; @@ -2932,4 +2964,43 @@ RewardsServiceImpl::GetAllNotifications() { return notification_service_->GetAllNotifications(); } +void RewardsServiceImpl::SetInlineTipSetting(const std::string& key, + bool enabled) { + bat_ledger_->SetInlineTipSetting(key, enabled); +} + +void RewardsServiceImpl::GetInlineTipSetting( + const std::string& key, + GetInlineTipSettingCallback callback) { + bat_ledger_->GetInlineTipSetting( + key, + base::BindOnce(&RewardsServiceImpl::OnInlineTipSetting, + AsWeakPtr(), + std::move(callback))); +} + +void RewardsServiceImpl::OnInlineTipSetting( + GetInlineTipSettingCallback callback, + bool enabled) { + std::move(callback).Run(enabled); +} + +void RewardsServiceImpl::GetShareURL( + const std::string& type, + const std::map& args, + GetShareURLCallback callback) { + bat_ledger_->GetShareURL( + type, + mojo::MapToFlatMap(args), + base::BindOnce(&RewardsServiceImpl::OnShareURL, + AsWeakPtr(), + std::move(callback))); +} + +void RewardsServiceImpl::OnShareURL( + GetShareURLCallback callback, + const std::string& url) { + std::move(callback).Run(url); +} + } // namespace brave_rewards diff --git a/components/brave_rewards/browser/rewards_service_impl.h b/components/brave_rewards/browser/rewards_service_impl.h index 3c4990522bbb..3c98ad4db6d5 100644 --- a/components/brave_rewards/browser/rewards_service_impl.h +++ b/components/brave_rewards/browser/rewards_service_impl.h @@ -218,6 +218,21 @@ class RewardsServiceImpl : public RewardsService, void SetContributionAmount(const double amount) const override; + void SaveTwitterPublisherInfo( + const std::map& args, + SaveMediaInfoCallback callback) override; + + void SetInlineTipSetting(const std::string& key, bool enabled) override; + + void GetInlineTipSetting( + const std::string& key, + GetInlineTipSettingCallback callback) override; + + void GetShareURL( + const std::string& type, + const std::map& args, + GetShareURLCallback callback) override; + // Testing methods void SetLedgerEnvForTesting(); void StartAutoContributeForTest(); @@ -321,6 +336,10 @@ class RewardsServiceImpl : public RewardsService, uint32_t result, ledger::PublisherInfoPtr info); + void OnInlineTipSetting(GetInlineTipSettingCallback callback, bool enabled); + + void OnShareURL(GetShareURLCallback callback, const std::string& url); + // ledger::LedgerClient std::string GenerateGUID() const override; void OnWalletInitialized(ledger::Result result) override; @@ -483,6 +502,9 @@ class RewardsServiceImpl : public RewardsService, RefreshPublisherCallback callback, const std::string& publisher_key, bool verified); + void OnTwitterPublisherInfoSaved(SaveMediaInfoCallback callback, + int32_t result, + ledger::PublisherInfoPtr publisher); bool Connected() const; void ConnectionClosed(); diff --git a/components/brave_rewards/resources/extension/brave_rewards/BUILD.gn b/components/brave_rewards/resources/extension/brave_rewards/BUILD.gn index 97ba4b306197..8d1b78729692 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/BUILD.gn +++ b/components/brave_rewards/resources/extension/brave_rewards/BUILD.gn @@ -9,7 +9,8 @@ group("brave_rewards") { transpile_web_ui("brave_rewards_panel") { entry_points = [ ["brave_rewards_panel", rebase_path("brave_rewards_panel.tsx")], - ["brave_rewards_panel_background", rebase_path("background.ts")] + ["brave_rewards_panel_background", rebase_path("background.ts")], + ["brave_rewards_panel_content_twitter", rebase_path("content_scripts/twitter.ts")] ] resource_name = "brave_rewards_panel" diff --git a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json index a66d9be7b6bb..097d5082b1ef 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json +++ b/components/brave_rewards/resources/extension/brave_rewards/_locales/en_US/messages.json @@ -412,5 +412,13 @@ "adsEarnings": { "message": "earned from ads", "description": "Description text for ad grants in grant details" + }, + "twitterTipsHoverText": { + "message": "Tip this tweet", + "description": "Hover text for Twitter tips action" + }, + "twitterTipsIconLabel": { + "message": "Tip", + "description": "Icon label for Twitter tips" } } diff --git a/components/brave_rewards/resources/extension/brave_rewards/background.ts b/components/brave_rewards/resources/extension/brave_rewards/background.ts index 5cb4bfda7dea..a28857c4fa99 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/background.ts +++ b/components/brave_rewards/resources/extension/brave_rewards/background.ts @@ -78,3 +78,47 @@ chrome.runtime.onConnect.addListener(function () { } }) }) + +const tipTwitterUser = (tweetMetaData: RewardsTip.TweetMetaData) => { + chrome.tabs.query({ + active: true, + windowId: chrome.windows.WINDOW_ID_CURRENT + }, (tabs) => { + if (!tabs || tabs.length === 0) { + return + } + const tabId = tabs[0].id + if (tabId === undefined) { + return + } + chrome.braveRewards.tipTwitterUser(tabId, tweetMetaData) + }) +} + +chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { + const action = typeof msg === 'string' ? msg : msg.type + switch (action) { + case 'tipTwitterUser': { + tipTwitterUser(msg.tweetMetaData) + return false + } + case 'rewardsEnabled': { + // Check if rewards is enabled + chrome.braveRewards.getRewardsMainEnabled(function (enabled: boolean) { + sendResponse({ enabled }) + }) + // Must return true for asynchronous calls to sendResponse + return true + } + case 'inlineTipSetting': { + // Check if inline tip is enabled + chrome.braveRewards.getInlineTipSetting(msg.key, function (enabled: boolean) { + sendResponse({ enabled }) + }) + // Must return true for asynchronous calls to sendResponse + return true + } + default: + return false + } +}) diff --git a/components/brave_rewards/resources/extension/brave_rewards/content_scripts/twitter.ts b/components/brave_rewards/resources/extension/brave_rewards/content_scripts/twitter.ts new file mode 100644 index 000000000000..c29c370cc81f --- /dev/null +++ b/components/brave_rewards/resources/extension/brave_rewards/content_scripts/twitter.ts @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Utils +import { getMessage } from '../background/api/locale_api' + +let timeout: any = null + +const getTweetMetaData = (tweet: Element): RewardsTip.TweetMetaData | null => { + if (!tweet) { + return null + } + + const tweetTextElements = tweet.getElementsByClassName('tweet-text') + if (!tweetTextElements || tweetTextElements.length === 0) { + return null + } + + const tweetText = tweetTextElements[0] as HTMLElement + + const tweetTimestampElements = tweet.getElementsByClassName('js-short-timestamp') + if (!tweetTimestampElements || tweetTimestampElements.length === 0) { + return null + } + + const tweetTimestamp = tweetTimestampElements[0].getAttribute('data-time') || '' + + return { + name: tweet.getAttribute('data-name') || '', + screenName: tweet.getAttribute('data-screen-name') || '', + userId: tweet.getAttribute('data-user-id') || '', + tweetId: tweet.getAttribute('data-tweet-id') || '', + tweetTimestamp: parseInt(tweetTimestamp, 10) || 0, + tweetText: tweetText.innerText || '' + } +} + +const createBraveTipAction = (tweet: Element) => { + // Create the tip action + const braveTipAction = document.createElement('div') + braveTipAction.className = 'ProfileTweet-action js-tooltip action-brave-tip' + braveTipAction.style.display = 'inline-block' + braveTipAction.style.minWidth = '80px' + braveTipAction.setAttribute('data-original-title', getMessage('twitterTipsHoverText')) + + // Create the tip button + const braveTipButton = document.createElement('button') + braveTipButton.className = 'ProfileTweet-actionButton u-textUserColorHover js-actionButton' + braveTipButton.style.background = 'transparent' + braveTipButton.style.border = '0' + braveTipButton.style.color = '#657786' + braveTipButton.style.cursor = 'pointer' + braveTipButton.style.display = 'inline-block' + braveTipButton.style.fontSize = '16px' + braveTipButton.style.lineHeight = '1' + braveTipButton.style.outline = '0' + braveTipButton.style.padding = '0 2px' + braveTipButton.style.position = 'relative' + braveTipButton.type = 'button' + braveTipButton.onclick = function (event) { + const tweetMetaData = getTweetMetaData(tweet) + if (tweetMetaData) { + const msg = { type: 'tipTwitterUser', tweetMetaData: tweetMetaData } + chrome.runtime.sendMessage(msg) + } + event.stopPropagation() + } + + // Create the tip icon container + const braveTipIconContainer = document.createElement('div') + braveTipIconContainer.className = 'IconContainer js-tooltip' + braveTipIconContainer.style.display = 'inline-block' + braveTipIconContainer.style.lineHeight = '0' + braveTipIconContainer.style.position = 'relative' + braveTipIconContainer.style.verticalAlign = 'middle' + braveTipButton.appendChild(braveTipIconContainer) + + // Create the tip icon + const braveTipIcon = document.createElement('span') + braveTipIcon.className = 'Icon Icon--medium' + braveTipIcon.style.background = 'transparent' + braveTipIcon.style.content = 'url(\'data:image/svg+xml;utf8,BAT_icon\')' + braveTipIcon.style.display = 'inline-block' + braveTipIcon.style.fontSize = '18px' + braveTipIcon.style.fontStyle = 'normal' + braveTipIcon.style.height = '16px' + braveTipIcon.style.marginTop = '5px' + braveTipIcon.style.position = 'relative' + braveTipIcon.style.verticalAlign = 'baseline' + braveTipIcon.style.width = '16px' + braveTipIconContainer.appendChild(braveTipIcon) + + // Create the tip action count (typically used to present a counter + // associated with the action, but we'll use it to display a static + // action label) + const braveTipActionCount = document.createElement('span') + braveTipActionCount.className = 'ProfileTweet-actionCount' + braveTipActionCount.style.color = '#657786' + braveTipActionCount.style.display = 'inline-block' + braveTipActionCount.style.fontSize = '12px' + braveTipActionCount.style.fontWeight = 'bold' + braveTipActionCount.style.lineHeight = '1' + braveTipActionCount.style.marginLeft = '6px' + braveTipActionCount.style.position = 'relative' + braveTipActionCount.style.verticalAlign = 'text-bottom' + braveTipButton.appendChild(braveTipActionCount) + + // Create the tip action count presentation + const braveTipActionCountPresentation = document.createElement('span') + braveTipActionCountPresentation.className = 'ProfileTweet-actionCountForPresentation' + braveTipActionCountPresentation.textContent = getMessage('twitterTipsIconLabel') + braveTipActionCount.appendChild(braveTipActionCountPresentation) + + // Create the shadow DOM root that hosts our injected DOM elements + const shadowRoot = braveTipAction.attachShadow({ mode: 'open' }) + shadowRoot.appendChild(braveTipButton) + + // Create style element for hover color + const style = document.createElement('style') + style.innerHTML = '.ProfileTweet-actionButton :hover { color: #FB542B }' + shadowRoot.appendChild(style) + + return braveTipAction +} + +const configureBraveTipAction = () => { + clearTimeout(timeout) + chrome.runtime.sendMessage('rewardsEnabled', function (rewards) { + const msg = { + type: 'inlineTipSetting', + key: 'twitter' + } + chrome.runtime.sendMessage(msg, function (inlineTip) { + const tweets = document.getElementsByClassName('tweet') + for (let i = 0; i < tweets.length; ++i) { + const actions = tweets[i].getElementsByClassName('js-actions')[0] + if (actions) { + const braveTipActions = actions.getElementsByClassName('action-brave-tip') + const tippingEnabled = rewards.enabled && inlineTip.enabled + if (tippingEnabled && braveTipActions.length === 0) { + actions.appendChild(createBraveTipAction(tweets[i])) + } else if (!tippingEnabled && braveTipActions.length === 1) { + actions.removeChild(braveTipActions[0]) + } + } + } + }) + }) + timeout = setTimeout(configureBraveTipAction, 3000) +} + +// In order to deal with infinite scrolling and overlays, periodically +// check if injection needs to occur (mitigate the performance cost +// by only running this when the foreground tab is active or visible) +document.addEventListener('visibilitychange', function () { + clearTimeout(timeout) + if (!document.hidden) { + timeout = setTimeout(configureBraveTipAction, 3000) + } +}) + +configureBraveTipAction() diff --git a/components/brave_rewards/resources/extension/brave_rewards/manifest.json b/components/brave_rewards/resources/extension/brave_rewards/manifest.json index 125117fa3db4..163ec2fe5570 100644 --- a/components/brave_rewards/resources/extension/brave_rewards/manifest.json +++ b/components/brave_rewards/resources/extension/brave_rewards/manifest.json @@ -25,6 +25,16 @@ "256": "img/bat-256.png" } }, + "content_scripts": [ + { + "matches": [ + "https://*.twitter.com/*" + ], + "js": [ + "out/brave_rewards_panel_content_twitter.bundle.js" + ] + } + ], "icons": { "16": "img/bat-16.png", "32": "img/bat-32.png", diff --git a/components/brave_rewards/resources/tip/actions/tip_actions.ts b/components/brave_rewards/resources/tip/actions/tip_actions.ts index db2204ae4aa3..705f0a935887 100644 --- a/components/brave_rewards/resources/tip/actions/tip_actions.ts +++ b/components/brave_rewards/resources/tip/actions/tip_actions.ts @@ -9,6 +9,11 @@ import { types } from '../constants/tip_types' export const onCloseDialog = () => action(types.ON_CLOSE_DIALOG) +export const onTweet = (name: string, tweetId: string) => action(types.ON_TWEET, { + name, + tweetId +}) + export const onPublisherBanner = (data: RewardsTip.Publisher) => action(types.ON_PUBLISHER_BANNER, { data }) diff --git a/components/brave_rewards/resources/tip/brave_tip.tsx b/components/brave_rewards/resources/tip/brave_tip.tsx index 4a8196a4f41a..c7d10cf7a32c 100644 --- a/components/brave_rewards/resources/tip/brave_tip.tsx +++ b/components/brave_rewards/resources/tip/brave_tip.tsx @@ -32,11 +32,10 @@ window.cr.define('brave_rewards_tip', function () { } const dialogArgsRaw = chrome.getVariableValue('dialogArguments') - let publisherKey + let dialogArgs try { - const args = JSON.parse(dialogArgsRaw) - chrome.send('brave_rewards_tip.getPublisherBanner', [args.publisherKey]) - publisherKey = args.publisherKey + dialogArgs = JSON.parse(dialogArgsRaw) + chrome.send('brave_rewards_tip.getPublisherBanner', [dialogArgs.publisherKey]) } catch (e) { console.error('Error parsing incoming dialog args', dialogArgsRaw, e) } @@ -44,7 +43,7 @@ window.cr.define('brave_rewards_tip', function () { render( - + , document.getElementById('root')) diff --git a/components/brave_rewards/resources/tip/components/app.tsx b/components/brave_rewards/resources/tip/components/app.tsx index 18c7e18f0ccd..5e9d10a0ee8f 100644 --- a/components/brave_rewards/resources/tip/components/app.tsx +++ b/components/brave_rewards/resources/tip/components/app.tsx @@ -7,105 +7,62 @@ import { bindActionCreators, Dispatch } from 'redux' import { connect } from 'react-redux' // Components -import Banner from './siteBanner' -import DonationOverlay from 'brave-ui/features/rewards/donationOverlay' +import TipSite from './tipSite' +import TipTwitterUser from './tipTwitterUser' // Utils import * as rewardsActions from '../actions/tip_actions' -interface Props extends RewardsTip.ComponentProps { +interface TipDialogArgs { publisherKey: string + tweetMetaData?: RewardsTip.TweetMetaData } -export class App extends React.Component { +interface Props extends RewardsTip.ComponentProps { + dialogArgs: TipDialogArgs +} +export class App extends React.Component { get actions () { return this.props.actions } - onClose = () => { - this.actions.onCloseDialog() - } - - generateTipOverlay = (publisher: RewardsTip.Publisher) => { - let domain = '' - let monthlyDate - const { - currentTipAmount, - currentTipRecurring, - reconcileStamp - } = this.props.rewardsDonateData - - const publisherKey = publisher && publisher.publisherKey - - if (!publisherKey) { - return null - } - - if (currentTipRecurring && reconcileStamp) { - monthlyDate = new Date(reconcileStamp * 1000).toLocaleDateString() - } - - if (publisher.provider && publisher.name) { - domain = publisher.name + getTipBanner = (publisher: RewardsTip.Publisher, tweetMetaData?: RewardsTip.TweetMetaData) => { + if (tweetMetaData) { + return ( + + ) } else { - domain = publisherKey - } - - const verified = publisher.verified - let logo = publisher.logo - - const internalFavicon = /^https:\/\/[a-z0-9-]+\.invalid(\/)?$/ - if (internalFavicon.test(publisher.logo)) { - logo = `chrome://favicon/size/160@2x/${publisher.logo}` + return ( + + ) } - - if (!verified) { - logo = '' - } - - setTimeout(() => { - this.onClose() - }, 3000) - - return ( - - ) } render () { - const { finished, error, publishers } = this.props.rewardsDonateData + const { publishers } = this.props.rewardsDonateData if (!publishers) { return null } - const publisher = publishers[this.props.publisherKey] + const tweetMetaData = this.props.dialogArgs.tweetMetaData + const publisherKey = this.props.dialogArgs.publisherKey + const publisher = publishers[publisherKey] if (!publisher) { return null } return ( - <> - { - !finished && !error - ? - : null - } - { - finished - ? this.generateTipOverlay(publisher) - : null - } - +
+ {this.getTipBanner(publisher, tweetMetaData)} +
) } } diff --git a/components/brave_rewards/resources/tip/components/siteBanner.tsx b/components/brave_rewards/resources/tip/components/siteBanner.tsx index c57136ab91d2..8af9d3aac690 100644 --- a/components/brave_rewards/resources/tip/components/siteBanner.tsx +++ b/components/brave_rewards/resources/tip/components/siteBanner.tsx @@ -7,8 +7,8 @@ import { bindActionCreators, Dispatch } from 'redux' import { connect } from 'react-redux' // Components -import { SiteBanner } from 'brave-ui/features/rewards' import { Provider } from 'brave-ui/features/rewards/profile' +import { SiteBanner, TweetBox } from 'brave-ui/features/rewards' // Utils import * as tipActions from '../actions/tip_actions' @@ -16,6 +16,7 @@ import * as utils from '../utils' interface Props extends RewardsTip.ComponentProps { publisher: RewardsTip.Publisher + tweetMetaData?: RewardsTip.TweetMetaData } interface State { @@ -118,6 +119,14 @@ class Banner extends React.Component { return !!recurringDonation } + getScreenName = (tweetMetaData?: RewardsTip.TweetMetaData) => { + if (!tweetMetaData) { + return '' + } + + return `@${tweetMetaData.screenName}` + } + get addFundsLink () { return 'chrome://rewards/#add-funds' } @@ -126,6 +135,7 @@ class Banner extends React.Component { const { walletInfo } = this.props.rewardsDonateData const { balance } = walletInfo + const tweetMetaData = this.props.tweetMetaData const publisher = this.props.publisher const verified = publisher.verified let logo = publisher.logo @@ -144,6 +154,7 @@ class Banner extends React.Component { domain={publisher.publisherKey} title={publisher.title} name={publisher.name} + screenName={this.getScreenName(tweetMetaData)} provider={publisher.provider as Provider} recurringDonation={this.hasRecurringTip(publisher.publisherKey)} balance={balance.toString() || '0'} @@ -160,7 +171,11 @@ class Banner extends React.Component { learnMoreNotice={'https://brave.com/faq-rewards/#unclaimed-funds'} addFundsLink={this.addFundsLink} > - {publisher.description} + { + this.props.tweetMetaData + ? + : publisher.description + } ) } diff --git a/components/brave_rewards/resources/tip/components/tipSite.tsx b/components/brave_rewards/resources/tip/components/tipSite.tsx new file mode 100644 index 000000000000..62bc437c18e4 --- /dev/null +++ b/components/brave_rewards/resources/tip/components/tipSite.tsx @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import { bindActionCreators, Dispatch } from 'redux' +import { connect } from 'react-redux' + +// Components +import Banner from './siteBanner' +import TransientTipOverlay from './transientTipOverlay' + +// Utils +import * as rewardsActions from '../actions/tip_actions' + +interface Props extends RewardsTip.ComponentProps { + publisher: RewardsTip.Publisher +} + +class TipSite extends React.Component { + get actions () { + return this.props.actions + } + + onTweet = () => { + this.actions.onTweet(this.props.publisher.name, '') + this.actions.onCloseDialog() + } + + render () { + const { finished, error } = this.props.rewardsDonateData + + return ( + <> + { + !finished && !error + ? + : null + } + { + finished + ? + : null + } + + ) + } +} + +export const mapStateToProps = (state: RewardsTip.ApplicationState) => ({ + rewardsDonateData: state.rewardsDonateData +}) + +export const mapDispatchToProps = (dispatch: Dispatch) => ({ + actions: bindActionCreators(rewardsActions, dispatch) +}) + +export default connect( + mapStateToProps, + mapDispatchToProps +)(TipSite) diff --git a/components/brave_rewards/resources/tip/components/tipTwitterUser.tsx b/components/brave_rewards/resources/tip/components/tipTwitterUser.tsx new file mode 100644 index 000000000000..3f1117dea3e8 --- /dev/null +++ b/components/brave_rewards/resources/tip/components/tipTwitterUser.tsx @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import { bindActionCreators, Dispatch } from 'redux' +import { connect } from 'react-redux' + +// Components +import Banner from './siteBanner' +import TransientTipOverlay from './transientTipOverlay' + +// Utils +import * as rewardsActions from '../actions/tip_actions' +import { getLocale } from '../../../../common/locale' + +interface Props extends RewardsTip.ComponentProps { + publisher: RewardsTip.Publisher + tweetMetaData: RewardsTip.TweetMetaData +} + +class TipTwitterUser extends React.Component { + + get actions () { + return this.props.actions + } + + onTweet = () => { + this.actions.onTweet( + `@${this.props.tweetMetaData.screenName}`, + this.props.tweetMetaData.tweetId) + this.actions.onCloseDialog() + } + + render () { + const { finished, error } = this.props.rewardsDonateData + + const publisher = this.props.publisher + const tweetMetaData = this.props.tweetMetaData + publisher.title = getLocale('tweetTipTitle', { user: tweetMetaData.screenName }) + + return ( + <> + { + !finished && !error + ? + : null + } + { + finished + ? + : null + } + + ) + } +} + +export const mapStateToProps = (state: RewardsTip.ApplicationState) => ({ + rewardsDonateData: state.rewardsDonateData +}) + +export const mapDispatchToProps = (dispatch: Dispatch) => ({ + actions: bindActionCreators(rewardsActions, dispatch) +}) + +export default connect( + mapStateToProps, + mapDispatchToProps +)(TipTwitterUser) diff --git a/components/brave_rewards/resources/tip/components/transientTipOverlay.tsx b/components/brave_rewards/resources/tip/components/transientTipOverlay.tsx new file mode 100644 index 000000000000..62f5df468a59 --- /dev/null +++ b/components/brave_rewards/resources/tip/components/transientTipOverlay.tsx @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import { bindActionCreators, Dispatch } from 'redux' +import { connect } from 'react-redux' + +// Components +import DonationOverlay from 'brave-ui/features/rewards/donationOverlay' + +// Utils +import * as rewardsActions from '../actions/tip_actions' + +interface Props extends RewardsTip.ComponentProps { + publisher: RewardsTip.Publisher + timeout?: number + onTweet?: () => void +} + +class TransientTipOverlay extends React.Component { + componentDidMount () { + if (this.props.timeout) { + setTimeout(() => { + this.onClose() + }, this.props.timeout) + } + } + + get actions () { + return this.props.actions + } + + onClose = () => { + this.actions.onCloseDialog() + } + + render () { + let domain = '' + let monthlyDate + const { + currentTipAmount, + currentTipRecurring, + reconcileStamp + } = this.props.rewardsDonateData + + const publisher = this.props.publisher + const publisherKey = publisher && publisher.publisherKey + + if (!publisherKey) { + return null + } + + if (currentTipRecurring && reconcileStamp) { + monthlyDate = new Date(reconcileStamp * 1000).toLocaleDateString() + } + + if (publisher.provider && publisher.name) { + domain = publisher.name + } else { + domain = publisherKey + } + + const verified = publisher.verified + let logo = publisher.logo + + const internalFavicon = /^https:\/\/[a-z0-9-]+\.invalid(\/)?$/ + if (internalFavicon.test(publisher.logo)) { + logo = `chrome://favicon/size/160@2x/${publisher.logo}` + } + + if (!verified) { + logo = '' + } + + return ( + + ) + } +} + +export const mapStateToProps = (state: RewardsTip.ApplicationState) => ({ + rewardsDonateData: state.rewardsDonateData +}) + +export const mapDispatchToProps = (dispatch: Dispatch) => ({ + actions: bindActionCreators(rewardsActions, dispatch) +}) + +export default connect( + mapStateToProps, + mapDispatchToProps +)(TransientTipOverlay) diff --git a/components/brave_rewards/resources/tip/constants/tip_types.ts b/components/brave_rewards/resources/tip/constants/tip_types.ts index e2a37d2f2cee..fc4e7189cb92 100644 --- a/components/brave_rewards/resources/tip/constants/tip_types.ts +++ b/components/brave_rewards/resources/tip/constants/tip_types.ts @@ -4,6 +4,7 @@ export const enum types { ON_CLOSE_DIALOG = '@@rewards/ON_CLOSE_DIALOG', + ON_TWEET = '@@rewards/ON_TWEET', ON_PUBLISHER_BANNER = '@@rewards/ON_PUBLISHER_BANNER', ON_WALLET_PROPERTIES = '@@rewards/ON_WALLET_PROPERTIES', GET_WALLET_PROPERTIES = '@@rewards/GET_WALLET_PROPERTIES', diff --git a/components/brave_rewards/resources/tip/reducers/tip_reducer.ts b/components/brave_rewards/resources/tip/reducers/tip_reducer.ts index fb361245ab95..e8267d24ec7a 100644 --- a/components/brave_rewards/resources/tip/reducers/tip_reducer.ts +++ b/components/brave_rewards/resources/tip/reducers/tip_reducer.ts @@ -31,6 +31,12 @@ const publishersReducer: Reducer = (state: RewardsTip.State = state.currentTipRecurring = false chrome.send('dialogClose') break + case types.ON_TWEET: + chrome.send('brave_rewards_tip.tweetTip', [ + payload.name, + payload.tweetId + ]) + break case types.ON_PUBLISHER_BANNER: { state = { ...state } if (!state.publishers) { diff --git a/components/brave_rewards/resources/ui/actions/rewards_actions.ts b/components/brave_rewards/resources/ui/actions/rewards_actions.ts index 1c4faed4b1d9..ace57b431813 100644 --- a/components/brave_rewards/resources/ui/actions/rewards_actions.ts +++ b/components/brave_rewards/resources/ui/actions/rewards_actions.ts @@ -200,3 +200,8 @@ export const onContributionSaved = (properties: Rewards.ContributionSaved) => action(types.ON_CONTRIBUTION_SAVED, { properties }) + +export const onInlineTipSettingChange = (key: string, value: boolean) => action(types.ON_INLINE_TIP_SETTINGS_CHANGE, { + key, + value +}) diff --git a/components/brave_rewards/resources/ui/components/tipsBox.tsx b/components/brave_rewards/resources/ui/components/tipsBox.tsx index 2b0a64d4e071..7f409072656f 100644 --- a/components/brave_rewards/resources/ui/components/tipsBox.tsx +++ b/components/brave_rewards/resources/ui/components/tipsBox.tsx @@ -7,6 +7,7 @@ import { bindActionCreators, Dispatch } from 'redux' import { connect } from 'react-redux' // Components +import { Checkbox, Grid, Column, ControlWrapper } from 'brave-ui/components' import { DisabledContent, Box, @@ -156,6 +157,43 @@ class TipBox extends React.Component { this.setState({ settings: !this.state.settings }) } + onInlineTipSettingChange = (key: string, selected: boolean) => { + this.actions.onInlineTipSettingChange(key, selected) + } + + donationSettingsChild = () => { + const { enabledMain } = this.props.rewardsData + if (!enabledMain) { + return null + } + + let value = this.props.rewardsData.inlineTip + + if (!value) { + value = { + twitter: true + } + } + + return ( + <> + + + + +
{getLocale('donationAbilityTwitter')}
+
+
+
+
+ + ) + } + render () { const { walletInfo, @@ -181,6 +219,7 @@ class TipBox extends React.Component { description={getLocale('donationDesc')} disabledContent={showDisabled ? this.disabledContent() : null} attachedAlert={this.importAlert(walletImported)} + settingsChild={this.donationSettingsChild()} settingsOpened={this.state.settings} onSettingsClick={this.onSettingsToggle} > diff --git a/components/brave_rewards/resources/ui/constants/rewards_types.ts b/components/brave_rewards/resources/ui/constants/rewards_types.ts index 845a0a2160ce..b62d9f39440e 100644 --- a/components/brave_rewards/resources/ui/constants/rewards_types.ts +++ b/components/brave_rewards/resources/ui/constants/rewards_types.ts @@ -61,5 +61,6 @@ export const enum types { GET_REWARDS_MAIN_ENABLED = '@@rewards/GET_REWARDS_MAIN_ENABLED', ON_RECURRING_TIP_SAVED = '@@rewards/ON_RECURRING_TIP_SAVED', ON_RECURRING_TIP_REMOVED = '@@rewards/ON_RECURRING_TIP_REMOVED', - ON_CONTRIBUTION_SAVED = '@@rewards/ON_CONTRIBUTION_SAVED' + ON_CONTRIBUTION_SAVED = '@@rewards/ON_CONTRIBUTION_SAVED', + ON_INLINE_TIP_SETTINGS_CHANGE = '@@rewards/ON_INLINE_TIP_SETTINGS_CHANGE' } diff --git a/components/brave_rewards/resources/ui/reducers/rewards_reducer.ts b/components/brave_rewards/resources/ui/reducers/rewards_reducer.ts index 2113f76cf111..f7f50c6a0fb6 100644 --- a/components/brave_rewards/resources/ui/reducers/rewards_reducer.ts +++ b/components/brave_rewards/resources/ui/reducers/rewards_reducer.ts @@ -178,6 +178,32 @@ const rewardsReducer: Reducer = (state: Rewards.State } break } + case types.ON_INLINE_TIP_SETTINGS_CHANGE: { + if (!state.inlineTip) { + state.inlineTip = { + twitter: true + } + } + + const key = action.payload.key + const value = action.payload.value + + if (!value || value === '') { + break + } + + let inlineTip = state.inlineTip + + inlineTip[key] = value + chrome.send('brave_rewards.setInlineTipSetting', [key, value.toString()]) + + state = { + ...state, + inlineTip + } + + break + } } return state diff --git a/components/brave_rewards/resources/ui/storage.ts b/components/brave_rewards/resources/ui/storage.ts index b1675e9a9ec3..a5b09aa52131 100644 --- a/components/brave_rewards/resources/ui/storage.ts +++ b/components/brave_rewards/resources/ui/storage.ts @@ -58,7 +58,10 @@ export const defaultState: Rewards.State = { }, pendingContributionTotal: 0, grants: [], - currentGrant: undefined + currentGrant: undefined, + inlineTip: { + twitter: true + } } const cleanData = (state: Rewards.State) => state diff --git a/components/definitions/chromel.d.ts b/components/definitions/chromel.d.ts index cd9f63acae77..0f8e5bdaef52 100644 --- a/components/definitions/chromel.d.ts +++ b/components/definitions/chromel.d.ts @@ -15,6 +15,7 @@ declare namespace chrome.dns { declare namespace chrome.braveRewards { const createWallet: () => {} const tipSite: (tabId: number, publisherKey: string) => {} + const tipTwitterUser: (tabId: number, tweetMetaData: RewardsTip.TweetMetaData) => {} const getPublisherData: (windowId: number, url: string, faviconUrl: string, publisherBlob: string | undefined) => {} const getWalletProperties: () => {} const getCurrentReport: () => {} @@ -73,6 +74,7 @@ declare namespace chrome.braveRewards { } const refreshPublisher: (publisherKey: string, callback: (enabled: boolean, publisherKey: string) => void) => {} const getAllNotifications: (callback: (list: RewardsExtension.Notification[]) => void) => {} + const getInlineTipSetting: (key: string, callback: (enabled: boolean) => void) => {} } declare namespace chrome.rewardsNotifications { diff --git a/components/definitions/rewards.d.ts b/components/definitions/rewards.d.ts index 3fd8dffd2748..d25050f391e3 100644 --- a/components/definitions/rewards.d.ts +++ b/components/definitions/rewards.d.ts @@ -41,6 +41,9 @@ declare namespace Rewards { enabledAds: boolean enabledContribute: boolean enabledMain: boolean + inlineTip: { + twitter: boolean + } firstLoad: boolean | null grants?: Grant[] excludedPublishersNumber: number diff --git a/components/definitions/rewardsTip.d.ts b/components/definitions/rewardsTip.d.ts index 2247fce7f7b2..321065a4979f 100644 --- a/components/definitions/rewardsTip.d.ts +++ b/components/definitions/rewardsTip.d.ts @@ -32,6 +32,15 @@ declare namespace RewardsTip { verified: boolean } + interface TweetMetaData { + name: string + screenName: string + userId: string + tweetId: string + tweetTimestamp: number + tweetText: string + } + export interface WalletProperties { balance: number choices: number[] diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index 104038ad9b07..58501e6f4ce7 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -236,7 +236,7 @@ 5 seconds 8 seconds 1 minute - Enable ability to give tips on ‘Like’ posts + Enable content-level tips on these sites YouTube Twitter Tip on the spot as you find gems. @@ -259,6 +259,9 @@ Recover now! Sorry, it appears that this grant has already been claimed. Next monthly tip date + + I just tipped $1user using the Brave Browser. Check it out at https://brave.com/tips. + Amount: @@ -457,6 +460,7 @@ Settings site sites + Tell others about your tip. Thank you You've just sent a tip to: Tip on like @@ -471,6 +475,8 @@ Turn on Ads This enables both ads and automatic contributions. You can turn them on or off separately at any time. Activate Rewards + Tweet + Tip @{{ user }} for their tweet: Type Brave Verified Publisher View Monthly Statement for Details diff --git a/components/services/bat_ledger/bat_ledger_impl.cc b/components/services/bat_ledger/bat_ledger_impl.cc index eef82fd04a5e..fadebecf8c97 100644 --- a/components/services/bat_ledger/bat_ledger_impl.cc +++ b/components/services/bat_ledger/bat_ledger_impl.cc @@ -511,6 +511,31 @@ void BatLedgerImpl::LoadPublisherInfo( std::bind(BatLedgerImpl::OnLoadPublisherInfo, holder, _1, _2)); } +// static +void BatLedgerImpl::OnSaveMediaInfoCallback( + CallbackHolder* holder, + ledger::Result result, + ledger::PublisherInfoPtr publisher_info) { + if (holder->is_valid()) { + std::move(holder->get()).Run(result, std::move(publisher_info)); + } + + delete holder; +} + +void BatLedgerImpl::SaveMediaInfo( + const std::string& type, + const base::flat_map& args, + SaveMediaInfoCallback callback) { + auto* holder = new CallbackHolder( + AsWeakPtr(), std::move(callback)); + + ledger_->SaveMediaInfo( + type, + mojo::FlatMapToMap(args), + std::bind(BatLedgerImpl::OnSaveMediaInfoCallback, holder, _1, _2)); +} + void BatLedgerImpl::OnRefreshPublisher( CallbackHolder* holder, bool verified) { @@ -534,4 +559,21 @@ void BatLedgerImpl::StartAutoContribute() { ledger_->StartAutoContribute(); } +void BatLedgerImpl::SetInlineTipSetting(const std::string& key, bool enabled) { + ledger_->SetInlineTipSetting(key, enabled); +} + +void BatLedgerImpl::GetInlineTipSetting( + const std::string& key, + GetInlineTipSettingCallback callback) { + std::move(callback).Run(ledger_->GetInlineTipSetting(key)); +} + +void BatLedgerImpl::GetShareURL( + const std::string& type, + const base::flat_map& args, + GetShareURLCallback callback) { + std::move(callback).Run(ledger_->GetShareURL(type, mojo::FlatMapToMap(args))); +} + } // namespace bat_ledger diff --git a/components/services/bat_ledger/bat_ledger_impl.h b/components/services/bat_ledger/bat_ledger_impl.h index f29f3a1b091d..3f15c7370ddf 100644 --- a/components/services/bat_ledger/bat_ledger_impl.h +++ b/components/services/bat_ledger/bat_ledger_impl.h @@ -153,6 +153,22 @@ class BatLedgerImpl : public mojom::BatLedger, const std::string& publisher_key, LoadPublisherInfoCallback callback) override; + void SaveMediaInfo( + const std::string& type, + const base::flat_map& args, + SaveMediaInfoCallback callback) override; + + void SetInlineTipSetting(const std::string& key, bool enabled) override; + + void GetInlineTipSetting( + const std::string& key, + GetInlineTipSettingCallback callback) override; + + void GetShareURL( + const std::string& type, + const base::flat_map& args, + GetShareURLCallback callback) override; + private: void SetCatalogIssuers(const std::string& info) override; void ConfirmAd(const std::string& info) override; @@ -218,6 +234,11 @@ class BatLedgerImpl : public mojom::BatLedger, ledger::Result result, ledger::PublisherInfoPtr info); + static void OnSaveMediaInfoCallback( + CallbackHolder* holder, + ledger::Result result, + ledger::PublisherInfoPtr info); + std::unique_ptr bat_ledger_client_mojo_proxy_; std::unique_ptr ledger_; diff --git a/components/services/bat_ledger/public/interfaces/bat_ledger.mojom b/components/services/bat_ledger/public/interfaces/bat_ledger.mojom index 000195a383b9..37337dff3d1d 100644 --- a/components/services/bat_ledger/public/interfaces/bat_ledger.mojom +++ b/components/services/bat_ledger/public/interfaces/bat_ledger.mojom @@ -118,6 +118,16 @@ interface BatLedger { RefreshPublisher(string publisher_key) => (bool verified); StartAutoContribute(); + + SaveMediaInfo(string type, map args) => (int32 result, + ledger.mojom.PublisherInfo? publisher_info); + + SetInlineTipSetting(string key, bool enabled); + + GetInlineTipSetting(string key) => (bool enabled); + + GetShareURL(string type, map args) => + (string url); }; interface BatLedgerClient { diff --git a/package-lock.json b/package-lock.json index de38530f1760..d289be2340bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -226,9 +226,9 @@ } }, "@ctrl/tinycolor": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-2.4.0.tgz", - "integrity": "sha512-ZLjdsst8/ENM6spDmh3qPQSM+iDSerTGjA05KhAXog7o/aOa9tn7qzWMeOtJzGaDMmsBLxh4IuZ5GH7nfda9gg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-2.5.1.tgz", + "integrity": "sha512-I5SD9ii2gh/4/LNyg+dXG6S5B41bZyQyXCldSZxNHMlNnFtDgo1h7Tn/PiCZ8qlRkAFmv+kx1ay/gtTyCVrGcw==", "dev": true }, "@jest/console": { @@ -562,7 +562,7 @@ }, "@types/filewriter": { "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.28.tgz", + "resolved": "http://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.28.tgz", "integrity": "sha1-wFTor02d11205jq8dviFFocU1LM=", "dev": true }, @@ -1065,7 +1065,7 @@ }, "array-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, @@ -1147,7 +1147,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1259,7 +1259,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1597,8 +1597,8 @@ } }, "brave-ui": { - "version": "github:brave/brave-ui#079dbadba9c270b975eac1962355914a43935b34", - "from": "github:brave/brave-ui#079dbadba9c270b975eac1962355914a43935b34", + "version": "github:brave/brave-ui#a2c96712dc69f033a654fee730feac75f0317c8f", + "from": "github:brave/brave-ui#a2c96712dc69f033a654fee730feac75f0317c8f", "dev": true, "requires": { "@ctrl/tinycolor": "^2.2.1", @@ -1637,7 +1637,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -1679,7 +1679,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1755,7 +1755,7 @@ }, "buffer-equals": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", + "resolved": "http://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=" }, "buffer-fill": { @@ -2206,7 +2206,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -2219,7 +2219,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -2347,7 +2347,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { @@ -2409,7 +2409,7 @@ }, "d": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { @@ -2606,7 +2606,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -2635,7 +2635,7 @@ }, "doctrine": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", + "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", "dev": true, "requires": { @@ -3257,7 +3257,7 @@ }, "file-loader": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "dev": true, "requires": { @@ -4490,7 +4490,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -4557,7 +4557,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -6022,7 +6022,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { @@ -6066,7 +6066,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -6074,7 +6074,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } @@ -6111,7 +6111,7 @@ }, "mp4-stream": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mp4-stream/-/mp4-stream-2.0.3.tgz", + "resolved": "http://registry.npmjs.org/mp4-stream/-/mp4-stream-2.0.3.tgz", "integrity": "sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g==", "requires": { "buffer-alloc": "^1.1.0", @@ -6209,7 +6209,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -6295,7 +6295,7 @@ "dependencies": { "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -6539,7 +6539,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true } @@ -6732,7 +6732,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -6750,7 +6750,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { @@ -7345,7 +7345,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -7659,7 +7659,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -7764,7 +7764,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -8116,7 +8116,7 @@ }, "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, @@ -8318,7 +8318,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -8326,7 +8326,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -8341,7 +8341,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -8369,7 +8369,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, @@ -8570,7 +8570,7 @@ }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -8856,7 +8856,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -9129,7 +9129,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, @@ -9267,7 +9267,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -9602,7 +9602,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -9621,7 +9621,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { diff --git a/package.json b/package.json index c3cdbe91cad7..594ebe4ecb03 100644 --- a/package.json +++ b/package.json @@ -277,7 +277,7 @@ "@types/react-redux": "6.0.4", "@types/redux-logger": "^3.0.7", "awesome-typescript-loader": "^5.2.1", - "brave-ui": "github:brave/brave-ui#079dbadba9c270b975eac1962355914a43935b34", + "brave-ui": "github:brave/brave-ui#a2c96712dc69f033a654fee730feac75f0317c8f", "css-loader": "^2.1.1", "csstype": "^2.5.5", "deep-freeze-node": "^1.1.3", diff --git a/vendor/bat-native-ledger/BUILD.gn b/vendor/bat-native-ledger/BUILD.gn index 97eb7594f35d..629e23586d86 100644 --- a/vendor/bat-native-ledger/BUILD.gn +++ b/vendor/bat-native-ledger/BUILD.gn @@ -112,6 +112,8 @@ source_set("ledger") { "src/bat/ledger/internal/media/helper.cc", "src/bat/ledger/internal/media/twitch.h", "src/bat/ledger/internal/media/twitch.cc", + "src/bat/ledger/internal/media/twitter.h", + "src/bat/ledger/internal/media/twitter.cc", "src/bat/ledger/internal/media/youtube.h", "src/bat/ledger/internal/media/youtube.cc", "src/bat/ledger/ledger.cc", diff --git a/vendor/bat-native-ledger/include/bat/ledger/ledger.h b/vendor/bat-native-ledger/include/bat/ledger/ledger.h index 799f15afac62..3df02bdce271 100644 --- a/vendor/bat-native-ledger/include/bat/ledger/ledger.h +++ b/vendor/bat-native-ledger/include/bat/ledger/ledger.h @@ -224,11 +224,6 @@ class LEDGER_EXPORT Ledger { virtual void RecoverWallet(const std::string& passPhrase) const = 0; - virtual void SaveMediaVisit(const std::string& publisher_id, - const ledger::VisitData& visit_data, - const uint64_t& duration, - const uint64_t window_id) = 0; - virtual void SetPublisherExclude( const std::string& publisher_id, const ledger::PUBLISHER_EXCLUDE& exclude) = 0; @@ -287,6 +282,18 @@ class LEDGER_EXPORT Ledger { ledger::OnRefreshPublisherCallback callback) = 0; virtual void StartAutoContribute() = 0; + + virtual void SaveMediaInfo(const std::string& type, + const std::map& data, + ledger::PublisherInfoCallback callback) = 0; + + virtual void SetInlineTipSetting(const std::string& key, bool enabled) = 0; + + virtual bool GetInlineTipSetting(const std::string& key) = 0; + + virtual std::string GetShareURL( + const std::string& type, + const std::map& args) = 0; }; } // namespace ledger diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.cc index 63be251c70b2..99179412b242 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.cc @@ -17,7 +17,8 @@ namespace braveledger_bat_get_media { BatGetMedia::BatGetMedia(bat_ledger::LedgerImpl* ledger): ledger_(ledger), media_youtube_(new braveledger_media::MediaYouTube(ledger)), - media_twitch_(new braveledger_media::MediaTwitch(ledger)) { + media_twitch_(new braveledger_media::MediaTwitch(ledger)), + media_twitter_(new braveledger_media::MediaTwitter(ledger)) { } BatGetMedia::~BatGetMedia() {} @@ -101,4 +102,22 @@ void BatGetMedia::OnMediaActivityError(const ledger::VisitData& visit_data, } } +void BatGetMedia::SaveMediaInfo(const std::string& type, + const std::map& data, + ledger::PublisherInfoCallback callback) { + if (type == TWITTER_MEDIA_TYPE) { + media_twitter_->SaveMediaInfo(data, callback); + return; + } +} + +std::string BatGetMedia::GetShareURL( + const std::string& type, + const std::map& args) { + if (type == TWITTER_MEDIA_TYPE) + return media_twitter_->GetShareURL(args); + + return std::string(); +} + } // namespace braveledger_bat_get_media diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.h b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.h index fd05080149ef..aac836162280 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_get_media.h @@ -12,6 +12,7 @@ #include "bat/ledger/internal/bat_helper.h" #include "bat/ledger/internal/media/twitch.h" +#include "bat/ledger/internal/media/twitter.h" #include "bat/ledger/internal/media/youtube.h" #include "bat/ledger/ledger.h" @@ -40,6 +41,13 @@ class BatGetMedia { const std::string& type, const std::string& publisher_blob); + void SaveMediaInfo(const std::string& type, + const std::map& data, + ledger::PublisherInfoCallback callback); + + std::string GetShareURL(const std::string& type, + const std::map& args); + private: void OnMediaActivityError(const ledger::VisitData& visit_data, const std::string& type, @@ -48,6 +56,7 @@ class BatGetMedia { bat_ledger::LedgerImpl* ledger_; // NOT OWNED std::unique_ptr media_youtube_; std::unique_ptr media_twitch_; + std::unique_ptr media_twitter_; }; } // namespace braveledger_bat_get_media diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc index 67243122211a..ed8f5277a592 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.cc @@ -1507,6 +1507,7 @@ CLIENT_STATE_ST::CLIENT_STATE_ST(const CLIENT_STATE_ST& other) { auto_contribute_ = other.auto_contribute_; rewards_enabled_ = other.rewards_enabled_; current_reconciles_ = other.current_reconciles_; + inline_tip_ = other.inline_tip_; } CLIENT_STATE_ST::~CLIENT_STATE_ST() {} @@ -1625,6 +1626,13 @@ bool CLIENT_STATE_ST::loadFromJson(const std::string & json) { i.Accept(writer); walletProperties_.loadFromJson(sb.GetString()); } + + if (d.HasMember("inlineTip") && d["inlineTip"].IsObject()) { + for (auto & k : d["inlineTip"].GetObject()) { + inline_tip_.insert( + std::make_pair(k.name.GetString(), k.value.GetBool())); + } + } } return !error; @@ -1719,6 +1727,14 @@ void saveToJson(JsonWriter* writer, const CLIENT_STATE_ST& data) { writer->String("walletProperties"); saveToJson(writer, data.walletProperties_); + writer->String("inlineTip"); + writer->StartObject(); + for (auto & p : data.inline_tip_) { + writer->String(p.first.c_str()); + writer->Bool(p.second); + } + writer->EndObject(); + writer->EndObject(); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h index c2087175828d..1aaa15cb923b 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_helper.h @@ -365,6 +365,7 @@ struct CLIENT_STATE_ST { CurrentReconciles current_reconciles_; bool auto_contribute_ = false; bool rewards_enabled_ = false; + std::map inline_tip_; }; struct GRANTS_PROPERTIES_ST { diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.cc index f29590fb1934..7ebdd8b5968d 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.cc @@ -68,6 +68,8 @@ std::string getProviderName(const std::string& publisher_id) { return YOUTUBE_MEDIA_TYPE; } else if (publisher_id.find(TWITCH_MEDIA_TYPE) != std::string::npos) { return TWITCH_MEDIA_TYPE; + } else if (publisher_id.find(TWITTER_MEDIA_TYPE) != std::string::npos) { + return TWITTER_MEDIA_TYPE; } return ""; } @@ -85,7 +87,8 @@ void BatPublishers::AddRecurringPayment(const std::string& publisher_id, void BatPublishers::saveVisit(const std::string& publisher_id, const ledger::VisitData& visit_data, const uint64_t& duration, - uint64_t window_id) { + uint64_t window_id, + const ledger::PublisherInfoCallback callback) { if (!ledger_->GetRewardsMainEnabled() || publisher_id.empty()) { return; } @@ -103,6 +106,7 @@ void BatPublishers::saveVisit(const std::string& publisher_id, visit_data, duration, window_id, + callback, _1, _2); ledger_->GetActivityInfo(filter, callbackGetPublishers); @@ -137,12 +141,13 @@ void BatPublishers::saveVisitInternal( ledger::VisitData visit_data, uint64_t duration, uint64_t window_id, + const ledger::PublisherInfoCallback callback, ledger::Result result, ledger::PublisherInfoPtr publisher_info) { DCHECK(result != ledger::Result::TOO_MANY_RESULTS); if (result != ledger::Result::LEDGER_OK && result != ledger::Result::NOT_FOUND) { - // TODO(anyone) error handling + callback(ledger::Result::LEDGER_ERROR, nullptr); return; } bool verified = isVerified(publisher_id); @@ -221,15 +226,20 @@ void BatPublishers::saveVisitInternal( ledger_->SetActivityInfo(std::move(publisher_info)); } - if (panel_info && window_id > 0) { + if (panel_info) { if (panel_info->favicon_url == ledger::_clear_favicon) { panel_info->favicon_url = std::string(); } - OnPanelPublisherInfo(ledger::Result::LEDGER_OK, - std::move(panel_info), - window_id, - visit_data); + auto callback_info = panel_info->Clone(); + callback(ledger::Result::LEDGER_OK, std::move(callback_info)); + + if (window_id > 0) { + OnPanelPublisherInfo(ledger::Result::LEDGER_OK, + std::move(panel_info), + window_id, + visit_data); + } } } @@ -735,6 +745,12 @@ void BatPublishers::getPublisherActivityFromUrl( new_data)); } +void BatPublishers::OnSaveVisitInternal( + ledger::Result result, + ledger::PublisherInfoPtr info) { + // TODO(nejczdovc): handle if needed +} + void BatPublishers::OnPanelPublisherInfo( ledger::Result result, ledger::PublisherInfoPtr info, @@ -745,10 +761,16 @@ void BatPublishers::OnPanelPublisherInfo( } if (result == ledger::Result::NOT_FOUND && !visit_data.domain.empty()) { + auto callback = std::bind(&BatPublishers::OnSaveVisitInternal, + this, + _1, + _2); + saveVisitInternal(visit_data.domain, visit_data, 0, windowId, + callback, result, nullptr); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.h b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.h index d65dc4d4370c..ce47b0384e6b 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_publishers.h @@ -38,7 +38,8 @@ class BatPublishers : public ledger::LedgerCallbackHandler { void saveVisit(const std::string& publisher_id, const ledger::VisitData& visit_data, const uint64_t& duration, - uint64_t window_id); + uint64_t window_id, + const ledger::PublisherInfoCallback callback); void AddRecurringPayment(const std::string& publisher_id, const double& value); @@ -144,6 +145,7 @@ class BatPublishers : public ledger::LedgerCallbackHandler { ledger::VisitData visit_data, uint64_t duration, uint64_t window_id, + const ledger::PublisherInfoCallback callback, ledger::Result result, ledger::PublisherInfoPtr publisher_info); @@ -186,6 +188,10 @@ class BatPublishers : public ledger::LedgerCallbackHandler { bool isPublisherVisible( const braveledger_bat_helper::PUBLISHER_ST& publisher_st); + void OnSaveVisitInternal( + ledger::Result result, + ledger::PublisherInfoPtr info); + void OnPanelPublisherInfo( ledger::Result result, ledger::PublisherInfoPtr publisher_info, diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.cc index e02944d34d7e..b91d4beeeb22 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.cc @@ -412,4 +412,18 @@ void BatState::SetAddress(std::map addresses) { SaveState(); } +void BatState::SetInlineTipSetting(const std::string& key, bool enabled) { + state_->inline_tip_[key] = enabled; + SaveState(); +} + +bool BatState::GetInlineTipSetting(const std::string& key) const { + if (state_->inline_tip_.find(key) == state_->inline_tip_.end()) { + // not found, all tips are on by default + return true; + } else { + return state_->inline_tip_[key]; + } +} + } // namespace braveledger_bat_state diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.h b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.h index 06fa80ddd145..4fe6bebbd953 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/bat_state.h @@ -149,6 +149,10 @@ class BatState { void SetAddress(std::map addresses); + void SetInlineTipSetting(const std::string& key, bool enabled); + + bool GetInlineTipSetting(const std::string& key) const; + private: void SaveState(); diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc index 82e9d4743780..0d86688feeb3 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.cc @@ -146,17 +146,35 @@ void LedgerImpl::OnShow(uint32_t tab_id, const uint64_t& current_time) { last_shown_tab_id_ = tab_id; } +void LedgerImpl::OnSaveVisit( + ledger::Result result, + ledger::PublisherInfoPtr info) { + // TODO(nejczdovc): handle if needed +} + void LedgerImpl::OnHide(uint32_t tab_id, const uint64_t& current_time) { if (tab_id != last_shown_tab_id_) { return; } + visit_data_iter iter = current_pages_.find(tab_id); if (iter == current_pages_.end() || last_tab_active_time_ == 0) { return; } + DCHECK(last_tab_active_time_); + + auto callback = std::bind(&LedgerImpl::OnSaveVisit, + this, + _1, + _2); + bat_publishers_->saveVisit( - iter->second.tld, iter->second, current_time - last_tab_active_time_, 0); + iter->second.tld, + iter->second, + current_time - last_tab_active_time_, + 0, + callback); last_tab_active_time_ = 0; } @@ -420,13 +438,18 @@ void LedgerImpl::SetMediaPublisherInfo(const std::string& media_key, void LedgerImpl::SaveMediaVisit(const std::string& publisher_id, const ledger::VisitData& visit_data, const uint64_t& duration, - const uint64_t window_id) { + const uint64_t window_id, + const ledger::PublisherInfoCallback callback) { uint64_t new_duration = duration; if (!bat_publishers_->getPublisherAllowVideos()) { new_duration = 0; } - bat_publishers_->saveVisit(publisher_id, visit_data, new_duration, window_id); + bat_publishers_->saveVisit(publisher_id, + visit_data, + new_duration, + window_id, + callback); } void LedgerImpl::SetPublisherExclude( @@ -1504,4 +1527,24 @@ scoped_refptr LedgerImpl::GetTaskRunner() { return task_runner_; } +void LedgerImpl::SaveMediaInfo(const std::string& type, + const std::map& data, + ledger::PublisherInfoCallback callback) { + bat_get_media_->SaveMediaInfo(type, data, callback); +} + +void LedgerImpl::SetInlineTipSetting(const std::string& key, bool enabled) { + bat_state_->SetInlineTipSetting(key, enabled); +} + +bool LedgerImpl::GetInlineTipSetting(const std::string& key) { + return bat_state_->GetInlineTipSetting(key); +} + +std::string LedgerImpl::GetShareURL( + const std::string& type, + const std::map& args) { + return bat_get_media_->GetShareURL(type, args); +} + } // namespace bat_ledger diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h index 351ce3a79274..37d2d64f891d 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/ledger_impl.h @@ -234,7 +234,8 @@ class LedgerImpl : public ledger::Ledger, void SaveMediaVisit(const std::string& publisher_id, const ledger::VisitData& visit_data, const uint64_t& duration, - const uint64_t window_id) override; + const uint64_t window_id, + const ledger::PublisherInfoCallback callback); void SetPublisherExclude( const std::string& publisher_id, @@ -440,6 +441,18 @@ class LedgerImpl : public ledger::Ledger, const std::string& publisher_key, ledger::OnRefreshPublisherCallback callback) override; + void SaveMediaInfo(const std::string& type, + const std::map& data, + ledger::PublisherInfoCallback callback) override; + + void SetInlineTipSetting(const std::string& key, bool enabled) override; + + bool GetInlineTipSetting(const std::string& key) override; + + std::string GetShareURL( + const std::string& type, + const std::map& args) override; + private: void AddRecurringPayment(const std::string& publisher_id, const double& value) override; @@ -451,6 +464,9 @@ class LedgerImpl : public ledger::Ledger, void OnShow(uint32_t tab_id, const uint64_t& current_time) override; + void OnSaveVisit(ledger::Result result, + ledger::PublisherInfoPtr info); + void OnHide(uint32_t tab_id, const uint64_t& current_time) override; void OnForeground(uint32_t tab_id, const uint64_t& current_time) override; diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.cc index 467901b4bc9b..71c32eea9a36 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.cc @@ -363,6 +363,12 @@ void MediaTwitch::ProcessActivityFromUrl(uint64_t window_id, } } +void MediaTwitch::OnSaveMediaVisit( + ledger::Result result, + ledger::PublisherInfoPtr info) { + // TODO(nejczdovc): handle if needed +} + void MediaTwitch::OnMediaPublisherInfo( const std::string& media_id, const std::string& media_key, @@ -405,8 +411,6 @@ void MediaTwitch::OnMediaPublisherInfo( updated_visit_data.favicon_url = ""; updated_visit_data.provider = TWITCH_MEDIA_TYPE; - - if (media_id.find("_vod_") != std::string::npos) { // VOD std::vector media_props = @@ -422,18 +426,17 @@ void MediaTwitch::OnMediaPublisherInfo( updated_visit_data.name = new_id; updated_visit_data.url = media_url + "/videos"; - auto callback = std::bind( - &MediaTwitch::OnEmbedResponse, - this, - real_duration, - media_key, - media_url, - updated_visit_data, - window_id, - user_id, - _1, - _2, - _3); + auto callback = std::bind(&MediaTwitch::OnEmbedResponse, + this, + real_duration, + media_key, + media_url, + updated_visit_data, + window_id, + user_id, + _1, + _2, + _3); const std::string url = (std::string)TWITCH_PROVIDER_URL + "?json&url=" + ledger_->URIEncode(oembed_url); @@ -447,10 +450,16 @@ void MediaTwitch::OnMediaPublisherInfo( updated_visit_data.name = media_id; updated_visit_data.url = GetMediaURL(media_id) + "/videos"; + auto callback = std::bind(&MediaTwitch::OnSaveMediaVisit, + this, + _1, + _2); + ledger_->SaveMediaVisit(publisher_key, updated_visit_data, real_duration, - window_id); + window_id, + callback); ledger_->SetMediaPublisherInfo(media_key, publisher_key); } else { ledger::VisitData updated_visit_data(visit_data); @@ -473,7 +482,16 @@ void MediaTwitch::OnMediaPublisherInfo( twitch_events[media_key] = new_event; std::string id = publisher_info->id; - ledger_->SaveMediaVisit(id, updated_visit_data, real_duration, window_id); + auto callback = std::bind(&MediaTwitch::OnSaveMediaVisit, + this, + _1, + _2); + + ledger_->SaveMediaVisit(id, + updated_visit_data, + real_duration, + window_id, + callback); } } @@ -521,7 +539,16 @@ void MediaTwitch::OnEmbedResponse( updated_visit_data.favicon_url = fav_icon; } - ledger_->SaveMediaVisit(id, updated_visit_data, duration, window_id); + auto callback = std::bind(&MediaTwitch::OnSaveMediaVisit, + this, + _1, + _2); + + ledger_->SaveMediaVisit(id, + updated_visit_data, + duration, + window_id, + callback); ledger_->SetMediaPublisherInfo(media_key, id); } @@ -646,10 +673,16 @@ void MediaTwitch::SavePublisherInfo(const uint64_t duration, updated_visit_data.name = publisher_name; updated_visit_data.url = url; + auto callback = std::bind(&MediaTwitch::OnSaveMediaVisit, + this, + _1, + _2); + ledger_->SaveMediaVisit(publisher_id, updated_visit_data, duration, - window_id); + window_id, + callback); if (!media_key.empty()) { ledger_->SetMediaPublisherInfo(media_key, publisher_id); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.h b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.h index b3736aec1a6f..cbdc5f53a02f 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitch.h @@ -72,6 +72,9 @@ class MediaTwitch : public ledger::LedgerCallbackHandler { static std::string GetFaviconUrl(const std::string& publisher_blob, const std::string& twitchHandle); + void OnSaveMediaVisit(ledger::Result result, + ledger::PublisherInfoPtr info); + void OnMediaPublisherInfo( const std::string& media_id, const std::string& media_key, diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.cc new file mode 100644 index 000000000000..f9ee08dd414b --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.cc @@ -0,0 +1,184 @@ +/* Copyright (c) 2019 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include + +#include "base/strings/stringprintf.h" +#include "bat/ledger/internal/ledger_impl.h" +#include "bat/ledger/internal/media/helper.h" +#include "bat/ledger/internal/media/twitter.h" + +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +namespace braveledger_media { + +MediaTwitter::MediaTwitter(bat_ledger::LedgerImpl* ledger): + ledger_(ledger) { +} + +MediaTwitter::~MediaTwitter() { +} + +// static +std::string MediaTwitter::GetProfileURL(const std::string& screen_name) { + if (screen_name.empty()) { + return std::string(); + } + + return base::StringPrintf("https://twitter.com/%s/", screen_name.c_str()); +} + +// static +std::string MediaTwitter::GetProfileImageURL(const std::string& screen_name) { + if (screen_name.empty()) { + return std::string(); + } + + return base::StringPrintf( + "https://twitter.com/%s/profile_image?size=original", + screen_name.c_str()); +} + +// static +std::string MediaTwitter::GetPublisherKey(const std::string& key) { + if (key.empty()) { + return std::string(); + } + + return (std::string)TWITTER_MEDIA_TYPE + "#channel:" + key; +} + +// static +std::string MediaTwitter::GetMediaKey(const std::string& screen_name) { + if (screen_name.empty()) { + return std::string(); + } + + return (std::string)TWITTER_MEDIA_TYPE + "_" + screen_name; +} + +void MediaTwitter::SaveMediaInfo(const std::map& data, + ledger::PublisherInfoCallback callback) { + auto user_id = data.find("user_id"); + auto screen_name = data.find("screen_name"); + if (user_id == data.end() || screen_name == data.end()) { + callback(ledger::Result::LEDGER_ERROR, nullptr); + return; + } + + const std::string media_key = GetMediaKey(screen_name->second); + + auto name = data.find("name"); + std::string publisher_name = screen_name->second; + if (name != data.end()) { + publisher_name = name->second; + } + + ledger_->GetMediaPublisherInfo( + media_key, + std::bind(&MediaTwitter::OnMediaPublisherInfo, + this, + 0, + user_id->second, + screen_name->second, + publisher_name, + callback, + _1, + _2)); +} + +std::string MediaTwitter::GetShareURL( + const std::map& args) { + auto comment = args.find("comment"); + auto name = args.find("name"); + auto tweet_id = args.find("tweet_id"); + if (comment == args.end() || name == args.end() || tweet_id == args.end()) + return std::string(); + + // If a tweet ID was specified, then quote the original tweet along + // with the supplied comment; otherwise, just tweet the comment. + std::string share_url; + if (!tweet_id->second.empty()) { + std::string quoted_tweet_url = + base::StringPrintf("https://twitter.com/%s/status/%s", + name->second.c_str(), tweet_id->second.c_str()); + share_url = + base::StringPrintf("https://twitter.com/intent/tweet?url=%s&text=%s", + quoted_tweet_url.c_str(), comment->second.c_str()); + } else { + share_url = base::StringPrintf("https://twitter.com/intent/tweet?text=%s", + comment->second.c_str()); + } + return share_url; +} + +void MediaTwitter::OnMediaPublisherInfo( + uint64_t window_id, + const std::string& user_id, + const std::string& screen_name, + const std::string& publisher_name, + ledger::PublisherInfoCallback callback, + ledger::Result result, + ledger::PublisherInfoPtr publisher_info) { + if (result != ledger::Result::LEDGER_OK && + result != ledger::Result::NOT_FOUND) { + callback(ledger::Result::LEDGER_ERROR, nullptr); + return; + } + + if (!publisher_info || result == ledger::Result::NOT_FOUND) { + SavePublisherInfo(0, + user_id, + screen_name, + publisher_name, + window_id, + callback); + } else { + // TODO(nejczdovc): we need to check if user is verified, + // but his image was not saved yet, so that we can fix it + callback(result, std::move(publisher_info)); + } +} + +void MediaTwitter::SavePublisherInfo( + const uint64_t duration, + const std::string& user_id, + const std::string& screen_name, + const std::string& publisher_name, + const uint64_t window_id, + ledger::PublisherInfoCallback callback) { + const std::string publisher_key = GetPublisherKey(user_id); + const std::string url = GetProfileURL(screen_name); + const std::string favicon_url = GetProfileImageURL(screen_name); + const std::string media_key = GetMediaKey(screen_name); + + if (publisher_key.empty()) { + callback(ledger::Result::LEDGER_ERROR, nullptr); + BLOG(ledger_, ledger::LogLevel::LOG_ERROR) << + "Publisher key is missing for: " << media_key; + return; + } + + ledger::VisitData visit_data; + visit_data.provider = TWITTER_MEDIA_TYPE; + visit_data.url = url; + visit_data.favicon_url = favicon_url; + visit_data.name = publisher_name; + + ledger_->SaveMediaVisit(publisher_key, + visit_data, + duration, + window_id, + callback); + if (!media_key.empty()) { + ledger_->SetMediaPublisherInfo(media_key, publisher_key); + } +} + +} // namespace braveledger_media diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.h b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.h new file mode 100644 index 000000000000..4e5f72c3f902 --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2019 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVELEDGER_MEDIA_TWITTER_H_ +#define BRAVELEDGER_MEDIA_TWITTER_H_ + +#include +#include +#include + +#include "base/gtest_prod_util.h" +#include "bat/ledger/ledger.h" + +namespace bat_ledger { +class LedgerImpl; +} + +namespace braveledger_media { + +class MediaTwitter : public ledger::LedgerCallbackHandler { + public: + explicit MediaTwitter(bat_ledger::LedgerImpl* ledger); + + ~MediaTwitter() override; + + void SaveMediaInfo(const std::map& data, + ledger::PublisherInfoCallback callback); + + std::string GetShareURL(const std::map& args); + + private: + static std::string GetProfileURL(const std::string& screen_name); + + static std::string GetProfileImageURL(const std::string& screen_name); + + static std::string GetPublisherKey(const std::string& key); + + static std::string GetMediaKey(const std::string& screen_name); + + void OnMediaPublisherInfo( + uint64_t window_id, + const std::string& user_id, + const std::string& screen_name, + const std::string& publisher_name, + ledger::PublisherInfoCallback callback, + ledger::Result result, + ledger::PublisherInfoPtr publisher_info); + + void SavePublisherInfo( + const uint64_t duration, + const std::string& user_id, + const std::string& screen_name, + const std::string& publisher_name, + const uint64_t window_id, + ledger::PublisherInfoCallback callback); + + bat_ledger::LedgerImpl* ledger_; // NOT OWNED +}; + +} // namespace braveledger_media + +#endif // BRAVELEDGER_MEDIA_TWITTER_H_ diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter_unittest.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter_unittest.cc new file mode 100644 index 000000000000..63845bd66324 --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/twitter_unittest.cc @@ -0,0 +1,19 @@ +/* Copyright (c) 2019 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ledger/internal/media/twitter.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=MediaTwitterTest.* + +namespace braveledger_media { + +class MediaTwitterTest : public testing::Test { +}; + +TEST(MediaTwitterTest, GetProfileURL) { +} + +} // namespace braveledger_media diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.cc index 8277957e4c8f..f5bdfddc95c2 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.cc @@ -376,6 +376,12 @@ void MediaYouTube::ProcessActivityFromUrl(uint64_t window_id, OnMediaActivityError(visit_data, window_id); } +void MediaYouTube::OnSaveMediaVisit( + ledger::Result result, + ledger::PublisherInfoPtr info) { + // TODO(nejczdovc): handle if needed +} + void MediaYouTube::OnMediaPublisherInfo( const std::string& media_id, const std::string& media_key, @@ -417,7 +423,17 @@ void MediaYouTube::OnMediaPublisherInfo( updated_visit_data.provider = YOUTUBE_MEDIA_TYPE; updated_visit_data.favicon_url = publisher_info->favicon_url; std::string id = publisher_info->id; - ledger_->SaveMediaVisit(id, updated_visit_data, duration, window_id); + + auto callback = std::bind(&MediaYouTube::OnSaveMediaVisit, + this, + _1, + _2); + + ledger_->SaveMediaVisit(id, + updated_visit_data, + duration, + window_id, + callback); } } @@ -545,10 +561,16 @@ void MediaYouTube::SavePublisherInfo(const uint64_t duration, updated_visit_data.name = publisher_name; updated_visit_data.url = url; + auto callback = std::bind(&MediaYouTube::OnSaveMediaVisit, + this, + _1, + _2); + ledger_->SaveMediaVisit(publisher_id, updated_visit_data, duration, - window_id); + window_id, + callback); if (!media_key.empty()) { ledger_->SetMediaPublisherInfo(media_key, publisher_id); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.h b/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.h index 3e16b2f7d264..3aef269d4c82 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/media/youtube.h @@ -71,6 +71,9 @@ class MediaYouTube : public ledger::LedgerCallbackHandler { void OnMediaActivityError(const ledger::VisitData& visit_data, uint64_t window_id); + void OnSaveMediaVisit(ledger::Result result, + ledger::PublisherInfoPtr info); + void OnMediaPublisherInfo( const std::string& media_id, const std::string& media_key, diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/static_values.h b/vendor/bat-native-ledger/src/bat/ledger/internal/static_values.h index 9935fd7ca9f8..20d27b259a7b 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/static_values.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/static_values.h @@ -63,6 +63,7 @@ #define YOUTUBE_MEDIA_TYPE "youtube" #define TWITCH_MEDIA_TYPE "twitch" +#define TWITTER_MEDIA_TYPE "twitter" #define YOUTUBE_PROVIDER_URL "https://www.youtube.com/oembed" #define TWITCH_PROVIDER_URL "https://api.twitch.tv/v5/oembed" #define YOUTUBE_TLD "youtube.com"