Add clip list component
This commit is contained in:
		
							parent
							
								
									53e6c9db9c
								
							
						
					
					
						commit
						c067088157
					
				| @ -57,15 +57,32 @@ div.clip-list-root { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		div.clip-item-content { | 		div.clip-item-content { | ||||||
|  | 			width: calc( 100% - 65px ); | ||||||
|  | 			padding-right: 10px; | ||||||
|  | 			max-width: 125px; | ||||||
| 			height: $clip-item-height; | 			height: $clip-item-height; | ||||||
| 			display: flex; | 			display: flex; | ||||||
| 			flex-direction: column; | 			flex-direction: column; | ||||||
| 			justify-content: center; | 			justify-content: center; | ||||||
| 			 | 
 | ||||||
|  | 			div { | ||||||
|  | 				white-space: nowrap; | ||||||
|  | 				text-overflow: ellipsis; | ||||||
|  | 				overflow: hidden; | ||||||
|  | 				width: 100%; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			div.info { | ||||||
|  | 				opacity: .75; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	div.clip-item:hover { | 	div.clip-item.disable { | ||||||
|  | 		cursor: not-allowed; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	div.clip-item.able:hover { | ||||||
| 
 | 
 | ||||||
| 		div.clip-icon-view { | 		div.clip-icon-view { | ||||||
| 
 | 
 | ||||||
| @ -98,7 +115,7 @@ div.dark.clip-list-root { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	div.clip-item:hover { | 	div.clip-item.able:hover { | ||||||
| 		color: $lt-font-color-lvl2-dark; | 		color: $lt-font-color-lvl2-dark; | ||||||
| 		background-color: $lt-bg-color-lvl2-dark; | 		background-color: $lt-bg-color-lvl2-dark; | ||||||
| 	} | 	} | ||||||
| @ -119,7 +136,7 @@ div.light.clip-list-root { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	div.clip-item:hover { | 	div.clip-item.able:hover { | ||||||
| 		color: $lt-font-color-lvl2-light; | 		color: $lt-font-color-lvl2-light; | ||||||
| 		background-color: $lt-bg-color-lvl2-light; | 		background-color: $lt-bg-color-lvl2-light; | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import { Localization } from "@Component/Localization/Localization"; | ||||||
| import { Theme } from "@Component/Theme/Theme"; | import { Theme } from "@Component/Theme/Theme"; | ||||||
| import { Icon } from "@fluentui/react"; | import { Icon } from "@fluentui/react"; | ||||||
| import { Clip } from "@Model/Clip"; | import { Clip } from "@Model/Clip"; | ||||||
| @ -6,20 +7,73 @@ import "./ClipList.scss"; | |||||||
| 
 | 
 | ||||||
| interface IClipListProps { | interface IClipListProps { | ||||||
| 	clips: Clip[]; | 	clips: Clip[]; | ||||||
|  | 	focus?: Clip; | ||||||
|  | 	disable?: boolean; | ||||||
| 	add?: () => any; | 	add?: () => any; | ||||||
|  | 	click?: (clip: Clip) => any; | ||||||
| 	delete?: (clip: Clip) => any; | 	delete?: (clip: Clip) => any; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ClipList extends Component<IClipListProps> { | class ClipList extends Component<IClipListProps> { | ||||||
| 
 | 
 | ||||||
|  | 	private isInnerClick: boolean = false; | ||||||
|  | 
 | ||||||
|  | 	private resolveCallback(fn?: (p: any) => any, p?: any): any { | ||||||
|  | 		if (this.props.disable) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		if (fn) { | ||||||
|  | 			return fn(p); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private parseTime(time?: number): string { | ||||||
|  | 		if (time === undefined) { | ||||||
|  | 			return "0:0:0:0"; | ||||||
|  | 		} | ||||||
|  | 		const h = Math.floor(time / 3600); | ||||||
|  | 		const m = Math.floor((time % 3600) / 60); | ||||||
|  | 		const s = Math.floor((time % 3600) % 60); | ||||||
|  | 		const ms = Math.floor((time % 1) * 1000); | ||||||
|  | 		return `${h}:${m}:${s}:${ms}`; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private getClipInfo(clip: Clip): string { | ||||||
|  | 		let fps = Math.floor(clip.frames.length / clip.time); | ||||||
|  | 		if (isNaN(fps)) fps = 0; | ||||||
|  | 		return `${this.parseTime(clip.time)} ${fps}fps`; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	private renderClip(clip: Clip) { | 	private renderClip(clip: Clip) { | ||||||
|  | 
 | ||||||
|  | 		const focus = clip.equal(this.props.focus); | ||||||
|  | 		const disable = this.props.disable; | ||||||
|  | 		const classList = ["clip-item"]; | ||||||
|  | 
 | ||||||
|  | 		if (focus) { | ||||||
|  | 			classList.push("focus"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (disable) { | ||||||
|  | 			classList.push("disable"); | ||||||
|  | 		} else { | ||||||
|  | 			classList.push("able"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		return <div | 		return <div | ||||||
| 			key={clip.id} | 			key={clip.id} | ||||||
| 			className="clip-item" | 			className={classList.join(" ")} | ||||||
|  | 			onClick={() => { | ||||||
|  | 				if (this.isInnerClick) { | ||||||
|  | 					this.isInnerClick = false; | ||||||
|  | 				} else { | ||||||
|  | 					this.resolveCallback(this.props.click, clip); | ||||||
|  | 				} | ||||||
|  | 			}} | ||||||
| 		> | 		> | ||||||
| 			<div className="clip-item-hole-view"> | 			<div className="clip-item-hole-view"> | ||||||
| 				{new Array(4).fill(0).map(() => { | 				{new Array(4).fill(0).map((_, index) => { | ||||||
| 					return <div className="clip-item-hole"/> | 					return <div className="clip-item-hole" key={index}/> | ||||||
| 				})} | 				})} | ||||||
| 			</div> | 			</div> | ||||||
| 			<div className="clip-icon-view"> | 			<div className="clip-icon-view"> | ||||||
| @ -28,21 +82,36 @@ class ClipList extends Component<IClipListProps> { | |||||||
| 					iconName="Delete" | 					iconName="Delete" | ||||||
| 					className="delete" | 					className="delete" | ||||||
| 					onClick={() => { | 					onClick={() => { | ||||||
| 						this.props.delete && this.props.delete(clip); | 						this.isInnerClick = true; | ||||||
|  | 						this.resolveCallback(this.props.delete, clip); | ||||||
| 					}} | 					}} | ||||||
| 				/> | 				/> | ||||||
| 			</div> | 			</div> | ||||||
| 			<div className="clip-item-content"> | 			<div className="clip-item-content"> | ||||||
| 				<div className="title">{clip.name}</div> | 				<div className="title">{clip.name}</div> | ||||||
| 				<div className="info">{clip.frames.length}</div> | 				<div className="info">{ | ||||||
|  | 					clip.isRecording ? | ||||||
|  | 						<Localization i18nKey="Panel.Info.Behavior.Clip.Uname.Clip"/> : | ||||||
|  | 						this.getClipInfo(clip) | ||||||
|  | 				}</div> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div>; | 		</div>; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private renderAddButton(): ReactNode { | 	private renderAddButton(): ReactNode { | ||||||
|  | 
 | ||||||
|  | 		const classList = ["clip-item", "add-button"]; | ||||||
|  | 
 | ||||||
|  | 		if (this.props.disable) { | ||||||
|  | 			classList.push("disable"); | ||||||
|  | 		} else { | ||||||
|  | 			classList.push("able"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		return <div | 		return <div | ||||||
| 			className="clip-item add-button" | 			key="ADD_BUTTON" | ||||||
| 			onClick={this.props.add} | 			className={classList.join(" ")} | ||||||
|  | 			onClick={() => this.resolveCallback(this.props.add)} | ||||||
| 		> | 		> | ||||||
|             <Icon iconName="Add"/> |             <Icon iconName="Add"/> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -52,6 +52,7 @@ class Actuator extends Emitter<IActuatorEvent> { | |||||||
| 
 | 
 | ||||||
| 		// 记录录制片段
 | 		// 记录录制片段
 | ||||||
| 		this.recordClip = clip; | 		this.recordClip = clip; | ||||||
|  | 		clip.isRecording = true; | ||||||
| 
 | 
 | ||||||
| 		// 如果仿真未开启,开启仿真
 | 		// 如果仿真未开启,开启仿真
 | ||||||
| 		if (!this.start()) this.start(true); | 		if (!this.start()) this.start(true); | ||||||
| @ -65,6 +66,9 @@ class Actuator extends Emitter<IActuatorEvent> { | |||||||
| 	 */ | 	 */ | ||||||
| 	public endRecord() { | 	public endRecord() { | ||||||
| 
 | 
 | ||||||
|  | 		this.recordClip && (this.recordClip.isRecording = false); | ||||||
|  | 		this.recordClip = undefined; | ||||||
|  | 
 | ||||||
| 		// 如果仿真未停止,停止仿真
 | 		// 如果仿真未停止,停止仿真
 | ||||||
| 		if (this.start()) this.start(false); | 		if (this.start()) this.start(false); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -44,6 +44,11 @@ class Clip { | |||||||
| 	 */ | 	 */ | ||||||
| 	public frames: IFrame[] = []; | 	public frames: IFrame[] = []; | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * 是否正在录制 | ||||||
|  | 	 */ | ||||||
|  | 	public isRecording: boolean = false; | ||||||
|  | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * 录制一帧 | 	 * 录制一帧 | ||||||
| 	 */ | 	 */ | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | |||||||
| import { Theme } from "@Component/Theme/Theme"; | import { Theme } from "@Component/Theme/Theme"; | ||||||
| import { Message } from "@Input/Message/Message"; | import { Message } from "@Input/Message/Message"; | ||||||
| import { Clip } from "@Model/Clip"; | import { Clip } from "@Model/Clip"; | ||||||
|  | import { ActuatorModel } from "@Model/Actuator"; | ||||||
| import "./ClipPlayer.scss"; | import "./ClipPlayer.scss"; | ||||||
| 
 | 
 | ||||||
| @useStatusWithEvent("clipChange", "focusClipChange", "actuatorStartChange") | @useStatusWithEvent("clipChange", "focusClipChange", "actuatorStartChange") | ||||||
| @ -14,8 +15,17 @@ class ClipPlayer extends Component<IMixinStatusProps> { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private renderClipList(clipList: Clip[]): ReactNode { | 	private renderClipList(clipList: Clip[]): ReactNode { | ||||||
|  | 
 | ||||||
|  | 		const disable = | ||||||
|  | 			!this.props.status?.focusClip &&  | ||||||
|  | 			( | ||||||
|  | 				this.props.status?.actuator.mod === ActuatorModel.Record || | ||||||
|  | 				this.props.status?.actuator.mod === ActuatorModel.Offline | ||||||
|  | 			); | ||||||
|  | 
 | ||||||
| 		return <ClipList | 		return <ClipList | ||||||
| 			clips={clipList} | 			clips={clipList} | ||||||
|  | 			disable={disable} | ||||||
| 		/>; | 		/>; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user