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 { | ||||
| 			width: calc( 100% - 65px ); | ||||
| 			padding-right: 10px; | ||||
| 			max-width: 125px; | ||||
| 			height: $clip-item-height; | ||||
| 			display: flex; | ||||
| 			flex-direction: column; | ||||
| 			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 { | ||||
| 
 | ||||
| @ -98,7 +115,7 @@ div.dark.clip-list-root { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	div.clip-item:hover { | ||||
| 	div.clip-item.able:hover { | ||||
| 		color: $lt-font-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; | ||||
| 		background-color: $lt-bg-color-lvl2-light; | ||||
| 	} | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import { Clip } from "@Model/Clip"; | ||||
| @ -6,20 +7,73 @@ import "./ClipList.scss"; | ||||
| 
 | ||||
| interface IClipListProps { | ||||
| 	clips: Clip[]; | ||||
| 	focus?: Clip; | ||||
| 	disable?: boolean; | ||||
| 	add?: () => any; | ||||
| 	click?: (clip: Clip) => any; | ||||
| 	delete?: (clip: Clip) => any; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 
 | ||||
| 		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 | ||||
| 			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"> | ||||
| 				{new Array(4).fill(0).map(() => { | ||||
| 					return <div className="clip-item-hole"/> | ||||
| 				{new Array(4).fill(0).map((_, index) => { | ||||
| 					return <div className="clip-item-hole" key={index}/> | ||||
| 				})} | ||||
| 			</div> | ||||
| 			<div className="clip-icon-view"> | ||||
| @ -28,21 +82,36 @@ class ClipList extends Component<IClipListProps> { | ||||
| 					iconName="Delete" | ||||
| 					className="delete" | ||||
| 					onClick={() => { | ||||
| 						this.props.delete && this.props.delete(clip); | ||||
| 						this.isInnerClick = true; | ||||
| 						this.resolveCallback(this.props.delete, clip); | ||||
| 					}} | ||||
| 				/> | ||||
| 			</div> | ||||
| 			<div className="clip-item-content"> | ||||
| 				<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>; | ||||
| 	} | ||||
| 
 | ||||
| 	private renderAddButton(): ReactNode { | ||||
| 
 | ||||
| 		const classList = ["clip-item", "add-button"]; | ||||
| 
 | ||||
| 		if (this.props.disable) { | ||||
| 			classList.push("disable"); | ||||
| 		} else { | ||||
| 			classList.push("able"); | ||||
| 		} | ||||
| 
 | ||||
| 		return <div | ||||
| 			className="clip-item add-button" | ||||
| 			onClick={this.props.add} | ||||
| 			key="ADD_BUTTON" | ||||
| 			className={classList.join(" ")} | ||||
| 			onClick={() => this.resolveCallback(this.props.add)} | ||||
| 		> | ||||
|             <Icon iconName="Add"/> | ||||
|         </div> | ||||
|  | ||||
| @ -52,6 +52,7 @@ class Actuator extends Emitter<IActuatorEvent> { | ||||
| 
 | ||||
| 		// 记录录制片段
 | ||||
| 		this.recordClip = clip; | ||||
| 		clip.isRecording = true; | ||||
| 
 | ||||
| 		// 如果仿真未开启,开启仿真
 | ||||
| 		if (!this.start()) this.start(true); | ||||
| @ -65,6 +66,9 @@ class Actuator extends Emitter<IActuatorEvent> { | ||||
| 	 */ | ||||
| 	public endRecord() { | ||||
| 
 | ||||
| 		this.recordClip && (this.recordClip.isRecording = false); | ||||
| 		this.recordClip = undefined; | ||||
| 
 | ||||
| 		// 如果仿真未停止,停止仿真
 | ||||
| 		if (this.start()) this.start(false); | ||||
| 
 | ||||
|  | ||||
| @ -44,6 +44,11 @@ class Clip { | ||||
| 	 */ | ||||
| 	public frames: IFrame[] = []; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 是否正在录制 | ||||
| 	 */ | ||||
| 	public isRecording: boolean = false; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 录制一帧 | ||||
| 	 */ | ||||
|  | ||||
| @ -4,6 +4,7 @@ import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { Message } from "@Input/Message/Message"; | ||||
| import { Clip } from "@Model/Clip"; | ||||
| import { ActuatorModel } from "@Model/Actuator"; | ||||
| import "./ClipPlayer.scss"; | ||||
| 
 | ||||
| @useStatusWithEvent("clipChange", "focusClipChange", "actuatorStartChange") | ||||
| @ -14,8 +15,17 @@ class ClipPlayer extends Component<IMixinStatusProps> { | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 			clips={clipList} | ||||
| 			disable={disable} | ||||
| 		/>; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user