Permit puiblic report

- Create report html
 - Add report flag
This commit is contained in:
Gregoire Parant 2021-01-29 21:09:10 +01:00
parent 86f1099247
commit 7eb38fae83
12 changed files with 231 additions and 96 deletions

View file

@ -154,7 +154,7 @@ export class GameScene extends ResizableScene implements CenterListener {
private actionableItems: Map<number, ActionableItem> = new Map<number, ActionableItem>();
// The item that can be selected by pressing the space key.
private outlinedItem: ActionableItem|null = null;
private userInputManager!: UserInputManager;
public userInputManager!: UserInputManager;
private isReconnecting: boolean = false;
private startLayerName!: string | null;
private openChatIcon!: OpenChatIcon;

View file

@ -2,7 +2,7 @@ import {LoginScene, LoginSceneName} from "../Login/LoginScene";
import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene";
import {gameManager} from "../Game/GameManager";
import {localUserStore} from "../../Connexion/LocalUserStore";
import {mediaManager} from "../../WebRtc/MediaManager";
import {mediaManager, ReportCallback, ShowReportCallBack} from "../../WebRtc/MediaManager";
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
export const MenuSceneName = 'MenuScene';
@ -10,6 +10,7 @@ const gameMenuKey = 'gameMenu';
const gameMenuIconKey = 'gameMenuIcon';
const gameSettingsMenuKey = 'gameSettingsMenu';
const gameShare = 'gameShare';
const gameReport = 'gameReport';
const closedSideMenuX = -200;
const openedSideMenuX = 0;
@ -21,9 +22,11 @@ export class MenuScene extends Phaser.Scene {
private menuElement!: Phaser.GameObjects.DOMElement;
private gameQualityMenuElement!: Phaser.GameObjects.DOMElement;
private gameShareElement!: Phaser.GameObjects.DOMElement;
private gameReportElement!: Phaser.GameObjects.DOMElement;
private sideMenuOpened = false;
private settingsMenuOpened = false;
private gameShareOpened = false;
private gameReportOpened = false;
private gameQualityValue: number;
private videoQualityValue: number;
private menuButton!: Phaser.GameObjects.DOMElement;
@ -40,6 +43,7 @@ export class MenuScene extends Phaser.Scene {
this.load.html(gameMenuIconKey, 'resources/html/gameMenuIcon.html');
this.load.html(gameSettingsMenuKey, 'resources/html/gameQualityMenu.html');
this.load.html(gameShare, 'resources/html/gameShare.html');
this.load.html(gameReport, 'resources/html/gameReport.html');
}
create() {
@ -64,6 +68,19 @@ export class MenuScene extends Phaser.Scene {
}
});
this.gameReportElement = this.add.dom(middleX, -400).createFromCache(gameReport);
this.revealMenusAfterInit(this.gameReportElement, gameReport);
this.gameReportElement.addListener('click');
this.gameReportElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'gameReportFormSubmit') {
this.submitReport();
}else if((event?.target as HTMLInputElement).id === 'gameReportFormCancel') {
this.closeGameReport();
}
});
mediaManager.setShowReportModalCallBacks(this.openGameReport.bind(this));
this.input.keyboard.on('keyup-TAB', () => {
this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
});
@ -221,6 +238,71 @@ export class MenuScene extends Phaser.Scene {
});
}
private openGameReport(userId: string, userName: string|undefined){
if (this.gameReportOpened) {
this.closeGameReport();
return;
}
//close all
this.closeAll();
const gameTitleReport = this.gameReportElement.getChildByID('nameReported') as HTMLElement;
gameTitleReport.innerText = userName ? `Report user: ${userName}` : 'Report user';
const gameIdUserReported = this.gameReportElement.getChildByID('idUserReported') as HTMLInputElement;
gameIdUserReported.value = userId;
this.gameReportOpened = true;
let middleY = (window.innerHeight / 3) - (257);
if(middleY < 0){
middleY = 0;
}
let middleX = (window.innerWidth / 3) - 298;
if(middleX < 0){
middleX = 0;
}
gameManager.getCurrentGameScene(this).userInputManager.clearAllInputKeyboard();
this.tweens.add({
targets: this.gameReportElement,
y: middleY,
x: middleX,
duration: 1000,
ease: 'Power3'
});
return;
}
private closeGameReport(): void{
this.gameReportOpened = false;
gameManager.getCurrentGameScene(this).userInputManager.initKeyBoardEvent();
this.tweens.add({
targets: this.gameReportElement,
y: -400,
duration: 1000,
ease: 'Power3'
});
}
private submitReport(): void{
const gamePError = this.gameReportElement.getChildByID('gameReportErr') as HTMLParagraphElement;
gamePError.innerText = '';
gamePError.style.display = 'none';
const gameTextArea = this.gameReportElement.getChildByID('gameReportInput') as HTMLInputElement;
const gameIdUserReported = this.gameReportElement.getChildByID('idUserReported') as HTMLInputElement;
if(!gameTextArea || !gameTextArea.value || !gameIdUserReported || !gameIdUserReported.value){
gamePError.innerText = 'Report message cannot to be empty.';
gamePError.style.display = 'block';
return;
}
gameManager.getCurrentGameScene(this).connection.emitReportPlayerMessage(
parseInt(gameIdUserReported.value),
gameTextArea.value
);
this.closeGameReport();
}
private onMenuClick(event:MouseEvent) {
event.preventDefault();
@ -280,5 +362,6 @@ export class MenuScene extends Phaser.Scene {
private closeAll(){
this.closeGameQualityMenu();
this.closeGameShare();
this.closeGameReport();
}
}

View file

@ -1,5 +1,5 @@
import {HtmlUtils} from "./HtmlUtils";
import {mediaManager, ReportCallback} from "./MediaManager";
import {mediaManager, ReportCallback, ShowReportCallBack} from "./MediaManager";
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
@ -99,7 +99,7 @@ export class DiscussionManager {
name: string|undefined,
img?: string|undefined,
isMe: boolean = false,
reportCallback?: ReportCallback
showReportCallBack?: ShowReportCallBack
) {
const divParticipant: HTMLDivElement = document.createElement('div');
divParticipant.classList.add('participant');
@ -128,8 +128,8 @@ export class DiscussionManager {
reportBanUserAction.classList.add('report-btn')
reportBanUserAction.innerText = 'Report';
reportBanUserAction.addEventListener('click', () => {
if(reportCallback) {
mediaManager.showReportModal(`${userId}`, name ?? '', reportCallback);
if(showReportCallBack) {
showReportCallBack(`${userId}`, name);
}else{
console.info('report feature is not activated!');
}

View file

@ -3,6 +3,8 @@ import {HtmlUtils} from "./HtmlUtils";
import {discussionManager, SendMessageCallback} from "./DiscussionManager";
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {VIDEO_QUALITY_SELECT} from "../Administration/ConsoleGlobalMessageManager";
import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
const localValueVideo = localStorage.getItem(VIDEO_QUALITY_SELECT);
@ -23,6 +25,7 @@ export type UpdatedLocalStreamCallback = (media: MediaStream|null) => void;
export type StartScreenSharingCallback = (media: MediaStream) => void;
export type StopScreenSharingCallback = (media: MediaStream) => void;
export type ReportCallback = (message: string) => void;
export type ShowReportCallBack = (userId: string, userName: string|undefined) => void;
// TODO: Split MediaManager in 2 classes: MediaManagerUI (in charge of HTML) and MediaManager (singleton in charge of the camera only)
// TODO: verify that microphone event listeners are not triggered plenty of time NOW (since MediaManager is created many times!!!!)
@ -46,6 +49,7 @@ export class MediaManager {
updatedLocalStreamCallBacks : Set<UpdatedLocalStreamCallback> = new Set<UpdatedLocalStreamCallback>();
startScreenSharingCallBacks : Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
private microphoneBtn: HTMLDivElement;
private cinemaBtn: HTMLDivElement;
private monitorBtn: HTMLDivElement;
@ -469,7 +473,7 @@ export class MediaManager {
return this.getCamera();
}
addActiveVideo(userId: string, reportCallBack: ReportCallback|undefined, userName: string = ""){
addActiveVideo(userId: string, userName: string = "", anonymous: boolean = true){
this.webrtcInAudio.play();
userName = userName.toUpperCase();
@ -482,7 +486,7 @@ export class MediaManager {
<i id="name-${userId}" style="background-color: ${color};">${userName}</i>
<img id="microphone-${userId}" src="resources/logos/microphone-close.svg">
` +
((reportCallBack!==undefined)?`<img id="report-${userId}" class="report active" src="resources/logos/report.svg">`:'')
((anonymous === false)?`<img id="report-${userId}" class="report active" src="resources/logos/report.svg">`:'')
+
`<video id="${userId}" autoplay></video>
</div>
@ -490,18 +494,22 @@ export class MediaManager {
layoutManager.add(DivImportance.Normal, userId, html);
if (reportCallBack) {
const reportBtn = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(`report-${userId}`);
reportBtn.addEventListener('click', (e: MouseEvent) => {
e.preventDefault();
this.showReportModal(userId, userName, reportCallBack);
});
}
this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId));
//permit to create participant in discussion part
this.addNewParticipant(userId, userName, undefined, reportCallBack);
const showReportUser = () => {
for(const callBack of this.showReportModalCallBacks){
callBack(userId, userName);
}
};
this.addNewParticipant(userId, userName, undefined, showReportUser);
if(!anonymous){
const reportBanUserAction: HTMLImageElement = HtmlUtils.getElementByIdOrFail<HTMLImageElement>(`report-${userId}`);
reportBanUserAction.addEventListener('click', () => {
showReportUser();
});
}
}
addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){
@ -645,65 +653,8 @@ export class MediaManager {
return color;
}
public showReportModal(userId: string, userName: string, reportCallBack: ReportCallback){
//create report text area
const mainContainer = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
const divReport = document.createElement('div');
divReport.classList.add('modal-report-user');
const inputHidden = document.createElement('input');
inputHidden.id = 'input-report-user';
inputHidden.type = 'hidden';
inputHidden.value = userId;
divReport.appendChild(inputHidden);
const titleMessage = document.createElement('p');
titleMessage.id = 'title-report-user';
titleMessage.innerText = 'Open a report';
divReport.appendChild(titleMessage);
const bodyMessage = document.createElement('p');
bodyMessage.id = 'body-report-user';
bodyMessage.innerText = `You are about to open a report regarding an offensive conduct from user ${userName.toUpperCase()}. Please explain to us how you think ${userName.toUpperCase()} breached the code of conduct.`;
divReport.appendChild(bodyMessage);
const imgReportUser = document.createElement('img');
imgReportUser.id = 'img-report-user';
imgReportUser.src = 'resources/logos/report.svg';
divReport.appendChild(imgReportUser);
const textareaUser = document.createElement('textarea');
textareaUser.id = 'textarea-report-user';
textareaUser.placeholder = 'Write ...';
divReport.appendChild(textareaUser);
const buttonReport = document.createElement('button');
buttonReport.id = 'button-save-report-user';
buttonReport.innerText = 'Report';
buttonReport.addEventListener('click', () => {
if(!textareaUser.value){
textareaUser.style.border = '1px solid red'
return;
}
reportCallBack(textareaUser.value);
divReport.remove();
});
divReport.appendChild(buttonReport);
const buttonCancel = document.createElement('img');
buttonCancel.id = 'cancel-report-user';
buttonCancel.src = 'resources/logos/close.svg';
buttonCancel.addEventListener('click', () => {
divReport.remove();
});
divReport.appendChild(buttonCancel);
mainContainer.appendChild(divReport);
}
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, reportCallBack?: ReportCallback){
discussionManager.addParticipant(userId, name, img, false, reportCallBack);
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, showReportUserCallBack?: ShowReportCallBack){
discussionManager.addParticipant(userId, name, img, false, showReportUserCallBack);
}
public removeParticipant(userId: number|string){
@ -769,6 +720,10 @@ export class MediaManager {
this.checkActiveUser();
}, this.focused ? 10000 : 1000);
}
public setShowReportModalCallBacks(callback: ShowReportCallBack){
this.showReportModalCallBacks.add(callback);
}
}
export const mediaManager = new MediaManager();

View file

@ -11,6 +11,8 @@ import {
import {ScreenSharingPeer} from "./ScreenSharingPeer";
import {MESSAGE_TYPE_CONSTRAINT, MESSAGE_TYPE_MESSAGE, VideoPeer} from "./VideoPeer";
import {RoomConnection} from "../Connexion/RoomConnection";
import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
export interface UserSimplePeerInterface{
userId: number;
@ -134,11 +136,7 @@ export class SimplePeer {
mediaManager.removeActiveVideo("" + user.userId);
const reportCallback = this.enableReporting ? (comment: string) => {
this.reportUser(user.userId, comment);
} : undefined;
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
mediaManager.addActiveVideo("" + user.userId, name, connectionManager.getConnexionType === GameConnexionTypes.anonymous);
const peer = new VideoPeer(user.userId, user.initiator ? user.initiator : false, this.Connection);
@ -391,13 +389,6 @@ export class SimplePeer {
}
}
/**
* Triggered locally when clicking on the report button
*/
public reportUser(userId: number, message: string) {
this.Connection.emitReportPlayerMessage(userId, message)
}
private sendLocalScreenSharingStreamToUser(userId: number): void {
// If a connection already exists with user (because it is already sharing a screen with us... let's use this connection)
if (this.PeerScreenSharingConnectionArray.has(userId)) {