Skip to content

Commit

Permalink
add notification badge for wait on unlock
Browse files Browse the repository at this point in the history
  • Loading branch information
rekmarks committed Mar 8, 2020
1 parent 6064c50 commit 597ac58
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 26 deletions.
4 changes: 3 additions & 1 deletion app/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ function setupController (initState, initLangCode) {
controller.encryptionPublicKeyManager.on('updateBadge', updateBadge)
controller.typedMessageManager.on('updateBadge', updateBadge)
controller.permissionsController.permissions.subscribe(updateBadge)
controller.appStateController.on('updateBadge', updateBadge)

/**
* Updates the Web Extension's "badge" number, on the little fox in the toolbar.
Expand All @@ -435,8 +436,9 @@ function setupController (initState, initLangCode) {
const unapprovedEncryptionPublicKeyMsgCount = controller.encryptionPublicKeyManager.unapprovedEncryptionPublicKeyMsgCount
const unapprovedTypedMessagesCount = controller.typedMessageManager.unapprovedTypedMessagesCount
const pendingPermissionRequests = Object.keys(controller.permissionsController.permissions.state.permissionsRequests).length
const waitingForUnlockCount = controller.appStateController.waitingForUnlock.length
const count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount +
unapprovedTypedMessagesCount + pendingPermissionRequests
unapprovedTypedMessagesCount + pendingPermissionRequests + waitingForUnlockCount
if (count) {
label = String(count)
}
Expand Down
47 changes: 45 additions & 2 deletions app/scripts/controllers/app-state.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,71 @@
import ObservableStore from 'obs-store'
import EventEmitter from 'events'

class AppStateController {
class AppStateController extends EventEmitter {
/**
* @constructor
* @param opts
*/
constructor (opts = {}) {
const { initState, onInactiveTimeout, preferencesStore } = opts
const {
addUnlockListener,
isUnlocked,
initState,
onInactiveTimeout,
preferencesStore,
} = opts
const { preferences } = preferencesStore.getState()

super()

this.onInactiveTimeout = onInactiveTimeout || (() => {})
this.store = new ObservableStore(Object.assign({
timeoutMinutes: 0,
mkrMigrationReminderTimestamp: null,
}, initState))
this.timer = null

this.isUnlocked = isUnlocked
this.waitingForUnlock = []
addUnlockListener(this.handleUnlock.bind(this))

preferencesStore.subscribe((state) => {
this._setInactiveTimeout(state.preferences.autoLockTimeLimit)
})

this._setInactiveTimeout(preferences.autoLockTimeLimit)
}

/**
* Get a Promise that resolves when the extension is unlocked.
* This Promise will never reject.
*
* @returns {Promise<void>} A promise that resolves when the extension is
* unlocked, or immediately if the extension is already unlocked.
*/
getUnlockPromise () {
return new Promise((resolve) => {
if (this.isUnlocked()) {
resolve()
} else {
this.waitingForUnlock.push({ resolve })
this.emit('updateBadge')
}
})
}

/**
* Drains the waitingForUnlock queue, resolving all the related Promises.
*/
handleUnlock () {
if (this.waitingForUnlock.length > 0) {
while (this.waitingForUnlock.length > 0) {
this.waitingForUnlock.shift().resolve()
}
this.emit('updateBadge')
}
}

setMkrMigrationReminderTimestamp (timestamp) {
this.store.updateState({
mkrMigrationReminderTimestamp: timestamp,
Expand Down
5 changes: 3 additions & 2 deletions app/scripts/controllers/permissions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ export class PermissionsController {
[HISTORY_STORE_KEY]: restoredState[HISTORY_STORE_KEY] || {},
})

this.getKeyringAccounts = getKeyringAccounts
this.getUnlockPromise = getUnlockPromise
this._notifyDomain = notifyDomain
this.notifyAllDomains = notifyAllDomains
this.getUnlockPromise = getUnlockPromise
this.getKeyringAccounts = getKeyringAccounts
this._platform = platform

this._restrictedMethods = getRestrictedMethods(this)
this.permissionsLog = new PermissionsLogController({
restrictedMethods: Object.keys(this._restrictedMethods),
Expand Down
38 changes: 17 additions & 21 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,11 @@ export default class MetamaskController extends EventEmitter {
})

this.appStateController = new AppStateController({
preferencesStore: this.preferencesController.store,
onInactiveTimeout: () => this.setLocked(),
addUnlockListener: this.addUnlockListener.bind(this),
isUnlocked: this.isUnlocked.bind(this),
initState: initState.AppStateController,
onInactiveTimeout: () => this.setLocked(),
preferencesStore: this.preferencesController.store,
})

this.currencyRateController = new CurrencyRateController(undefined, initState.CurrencyController)
Expand Down Expand Up @@ -209,11 +211,11 @@ export default class MetamaskController extends EventEmitter {

this.permissionsController = new PermissionsController({
getKeyringAccounts: this.keyringController.getAccounts.bind(this.keyringController),
platform: opts.platform,
getRestrictedMethods,
getUnlockPromise: this.appStateController.getUnlockPromise.bind(this.appStateController),
notifyDomain: this.notifyConnections.bind(this),
notifyAllDomains: this.notifyAllConnections.bind(this),
getRestrictedMethods,
getUnlockPromise: this.getUnlockPromise.bind(this),
platform: opts.platform,
}, initState.PermissionsController, initState.PermissionsMetadata)

this.detectTokensController = new DetectTokensController({
Expand Down Expand Up @@ -772,6 +774,8 @@ export default class MetamaskController extends EventEmitter {
*/
async submitPassword (password) {
await this.keyringController.submitPassword(password)
this.emit('unlocked')

const accounts = await this.keyringController.getAccounts()

// verify keyrings
Expand Down Expand Up @@ -1803,27 +1807,19 @@ export default class MetamaskController extends EventEmitter {
}

/**
* Get a Promise that resolves when the extension is unlocked.
* This Promise will never reject.
*
* @returns {Promise<void>} A promise that resolves when the extension is
* unlocked, or immediately if the extension is already unlocked.
* @returns {boolean} Whether the extension is unlocked.
*/
getUnlockPromise () {
return new Promise((resolve) => {
if (this.isUnlocked()) {
resolve()
} else {
this.once('unlock', resolve)
}
})
isUnlocked () {
return this.keyringController.memStore.getState().isUnlocked
}

/**
* @returns {boolean} Whether the extension is unlocked.
* Adds an 'unlock' event listener to the MetaMask Controller with the
* given handler.
* @param {Function} handler - The event handler.
*/
isUnlocked () {
return this.keyringController.memStore.getState().isUnlocked
addUnlockListener (handler) {
this.on('unlocked', handler)
}

//=============================================================================
Expand Down

0 comments on commit 597ac58

Please sign in to comment.