refactor: dialogs (#1224)

* refactor: dialogs

* fix: storeAvatarImage

* FriendLog.vue

* FriendLog.vue

* FriendLog.vue

* GameLog.vue

* fix: next day button jumping to the wrong date

* sync master

* fix: launchGame

* Notification.vue

* Feed.vue

* Search.vue

* Profile.vue

* PlayerList.vue

* Login.vue

* utils

* update dialog

* del gameLog.pug

* fix

* fix: group role cannot be displayed currently

* fix: "Hide Friends in Same Instance" hides players in unrelated private instances (#1210)

* fix

* fix: "Hide Friends in Same Instance" does not work when "Split Favorite Friends" is enabled

* fix Notification.vue message

* fix: deleteFavoriteNoConfirm

* fix: feed status style

* fix: infinite loading when deleting note

* fix: private players will not be hidden when 'Hide Friends in Same Instance', and 'Hide Friends in Same Instance' will not work when 'Split Favorite Friends'
This commit is contained in:
pa
2025-05-14 19:01:15 +09:00
committed by GitHub
parent 5ca028b30a
commit e792ed481b
130 changed files with 14208 additions and 10462 deletions

View File

@@ -239,13 +239,12 @@ export default class extends baseClass {
API.websocketDomain = API.websocketDomainVrchat;
}
return new Promise((resolve, reject) => {
this.loginForm.loading = true;
if (this.enablePrimaryPassword) {
this.checkPrimaryPassword(loginParmas)
.then((pwd) => {
this.loginForm.loading = true;
return API.getConfig()
.catch((err) => {
this.loginForm.loading = false;
reject(err);
})
.then(() => {
@@ -257,12 +256,10 @@ export default class extends baseClass {
websocket: loginParmas.websocket
})
.catch((err2) => {
this.loginForm.loading = false;
// API.logout();
reject(err2);
})
.then(() => {
this.loginForm.loading = false;
resolve();
});
});
@@ -277,7 +274,6 @@ export default class extends baseClass {
} else {
API.getConfig()
.catch((err) => {
this.loginForm.loading = false;
reject(err);
})
.then(() => {
@@ -288,17 +284,15 @@ export default class extends baseClass {
websocket: loginParmas.websocket
})
.catch((err2) => {
this.loginForm.loading = false;
API.logout();
reject(err2);
})
.then(() => {
this.loginForm.loading = false;
resolve();
});
});
}
});
}).finally(() => (this.loginForm.loading = false));
},
async deleteSavedLogin(userId) {
@@ -325,100 +319,90 @@ export default class extends baseClass {
async login() {
await webApiService.clearCookies();
this.$refs.loginForm.validate((valid) => {
if (valid && !this.loginForm.loading) {
this.loginForm.loading = true;
if (this.loginForm.endpoint) {
API.endpointDomain = this.loginForm.endpoint;
API.websocketDomain = this.loginForm.websocket;
} else {
API.endpointDomain = API.endpointDomainVrchat;
API.websocketDomain = API.websocketDomainVrchat;
}
API.getConfig()
.catch((err) => {
this.loginForm.loading = false;
throw err;
})
.then((args) => {
if (
this.loginForm.saveCredentials &&
this.enablePrimaryPassword
) {
$app.$prompt(
$t('prompt.primary_password.description'),
$t('prompt.primary_password.header'),
{
inputType: 'password',
inputPattern: /[\s\S]{1,32}/
}
)
.then(({ value }) => {
let saveCredential =
this.loginForm.savedCredentials[
Object.keys(
this.loginForm
.savedCredentials
)[0]
];
security
.decrypt(
saveCredential.loginParmas
.password,
value
)
.then(() => {
security
.encrypt(
this.loginForm.password,
value
)
.then((pwd) => {
API.login({
username:
this.loginForm
.username,
password:
this.loginForm
.password,
endpoint:
this.loginForm
.endpoint,
websocket:
this.loginForm
.websocket,
saveCredentials:
this.loginForm
.saveCredentials,
cipher: pwd
}).then(() => {
this.$refs.loginForm.resetFields();
});
if (!this.loginForm.loading) {
this.loginForm.loading = true;
if (this.loginForm.endpoint) {
API.endpointDomain = this.loginForm.endpoint;
API.websocketDomain = this.loginForm.websocket;
} else {
API.endpointDomain = API.endpointDomainVrchat;
API.websocketDomain = API.websocketDomainVrchat;
}
API.getConfig()
.catch((err) => {
this.loginForm.loading = false;
throw err;
})
.then((args) => {
if (
this.loginForm.saveCredentials &&
this.enablePrimaryPassword
) {
$app.$prompt(
$t('prompt.primary_password.description'),
$t('prompt.primary_password.header'),
{
inputType: 'password',
inputPattern: /[\s\S]{1,32}/
}
)
.then(({ value }) => {
let saveCredential =
this.loginForm.savedCredentials[
Object.keys(
this.loginForm.savedCredentials
)[0]
];
security
.decrypt(
saveCredential.loginParmas.password,
value
)
.then(() => {
security
.encrypt(
this.loginForm.password,
value
)
.then((pwd) => {
API.login({
username:
this.loginForm
.username,
password:
this.loginForm
.password,
endpoint:
this.loginForm
.endpoint,
websocket:
this.loginForm
.websocket,
saveCredentials:
this.loginForm
.saveCredentials,
cipher: pwd
});
});
})
.finally(() => {
this.loginForm.loading = false;
});
return args;
}
API.login({
username: this.loginForm.username,
password: this.loginForm.password,
endpoint: this.loginForm.endpoint,
websocket: this.loginForm.websocket,
saveCredentials: this.loginForm.saveCredentials
})
.then(() => {
this.$refs.loginForm.resetFields();
});
});
})
.finally(() => {
this.loginForm.loading = false;
});
return args;
}
API.login({
username: this.loginForm.username,
password: this.loginForm.password,
endpoint: this.loginForm.endpoint,
websocket: this.loginForm.websocket,
saveCredentials: this.loginForm.saveCredentials
}).finally(() => {
this.loginForm.loading = false;
});
}
});
return args;
});
}
},
logout() {

View File

@@ -1,104 +0,0 @@
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { notificationRequest } from '../api';
export default class extends baseClass {
constructor(_app, _API, _t) {
super(_app, _API, _t);
}
init() {
/**
* @params {{
userId: string,
emojiId: string
}} params
* @returns {Promise<{json: any, params}>}
*/
API.sendBoop = function (params) {
return this.call(`users/${params.userId}/boop`, {
method: 'POST',
params
}).then((json) => {
var args = {
json,
params
};
this.$emit('BOOP:SEND', args);
return args;
});
};
}
_data = {
sendBoopDialog: {
visible: false,
userId: '',
fileId: ''
}
};
_methods = {
sendBoop() {
var D = this.sendBoopDialog;
this.dismissBoop(D.userId);
var params = {
userId: D.userId
};
if (D.fileId) {
params.emojiId = D.fileId;
}
API.sendBoop(params);
D.visible = false;
},
dismissBoop(userId) {
// JANK: This is a hack to remove boop notifications when responding
var array = this.notificationTable.data;
for (var i = array.length - 1; i >= 0; i--) {
var ref = array[i];
if (
ref.type !== 'boop' ||
ref.$isExpired ||
ref.senderUserId !== userId
) {
continue;
}
notificationRequest.sendNotificationResponse({
notificationId: ref.id,
responseType: 'delete',
responseData: ''
});
}
},
showSendBoopDialog(userId) {
this.$nextTick(() =>
$app.adjustDialogZ(this.$refs.sendBoopDialog.$el)
);
var D = this.sendBoopDialog;
D.userId = userId;
D.visible = true;
if (this.emojiTable.length === 0 && API.currentUser.$isVRCPlus) {
this.refreshEmojiTable();
}
},
getEmojiValue(emojiName) {
if (!emojiName) {
return '';
}
return `vrchat_${emojiName.replace(/ /g, '_').toLowerCase()}`;
},
getEmojiName(emojiValue) {
// uppercase first letter of each word
if (!emojiValue) {
return '';
}
return emojiValue
.replace('vrchat_', '')
.replace(/_/g, ' ')
.replace(/\b\w/g, (l) => l.toUpperCase());
}
};
}

View File

@@ -1,4 +1,5 @@
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { isRealInstance, parseLocation } from '../composables/instance/utils';
import { $app, API, baseClass } from './baseClass.js';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -83,8 +84,8 @@ export default class extends baseClass {
args.ref = this.applyCurrentUser(json);
// when isGameRunning use gameLog instead of API
var $location = $app.parseLocation($app.lastLocation.location);
var $travelingLocation = $app.parseLocation(
var $location = parseLocation($app.lastLocation.location);
var $travelingLocation = parseLocation(
$app.lastLocationDestination
);
var location = $app.lastLocation.location;
@@ -94,12 +95,12 @@ export default class extends baseClass {
var travelingToWorld = $travelingLocation.worldId;
var travelingToInstance = $travelingLocation.instanceId;
if (!$app.isGameRunning && json.presence) {
if ($utils.isRealInstance(json.presence.world)) {
if (isRealInstance(json.presence.world)) {
location = `${json.presence.world}:${json.presence.instance}`;
} else {
location = json.presence.world;
}
if ($utils.isRealInstance(json.presence.travelingToWorld)) {
if (isRealInstance(json.presence.travelingToWorld)) {
travelingToLocation = `${json.presence.travelingToWorld}:${json.presence.travelingToInstance}`;
} else {
travelingToLocation = json.presence.travelingToWorld;
@@ -175,7 +176,7 @@ export default class extends baseClass {
}
Object.assign(ref, json);
if (ref.homeLocation !== ref.$homeLocation.tag) {
ref.$homeLocation = $app.parseLocation(ref.homeLocation);
ref.$homeLocation = parseLocation(ref.homeLocation);
// apply home location name to user dialog
if (
$app.userDialog.visible &&
@@ -295,13 +296,12 @@ export default class extends baseClass {
$languages: [],
$locationTag: '',
$travelingToLocation: '',
$vrchatcredits: null,
...json
};
if ($app.isGameRunning) {
ref.$previousAvatarSwapTime = Date.now();
}
ref.$homeLocation = $app.parseLocation(ref.homeLocation);
ref.$homeLocation = parseLocation(ref.homeLocation);
ref.$isVRCPlus = ref.tags.includes('system_supporter');
this.applyUserTrustLevel(ref);
this.applyUserLanguage(ref);
@@ -316,32 +316,6 @@ export default class extends baseClass {
}
return ref;
};
/**
* @typedef {{
* status: 'active' | 'offline' | 'busy' | 'ask me' | 'join me',
* statusDescription: string
* }} SaveCurrentUserParameters
*/
/**
* Updates current user's status.
* @param params {SaveCurrentUserParameters} new status to be set
* @returns {Promise<{json: any, params}>}
*/
API.saveCurrentUser = function (params) {
return this.call(`users/${this.currentUser.id}`, {
method: 'PUT',
params
}).then((json) => {
var args = {
json,
params
};
this.$emit('USER:CURRENT:SAVE', args);
return args;
});
};
}
_data = {};

View File

@@ -1,6 +1,8 @@
import configRepository from '../service/config.js';
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { worldRequest } from '../api';
import { parseLocation } from '../composables/instance/utils';
import { getLaunchURL } from '../composables/shared/utils';
import configRepository from '../service/config.js';
import { API, baseClass } from './baseClass.js';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -36,7 +38,7 @@ export default class extends baseClass {
var L = this.lastLocation$;
if (currentLocation !== this.lastLocation$.tag) {
Discord.SetTimestamps(timeStamp, 0);
L = $app.parseLocation(currentLocation);
L = parseLocation(currentLocation);
L.worldName = '';
L.thumbnailImageUrl = '';
L.worldCapacity = 0;
@@ -76,7 +78,7 @@ export default class extends baseClass {
}
switch (L.accessType) {
case 'public':
L.joinUrl = $utils.getLaunchURL(L);
L.joinUrl = getLaunchURL(L);
L.accessName = `Public #${L.instanceName} (${platform})`;
break;
case 'invite+':

View File

@@ -1,8 +1,9 @@
import * as workerTimers from 'worker-timers';
import { parseLocation } from '../composables/instance/utils';
import gameLogService from '../service/gamelog.js';
import configRepository from '../service/config.js';
import database from '../service/database.js';
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { baseClass, $app, API, $utils } from './baseClass.js';
import { userRequest } from '../api';
import dayjs from 'dayjs';
@@ -80,7 +81,7 @@ export default class extends baseClass {
this.lastLocation.location,
gameLog.dt
);
var worldName = this.replaceBioSymbols(gameLog.worldName);
var worldName = $utils.replaceBioSymbols(gameLog.worldName);
if (this.isGameRunning) {
this.lastLocationReset(gameLog.dt);
this.clearNowPlaying();
@@ -100,7 +101,7 @@ export default class extends baseClass {
this.applyGroupDialogInstances();
}
this.addInstanceJoinHistory(gameLog.location, gameLog.dt);
var L = $utils.parseLocation(gameLog.location);
var L = parseLocation(gameLog.location);
var entry = {
created_at: gameLog.dt,
type: 'Location',
@@ -789,7 +790,7 @@ export default class extends baseClass {
var videoPos = Number(data[1]);
var videoLength = Number(data[2]);
var displayName = data[3];
var videoName = this.replaceBioSymbols(data[4]);
var videoName = $utils.replaceBioSymbols(data[4]);
var videoUrl = videoName;
var videoId = 'LSMedia';
if (videoUrl === this.nowPlaying.url) {
@@ -981,29 +982,6 @@ export default class extends baseClass {
this.addGameLogEntry(gameLog, this.lastLocation.location);
},
deleteGameLogEntryPrompt(row) {
this.$confirm('Continue? Delete Log', 'Confirm', {
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
type: 'info',
callback: (action) => {
if (action === 'confirm') {
this.deleteGameLogEntry(row);
}
}
});
},
deleteGameLogEntry(row) {
$app.removeFromArray(this.gameLogTable.data, row);
database.deleteGameLogEntry(row);
console.log(row);
database.getGamelogDatabase().then((data) => {
this.gameLogSessionTable = data;
this.updateSharedFeed(true);
});
},
gameLogSearch(row) {
var value = this.gameLogTable.search.toUpperCase();
if (!value) {

View File

@@ -1,8 +1,14 @@
import * as workerTimers from 'worker-timers';
import { displayLocation, parseLocation } from '../composables/instance/utils';
import { checkVRChatCache } from '../composables/shared/utils';
import configRepository from '../service/config.js';
import database from '../service/database.js';
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { baseClass, $app, API, $utils } from './baseClass.js';
import { instanceRequest, userRequest } from '../api';
import {
photonEmojis,
photonEventType
} from '../composables/shared/constants/photon.js';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -80,111 +86,6 @@ export default class extends baseClass {
}
},
photonEventType: [
'MeshVisibility',
'AnimationFloat',
'AnimationBool',
'AnimationTrigger',
'AudioTrigger',
'PlayAnimation',
'SendMessage',
'SetParticlePlaying',
'TeleportPlayer',
'RunConsoleCommand',
'SetGameObjectActive',
'SetWebPanelURI',
'SetWebPanelVolume',
'SpawnObject',
'SendRPC',
'ActivateCustomTrigger',
'DestroyObject',
'SetLayer',
'SetMaterial',
'AddHealth',
'AddDamage',
'SetComponentActive',
'AnimationInt',
'AnimationIntAdd',
'AnimationIntSubtract',
'AnimationIntMultiply',
'AnimationIntDivide',
'AddVelocity',
'SetVelocity',
'AddAngularVelocity',
'SetAngularVelocity',
'AddForce',
'SetUIText',
'CallUdonMethod'
],
photonEmojis: [
'Angry',
'Blushing',
'Crying',
'Frown',
'Hand Wave',
'Hang Ten',
'In Love',
'Jack O Lantern',
'Kiss',
'Laugh',
'Skull',
'Smile',
'Spooky Ghost',
'Stoic',
'Sunglasses',
'Thinking',
'Thumbs Down',
'Thumbs Up',
'Tongue Out',
'Wow',
'Arrow Point',
"Can't see",
'Hourglass',
'Keyboard',
'No Headphones',
'No Mic',
'Portal',
'Shush',
'Bats',
'Cloud',
'Fire',
'Snow Fall',
'Snowball',
'Splash',
'Web',
'Beer',
'Candy',
'Candy Cane',
'Candy Corn',
'Champagne',
'Drink',
'Gingerbread',
'Ice Cream',
'Pineapple',
'Pizza',
'Tomato',
'Beachball',
'Coal',
'Confetti',
'Gift',
'Gifts',
'Life Ring',
'Mistletoe',
'Money',
'Neon Shades',
'Sun Lotion',
'Boo',
'Broken Heart',
'Exclamation',
'Go',
'Heart',
'Music Note',
'Question',
'Stop',
'Zzz'
],
photonEventTableFilter: '',
photonEventTableTypeFilter: [],
photonEventTableTypeOverlayFilter: [],
@@ -894,7 +795,7 @@ export default class extends baseClass {
var imageUrl = '';
if (type === 0) {
var emojiId = data.Parameters[245][2];
emojiName = this.photonEmojis[emojiId];
emojiName = photonEmojis[emojiId];
} else if (type === 1) {
emojiName = 'Custom';
var fileId = data.Parameters[245][1];
@@ -982,7 +883,7 @@ export default class extends baseClass {
if (this.debugPhotonLogging) {
var displayName = this.getDisplayNameFromPhotonId(senderId);
var feed = `RPC ${displayName} ${
this.photonEventType[eventData.EventType]
photonEventType[eventData.EventType]
}${eventName}`;
console.log('VrcRpc:', feed);
}
@@ -1026,7 +927,7 @@ export default class extends baseClass {
shortName
});
var location = instance.json.location;
var L = $utils.parseLocation(location);
var L = parseLocation(location);
var groupName = '';
if (L.groupId) {
groupName = await this.getGroupName(L.groupId);
@@ -1040,14 +941,14 @@ export default class extends baseClass {
// if (shortName === newShortName) {
// portalType = 'Unlocked';
// }
var displayLocation = this.displayLocation(
var _displayLocation = displayLocation(
location,
worldName,
groupName
);
this.addEntryPhotonEvent({
photonId: this.getPhotonIdFromUserId(userId),
text: `PortalSpawn to ${displayLocation}`,
text: `PortalSpawn to ${_displayLocation}`,
type: 'PortalSpawn',
shortName,
location,
@@ -1210,10 +1111,10 @@ export default class extends baseClass {
type: 'ChangeStatus',
status: photonUser.status,
previousStatus: ref.status,
statusDescription: this.replaceBioSymbols(
statusDescription: $utils.replaceBioSymbols(
photonUser.statusDescription
),
previousStatusDescription: this.replaceBioSymbols(
previousStatusDescription: $utils.replaceBioSymbols(
ref.statusDescription
),
created_at: Date.parse(gameLogDate)
@@ -1227,8 +1128,8 @@ export default class extends baseClass {
return;
}
var avatar = user.avatarDict;
avatar.name = this.replaceBioSymbols(avatar.name);
avatar.description = this.replaceBioSymbols(avatar.description);
avatar.name = $utils.replaceBioSymbols(avatar.name);
avatar.description = $utils.replaceBioSymbols(avatar.description);
var platform = '';
if (user.last_platform === 'android') {
platform = 'Android';
@@ -1240,7 +1141,7 @@ export default class extends baseClass {
platform = 'Desktop';
}
this.photonUserSusieCheck(photonId, user, gameLogDate);
$utils.checkVRChatCache(avatar).then((cacheInfo) => {
checkVRChatCache(avatar).then((cacheInfo) => {
var inCache = false;
if (cacheInfo.Item1 > 0) {
inCache = true;
@@ -1410,9 +1311,11 @@ export default class extends baseClass {
oldAvatarId !== avatar.id &&
photonId !== this.photonLobbyCurrentUser
) {
avatar.name = this.replaceBioSymbols(avatar.name);
avatar.description = this.replaceBioSymbols(avatar.description);
$utils.checkVRChatCache(avatar).then((cacheInfo) => {
avatar.name = $utils.replaceBioSymbols(avatar.name);
avatar.description = $utils.replaceBioSymbols(
avatar.description
);
checkVRChatCache(avatar).then((cacheInfo) => {
var inCache = false;
if (cacheInfo.Item1 > 0) {
inCache = true;

View File

@@ -7,6 +7,7 @@ import {
instanceRequest,
groupRequest
} from '../api';
import $utils from './utils';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -171,8 +172,8 @@ export default class extends baseClass {
var D = $app.groupDialog;
if (D.id === args.params.groupId) {
for (var post of args.posts) {
post.title = $app.replaceBioSymbols(post.title);
post.text = $app.replaceBioSymbols(post.text);
post.title = $utils.replaceBioSymbols(post.title);
post.text = $utils.replaceBioSymbols(post.text);
}
if (args.posts.length > 0) {
D.announcement = args.posts[0];
@@ -189,8 +190,8 @@ export default class extends baseClass {
}
var newPost = args.json;
newPost.title = $app.replaceBioSymbols(newPost.title);
newPost.text = $app.replaceBioSymbols(newPost.text);
newPost.title = $utils.replaceBioSymbols(newPost.title);
newPost.text = $utils.replaceBioSymbols(newPost.text);
var hasPost = false;
// update existing post
for (var post of D.posts) {
@@ -275,9 +276,9 @@ export default class extends baseClass {
API.applyGroup = function (json) {
var ref = this.cachedGroups.get(json.id);
json.rules = $app.replaceBioSymbols(json.rules);
json.name = $app.replaceBioSymbols(json.name);
json.description = $app.replaceBioSymbols(json.description);
json.rules = $utils.replaceBioSymbols(json.rules);
json.name = $utils.replaceBioSymbols(json.name);
json.description = $utils.replaceBioSymbols(json.description);
if (typeof ref === 'undefined') {
ref = {
id: '',
@@ -912,9 +913,6 @@ export default class extends baseClass {
case 'Unsubscribe To Announcements':
this.setGroupSubscription(D.id, false);
break;
case 'Invite To Group':
this.showInviteGroupDialog(D.id, '');
break;
}
},
@@ -1050,17 +1048,6 @@ export default class extends baseClass {
this.userDialog.representedGroup = args.json;
return args;
});
},
showInviteGroupDialog(groupId, userId) {
const D = this.inviteGroupDialog;
D.userIds = '';
D.groups = [];
D.groupId = groupId;
D.groupName = groupId;
D.userId = userId;
D.userObject = {};
D.visible = true;
}
};
}

View File

@@ -24,85 +24,9 @@ export default class extends baseClass {
}
$app.languageDialog.languages = data;
});
API.$on('LOGOUT', function () {
$app.languageDialog.visible = false;
});
}
_data = {
// vrchat to famfamfam language mappings
languageMappings: {
eng: 'us',
kor: 'kr',
rus: 'ru',
spa: 'es',
por: 'pt',
zho: 'cn',
deu: 'de',
jpn: 'jp',
fra: 'fr',
swe: 'se',
nld: 'nl',
pol: 'pl',
dan: 'dk',
nor: 'no',
ita: 'it',
tha: 'th',
fin: 'fi',
hun: 'hu',
ces: 'cz',
tur: 'tr',
ara: 'ae',
ron: 'ro',
vie: 'vn',
ukr: 'ua',
ase: 'us',
bfi: 'gb',
dse: 'nl',
fsl: 'fr',
jsl: 'jp',
kvk: 'kr',
mlt: 'mt',
ind: 'id',
hrv: 'hr',
heb: 'he',
afr: 'af',
ben: 'be',
bul: 'bg',
cmn: 'cn',
cym: 'cy',
ell: 'el',
est: 'et',
fil: 'ph',
gla: 'gd',
gle: 'ga',
hin: 'hi',
hmn: 'cn',
hye: 'hy',
isl: 'is',
lav: 'lv',
lit: 'lt',
ltz: 'lb',
mar: 'hi',
mkd: 'mk',
msa: 'my',
sco: 'gd',
slk: 'sk',
slv: 'sl',
tel: 'hi',
mri: 'nz',
wuu: 'cn',
yue: 'cn',
tws: 'cn',
asf: 'au',
nzs: 'nz',
gsg: 'de',
epo: 'eo',
tok: 'tok'
},
subsetOfLanguages: [],
languageDialog: {
@@ -113,54 +37,5 @@ export default class extends baseClass {
}
};
_methods = {
languageClass(language) {
var style = {};
var mapping = this.languageMappings[language];
if (typeof mapping !== 'undefined') {
style[mapping] = true;
} else {
style.unknown = true;
}
return style;
},
addUserLanguage(language) {
if (language !== String(language)) {
return;
}
const D = this.languageDialog;
D.loading = true;
userRequest
.addUserTags({
tags: [`language_${language}`]
})
.finally(function () {
D.loading = false;
});
},
removeUserLanguage(language) {
if (language !== String(language)) {
return;
}
const D = this.languageDialog;
D.loading = true;
userRequest
.removeUserTags({
tags: [`language_${language}`]
})
.finally(function () {
D.loading = false;
});
},
showLanguageDialog() {
this.$nextTick(() =>
$app.adjustDialogZ(this.$refs.languageDialog.$el)
);
var D = this.languageDialog;
D.visible = true;
}
};
_methods = {};
}

View File

@@ -27,11 +27,6 @@ export default class extends baseClass {
}
},
onUserMemoChange() {
var D = this.userDialog;
this.saveUserMemo(D.id, D.memo);
},
async getUserMemo(userId) {
try {
return await database.getUserMemo(userId);

View File

@@ -132,139 +132,6 @@ export default class extends baseClass {
);
},
promptUserIdDialog() {
this.$prompt(
$t('prompt.direct_access_user_id.description'),
$t('prompt.direct_access_user_id.header'),
{
distinguishCancelAndClose: true,
confirmButtonText: $t('prompt.direct_access_user_id.ok'),
cancelButtonText: $t('prompt.direct_access_user_id.cancel'),
inputPattern: /\S+/,
inputErrorMessage: $t(
'prompt.direct_access_user_id.input_error'
),
callback: (action, instance) => {
if (action === 'confirm' && instance.inputValue) {
var testUrl = instance.inputValue.substring(0, 15);
if (testUrl === 'https://vrchat.') {
var userId = this.parseUserUrl(
instance.inputValue
);
if (userId) {
this.showUserDialog(userId);
} else {
this.$message({
message: $t(
'prompt.direct_access_user_id.message.error'
),
type: 'error'
});
}
} else {
this.showUserDialog(instance.inputValue);
}
}
}
}
);
},
promptUsernameDialog() {
this.$prompt(
$t('prompt.direct_access_username.description'),
$t('prompt.direct_access_username.header'),
{
distinguishCancelAndClose: true,
confirmButtonText: $t('prompt.direct_access_username.ok'),
cancelButtonText: $t(
'prompt.direct_access_username.cancel'
),
inputPattern: /\S+/,
inputErrorMessage: $t(
'prompt.direct_access_username.input_error'
),
callback: (action, instance) => {
if (action === 'confirm' && instance.inputValue) {
this.lookupUser({
displayName: instance.inputValue
});
}
}
}
);
},
promptWorldDialog() {
this.$prompt(
$t('prompt.direct_access_world_id.description'),
$t('prompt.direct_access_world_id.header'),
{
distinguishCancelAndClose: true,
confirmButtonText: $t('prompt.direct_access_world_id.ok'),
cancelButtonText: $t(
'prompt.direct_access_world_id.cancel'
),
inputPattern: /\S+/,
inputErrorMessage: $t(
'prompt.direct_access_world_id.input_error'
),
callback: (action, instance) => {
if (action === 'confirm' && instance.inputValue) {
if (!this.directAccessWorld(instance.inputValue)) {
this.$message({
message: $t(
'prompt.direct_access_world_id.message.error'
),
type: 'error'
});
}
}
}
}
);
},
promptAvatarDialog() {
this.$prompt(
$t('prompt.direct_access_avatar_id.description'),
$t('prompt.direct_access_avatar_id.header'),
{
distinguishCancelAndClose: true,
confirmButtonText: $t('prompt.direct_access_avatar_id.ok'),
cancelButtonText: $t(
'prompt.direct_access_avatar_id.cancel'
),
inputPattern: /\S+/,
inputErrorMessage: $t(
'prompt.direct_access_avatar_id.input_error'
),
callback: (action, instance) => {
if (action === 'confirm' && instance.inputValue) {
var testUrl = instance.inputValue.substring(0, 15);
if (testUrl === 'https://vrchat.') {
var avatarId = this.parseAvatarUrl(
instance.inputValue
);
if (avatarId) {
this.showAvatarDialog(avatarId);
} else {
this.$message({
message: $t(
'prompt.direct_access_avatar_id.message.error'
),
type: 'error'
});
}
} else {
this.showAvatarDialog(instance.inputValue);
}
}
}
}
);
},
promptOmniDirectDialog() {
this.$prompt(
$t('prompt.direct_access_omni.description'),

View File

@@ -1,8 +1,9 @@
import Vue from 'vue';
import VueMarkdown from 'vue-markdown';
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { instanceRequest, userRequest } from '../api';
import utils from './utils';
import { hasGroupPermission } from '../composables/group/utils';
import { parseLocation } from '../composables/instance/utils';
import { $app, $t, API, baseClass } from './baseClass.js';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -60,7 +61,7 @@ export default class extends baseClass {
this.selfInvite(this.location, this.shortname);
},
selfInvite(location, shortName) {
const L = utils.parseLocation(location);
const L = parseLocation(location);
if (!L.isRealInstance) {
return;
}
@@ -165,7 +166,7 @@ export default class extends baseClass {
if (!this.location) {
return;
}
var L = $utils.parseLocation(this.location);
var L = parseLocation(this.location);
if (!L.groupId) {
return;
}
@@ -320,7 +321,7 @@ export default class extends baseClass {
// check group perms
var groupId = this.instance.ownerId;
var group = API.cachedGroups.get(groupId);
this.canCloseInstance = utils.hasGroupPermission(
this.canCloseInstance = hasGroupPermission(
group,
'group-instance-moderate'
);

View File

@@ -1,8 +1,5 @@
import Noty from 'noty';
let echarts = null;
// messy here, organize later
const _utils = {
removeFromArray(array, item) {
var { length } = array;
@@ -14,7 +11,6 @@ const _utils = {
}
return false;
},
arraysMatch(a, b) {
if (!Array.isArray(a) || !Array.isArray(b)) {
return false;
@@ -27,12 +23,10 @@ const _utils = {
)
);
},
escapeTag(tag) {
var s = String(tag);
return s.replace(/["&'<>]/g, (c) => `&#${c.charCodeAt(0)};`);
},
escapeTagRecursive(obj) {
if (typeof obj === 'string') {
return this.escapeTag(obj);
@@ -44,7 +38,6 @@ const _utils = {
}
return obj;
},
timeToText(sec, isNeedSeconds = false) {
let n = Number(sec);
if (isNaN(n)) {
@@ -72,7 +65,6 @@ const _utils = {
}
return arr.join(' ');
},
textToHex(text) {
var s = String(text);
return s
@@ -80,7 +72,6 @@ const _utils = {
.map((c) => c.charCodeAt(0).toString(16))
.join(' ');
},
commaNumber(num) {
if (!num) {
return '0';
@@ -88,182 +79,6 @@ const _utils = {
var s = String(Number(num));
return s.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
},
isRealInstance(instanceId) {
if (!instanceId) {
return false;
}
switch (instanceId) {
case ':':
case 'offline':
case 'offline:offline':
case 'private':
case 'private:private':
case 'traveling':
case 'traveling:traveling':
case instanceId.startsWith('local'):
return false;
}
return true;
},
parseLocation(tag) {
var _tag = String(tag || '');
var ctx = {
tag: _tag,
isOffline: false,
isPrivate: false,
isTraveling: false,
isRealInstance: false,
worldId: '',
instanceId: '',
instanceName: '',
accessType: '',
accessTypeName: '',
region: '',
shortName: '',
userId: null,
hiddenId: null,
privateId: null,
friendsId: null,
groupId: null,
groupAccessType: null,
canRequestInvite: false,
strict: false,
ageGate: false
};
if (_tag === 'offline' || _tag === 'offline:offline') {
ctx.isOffline = true;
} else if (_tag === 'private' || _tag === 'private:private') {
ctx.isPrivate = true;
} else if (_tag === 'traveling' || _tag === 'traveling:traveling') {
ctx.isTraveling = true;
} else if (!_tag.startsWith('local')) {
ctx.isRealInstance = true;
var sep = _tag.indexOf(':');
// technically not part of instance id, but might be there when coping id from url so why not support it
var shortNameQualifier = '&shortName=';
var shortNameIndex = _tag.indexOf(shortNameQualifier);
if (shortNameIndex >= 0) {
ctx.shortName = _tag.substr(
shortNameIndex + shortNameQualifier.length
);
_tag = _tag.substr(0, shortNameIndex);
}
if (sep >= 0) {
ctx.worldId = _tag.substr(0, sep);
ctx.instanceId = _tag.substr(sep + 1);
ctx.instanceId.split('~').forEach((s, i) => {
if (i) {
var A = s.indexOf('(');
var Z = A >= 0 ? s.lastIndexOf(')') : -1;
var key = Z >= 0 ? s.substr(0, A) : s;
var value = A < Z ? s.substr(A + 1, Z - A - 1) : '';
if (key === 'hidden') {
ctx.hiddenId = value;
} else if (key === 'private') {
ctx.privateId = value;
} else if (key === 'friends') {
ctx.friendsId = value;
} else if (key === 'canRequestInvite') {
ctx.canRequestInvite = true;
} else if (key === 'region') {
ctx.region = value;
} else if (key === 'group') {
ctx.groupId = value;
} else if (key === 'groupAccessType') {
ctx.groupAccessType = value;
} else if (key === 'strict') {
ctx.strict = true;
} else if (key === 'ageGate') {
ctx.ageGate = true;
}
} else {
ctx.instanceName = s;
}
});
ctx.accessType = 'public';
if (ctx.privateId !== null) {
if (ctx.canRequestInvite) {
// InvitePlus
ctx.accessType = 'invite+';
} else {
// InviteOnly
ctx.accessType = 'invite';
}
ctx.userId = ctx.privateId;
} else if (ctx.friendsId !== null) {
// FriendsOnly
ctx.accessType = 'friends';
ctx.userId = ctx.friendsId;
} else if (ctx.hiddenId !== null) {
// FriendsOfGuests
ctx.accessType = 'friends+';
ctx.userId = ctx.hiddenId;
} else if (ctx.groupId !== null) {
// Group
ctx.accessType = 'group';
}
ctx.accessTypeName = ctx.accessType;
if (ctx.groupAccessType !== null) {
if (ctx.groupAccessType === 'public') {
ctx.accessTypeName = 'groupPublic';
} else if (ctx.groupAccessType === 'plus') {
ctx.accessTypeName = 'groupPlus';
}
}
} else {
ctx.worldId = _tag;
}
}
return ctx;
},
displayLocation(location, worldName, groupName) {
var text = worldName;
var L = this.parseLocation(location);
if (L.isOffline) {
text = 'Offline';
} else if (L.isPrivate) {
text = 'Private';
} else if (L.isTraveling) {
text = 'Traveling';
} else if (L.worldId) {
if (groupName) {
text = `${worldName} ${L.accessTypeName}(${groupName})`;
} else if (L.instanceId) {
text = `${worldName} ${L.accessTypeName}`;
}
}
return text;
},
extractFileId(s) {
var match = String(s).match(/file_[0-9A-Za-z-]+/);
return match ? match[0] : '';
},
extractFileVersion(s) {
var match = /(?:\/file_[0-9A-Za-z-]+\/)([0-9]+)/gi.exec(s);
return match ? match[1] : '';
},
extractVariantVersion(url) {
if (!url) {
return '0';
}
try {
const params = new URLSearchParams(new URL(url).search);
const version = params.get('v');
if (version) {
return version;
}
return '0';
} catch {
return '0';
}
},
buildTreeData(json) {
var node = [];
for (var key in json) {
@@ -325,8 +140,6 @@ const _utils = {
});
return node;
},
// app.js 4900ln
// descending
compareByCreatedAt(a, b) {
if (
@@ -406,298 +219,69 @@ const _utils = {
}
return false;
},
convertFileUrlToImageUrl(url, resolution = 128) {
if (!url) {
compareByName(a, b) {
if (typeof a.name !== 'string' || typeof b.name !== 'string') {
return 0;
}
return a.name.localeCompare(b.name);
},
replaceBioSymbols(text) {
if (!text) {
return '';
}
/**
* possible patterns?
* /file/file_fileId/version
* /file/file_fileId/version/
* /file/file_fileId/version/file
* /file/file_fileId/version/file/
*/
const pattern = /file\/file_([a-f0-9-]+)\/(\d+)(\/file)?\/?$/;
const match = url.match(pattern);
if (match) {
const fileId = match[1];
const version = match[2];
return `https://api.vrchat.cloud/api/1/image/file_${fileId}/${version}/${resolution}`;
var symbolList = {
'@': '',
'#': '',
$: '',
'%': '',
'&': '',
'=': '',
'+': '',
'/': '',
'\\': '',
';': ';',
':': '˸',
',': '',
'?': '',
'!': 'ǃ',
'"': '',
'<': '≺',
'>': '≻',
'.': '',
'^': '',
'{': '',
'}': '',
'[': '',
']': '',
'(': '',
')': '',
'|': '',
'*': ''
};
var newText = text;
for (var key in symbolList) {
var regex = new RegExp(symbolList[key], 'g');
newText = newText.replace(regex, key);
}
// no match return origin url
return url;
return newText.replace(/ {1,}/g, ' ').trimRight();
},
replaceVrcPackageUrl(url) {
if (!url) {
return '';
}
return url.replace('https://api.vrchat.cloud/', 'https://vrchat.com/');
},
getLaunchURL(instance) {
var L = instance;
if (L.instanceId) {
if (L.shortName) {
return `https://vrchat.com/home/launch?worldId=${encodeURIComponent(
L.worldId
)}&instanceId=${encodeURIComponent(
L.instanceId
)}&shortName=${encodeURIComponent(L.shortName)}`;
}
return `https://vrchat.com/home/launch?worldId=${encodeURIComponent(
L.worldId
)}&instanceId=${encodeURIComponent(L.instanceId)}`;
}
return `https://vrchat.com/home/launch?worldId=${encodeURIComponent(
L.worldId
)}`;
},
getFaviconUrl(resource) {
try {
const url = new URL(resource);
return `https://icons.duckduckgo.com/ip2/${url.host}.ico`;
} catch (err) {
return '';
}
},
copyToClipboard(text) {
navigator.clipboard
.writeText(text)
.then(() => {
window.$app.$message({
message: 'Copied successfully!',
type: 'success'
});
})
.catch((err) => {
console.error('Copy failed:', err);
this.$message.error('Copy failed!');
});
},
hasGroupPermission(ref, permission) {
// descending
compareByUpdatedAt(a, b) {
if (
ref &&
ref.myMember &&
ref.myMember.permissions &&
(ref.myMember.permissions.includes('*') ||
ref.myMember.permissions.includes(permission))
typeof a.updated_at !== 'string' ||
typeof b.updated_at !== 'string'
) {
return true;
return 0;
}
return false;
},
compareUnityVersion(unitySortNumber) {
if (!window.API.cachedConfig.sdkUnityVersion) {
console.error('No cachedConfig.sdkUnityVersion');
return false;
var A = a.updated_at.toUpperCase();
var B = b.updated_at.toUpperCase();
if (A < B) {
return 1;
}
// 2022.3.6f1 2022 03 06 000
// 2019.4.31f1 2019 04 31 000
// 5.3.4p1 5 03 04 010
// 2019.4.31f1c1 is a thing
var array = API.cachedConfig.sdkUnityVersion.split('.');
if (array.length < 3) {
console.error('Invalid cachedConfig.sdkUnityVersion');
return false;
if (A > B) {
return -1;
}
var currentUnityVersion = array[0];
currentUnityVersion += array[1].padStart(2, '0');
var indexFirstLetter = array[2].search(/[a-zA-Z]/);
if (indexFirstLetter > -1) {
currentUnityVersion += array[2]
.substr(0, indexFirstLetter)
.padStart(2, '0');
currentUnityVersion += '0';
var letter = array[2].substr(indexFirstLetter, 1);
if (letter === 'p') {
currentUnityVersion += '1';
} else {
// f
currentUnityVersion += '0';
}
currentUnityVersion += '0';
} else {
// just in case
currentUnityVersion += '000';
}
// just in case
currentUnityVersion = currentUnityVersion.replace(/\D/g, '');
if (
parseInt(unitySortNumber, 10) <= parseInt(currentUnityVersion, 10)
) {
return true;
}
return false;
},
async checkVRChatCache(ref) {
if (!ref.unityPackages) {
return { Item1: -1, Item2: false, Item3: '' };
}
var assetUrl = '';
var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i];
if (unityPackage.variant && unityPackage.variant !== 'security') {
continue;
}
if (
unityPackage.platform === 'standalonewindows' &&
_utils.compareUnityVersion(unityPackage.unitySortNumber)
) {
assetUrl = unityPackage.assetUrl;
if (unityPackage.variant !== 'standard') {
variant = unityPackage.variant;
}
break;
}
}
if (!assetUrl) {
assetUrl = ref.assetUrl;
}
var id = _utils.extractFileId(assetUrl);
var version = parseInt(_utils.extractFileVersion(assetUrl), 10);
var variantVersion = parseInt(
_utils.extractVariantVersion(assetUrl),
10
);
if (!id || !version) {
return { Item1: -1, Item2: false, Item3: '' };
}
return AssetBundleManager.CheckVRChatCache(
id,
version,
variant,
variantVersion
);
},
async deleteVRChatCache(ref) {
var assetUrl = '';
var variant = '';
for (var i = ref.unityPackages.length - 1; i > -1; i--) {
var unityPackage = ref.unityPackages[i];
if (
unityPackage.variant &&
unityPackage.variant !== 'standard' &&
unityPackage.variant !== 'security'
) {
continue;
}
if (
unityPackage.platform === 'standalonewindows' &&
$utils.compareUnityVersion(unityPackage.unitySortNumber)
) {
assetUrl = unityPackage.assetUrl;
if (unityPackage.variant !== 'standard') {
variant = unityPackage.variant;
}
break;
}
}
var id = $utils.extractFileId(assetUrl);
var version = parseInt($utils.extractFileVersion(assetUrl), 10);
var variantVersion = parseInt(
$utils.extractVariantVersion(assetUrl),
10
);
await AssetBundleManager.DeleteCache(
id,
version,
variant,
variantVersion
);
},
downloadAndSaveJson(fileName, data) {
if (!fileName || !data) {
return;
}
try {
var link = document.createElement('a');
link.setAttribute(
'href',
`data:application/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(data, null, 2)
)}`
);
link.setAttribute('download', `${fileName}.json`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch {
new Noty({
type: 'error',
text: $app.escapeTag('Failed to download JSON.')
}).show();
}
},
getAvailablePlatforms(unityPackages) {
var isPC = false;
var isQuest = false;
var isIos = false;
if (typeof unityPackages === 'object') {
for (var unityPackage of unityPackages) {
if (
unityPackage.variant &&
unityPackage.variant !== 'standard' &&
unityPackage.variant !== 'security'
) {
continue;
}
if (unityPackage.platform === 'standalonewindows') {
isPC = true;
} else if (unityPackage.platform === 'android') {
isQuest = true;
} else if (unityPackage.platform === 'ios') {
isIos = true;
}
}
}
return { isPC, isQuest, isIos };
},
getPlatformInfo(unityPackages) {
var pc = {};
var android = {};
var ios = {};
if (typeof unityPackages === 'object') {
for (var unityPackage of unityPackages) {
if (
unityPackage.variant &&
unityPackage.variant !== 'standard' &&
unityPackage.variant !== 'security'
) {
continue;
}
if (unityPackage.platform === 'standalonewindows') {
if (
unityPackage.performanceRating === 'None' &&
pc.performanceRating
) {
continue;
}
pc = unityPackage;
} else if (unityPackage.platform === 'android') {
if (
unityPackage.performanceRating === 'None' &&
android.performanceRating
) {
continue;
}
android = unityPackage;
} else if (unityPackage.platform === 'ios') {
if (
unityPackage.performanceRating === 'None' &&
ios.performanceRating
) {
continue;
}
ios = unityPackage;
}
}
}
return { pc, android, ios };
return 0;
}
};

View File

@@ -1,5 +1,7 @@
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
import { userRequest } from '../api';
import { displayLocation } from '../composables/instance/utils';
import { extractFileId, extractFileVersion } from '../composables/shared/utils';
import { $app, API, baseClass } from './baseClass.js';
export default class extends baseClass {
constructor(_app, _API, _t) {
@@ -356,8 +358,8 @@ export default class extends baseClass {
async notySaveImage(noty) {
var imageUrl = await this.notyGetImage(noty);
var fileId = this.extractFileId(imageUrl);
var fileVersion = this.extractFileVersion(imageUrl);
var fileId = extractFileId(imageUrl);
var fileVersion = extractFileVersion(imageUrl);
var imageLocation = '';
try {
if (fileId && fileVersion) {
@@ -414,7 +416,7 @@ export default class extends baseClass {
break;
case 'GPS':
this.speak(
`${displayName} is in ${this.displayLocation(
`${displayName} is in ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -424,7 +426,7 @@ export default class extends baseClass {
case 'Online':
var locationName = '';
if (noty.worldName) {
locationName = ` to ${this.displayLocation(
locationName = ` to ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -442,7 +444,7 @@ export default class extends baseClass {
break;
case 'invite':
this.speak(
`${displayName} has invited you to ${this.displayLocation(
`${displayName} has invited you to ${displayLocation(
noty.details.worldId,
noty.details.worldName,
noty.groupName
@@ -513,7 +515,7 @@ export default class extends baseClass {
case 'PortalSpawn':
if (displayName) {
this.speak(
`${displayName} has spawned a portal to ${this.displayLocation(
`${displayName} has spawned a portal to ${displayLocation(
noty.instanceId,
noty.worldName,
noty.groupName
@@ -599,7 +601,7 @@ export default class extends baseClass {
case 'GPS':
AppApi.XSNotification(
'VRCX',
`${noty.displayName} is in ${this.displayLocation(
`${noty.displayName} is in ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -611,7 +613,7 @@ export default class extends baseClass {
case 'Online':
var locationName = '';
if (noty.worldName) {
locationName = ` to ${this.displayLocation(
locationName = ` to ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -645,7 +647,7 @@ export default class extends baseClass {
'VRCX',
`${
noty.senderUsername
} has invited you to ${this.displayLocation(
} has invited you to ${displayLocation(
noty.details.worldId,
noty.details.worldName
)}${message}`,
@@ -755,7 +757,7 @@ export default class extends baseClass {
'VRCX',
`${
noty.displayName
} has spawned a portal to ${this.displayLocation(
} has spawned a portal to ${displayLocation(
noty.instanceId,
noty.worldName,
noty.groupName
@@ -915,7 +917,7 @@ export default class extends baseClass {
playOvrtHudNotifications,
playOvrtWristNotifications,
'VRCX',
`${noty.displayName} is in ${this.displayLocation(
`${noty.displayName} is in ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -927,7 +929,7 @@ export default class extends baseClass {
case 'Online':
var locationName = '';
if (noty.worldName) {
locationName = ` to ${this.displayLocation(
locationName = ` to ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -969,7 +971,7 @@ export default class extends baseClass {
'VRCX',
`${
noty.senderUsername
} has invited you to ${this.displayLocation(
} has invited you to ${displayLocation(
noty.details.worldId,
noty.details.worldName
)}${message}`,
@@ -1155,7 +1157,7 @@ export default class extends baseClass {
'VRCX',
`${
noty.displayName
} has spawned a portal to ${this.displayLocation(
} has spawned a portal to ${displayLocation(
noty.instanceId,
noty.worldName,
noty.groupName
@@ -1345,7 +1347,7 @@ export default class extends baseClass {
case 'GPS':
this.desktopNotification(
noty.displayName,
`is in ${this.displayLocation(
`is in ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -1356,7 +1358,7 @@ export default class extends baseClass {
case 'Online':
var locationName = '';
if (noty.worldName) {
locationName = ` to ${this.displayLocation(
locationName = ` to ${displayLocation(
noty.location,
noty.worldName,
noty.groupName
@@ -1385,7 +1387,7 @@ export default class extends baseClass {
case 'invite':
this.desktopNotification(
noty.senderUsername,
`has invited you to ${this.displayLocation(
`has invited you to ${displayLocation(
noty.details.worldId,
noty.details.worldName
)}${message}`,
@@ -1515,7 +1517,7 @@ export default class extends baseClass {
if (noty.displayName) {
this.desktopNotification(
noty.displayName,
`has spawned a portal to ${this.displayLocation(
`has spawned a portal to ${displayLocation(
noty.instanceId,
noty.worldName,
noty.groupName

View File

@@ -1,5 +1,6 @@
import * as workerTimers from 'worker-timers';
import Noty from 'noty';
import { parseLocation } from '../composables/instance/utils';
import { baseClass, $app, API, $utils } from './baseClass.js';
import { groupRequest } from '../api';
@@ -265,8 +266,8 @@ export default class extends baseClass {
case 'friend-online':
// Where is instanceId, travelingToWorld, travelingToInstance?
// More JANK, what a mess
var $location = $utils.parseLocation(content.location);
var $travelingToLocation = $utils.parseLocation(
var $location = parseLocation(content.location);
var $travelingToLocation = parseLocation(
content.travelingToLocation
);
if (content?.user?.id) {
@@ -367,8 +368,8 @@ export default class extends baseClass {
break;
case 'friend-location':
var $location = $utils.parseLocation(content.location);
var $travelingToLocation = $utils.parseLocation(
var $location = parseLocation(content.location);
var $travelingToLocation = parseLocation(
content.travelingToLocation
);
if (!content?.user?.id) {