mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added warning modals
This commit is contained in:
parent
0c391df69f
commit
9bd206a750
@ -301,7 +301,8 @@ export enum OlympusState {
|
||||
AUDIO = "Audio",
|
||||
AIRBASE = "Airbase",
|
||||
GAME_MASTER = "Game master",
|
||||
IMPORT_EXPORT = "Import/export"
|
||||
IMPORT_EXPORT = "Import/export",
|
||||
WARNING = "Warning modal"
|
||||
}
|
||||
|
||||
export const NO_SUBSTATE = "No substate";
|
||||
@ -353,6 +354,12 @@ export enum ImportExportSubstate {
|
||||
EXPORT = "EXPORT"
|
||||
}
|
||||
|
||||
export enum WarningSubstate {
|
||||
NO_SUBSTATE = "No substate",
|
||||
NOT_CHROME = "Not chrome",
|
||||
NOT_SECURE = "Not secure"
|
||||
}
|
||||
|
||||
|
||||
export type OlympusSubState = DrawSubState | JTACSubState | SpawnSubState | OptionsSubstate | string;
|
||||
|
||||
@ -379,9 +386,10 @@ export const MAP_OPTIONS_DEFAULTS: MapOptions = {
|
||||
cameraPluginRatio: 1,
|
||||
cameraPluginEnabled: false,
|
||||
cameraPluginMode: "map",
|
||||
tabletMode: false,
|
||||
AWACSMode: false,
|
||||
AWACSCoalition: "blue",
|
||||
hideChromeWarning: false,
|
||||
hideSecureWarning: false
|
||||
};
|
||||
|
||||
export const MAP_HIDDEN_TYPES_DEFAULTS = {
|
||||
|
||||
@ -559,6 +559,9 @@ export class Map extends L.Map {
|
||||
|
||||
setSpawnRequestTable(spawnRequestTable: SpawnRequestTable) {
|
||||
this.#spawnRequestTable = spawnRequestTable;
|
||||
|
||||
this.#currentSpawnMarker?.removeFrom(this);
|
||||
this.#currentSpawnMarker = this.addTemporaryMarker(spawnRequestTable.unit.location, spawnRequestTable.unit.unitType, spawnRequestTable.coalition, true);
|
||||
}
|
||||
|
||||
addStarredSpawnRequestTable(key, spawnRequestTable: SpawnRequestTable, quickAccessName: string) {
|
||||
@ -693,8 +696,8 @@ export class Map extends L.Map {
|
||||
return this.#miniMapLayerGroup;
|
||||
}
|
||||
|
||||
addTemporaryMarker(latlng: L.LatLng, name: string, coalition: string, commandHash?: string) {
|
||||
var marker = new TemporaryUnitMarker(latlng, name, coalition, commandHash);
|
||||
addTemporaryMarker(latlng: L.LatLng, name: string, coalition: string, headingHandle: boolean, commandHash?: string) {
|
||||
var marker = new TemporaryUnitMarker(latlng, name, coalition, headingHandle, commandHash);
|
||||
marker.addTo(this);
|
||||
this.#temporaryMarkers.push(marker);
|
||||
return marker;
|
||||
@ -828,7 +831,8 @@ export class Map extends L.Map {
|
||||
this.#currentSpawnMarker = new TemporaryUnitMarker(
|
||||
new L.LatLng(0, 0),
|
||||
this.#spawnRequestTable?.unit.unitType ?? "",
|
||||
this.#spawnRequestTable?.coalition ?? "neutral"
|
||||
this.#spawnRequestTable?.coalition ?? "neutral",
|
||||
false
|
||||
);
|
||||
this.#currentSpawnMarker.addTo(this);
|
||||
} else if (subState === SpawnSubState.SPAWN_EFFECT) {
|
||||
@ -1073,8 +1077,10 @@ export class Map extends L.Map {
|
||||
MouseMovedEvent.dispatch(e.latlng, elevation);
|
||||
});
|
||||
|
||||
if (this.#currentSpawnMarker) this.#currentSpawnMarker.setLatLng(e.latlng);
|
||||
if (this.#currentEffectMarker) this.#currentEffectMarker.setLatLng(e.latlng);
|
||||
if (getApp().getState() === OlympusState.SPAWN) {
|
||||
if (this.#currentSpawnMarker) this.#currentSpawnMarker.setLatLng(e.latlng);
|
||||
if (this.#currentEffectMarker) this.#currentEffectMarker.setLatLng(e.latlng);
|
||||
}
|
||||
} else {
|
||||
this.#destionationWasRotated = true;
|
||||
this.#destinationRotation -= e.originalEvent.movementX;
|
||||
@ -1202,7 +1208,7 @@ export class Map extends L.Map {
|
||||
if (this.#keepRelativePositions) {
|
||||
selectedUnits.forEach((unit) => {
|
||||
if (this.#contextAction?.getOptions().type === ContextActionType.MOVE || this.#contextAction === null) {
|
||||
this.#destinationPreviewMarkers[unit.ID] = new TemporaryUnitMarker(new L.LatLng(0, 0), unit.getName(), unit.getCoalition());
|
||||
this.#destinationPreviewMarkers[unit.ID] = new TemporaryUnitMarker(new L.LatLng(0, 0), unit.getName(), unit.getCoalition(), false);
|
||||
} else if (this.#contextAction?.getTarget() === ContextActionTarget.POINT) {
|
||||
this.#destinationPreviewMarkers[unit.ID] = new TargetMarker(new L.LatLng(0, 0));
|
||||
}
|
||||
|
||||
@ -9,12 +9,14 @@ export class TemporaryUnitMarker extends CustomMarker {
|
||||
#coalition: string;
|
||||
#commandHash: string | undefined = undefined;
|
||||
#timer: number = 0;
|
||||
#headingHandle: boolean;
|
||||
|
||||
constructor(latlng: LatLng, name: string, coalition: string, commandHash?: string) {
|
||||
constructor(latlng: LatLng, name: string, coalition: string, headingHandle: boolean, commandHash?: string) {
|
||||
super(latlng, { interactive: false });
|
||||
this.#name = name;
|
||||
this.#coalition = coalition;
|
||||
this.#commandHash = commandHash;
|
||||
this.#headingHandle = headingHandle;
|
||||
|
||||
if (commandHash !== undefined) this.setCommandHash(commandHash);
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ import { WeaponsManager } from "./weapon/weaponsmanager";
|
||||
import { ServerManager } from "./server/servermanager";
|
||||
import { AudioManager } from "./audio/audiomanager";
|
||||
|
||||
import { GAME_MASTER, LoginSubState, NO_SUBSTATE, OlympusState, OlympusSubState } from "./constants/constants";
|
||||
import { GAME_MASTER, LoginSubState, NO_SUBSTATE, OlympusState, OlympusSubState, WarningSubstate } from "./constants/constants";
|
||||
import { AppStateChangedEvent, ConfigLoadedEvent, InfoPopupEvent, MapOptionsChangedEvent, SelectedUnitsChangedEvent, ShortcutsChangedEvent } from "./events";
|
||||
import { OlympusConfig } from "./interfaces";
|
||||
import { SessionDataManager } from "./sessiondata";
|
||||
@ -38,6 +38,7 @@ export class OlympusApp {
|
||||
#state: OlympusState = OlympusState.NOT_INITIALIZED;
|
||||
#subState: OlympusSubState = NO_SUBSTATE;
|
||||
#infoMessages: string[] = [];
|
||||
#startupWarningsShown: boolean = false;
|
||||
|
||||
/* Main leaflet map, extended by custom methods */
|
||||
#map: Map;
|
||||
@ -306,6 +307,16 @@ export class OlympusApp {
|
||||
this.#state = state;
|
||||
this.#subState = subState;
|
||||
|
||||
if (this.#state === OlympusState.IDLE && !this.#startupWarningsShown) {
|
||||
window.setTimeout(() => {
|
||||
const isChrome = navigator.userAgent.indexOf("Chrome") > -1;
|
||||
if (!isChrome && !this.getMap().getOptions().hideChromeWarning) this.setState(OlympusState.WARNING, WarningSubstate.NOT_CHROME);
|
||||
if (!isSecureContext && !this.getMap().getOptions().hideSecureWarning) this.setState(OlympusState.WARNING, WarningSubstate.NOT_SECURE);
|
||||
}, 200);
|
||||
|
||||
this.#startupWarningsShown = true;
|
||||
}
|
||||
|
||||
console.log(`App state set to ${state}, substate ${subState}`);
|
||||
AppStateChangedEvent.dispatch(state, subState);
|
||||
}
|
||||
|
||||
@ -25,9 +25,10 @@ export type MapOptions = {
|
||||
cameraPluginRatio: number;
|
||||
cameraPluginEnabled: boolean;
|
||||
cameraPluginMode: string;
|
||||
tabletMode: boolean;
|
||||
AWACSMode: boolean;
|
||||
AWACSCoalition: Coalition;
|
||||
hideChromeWarning: boolean;
|
||||
hideSecureWarning: boolean;
|
||||
};
|
||||
|
||||
export type MapHiddenTypes = {
|
||||
|
||||
115
frontend/react/src/ui/modals/warningmodal.tsx
Normal file
115
frontend/react/src/ui/modals/warningmodal.tsx
Normal file
@ -0,0 +1,115 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "./components/modal";
|
||||
import { FaExclamationTriangle } from "react-icons/fa";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { MAP_OPTIONS_DEFAULTS, NO_SUBSTATE, OlympusState, WarningSubstate } from "../../constants/constants";
|
||||
import { AppStateChangedEvent, MapOptionsChangedEvent } from "../../events";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
|
||||
export function WarningModal(props: { open: boolean }) {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [appSubState, setAppSubState] = useState(NO_SUBSTATE);
|
||||
const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
|
||||
|
||||
useEffect(() => {
|
||||
AppStateChangedEvent.on((appState, appSubState) => {
|
||||
setAppState(appState);
|
||||
setAppSubState(appSubState);
|
||||
});
|
||||
MapOptionsChangedEvent.on((mapOptions) => setMapOptions({ ...mapOptions }));
|
||||
}, []);
|
||||
|
||||
let warningText;
|
||||
if (appState === OlympusState.WARNING) {
|
||||
switch (appSubState) {
|
||||
case WarningSubstate.NOT_CHROME:
|
||||
warningText = (
|
||||
<div className="flex flex-col gap-2 text-gray-400">
|
||||
<span>Non-Google Chrome Browser Detected.</span>
|
||||
<span>
|
||||
It appears you are using a browser other than Google Chrome.
|
||||
</span>
|
||||
<span>If you encounter any problems, we strongly suggest you use a Chrome based browser. Many features, especially advanced ones such as audio playback and capture, were developed specifically for Chrome based browsers. </span>
|
||||
<div className="mt-5 flex gap-4">
|
||||
<OlCheckbox
|
||||
checked={mapOptions.hideChromeWarning}
|
||||
onChange={() => {
|
||||
getApp().getMap().setOption("hideChromeWarning", !mapOptions.hideChromeWarning);
|
||||
}}
|
||||
/>{" "}
|
||||
<span>Don't show this warning again</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case WarningSubstate.NOT_SECURE:
|
||||
case WarningSubstate.NOT_CHROME:
|
||||
warningText = (
|
||||
<div className="flex flex-col gap-2 text-gray-400">
|
||||
<span>Your connection to DCS Olympus is not secure.</span>
|
||||
<span>
|
||||
To protect your personal data some advanced DCS Olympus features like the camera plugin or the audio backend
|
||||
have been disabled.
|
||||
</span>
|
||||
<span>
|
||||
To solve this issue, DCS Olympus should be served using the <span className={`
|
||||
italic
|
||||
`}>https</span> protocol.
|
||||
</span>
|
||||
<span>To do so, we suggest using a dedicated server and a reverse proxy with SSL enabled.</span>
|
||||
<div className="mt-5 flex gap-4">
|
||||
<OlCheckbox
|
||||
checked={mapOptions.hideSecureWarning}
|
||||
onChange={() => {
|
||||
getApp().getMap().setOption("hideSecureWarning", !mapOptions.hideSecureWarning);
|
||||
}}
|
||||
/>{" "}
|
||||
<span>Don't show this warning again</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={props.open}
|
||||
className={`
|
||||
inline-flex h-[50%] max-h-[600px] w-[40%] max-w-[1100px] overflow-y-auto
|
||||
scroll-smooth bg-white
|
||||
dark:bg-olympus-800
|
||||
max-md:h-full max-md:max-h-full max-md:w-full max-md:rounded-none
|
||||
max-md:border-none
|
||||
`}
|
||||
>
|
||||
<div className="flex h-full w-full flex-col p-14">
|
||||
<div className="flex gap-2 text-xl text-white">
|
||||
<FaExclamationTriangle className={`my-auto text-4xl text-yellow-300`} />
|
||||
<div className="my-auto">Warning</div>
|
||||
</div>
|
||||
<div className="mt-10 text-white">{warningText}</div>
|
||||
<div className="ml-auto mt-auto flex">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => getApp().setState(OlympusState.IDLE)}
|
||||
className={`
|
||||
mb-2 me-2 flex content-center items-center gap-2 rounded-sm
|
||||
bg-blue-700 px-5 py-2.5 text-sm font-medium text-white
|
||||
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
|
||||
focus:outline-none focus:ring-4 focus:ring-blue-300
|
||||
hover:bg-blue-800
|
||||
`}
|
||||
>
|
||||
Continue
|
||||
<FontAwesomeIcon className={`my-auto`} icon={faArrowRight} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -8,7 +8,13 @@ import { MainMenu } from "./panels/mainmenu";
|
||||
import { SideBar } from "./panels/sidebar";
|
||||
import { OptionsMenu } from "./panels/optionsmenu";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
import { NO_SUBSTATE, OlympusState, OlympusSubState, OptionsSubstate, SpawnSubState, UnitControlSubState } from "../constants/constants";
|
||||
import {
|
||||
NO_SUBSTATE,
|
||||
OlympusState,
|
||||
OlympusSubState,
|
||||
OptionsSubstate,
|
||||
UnitControlSubState
|
||||
} from "../constants/constants";
|
||||
import { getApp, setupApp } from "../olympusapp";
|
||||
import { LoginModal } from "./modals/loginmodal";
|
||||
|
||||
@ -34,6 +40,7 @@ import { RadiosSummaryPanel } from "./panels/radiossummarypanel";
|
||||
import { AWACSMenu } from "./panels/awacsmenu";
|
||||
import { ServerOverlay } from "./serveroverlay";
|
||||
import { ImportExportModal } from "./modals/importexportmodal";
|
||||
import { WarningModal } from "./modals/warningmodal";
|
||||
|
||||
export type OlympusUIState = {
|
||||
mainMenuVisible: boolean;
|
||||
@ -83,6 +90,8 @@ export function UI() {
|
||||
<ProtectionPromptModal open={appState === OlympusState.UNIT_CONTROL && appSubState == UnitControlSubState.PROTECTION} />
|
||||
<KeybindModal open={appState === OlympusState.OPTIONS && appSubState === OptionsSubstate.KEYBIND} />
|
||||
<ImportExportModal open={appState === OlympusState.IMPORT_EXPORT} />
|
||||
<LoginModal open={appState === OlympusState.LOGIN} />
|
||||
<WarningModal open={appState === OlympusState.WARNING} />
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user