新增功能
This commit is contained in:
Generated
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
import { CallStatus, CallRole, CallMediaType, VideoDisplayMode, VideoResolution, CameraPosition, LayoutMode, NAME } from '../const/index';
|
||||
import { ICallStore } from '../interface/ICallStore';
|
||||
import { t } from '../locales/index';
|
||||
import { getLanguage } from '../utils/common-utils';
|
||||
import { deepClone } from "../utils/index";
|
||||
|
||||
export default class CallStore {
|
||||
public defaultStore: ICallStore = {
|
||||
callStatus: CallStatus.IDLE,
|
||||
callRole: CallRole.UNKNOWN,
|
||||
callMediaType: CallMediaType.UNKNOWN,
|
||||
localUserInfo: { userId: '' },
|
||||
localUserInfoExcludeVolume: { userId: '' },
|
||||
remoteUserInfoList: [],
|
||||
remoteUserInfoExcludeVolumeList: [],
|
||||
callerUserInfo: { userId: '' },
|
||||
isGroup: false,
|
||||
callDuration: '00:00:00', // 通话时长
|
||||
callTips: '', // 通话提示的信息. 例如: '等待谁接听', 'xxx 拒绝通话', 'xxx 挂断通话'
|
||||
toastInfo: { text: '' }, // 远端用户挂断、拒绝、超时、忙线等的 toast 提示信息
|
||||
isMinimized: false, // 用来记录当前是否悬浮窗模式
|
||||
enableFloatWindow: false, // 开启/关闭悬浮窗功能,设置为false,通话界面左上角的悬浮窗按钮会隐藏
|
||||
bigScreenUserId: '', // 当前大屏幕显示的 userID 用户
|
||||
language: getLanguage(), // en, zh-cn
|
||||
isClickable: false, // 是否可点击, 用于按钮增加 loading 效果,不可点击
|
||||
deviceList: { cameraList: [], microphoneList: [], currentCamera: {}, currentMicrophone: {} },
|
||||
showPermissionTip: false,
|
||||
netWorkQualityList: [], // 显示网络状态差的提示
|
||||
isMuteSpeaker: false,
|
||||
callID: '', // callEngine 3.1 support
|
||||
groupID: '',
|
||||
roomID: 0,
|
||||
roomIdType: 0,
|
||||
cameraPosition: CameraPosition.FRONT, // 前置或后置,值为front, back
|
||||
groupCallMembers: [], // chat 群会话在的通话中的成员
|
||||
// TUICallKit 组件上的属性
|
||||
displayMode: VideoDisplayMode.COVER, // 设置预览远端的画面显示模式
|
||||
videoResolution: VideoResolution.RESOLUTION_720P,
|
||||
showSelectUser: false,
|
||||
// 小程序相关属性
|
||||
pusher: {},
|
||||
player: [],
|
||||
isEarPhone: false, // 是否是听筒, 默认: false
|
||||
pusherId: '', // 重新渲染 live-Pusher 的标识位
|
||||
// 是否开启虚拟背景, 目前仅 web 支持
|
||||
isShowEnableVirtualBackground: false, // 是否显示虚拟背景图标, 默认: false
|
||||
enableVirtualBackground: false, // 是否开启虚拟背景, 默认: false
|
||||
// customUIConfig
|
||||
customUIConfig: {
|
||||
button: {},
|
||||
viewBackground: {},
|
||||
layoutMode: LayoutMode.RemoteInLargeView,
|
||||
},
|
||||
// translate function
|
||||
translate: t,
|
||||
isForceUseV2API: false,
|
||||
};
|
||||
public store: ICallStore = deepClone(this.defaultStore);
|
||||
public prevStore: ICallStore = deepClone(this.defaultStore);
|
||||
|
||||
public update(key: keyof ICallStore, data: any): void {
|
||||
switch (key) {
|
||||
case NAME.CALL_TIPS:
|
||||
const preData = this.getData(key);
|
||||
(this.prevStore[key] as any) = preData;
|
||||
default:
|
||||
// resolve "Type 'any' is not assignable to type 'never'.ts", ref: https://github.com/microsoft/TypeScript/issues/31663
|
||||
(this.store[key] as any) = data as any;
|
||||
}
|
||||
}
|
||||
|
||||
public getPrevData(key: string | undefined): any {
|
||||
if (!key) return this.prevStore;
|
||||
return this.prevStore[key as keyof ICallStore];
|
||||
}
|
||||
|
||||
public getData(key: string | undefined): any {
|
||||
if (!key) return this.store;
|
||||
return this.store[key as keyof ICallStore];
|
||||
}
|
||||
// reset call store
|
||||
public reset(keyList: Array<string> = []) {
|
||||
if (keyList.length === 0) {
|
||||
keyList = Object.keys(this.store);
|
||||
}
|
||||
const resetToDefault = keyList.reduce((acc, key) => ({ ...acc, [key]: this.defaultStore[key as keyof ICallStore] }), {});
|
||||
this.store = {
|
||||
...this.defaultStore,
|
||||
...this.store,
|
||||
...resetToDefault,
|
||||
};
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+167
@@ -0,0 +1,167 @@
|
||||
import { ITUIStore, IOptions, Task } from '../interface/ITUIStore';
|
||||
import { StoreName, NAME } from '../const/index';
|
||||
import CallStore from './callStore';
|
||||
import { isString, isNumber, isBoolean } from '../utils/common-utils';
|
||||
|
||||
export default class TUIStore implements ITUIStore {
|
||||
static instance: TUIStore;
|
||||
public task: Task;
|
||||
private storeMap: Partial<Record<StoreName, any>>;
|
||||
private timerId: number = -1;
|
||||
constructor() {
|
||||
this.storeMap = {
|
||||
[StoreName.CALL]: new CallStore(),
|
||||
};
|
||||
// todo 此处后续优化结构后调整
|
||||
this.task = {} as Task; // 保存监听回调列表
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 TUIStore 实例
|
||||
* @returns {TUIStore}
|
||||
*/
|
||||
static getInstance() {
|
||||
if (!TUIStore.instance) {
|
||||
TUIStore.instance = new TUIStore();
|
||||
}
|
||||
return TUIStore.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* UI 组件注册监听回调
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {IOptions} options 监听信息
|
||||
* @param {Object} params 扩展参数
|
||||
* @param {String} params.notifyRangeWhenWatch 注册时监听时的通知范围, 'all' - 通知所有注册该 key 的监听; 'myself' - 通知本次注册该 key 的监听; 默认不通知
|
||||
*/
|
||||
watch(storeName: StoreName, options: IOptions, params?: any) {
|
||||
if (!this.task[storeName]) {
|
||||
this.task[storeName] = {};
|
||||
}
|
||||
const watcher = this.task[storeName];
|
||||
Object.keys(options).forEach((key) => {
|
||||
const callback = options[key];
|
||||
if (!watcher[key]) {
|
||||
watcher[key] = new Map();
|
||||
}
|
||||
watcher[key].set(callback, 1);
|
||||
const { notifyRangeWhenWatch } = params || {};
|
||||
// 注册监听后, 通知所有注册该 key 的监听,使用 'all' 时要特别注意是否对其他地方的监听产生影响
|
||||
if (notifyRangeWhenWatch === NAME.ALL) {
|
||||
this.notify(storeName, key);
|
||||
}
|
||||
// 注册监听后, 仅通知自己本次监听该 key 的数据
|
||||
if (notifyRangeWhenWatch === NAME.MYSELF) {
|
||||
const data = this.getData(storeName, key);
|
||||
callback.call(this, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* UI 取消组件监听回调
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {IOptions} options 监听信息,包含需要取消的回掉等
|
||||
*/
|
||||
unwatch(storeName: StoreName, options: IOptions) {
|
||||
// todo 该接口暂未支持,unwatch掉同一类,如仅传入store注销掉该store下的所有callback,同样options仅传入key注销掉该key下的所有callback
|
||||
// options的callback function为必填参数,后续修改
|
||||
if (!this.task[storeName]) {
|
||||
return;
|
||||
};
|
||||
// if (isString(options)) {
|
||||
// // 移除所有的监听
|
||||
// if (options === '*') {
|
||||
// const watcher = this.task[storeName];
|
||||
// Object.keys(watcher).forEach(key => {
|
||||
// watcher[key].clear();
|
||||
// });
|
||||
// } else {
|
||||
// console.warn(`${NAME.PREFIX}unwatch warning: options is ${options}`);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
const watcher = this.task[storeName];
|
||||
Object.keys(options).forEach((key: string) => {
|
||||
watcher[key].delete(options[key]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用 store 数据更新,messageList 的变更需要单独处理
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {string} key 变更的 key
|
||||
* @param {unknown} data 变更的数据
|
||||
*/
|
||||
update(storeName: StoreName, key: string, data: unknown) {
|
||||
// 基本数据类型时, 如果相等, 就不进行更新, 减少不必要的 notify
|
||||
if (isString(data) || isNumber(data) || isBoolean(data)) {
|
||||
const currentData = this.storeMap[storeName]['store'][key]; // eslint-disable-line
|
||||
if (currentData === data) return;
|
||||
}
|
||||
this.storeMap[storeName]?.update(key, data);
|
||||
this.notify(storeName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Store 的上一个状态值
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {string} key 待获取的 key
|
||||
* @returns {Any}
|
||||
*/
|
||||
getPrevData(storeName: StoreName, key: string) {
|
||||
return this.storeMap[storeName]?.getPrevData(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Store 数据
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {string} key 待获取的 key
|
||||
* @returns {Any}
|
||||
*/
|
||||
getData(storeName: StoreName, key: string) {
|
||||
return this.storeMap[storeName]?.getData(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI 组件注册监听回调
|
||||
* @param {StoreName} storeName store 名称
|
||||
* @param {string} key 变更的 key
|
||||
*/
|
||||
private notify(storeName: StoreName, key: string) {
|
||||
if (!this.task[storeName]) {
|
||||
return;
|
||||
}
|
||||
const watcher = this.task[storeName];
|
||||
if (watcher[key]) {
|
||||
const callbackMap = watcher[key];
|
||||
const data = this.getData(storeName, key);
|
||||
for (const [callback] of callbackMap.entries()) {
|
||||
callback.call(this, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public reset(storeName: StoreName, keyList: Array<string> = [], isNotificationNeeded = false) {
|
||||
if (storeName in this.storeMap) {
|
||||
const store = this.storeMap[storeName];
|
||||
// reset all
|
||||
if (keyList.length === 0) {
|
||||
keyList = Object.keys(store?.store);
|
||||
}
|
||||
store.reset(keyList);
|
||||
if (isNotificationNeeded) {
|
||||
keyList.forEach((key) => {
|
||||
this.notify(storeName, key);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 批量修改多个 key-value
|
||||
public updateStore(params: any, name?: StoreName): void {
|
||||
const storeName = name ? name : StoreName.CALL;
|
||||
Object.keys(params).forEach((key) => {
|
||||
this.update(storeName, key, params[key]);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user