UNPKG

agora-edu-core

Version:

Core APIs for building an online classroom

465 lines (445 loc) 17.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AgoraWidgetController = void 0; var _agoraRteSdk = require("agora-rte-sdk"); var _difference = _interopRequireDefault(require("lodash/difference")); var _get = _interopRequireDefault(require("lodash/get")); var _isEqual = _interopRequireDefault(require("lodash/isEqual")); var _mobx = require("mobx"); var _configs = require("../../../../configs"); var _helper = require("./helper"); var _type = require("./type"); var _batch = require("../../../../utils/batch"); var _dec, _dec2, _dec3, _class, _class2, _descriptor; function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _initializerDefineProperty(e, i, r, l) { r && Object.defineProperty(e, i, { enumerable: r.enumerable, configurable: r.configurable, writable: r.writable, value: r.initializer ? r.initializer.call(l) : void 0 }); } function _applyDecoratedDescriptor(i, e, r, n, l) { var a = {}; return Object.keys(n).forEach(function (i) { a[i] = n[i]; }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) { return n(i, e, r) || r; }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a; } function _initializerWarningHelper(r, e) { throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform."); } let AgoraWidgetController = exports.AgoraWidgetController = (_dec = _agoraRteSdk.Log.attach({ proxyMethods: false }), _dec2 = _mobx.action.bound, _dec3 = _mobx.action.bound, _dec(_class = (_class2 = class AgoraWidgetController { constructor(_scene, _api, _stateListeners) { this._scene = _scene; this._api = _api; this._stateListeners = _stateListeners; this.logger = void 0; this._eventBus = new _agoraRteSdk.AGEventEmitter(); this._zIndexController = new AgoraWidgetZIndexController(); _initializerDefineProperty(this, "_widgetIds", _descriptor, this); this._cache = (0, _helper.createClosure)(); this._addEventListener(); } /** * widget消息总线 */ get eventBus() { return this._eventBus; } /** * 当前存在的 Widget 实例ID列表 */ get widgetIds() { return this._widgetIds; } /** * 层级控制器 */ get zIndexController() { return this._zIndexController; } /** * 房间配置 */ get classroomConfig() { return _configs.EduClassroomConfig.shared; } /** * 添加一个组件状态监听器 * @param listener */ /** @en * * @param listener */ addWidgetStateListener(listener) { this._stateListeners.push(listener); } /** * 移除一个组件状态监听器 * @param listener */ removeWidgetStateListener(listener) { this._stateListeners = this._stateListeners.filter(ls => listener !== ls); } /** * 向指定 Widget 发送消息 * @param toWidgetId * @param messageType * @param args */ sendMessage(toWidgetId, messageType, message) { this._eventBus.emit(`widget-message-${toWidgetId}-${messageType}`, message); } /** * 增加一个消息监听器 * @param listener */ addWidgetMessageListener(listener) { this._eventBus.on(`widget-message-${listener.widgetId}-${listener.messageType}`, listener.onMessage); } /** * 移除一个消息监听器 * @param listener */ removeWidgetMessageListener(listener) { this._eventBus.off(`widget-message-${listener.widgetId}-${listener.messageType}`, listener.onMessage); } /** * 广播消息 */ broadcast(messageType, message) { this._eventBus.emit(`broadcast:${messageType}`, message); } /** * 监听广播消息 */ addBroadcastListener(listener) { this._eventBus.on(`broadcast:${listener.messageType}`, listener.onMessage); } /** * 移除一个广播消息监听器 */ removeBroadcastListener(listener) { this._eventBus.off(`broadcast:${listener.messageType}`, listener.onMessage); } /** * 设置 widget 为活跃 * @param widgetId * @param extra * @returns */ setWidegtActive(widgetId, props, ownerUserUuid) { return this._api.updateWidgetProperties(this._scene.sceneId, widgetId, _objectSpread(_objectSpread({}, props), {}, { ownerUserUuid, state: _type.WidgetState.Active })); } /** * 设置 widget 为不活跃 * @param widgetId * @returns */ setWidgetInactive(widgetId, props) { return this._api.updateWidgetProperties(this._scene.sceneId, widgetId, _objectSpread(_objectSpread({}, props), {}, { state: _type.WidgetState.Inactive })); } /** * 删除房间 Widget * @param widgetId * @param keys * @returns */ deleteWidget(widgetId) { return this._api.deleteWidget(this._scene.sceneId, widgetId); } /** * 删除用户属性字段 * @param widgetId * @param keys * @returns */ removeWidgetUserProperties(widgetId, keys) { const { userUuid } = _configs.EduClassroomConfig.shared.sessionInfo; return this._api.removeWidgetUserProperties(this._scene.sceneId, widgetId, userUuid, { properties: keys }); } /** * 删除扩展信息字段 * @param widgetId * @param keys * @returns */ removeWidgetExtraProperties(widgetId, keys) { return this._api.removeWidgetExtraProperties(this._scene.sceneId, widgetId, { properties: keys }); } /** * 更新 widget 属性 * @param widgetId * @param props * @returns */ updateWidgetProperties(widgetId, props) { return this._api.updateWidgetProperties(this._scene.sceneId, widgetId, _objectSpread({}, props)); } /** * 更新 widget 用户属性 * @param widgetId * @param props */ updateWidgetUserProperties(widgetId, props) { const { userUuid } = _configs.EduClassroomConfig.shared.sessionInfo; this._api.updateWidgetUserProperties(this._scene.sceneId, widgetId, userUuid, _objectSpread({}, props)); } /** * 销毁 */ destroy() { this._removeEventListener(); } /** * 获取 Widget 属性 * @param widgetId * @returns */ getWidgetProperties(widgetId) { const key = `properties-${widgetId}`; const prev = this._cache.prev(key); return prev; } /** * 获取 Widget 用户属性 * @param widgetId * @returns */ getWidgetUserProperties(widgetId) { const key = `user-${widgetId}`; const prev = this._cache.prev(key); return prev; } /** * 获取 Widget 轨迹同步信息 * @param widgetId * @returns */ getWidgetTrack(widgetId) { const key = `track-${widgetId}`; const prev = this._cache.prev(key); return prev; } /** * 获取 Widget 状态 * @param widgetId */ getWidgetState(widgetId) { const key = `state-${widgetId}`; const prev = this._cache.prev(key); return prev; } _addEventListener() { this._scene.on(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange); this._scene.on(_agoraRteSdk.AgoraRteEventType.UserPropertyUpdated, this._handleUserPropertiesChange); this._scene.on(_agoraRteSdk.AgoraRteEventType.UserPropertyListUpdated, this._updateBatchUserProperties); this._scene.on(_agoraRteSdk.AgoraRteEventType.UserAdded, this._handleUserAdded); } _removeEventListener() { this._scene.off(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange); this._scene.off(_agoraRteSdk.AgoraRteEventType.UserPropertyUpdated, this._handleUserPropertiesChange); this._scene.off(_agoraRteSdk.AgoraRteEventType.UserPropertyListUpdated, this._updateBatchUserProperties); this._scene.off(_agoraRteSdk.AgoraRteEventType.UserAdded, this._handleUserAdded); } _handleWidgetStateChange(widgetId, state) { this._stateListeners.forEach(listener => { if (state === _type.WidgetState.Active) { listener.onActive(widgetId); } else if (state === _type.WidgetState.Inactive) { listener.onInactive(widgetId); } }); } _handleWidgetPropertiesChange(widgetId, props) { this._stateListeners.forEach(listener => { listener.onPropertiesUpdate(widgetId, props); }); } _handleWidgetUserPropertiesChange(widgetId, props) { this._stateListeners.forEach(listener => { listener.onUserPropertiesUpdate(widgetId, props); }); } _handleWidgetTrackChange(widgetId, track) { this._stateListeners.forEach(listener => { listener.onTrackUpdate(widgetId, track); }); } _extractProps(props) { var _others$extra; // pick out state prop which cause additional change callback const { state, size, position } = props, others = _objectWithoutProperties(props, ["state", "size", "position"]); const _ref = (_others$extra = others.extra) !== null && _others$extra !== void 0 ? _others$extra : {}, { zIndex } = _ref, extra = _objectWithoutProperties(_ref, ["zIndex"]); const rs = [state, _objectSpread(_objectSpread({}, others), {}, { extra })]; if (props.size !== undefined || props.position !== undefined) { rs.push({ size: props.size, position: props.position, zIndex }); } return rs; } _compareToPrevious(widgetId, keyPath, next) { const key = `${keyPath}-${widgetId}`; const prev = this._cache.prev(key); const rawPrev = JSON.stringify(prev); const rawNext = JSON.stringify(next); // prevent unnecessary re-rendering if (rawPrev !== rawNext) { this._cache.next(key, next); return true; } return false; } _clearCache(widgetId) { this._cache.next(`properties-${widgetId}`, undefined); this._cache.next(`user-${widgetId}`, undefined); this._cache.next(`track-${widgetId}`, undefined); this._cache.next(`state-${widgetId}`, undefined); } _handleRoomPropertiesChange(changedRoomProperties, roomProperties, operator, cause) { // 处理变更逻辑 changedRoomProperties.forEach((0, _mobx.action)(key => { if (key === 'widgets') { const widgetsMap = (0, _get.default)(roomProperties, `widgets`, {}); const widgetIds = Object.keys(widgetsMap).sort(); const removedWidgetIds = (0, _difference.default)(this._widgetIds, widgetIds); // Widget被移除,反激活 removedWidgetIds.forEach(widgetId => { this._handleWidgetStateChange(widgetId, _type.WidgetState.Inactive); this._clearCache(widgetId); }); // 阻止无意义的变更 if (!(0, _isEqual.default)(this._widgetIds, widgetIds)) { this._widgetIds = widgetIds; } // 遍历当前widget列表并更新widget状态 for (const widgetId in widgetsMap) { const widgetProperties = (0, _get.default)(roomProperties, `widgets.${widgetId}`, {}); const [state, props, trackProps] = this._extractProps(widgetProperties); // 处理属性更新逻辑 const propertiesChanged = this._compareToPrevious(widgetId, 'properties', props); if (propertiesChanged) { this._handleWidgetPropertiesChange(widgetId, props); } const trackChanged = this._compareToPrevious(widgetId, 'track', trackProps); // 处理轨迹同步更新逻辑 if (trackChanged && operator.userUuid !== _configs.EduClassroomConfig.shared.sessionInfo.userUuid) { this._handleWidgetTrackChange(widgetId, trackProps); } const stateCacheKey = `state-${widgetId}`; const prevState = this._cache.prev(stateCacheKey); const becomeActive = prevState !== _type.WidgetState.Active && state === _type.WidgetState.Active; const becomeInactive = prevState === _type.WidgetState.Active && state === _type.WidgetState.Inactive; // 处理 widget 激活逻辑 if (becomeActive) { this._handleWidgetStateChange(widgetId, _type.WidgetState.Active); } // 处理 widget 反激活逻辑 if (becomeInactive) { this._handleWidgetStateChange(widgetId, _type.WidgetState.Inactive); } this._cache.next(stateCacheKey, state); } } })); } _handleUserPropertiesChange(userUuid, userProperties, operator, cause) { const { userUuid: localUserUuid } = _configs.EduClassroomConfig.shared.sessionInfo; if (userUuid === localUserUuid) { const widgetsMap = (0, _get.default)(userProperties, `widgets`, {}); // 遍历当前widget列表并更新widget状态 for (const widgetId in widgetsMap) { const widgetProperties = (0, _get.default)(userProperties, `widgets.${widgetId}`, {}); // 处理属性变更逻辑 const changed = this._compareToPrevious(widgetId, 'user', widgetProperties); if (changed) { this._handleWidgetUserPropertiesChange(widgetId, widgetProperties); } } } } _updateBatchUserProperties(users, batch, operator, cause) { _batch.BatchRecord.getBatchRecord(batch.id).setCurrent(batch.index).setTotal(batch.total).setCallback(batchArray => { const allUsers = batchArray.flat(); for (const user of allUsers) { const { userUuid, userProperties } = user; this._handleUserPropertiesChange(userUuid, userProperties); } }).addChunk(users).execute(); } _handleUserAdded(users) { users.forEach(_ref2 => { let { userUuid, userProperties } = _ref2; const { userUuid: localUserUuid } = _configs.EduClassroomConfig.shared.sessionInfo; if (userUuid === localUserUuid) { const widgetsMap = userProperties.get('widgets') || {}; // 遍历当前widget列表并更新widget状态 for (const widgetId in widgetsMap) { const widgetProperties = (0, _get.default)(widgetsMap, widgetId, {}); // 处理属性变更逻辑 const changed = this._compareToPrevious(widgetId, 'user', widgetProperties); if (changed) { this._handleWidgetUserPropertiesChange(widgetId, widgetProperties); } } } }); } }, _descriptor = _applyDecoratedDescriptor(_class2.prototype, "_widgetIds", [_mobx.observable], { configurable: true, enumerable: true, writable: true, initializer: function () { return []; } }), _applyDecoratedDescriptor(_class2.prototype, "widgetIds", [_mobx.computed], Object.getOwnPropertyDescriptor(_class2.prototype, "widgetIds"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_handleRoomPropertiesChange", [_dec2], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleRoomPropertiesChange"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_handleUserPropertiesChange", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleUserPropertiesChange"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_updateBatchUserProperties", [_dec3], Object.getOwnPropertyDescriptor(_class2.prototype, "_updateBatchUserProperties"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_handleUserAdded", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleUserAdded"), _class2.prototype), _class2)) || _class); class AgoraWidgetZIndexController { constructor() { this._latestZIndex = 0; } incrementZIndex() { return this._latestZIndex += 1; } get latestZIndex() { return this._latestZIndex; } setZIndex(zIndex) { this._latestZIndex = Math.max(this._latestZIndex, zIndex); } }