2020-03-23 17:25:55 +01:00
|
|
|
import EventEmitter from 'events'
|
2020-12-16 22:14:49 +01:00
|
|
|
import { ObservableStore } from '@metamask/obs-store'
|
2019-05-13 18:16:09 +02:00
|
|
|
|
2020-05-06 00:19:38 +02:00
|
|
|
export default class AppStateController extends EventEmitter {
|
2019-05-13 18:16:09 +02:00
|
|
|
/**
|
|
|
|
* @constructor
|
2020-11-10 18:30:41 +01:00
|
|
|
* @param {Object} opts
|
2019-05-13 18:16:09 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
constructor(opts = {}) {
|
2020-03-23 17:25:55 +01:00
|
|
|
const {
|
|
|
|
addUnlockListener,
|
|
|
|
isUnlocked,
|
|
|
|
initState,
|
|
|
|
onInactiveTimeout,
|
2020-05-05 16:03:21 +02:00
|
|
|
showUnlockRequest,
|
2020-03-23 17:25:55 +01:00
|
|
|
preferencesStore,
|
|
|
|
} = opts
|
|
|
|
super()
|
|
|
|
|
2020-08-14 13:47:02 +02:00
|
|
|
this.onInactiveTimeout = onInactiveTimeout || (() => undefined)
|
2020-08-19 18:27:05 +02:00
|
|
|
this.store = new ObservableStore({
|
2019-05-13 18:16:09 +02:00
|
|
|
timeoutMinutes: 0,
|
2020-04-22 19:11:36 +02:00
|
|
|
connectedStatusPopoverHasBeenShown: true,
|
2020-10-06 20:28:38 +02:00
|
|
|
swapsWelcomeMessageHasBeenShown: false,
|
2020-11-03 00:41:28 +01:00
|
|
|
defaultHomeActiveTabName: null,
|
|
|
|
...initState,
|
2020-08-19 18:27:05 +02:00
|
|
|
})
|
2019-05-13 18:16:09 +02:00
|
|
|
this.timer = null
|
|
|
|
|
2020-03-23 17:25:55 +01:00
|
|
|
this.isUnlocked = isUnlocked
|
|
|
|
this.waitingForUnlock = []
|
|
|
|
addUnlockListener(this.handleUnlock.bind(this))
|
|
|
|
|
2020-05-05 16:03:21 +02:00
|
|
|
this._showUnlockRequest = showUnlockRequest
|
|
|
|
|
2020-05-06 01:30:50 +02:00
|
|
|
preferencesStore.subscribe(({ preferences }) => {
|
|
|
|
const currentState = this.store.getState()
|
|
|
|
if (currentState.timeoutMinutes !== preferences.autoLockTimeLimit) {
|
|
|
|
this._setInactiveTimeout(preferences.autoLockTimeLimit)
|
|
|
|
}
|
2019-05-13 18:16:09 +02:00
|
|
|
})
|
|
|
|
|
2020-08-18 18:36:45 +02:00
|
|
|
const { preferences } = preferencesStore.getState()
|
2020-01-21 23:09:53 +01:00
|
|
|
this._setInactiveTimeout(preferences.autoLockTimeLimit)
|
2019-05-13 18:16:09 +02:00
|
|
|
}
|
|
|
|
|
2020-03-23 17:25:55 +01:00
|
|
|
/**
|
|
|
|
* Get a Promise that resolves when the extension is unlocked.
|
|
|
|
* This Promise will never reject.
|
|
|
|
*
|
2020-05-05 16:03:21 +02:00
|
|
|
* @param {boolean} shouldShowUnlockRequest - Whether the extension notification
|
|
|
|
* popup should be opened.
|
2020-03-23 17:25:55 +01:00
|
|
|
* @returns {Promise<void>} A promise that resolves when the extension is
|
|
|
|
* unlocked, or immediately if the extension is already unlocked.
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
getUnlockPromise(shouldShowUnlockRequest) {
|
2020-03-23 17:25:55 +01:00
|
|
|
return new Promise((resolve) => {
|
|
|
|
if (this.isUnlocked()) {
|
|
|
|
resolve()
|
|
|
|
} else {
|
2020-05-05 16:03:21 +02:00
|
|
|
this.waitForUnlock(resolve, shouldShowUnlockRequest)
|
2020-03-23 17:25:55 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-05 16:03:21 +02:00
|
|
|
/**
|
|
|
|
* Adds a Promise's resolve function to the waitingForUnlock queue.
|
|
|
|
* Also opens the extension popup if specified.
|
|
|
|
*
|
|
|
|
* @param {Promise.resolve} resolve - A Promise's resolve function that will
|
|
|
|
* be called when the extension is unlocked.
|
|
|
|
* @param {boolean} shouldShowUnlockRequest - Whether the extension notification
|
|
|
|
* popup should be opened.
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
waitForUnlock(resolve, shouldShowUnlockRequest) {
|
2020-05-05 16:03:21 +02:00
|
|
|
this.waitingForUnlock.push({ resolve })
|
|
|
|
this.emit('updateBadge')
|
|
|
|
if (shouldShowUnlockRequest) {
|
|
|
|
this._showUnlockRequest()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:25:55 +01:00
|
|
|
/**
|
|
|
|
* Drains the waitingForUnlock queue, resolving all the related Promises.
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
handleUnlock() {
|
2020-03-23 17:25:55 +01:00
|
|
|
if (this.waitingForUnlock.length > 0) {
|
|
|
|
while (this.waitingForUnlock.length > 0) {
|
|
|
|
this.waitingForUnlock.shift().resolve()
|
|
|
|
}
|
|
|
|
this.emit('updateBadge')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-25 21:01:28 +02:00
|
|
|
/**
|
|
|
|
* Sets the default home tab
|
|
|
|
* @param {string} [defaultHomeActiveTabName] - the tab name
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setDefaultHomeActiveTabName(defaultHomeActiveTabName) {
|
2020-05-25 21:01:28 +02:00
|
|
|
this.store.updateState({
|
|
|
|
defaultHomeActiveTabName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-22 19:11:36 +02:00
|
|
|
/**
|
|
|
|
* Record that the user has seen the connected status info popover
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setConnectedStatusPopoverHasBeenShown() {
|
2020-04-22 19:11:36 +02:00
|
|
|
this.store.updateState({
|
|
|
|
connectedStatusPopoverHasBeenShown: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-06 20:28:38 +02:00
|
|
|
/**
|
|
|
|
* Record that the user has seen the swap screen welcome message
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setSwapsWelcomeMessageHasBeenShown() {
|
2020-10-06 20:28:38 +02:00
|
|
|
this.store.updateState({
|
|
|
|
swapsWelcomeMessageHasBeenShown: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-05-13 18:16:09 +02:00
|
|
|
/**
|
|
|
|
* Sets the last active time to the current time
|
2020-01-13 19:36:36 +01:00
|
|
|
* @returns {void}
|
2019-05-13 18:16:09 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setLastActiveTime() {
|
2019-05-13 18:16:09 +02:00
|
|
|
this._resetTimer()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the inactive timeout for the app
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {number} timeoutMinutes - the inactive timeout in minutes
|
|
|
|
* @returns {void}
|
2019-05-13 18:16:09 +02:00
|
|
|
* @private
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
_setInactiveTimeout(timeoutMinutes) {
|
2019-11-26 21:44:29 +01:00
|
|
|
this.store.updateState({
|
2019-05-13 18:16:09 +02:00
|
|
|
timeoutMinutes,
|
|
|
|
})
|
|
|
|
|
|
|
|
this._resetTimer()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resets the internal inactive timer
|
|
|
|
*
|
|
|
|
* If the {@code timeoutMinutes} state is falsy (i.e., zero) then a new
|
|
|
|
* timer will not be created.
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @returns {void}
|
2019-05-13 18:16:09 +02:00
|
|
|
* @private
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
_resetTimer() {
|
2019-12-03 21:50:55 +01:00
|
|
|
const { timeoutMinutes } = this.store.getState()
|
2019-05-13 18:16:09 +02:00
|
|
|
|
|
|
|
if (this.timer) {
|
|
|
|
clearTimeout(this.timer)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!timeoutMinutes) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
this.timer = setTimeout(
|
|
|
|
() => this.onInactiveTimeout(),
|
|
|
|
timeoutMinutes * 60 * 1000,
|
|
|
|
)
|
2019-05-13 18:16:09 +02:00
|
|
|
}
|
|
|
|
}
|