Files
VRCX/src/components/dialogs/LaunchDialog.vue

314 lines
12 KiB
Vue

<template>
<el-dialog :z-index="launchDialogIndex" v-model="isVisible" :title="t('dialog.launch.header')" width="450px">
<el-form :model="launchDialog" label-width="100px">
<el-form-item :label="t('dialog.launch.url')">
<el-input
v-model="launchDialog.url"
size="small"
style="width: 230px"
@click="$event.target.tagName === 'INPUT' && $event.target.select()" />
<el-tooltip placement="right" :content="t('dialog.launch.copy_tooltip')">
<el-button
size="small"
:icon="CopyDocument"
style="margin-left: 5px"
circle
@click="copyInstanceMessage(launchDialog.url)" />
</el-tooltip>
</el-form-item>
<el-form-item v-if="launchDialog.shortUrl">
<template #label>
<span>{{ t('dialog.launch.short_url') }}</span>
<el-tooltip placement="top" :content="t('dialog.launch.short_url_notice')">
<el-icon style="display: inline-block; margin-left: 5px"><Warning /></el-icon>
</el-tooltip>
</template>
<el-input
v-model="launchDialog.shortUrl"
size="small"
style="width: 230px"
@click="$event.target.tagName === 'INPUT' && $event.target.select()" />
<el-tooltip placement="right" :content="t('dialog.launch.copy_tooltip')">
<el-button
size="small"
:icon="CopyDocument"
style="display: inline-block; margin-left: 5px"
circle
@click="copyInstanceMessage(launchDialog.shortUrl)" />
</el-tooltip>
</el-form-item>
<el-form-item :label="t('dialog.launch.location')">
<el-input
v-model="launchDialog.location"
size="small"
style="width: 230px"
@click="$event.target.tagName === 'INPUT' && $event.target.select()" />
<el-tooltip placement="right" :content="t('dialog.launch.copy_tooltip')">
<el-button
size="small"
:icon="CopyDocument"
style="display: inline-block; margin-left: 5px"
circle
@click="copyInstanceMessage(launchDialog.location)" />
</el-tooltip>
</el-form-item>
</el-form>
<el-checkbox
v-model="launchDialog.desktop"
style="display: inline-flex; align-items: center; margin-top: 5px"
@change="saveLaunchDialog">
{{ t('dialog.launch.start_as_desktop') }}
</el-checkbox>
<template #footer>
<el-button
:disabled="!checkCanInvite(launchDialog.location)"
@click="showInviteDialog(launchDialog.location)">
{{ t('dialog.launch.invite') }}
</el-button>
<template v-if="canOpenInstanceInGame()">
<el-button
:disabled="!launchDialog.secureOrShortName"
@click="handleLaunchGame(launchDialog.location, launchDialog.shortName, launchDialog.desktop)">
{{ t('dialog.launch.launch') }}
</el-button>
<el-button
type="primary"
:disabled="!launchDialog.secureOrShortName"
@click="handleAttachGame(launchDialog.location, launchDialog.shortName)">
{{ t('dialog.launch.open_ingame') }}
</el-button>
</template>
<template v-else>
<el-button
:disabled="!launchDialog.secureOrShortName"
@click="selfInvite(launchDialog.location, launchDialog.shortName)">
{{ t('dialog.launch.self_invite') }}
</el-button>
<el-button
type="primary"
:disabled="!launchDialog.secureOrShortName"
@click="handleLaunchGame(launchDialog.location, launchDialog.shortName, launchDialog.desktop)">
{{ t('dialog.launch.launch') }}
</el-button>
</template>
</template>
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
</el-dialog>
</template>
<script setup>
import { CopyDocument, Warning } from '@element-plus/icons-vue';
import { ref, computed, nextTick, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { instanceRequest, worldRequest } from '../../api';
import configRepository from '../../service/config';
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import {
useFriendStore,
useInviteStore,
useInstanceStore,
useLaunchStore,
useLocationStore,
useGameStore
} from '../../stores';
import InviteDialog from './InviteDialog/InviteDialog.vue';
const { t } = useI18n();
const { friends } = storeToRefs(useFriendStore());
const { lastLocation } = storeToRefs(useLocationStore());
const { launchGame, tryOpenInstanceInVrc } = useLaunchStore();
const { launchDialogData } = storeToRefs(useLaunchStore());
const { showPreviousInstancesInfoDialog } = useInstanceStore();
const { canOpenInstanceInGame } = useInviteStore();
const { isGameRunning } = storeToRefs(useGameStore());
const launchDialogIndex = ref(2000);
const launchDialog = ref({
loading: false,
desktop: false,
tag: '',
location: '',
url: '',
shortName: '',
shortUrl: '',
secureOrShortName: ''
});
const inviteDialog = ref({
visible: false,
loading: false,
worldId: '',
worldName: '',
userIds: [],
friendsInInstance: []
});
const isVisible = computed({
get() {
return launchDialogData.value.visible;
},
set(value) {
launchDialogData.value.visible = value;
}
});
watch(
() => launchDialogData.value.loading,
(loading) => {
if (loading) {
getConfig();
initLaunchDialog();
}
}
);
getConfig();
function closeInviteDialog() {
inviteDialog.value.visible = false;
}
function showInviteDialog(tag) {
if (!isRealInstance(tag)) {
return;
}
const L = parseLocation(tag);
worldRequest
.getCachedWorld({
worldId: L.worldId
})
.then((args) => {
const D = inviteDialog.value;
D.userIds = [];
D.worldId = L.tag;
D.worldName = args.ref.name;
D.friendsInInstance = [];
const friendsInCurrentInstance = lastLocation.value.friendList;
for (const friend of friendsInCurrentInstance.values()) {
const ctx = friends.value.get(friend.userId);
if (typeof ctx.ref === 'undefined') {
continue;
}
D.friendsInInstance.push(ctx);
}
D.visible = true;
});
}
function handleLaunchGame(location, shortName, desktop) {
if (isGameRunning.value) {
ElMessageBox.confirm(t('dialog.launch.game_running_warning'), t('dialog.launch.header'), {
confirmButtonText: t('dialog.launch.confirm_yes'),
cancelButtonText: t('dialog.launch.confirm_no'),
type: 'warning'
})
.then((action) => {
if (action === 'confirm') {
launchGame(location, shortName, desktop);
isVisible.value = false;
}
})
.catch(() => {});
return;
}
launchGame(location, shortName, desktop);
isVisible.value = false;
}
function handleAttachGame(location, shortName) {
tryOpenInstanceInVrc(location, shortName);
isVisible.value = false;
}
function selfInvite(location, shortName) {
const L = parseLocation(location);
if (!L.isRealInstance) {
return;
}
instanceRequest
.selfInvite({
instanceId: L.instanceId,
worldId: L.worldId,
shortName
})
.then((args) => {
ElMessage({
message: 'Self invite sent',
type: 'success'
});
return args;
});
}
function getConfig() {
configRepository.getBool('launchAsDesktop').then((value) => (launchDialog.value.desktop = value));
}
function saveLaunchDialog() {
configRepository.setBool('launchAsDesktop', launchDialog.value.desktop);
}
async function initLaunchDialog() {
const { tag, shortName } = launchDialogData.value;
if (!isRealInstance(tag)) {
return;
}
nextTick(() => {
launchDialogIndex.value = getNextDialogIndex();
});
const D = launchDialog.value;
D.tag = tag;
D.secureOrShortName = shortName;
D.shortUrl = '';
D.shortName = shortName;
const L = parseLocation(tag);
L.shortName = shortName;
if (shortName) {
D.shortUrl = `https://vrch.at/${shortName}`;
}
if (L.instanceId) {
D.location = `${L.worldId}:${L.instanceId}`;
} else {
D.location = L.worldId;
}
D.url = getLaunchURL(L);
if (!shortName) {
const res = await instanceRequest.getInstanceShortName({
worldId: L.worldId,
instanceId: L.instanceId
});
if (!res.json) {
return;
}
const resLocation = `${res.instance.worldId}:${res.instance.instanceId}`;
if (resLocation === launchDialog.value.tag) {
const resShortName = res.json.shortName;
const secureOrShortName = res.json.shortName || res.json.secureName;
const parsedL = parseLocation(resLocation);
parsedL.shortName = resShortName;
launchDialog.value.shortName = resShortName;
launchDialog.value.secureOrShortName = secureOrShortName;
if (resShortName) {
launchDialog.value.shortUrl = `https://vrch.at/${resShortName}`;
}
launchDialog.value.url = getLaunchURL(parsedL);
}
}
}
async function copyInstanceMessage(input) {
try {
await navigator.clipboard.writeText(input);
ElMessage({
message: 'Instance copied to clipboard',
type: 'success'
});
} catch (error) {
ElMessage({
message: 'Instance copied failed',
type: 'error'
});
console.error(error.message);
}
}
</script>