From 2850702c8a76736d746686bfa8b854aa5e154d2b Mon Sep 17 00:00:00 2001 From: Ayumi Yu Date: Tue, 20 Sep 2016 18:13:34 -0700 Subject: [PATCH 1/2] Record firstRunTimestamp in sessionStore Auditors: @bsclifton Test Plan: Upgrading existing userData 1. Be on `master` and close Brave 2. Open session-store-1 with less (e.g. ~/Library/Application\ Support/brave-development/session-store-1) 3. See firstRunTimestamp is not there 4. Check out this branch 5. Open Brave, then close it 6. View again session-store-1 and see firstRunTimestamp is there 8. Restart Brave again, then close it 9. See firstRunTimestamp is see firstRunTimestamp is unchanged New profile 1. Delete userData dir (e.g. ~/Library/Application\ Support/brave-development) 2. Open Brave 3. Close Brave 4. View session-store-1 and see firstRunTimestamp --- app/sessionStore.js | 3 +++ docs/state.md | 1 + test/app/sessionStoreTest.js | 41 ++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/app/sessionStore.js b/app/sessionStore.js index 63bc076f908..3363dd354ec 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -356,6 +356,9 @@ module.exports.loadAppState = () => { module.exports.cleanAppData(data, false) } data = Object.assign(module.exports.defaultAppState(), data) + if (!data.firstRunTimestamp) { + data.firstRunTimestamp = new Date().getTime() + } data.cleanedOnShutdown = false // Always recalculate the update status if (data.updates) { diff --git a/docs/state.md b/docs/state.md index bcc3129dc97..3dbf4b7ef1f 100644 --- a/docs/state.md +++ b/docs/state.md @@ -9,6 +9,7 @@ AppStore ```javascript { + firstRunTimestamp: integer, extensions: { [id]: { // the unique id of the extension id: string, diff --git a/test/app/sessionStoreTest.js b/test/app/sessionStoreTest.js index e61bd5789d7..0627bf24a13 100644 --- a/test/app/sessionStoreTest.js +++ b/test/app/sessionStoreTest.js @@ -60,4 +60,45 @@ describe('sessionStore', function () { yield Brave.app.client.waitForExist(navigatorBookmarked) }) }) + + describe('firstRunTimestamp', function () { + Brave.beforeAllServerSetup(this) + before(function * () { + // AY: Why do I need to start, stop and start for this to work properly? + yield Brave.startApp() + yield setup(Brave.app.client) + yield Brave.stopApp(false) + yield Brave.startApp() + yield setup(Brave.app.client) + }) + + after(function * () { + yield Brave.stopApp() + }) + + it('sets it once', function * () { + const timestamp = new Date().getTime() + let firstRunTimestamp + yield Brave.app.client + .waitUntil(function () { + return this.getAppState().then((val) => { + firstRunTimestamp = val.value.firstRunTimestamp + return ( + firstRunTimestamp > (timestamp - 30 * 1000) && + firstRunTimestamp <= timestamp + ) + }) + }) + + yield Brave.stopApp(false) + yield Brave.startApp() + yield setup(Brave.app.client) + yield Brave.app.client + .waitUntil(function () { + return this.getAppState().then((val) => { + return (val.value.firstRunTimestamp === firstRunTimestamp) + }) + }) + }) + }) }) From 35971f58374f99a0dc603b223b060e716fe1a645 Mon Sep 17 00:00:00 2001 From: Ayumi Yu Date: Tue, 20 Sep 2016 19:10:34 -0700 Subject: [PATCH 2/2] Notification suggesting the user try Payments Auditors: @bsclifton @diracdeltas Test Plan: 1. Edit `ledger.js` to reduce showNotifications delay interval to 3 * msecs.second 2. Run Brave with an existing profile 3. Confirm there's no notification 4. Close Brave 5. Update userData session-store-1 firstRunTimestamp to be way in the past e.g. from '14..' to '13..' (~/Library/Application\ Support/session-store-1) 6. Open Brave 7. Confirm notification --- .../brave/locales/en-US/app.properties | 3 + app/ledger.js | 73 +++++++++++++++---- app/locale.js | 3 + js/constants/appConfig.js | 4 + js/constants/settings.js | 1 + 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/app/extensions/brave/locales/en-US/app.properties b/app/extensions/brave/locales/en-US/app.properties index 892dc2b2680..39b5ebb74fc 100644 --- a/app/extensions/brave/locales/en-US/app.properties +++ b/app/extensions/brave/locales/en-US/app.properties @@ -170,9 +170,12 @@ notificationPasswordWithUserName=Would you like Brave to remember the password f notificationPassword=Would you like Brave to remember your password on {{origin}}? notificationPasswordSettings=[Password settings] notificationPaymentDone=Your contribution of {{amount}} {{currency}} has been processed. Thanks for supporting your favorite websites! +notificationTryPayments=Are you ready to support the sites you use most? +notificationTryPaymentsYes=Sure, I'll try prefsRestart=Do you want to restart now? yes=Yes no=No +noThanks=No thanks neverForThisSite=Never for this site browserHistory=Browser history downloadHistory=Download history diff --git a/app/ledger.js b/app/ledger.js index 7fd382d40bd..b08223a1280 100644 --- a/app/ledger.js +++ b/app/ledger.js @@ -41,6 +41,7 @@ const underscore = require('underscore') const uuid = require('node-uuid') const appActions = require('../js/actions/appActions') +const appConfig = require('../js/constants/appConfig') const appConstants = require('../js/constants/appConstants') const appDispatcher = require('../js/dispatcher/appDispatcher') const messages = require('../js/constants/messages') @@ -100,6 +101,7 @@ const msecs = { year: 365 * 24 * 60 * 60 * 1000, let addFundsMessage let reconciliationMessage let notificationPaymentDoneMessage +let notificationTryPaymentsMessage let suppressNotifications = false let reconciliationNotificationShown = false let notificationTimeout = null @@ -252,6 +254,13 @@ if (ipc) { setTimeout(() => { reconciliationNotificationShown = false }, 1 * msecs.day) } else if (message === notificationPaymentDoneMessage) { appActions.hideMessageBox(message) + } else if (message === notificationTryPaymentsMessage) { + appActions.hideMessageBox(message) + if (buttonIndex === 1 && win) { + win.webContents.send(messages.SHORTCUT_NEW_FRAME, + 'about:preferences#payments', { singleFrame: true }) + } + appActions.changeSetting(settings.PAYMENTS_NOTIFICATION_TRY_PAYMENTS_DISMISSED, true) } }) @@ -383,6 +392,12 @@ eventStore.addChangeListener(() => { var initialize = (onoff) => { enable(onoff) + // Check if relevant browser notifications should be shown every 15 minutes + if (notificationTimeout) { + clearInterval(notificationTimeout) + } + notificationTimeout = setInterval(showNotifications, 15 * msecs.minute) + if (!onoff) { client = null return appActions.updateLedgerInfo({}) @@ -430,12 +445,12 @@ var initialize = (onoff) => { } var enable = (onoff) => { + if (onoff && !getSetting(settings.PAYMENTS_NOTIFICATION_TRY_PAYMENTS_DISMISSED)) { + appActions.changeSetting(settings.PAYMENTS_NOTIFICATION_TRY_PAYMENTS_DISMISSED, true) + } + if (!onoff) { synopsis = null - if (notificationTimeout) { - clearInterval(notificationTimeout) - notificationTimeout = null - } return updatePublisherInfo() } @@ -475,9 +490,6 @@ var enable = (onoff) => { }) updatePublisherInfo() - // Check if relevant browser notifications should be shown every 15 minutes - notificationTimeout = setInterval(showNotifications, 15 * msecs.minute) - fs.readFile(pathName(publisherPath), (err, data) => { if (err) { if (err.code !== 'ENOENT') console.log('publisherPath read error: ' + err.toString()) @@ -1290,17 +1302,46 @@ var pathName = (name) => { * UI controller functionality */ -/** - * Show message that it's time to add funds if reconciliation is less than - * a day in the future and balance is too low. - * 24 hours prior to reconciliation, show message asking user to review - * their votes. - */ const showNotifications = () => { - if (!getSetting(settings.PAYMENTS_ENABLED) || - !getSetting(settings.PAYMENTS_NOTIFICATIONS) || suppressNotifications) { - return + if (getSetting(settings.PAYMENTS_ENABLED) && + getSetting(settings.PAYMENTS_NOTIFICATIONS) && + !suppressNotifications) { + showEnabledNotifications() + } else if (!getSetting(settings.PAYMENTS_ENABLED)) { + showDisabledNotifications() } +} + +// When Payments is disabled +const showDisabledNotifications = () => { + if (!getSetting(settings.PAYMENTS_NOTIFICATION_TRY_PAYMENTS_DISMISSED)) { + const firstRunTimestamp = appStore.getState().get('firstRunTimestamp') + if (new Date().getTime() - firstRunTimestamp < appConfig.payments.delayNotificationTryPayments) { + return + } + notificationTryPaymentsMessage = locale.translation('notificationTryPayments') + appActions.showMessageBox({ + greeting: locale.translation('updateHello'), + message: notificationTryPaymentsMessage, + buttons: [ + {text: locale.translation('noThanks')}, + {text: locale.translation('notificationTryPaymentsYes'), className: 'primary'} + ], + options: { + style: 'greetingStyle', + persist: false + } + }) + } +} + +/** +* Show message that it's time to add funds if reconciliation is less than +* a day in the future and balance is too low. +* 24 hours prior to reconciliation, show message asking user to review +* their votes. +*/ +const showEnabledNotifications = () => { const reconcileStamp = ledgerInfo.reconcileStamp const balance = Number(ledgerInfo.balance || 0) const unconfirmed = Number(ledgerInfo.unconfirmed || 0) diff --git a/app/locale.js b/app/locale.js index efce79fdad5..fde1d470953 100644 --- a/app/locale.js +++ b/app/locale.js @@ -194,9 +194,12 @@ var rendererIdentifiers = function () { 'notificationPassword', 'notificationPasswordSettings', 'notificationPaymentDone', + 'notificationTryPayments', + 'notificationTryPaymentsYes', 'prefsRestart', 'yes', 'no', + 'noThanks', 'neverForThisSite', 'passwordsManager', 'downloadItemPause', diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 5ef8d5f2f88..ff203d01f2c 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -68,6 +68,9 @@ module.exports = { crashes: { crashSubmitUrl: crashURL }, + payments: { + delayNotificationTryPayments: 1000 * 60 * 60 * 24 * 10 // 10 days (from firstRunTimestamp) + }, updates: { // Check for front end updates every hour appUpdateCheckFrequency: 1000 * 60 * 60, @@ -103,6 +106,7 @@ module.exports = { 'bookmarks.toolbar.showOnlyFavicon': false, 'payments.enabled': false, 'payments.notifications': false, + 'payments.notificationTryPaymentsDismissed': false, // True if you dismiss the message or enable Payments 'payments.contribution-amount': 5, // USD 'privacy.autofill-enabled': true, 'privacy.do-not-track': false, diff --git a/js/constants/settings.js b/js/constants/settings.js index d586fe30ba3..7f489fa1574 100644 --- a/js/constants/settings.js +++ b/js/constants/settings.js @@ -49,6 +49,7 @@ const settings = { // Payments Tab PAYMENTS_ENABLED: 'payments.enabled', PAYMENTS_NOTIFICATIONS: 'payments.notifications', + PAYMENTS_NOTIFICATION_TRY_PAYMENTS_DISMISSED: 'payments.notificationTryPaymentsDismissed', PAYMENTS_CONTRIBUTION_AMOUNT: 'payments.contribution-amount', // Advanced settings HARDWARE_ACCELERATION_ENABLED: 'advanced.hardware-acceleration-enabled',