/**
* @namespace qui.mainui.status
*/
import $ from '$qui/lib/jquery.module.js'
import Icon from '$qui/icons/icon.js'
import StockIcon from '$qui/icons/stock-icon.js'
import * as Icons from '$qui/icons/icons.js'
import * as Toast from '$qui/messages/toast.js'
import * as Theme from '$qui/theme.js'
import VisibilityManager from '$qui/utils/visibility-manager.js'
import * as Window from '$qui/window.js'
const STATUS_LOCK_TIMEOUT = 500
/**
* @alias qui.mainui.status.STATUS_OK
*/
export const STATUS_OK = 'ok'
/**
* @alias qui.mainui.status.STATUS_INFO
*/
export const STATUS_INFO = 'info'
/**
* @alias qui.mainui.status.STATUS_WARNING
*/
export const STATUS_WARNING = 'warning'
/**
* @alias qui.mainui.status.STATUS_ERROR
*/
export const STATUS_ERROR = 'error'
/**
* @alias qui.mainui.status.STATUS_SYNC
*/
export const STATUS_SYNC = 'sync'
let statusIndicator = null
let pendingStatusParams = null
let statusLockTimeoutHandle = null
let statusIndicatorVisibilityManager = null
let lastStatus = null
let lastMessage = null
/**
* Update the status indicator.
* @alias qui.mainui.status.set
* @param {String} status one of the following statuses:
* * {@link qui.mainui.status.STATUS_INFO}
* * {@link qui.mainui.status.STATUS_WARNING}
* * {@link qui.mainui.status.STATUS_ERROR}
* * {@link qui.mainui.status.STATUS_SYNC}
* * {@link qui.mainui.status.STATUS_OK}
* @param {String} [message] an optional status message
*/
export function set(status, message = null) {
update(status, message)
}
function update(status, message, forceIcon = false) {
if (statusLockTimeoutHandle) {
forceIcon = forceIcon || Boolean(pendingStatusParams && pendingStatusParams.forceIcon)
pendingStatusParams = {status, message, forceIcon}
return
}
lastStatus = status
lastMessage = message
if (status === 'ok') {
statusIndicatorVisibilityManager.hideElement()
}
else {
statusIndicatorVisibilityManager.showElement()
/* Keep status locked for STATUS_LOCK_TIMEOUT milliseconds, unless "ok" */
statusLockTimeoutHandle = setTimeout(function () {
statusLockTimeoutHandle = null
if (pendingStatusParams) {
update(pendingStatusParams.status, pendingStatusParams.message, pendingStatusParams.forceIcon)
pendingStatusParams = null
}
}, STATUS_LOCK_TIMEOUT)
}
let type = status
let iconName = null
let decoration = status
let animation = null
switch (status) {
case STATUS_INFO: {
iconName = 'info'
break
}
case STATUS_WARNING: {
iconName = 'exclam'
break
}
case STATUS_ERROR: {
iconName = 'exclam'
break
}
case STATUS_SYNC: {
type = 'info'
decoration = null
iconName = 'sync'
animation = Icons.ANIMATION_SPIN
break
}
case STATUS_OK: {
type = 'info'
decoration = 'info'
iconName = 'check'
break
}
}
if (iconName) {
/* No decoration is drawn for the sync status, which asks for none, nor for the info one, which would not
* stand out against the icon anyway. Anything else names a theme colour.
*
* The null case used to fall through to the lookup below and ask the theme for a "null-color", which resolves
* to undefined and so happened to produce the right result. */
if (decoration != null && decoration !== 'info') {
decoration = Theme.getVar(`${decoration}-color`)
}
else {
decoration = null
}
let variant = 'foreground'
if (Window.isSmallScreen()) {
/* On small screens, we always want white icons on top bar */
variant = 'white'
}
else if (message) {
variant = 'interactive'
}
let icon = new StockIcon({
name: iconName,
decoration: decoration,
variant: variant,
animation: animation
})
/* The status is set again after every server response, mostly unchanged, and rendering an icon rebuilds it.
* A theme change keeps the same icon attributes but not the colors they stand for, so it forces a render. */
let iconElement = statusIndicator.find('.qui-icon')
if (forceIcon || !icon.equals(Icon.getFromElement(iconElement))) {
icon.applyTo(iconElement)
}
}
if (message) {
statusIndicator.attr('data-message', message)
statusIndicator.attr('data-type', type)
}
else {
statusIndicator.attr('data-message', '')
statusIndicator.attr('data-type', type)
}
}
export function init() {
statusIndicator = $('div.qui-top-bar div.qui-status-indicator')
statusIndicator.on('click', function () {
let message = statusIndicator.attr('data-message')
if (!message) {
return
}
let type = statusIndicator.attr('data-type')
Toast.show({message, type})
})
statusIndicatorVisibilityManager = new VisibilityManager({element: statusIndicator})
Window.screenLayoutChangeSignal.connect(function () {
set(lastStatus, lastMessage)
})
Theme.changeSignal.connect(function () {
update(lastStatus, lastMessage, /* forceIcon = */ true)
})
set(STATUS_OK)
}