diff --git a/.vscode/settings.json b/.vscode/settings.json
index 17dee1bc..4f8c231c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,10 @@
{
- "i18n-ally.localesPaths": ["html/src/localization/strings"],
- "i18n-ally.keystyle": "nested",
- "i18n-ally.sourceLanguage": "en"
+ "i18n-ally.localesPaths": ["html/src/localization/strings"],
+ "i18n-ally.keystyle": "nested",
+ "i18n-ally.sourceLanguage": "en",
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true,
+ "[javascript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ }
}
diff --git a/AppApi.cs b/AppApi.cs
index 2036e111..7820a04f 100644
--- a/AppApi.cs
+++ b/AppApi.cs
@@ -255,7 +255,7 @@ namespace VRCX
return ImageCache.GetImage(url, fileId, version);
}
- public void DesktopNotification(string BoldText, string Text, string Image)
+ public void DesktopNotification(string BoldText, string Text = "", string Image = "")
{
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText02);
XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
@@ -288,7 +288,7 @@ namespace VRCX
public string sourceApp { get; set; }
}
- public void XSNotification(string Title, string Content, int Timeout, string Image)
+ public void XSNotification(string Title, string Content, int Timeout, string Image = "")
{
bool UseBase64Icon;
string Icon;
diff --git a/html/src/app.js b/html/src/app.js
index 03a6bc69..440bd4b5 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -826,9 +826,9 @@ speechSynthesis.getVoices();
template:
"" +
'' +
- '{{ text }}' +
- '({{ groupName }})' +
- '' +
+ '{{ text }}' +
+ '({{ groupName }})' +
+ '' +
'',
props: {
location: String,
@@ -955,9 +955,9 @@ speechSynthesis.getVoices();
template:
'' +
'' +
- ' #{{ instanceName }} {{ accessType }}' +
- '({{ groupName }})' +
- '' +
+ ' #{{ instanceName }} {{ accessType }}' +
+ '({{ groupName }})' +
+ '' +
'',
props: {
locationobject: Object,
@@ -1009,9 +1009,11 @@ speechSynthesis.getVoices();
this.groupName = this.grouphint;
} else if (this.locationobject.groupId) {
this.groupName = this.locationobject.groupId;
- $app.getGroupName(this.location).then((groupName) => {
- this.groupName = groupName;
- });
+ $app.getGroupName(this.locationobject.groupId).then(
+ (groupName) => {
+ this.groupName = groupName;
+ }
+ );
}
},
showLaunchDialog() {
@@ -1188,14 +1190,19 @@ speechSynthesis.getVoices();
args.ref = this.applyCurrentUser(json);
var location = '';
var travelingToLocation = '';
- if (json.presence?.world && $app.isRealInstance(json.presence.world)) {
- location = `${json.presence.world}:${json.presence.instance}`;
+ if (json.presence?.world) {
+ if ($app.isRealInstance(json.presence.world)) {
+ location = `${json.presence.world}:${json.presence.instance}`;
+ } else {
+ location = json.presence.world;
+ }
}
- if (
- json.presence?.travelingToWorld &&
- $app.isRealInstance(json.presence.travelingToWorld)
- ) {
- travelingToLocation = `${json.presence.travelingToWorld}:${json.presence.travelingToInstance}`;
+ if (json.presence?.travelingToWorld) {
+ if ($app.isRealInstance(json.presence.travelingToWorld)) {
+ travelingToLocation = `${json.presence.travelingToWorld}:${json.presence.travelingToInstance}`;
+ } else {
+ travelingToLocation = json.presence.travelingToWorld;
+ }
}
this.applyUser({
id: json.id,
@@ -1892,6 +1899,24 @@ speechSynthesis.getVoices();
});
};
+ /*
+ params: {
+ userId: string
+ }
+ */
+ API.getUserFeedback = function (params) {
+ return this.call(`users/${params.userId}/feedback`, {
+ method: 'GET'
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('USER:FEEDBACK', args);
+ return args;
+ });
+ };
+
// API: World
API.cachedWorlds = new Map();
@@ -3785,7 +3810,11 @@ speechSynthesis.getVoices();
return;
}
this.isFavoriteLoading = true;
- await this.getFavoriteLimits();
+ try {
+ await this.getFavoriteLimits();
+ } catch (err) {
+ console.error(err);
+ }
this.expireFavorites();
this.bulk({
fn: 'getFavorites',
@@ -7760,10 +7789,9 @@ speechSynthesis.getVoices();
var groupName = '';
var groupId = data;
if (!data.startsWith('grp_')) {
- var L = API.parseLocation(location);
- if (L.groupId) {
- groupId = L.groupId;
- } else {
+ var L = API.parseLocation(data);
+ groupId = L.groupId;
+ if (!L.groupId) {
return '';
}
}
@@ -9489,7 +9517,7 @@ speechSynthesis.getVoices();
if (!this.photonLobbyWatcherLoop) {
return;
}
- if (this.photonLobbyCurrent.size <= 1) {
+ if (this.photonLobbyCurrent.size === 0) {
this.photonLobbyWatcherLoopStop();
return;
}
@@ -10466,8 +10494,12 @@ speechSynthesis.getVoices();
type: 'ChangeStatus',
status: photonUser.status,
previousStatus: ref.status,
- statusDescription: photonUser.statusDescription,
- previousStatusDescription: ref.statusDescription,
+ statusDescription: this.replaceBioSymbols(
+ photonUser.statusDescription
+ ),
+ previousStatusDescription: this.replaceBioSymbols(
+ ref.statusDescription
+ ),
created_at: Date.parse(gameLogDate)
});
}
@@ -10479,6 +10511,8 @@ speechSynthesis.getVoices();
return;
}
var avatar = user.avatarDict;
+ avatar.name = this.replaceBioSymbols(avatar.name);
+ avatar.description = this.replaceBioSymbols(avatar.description);
var platform = '';
if (user.last_platform === 'android') {
platform = 'Quest';
@@ -10613,6 +10647,8 @@ speechSynthesis.getVoices();
oldAvatarId !== avatar.id &&
photonId !== this.photonLobbyCurrentUser
) {
+ avatar.name = this.replaceBioSymbols(avatar.name);
+ avatar.description = this.replaceBioSymbols(avatar.description);
this.checkVRChatCache(avatar).then((cacheInfo) => {
var inCache = false;
if (cacheInfo[0] > 0) {
@@ -10662,7 +10698,7 @@ speechSynthesis.getVoices();
}
var {groupOnNameplate} = this.photonLobbyJointime.get(photonId);
if (
- groupOnNameplate &&
+ typeof groupOnNameplate !== 'undefined' &&
groupOnNameplate !== groupId &&
photonId !== this.photonLobbyCurrentUser
) {
@@ -11412,11 +11448,6 @@ speechSynthesis.getVoices();
this.showUserDialog(ref.userId);
return;
}
- if (ref.displayName === 'F⁄A-18E Super Hornet') {
- // :eyes:
- this.showUserDialog('usr_5cd9007b-1802-45fe-92e2-0b6617639344');
- return;
- }
if (!ref.displayName || ref.displayName.substring(0, 3) === 'ID:') {
return;
}
@@ -12683,6 +12714,7 @@ speechSynthesis.getVoices();
$app.data.configTreeData = [];
$app.data.currentUserTreeData = [];
+ $app.data.currentUserFeedbackData = [];
$app.data.pastDisplayNameTable = {
data: [],
tableProps: {
@@ -19768,7 +19800,7 @@ speechSynthesis.getVoices();
var name = ref.displayName;
if (ref.statusDescription) {
var statusRegex =
- /(?:^|\n*)(?:(?:[^\n:]|\|)*(?::|˸|discord)[\t\v\f\r]*)?([^\n]*(#|#)(?: )?\d{4})/gi.exec(
+ /(?:^|\n*)(?:(?:[^\n:])*(?::|˸|discord)[\t\v\f\r]*)?([^\n]*(#|#)(?: )?\d{4})/gi.exec(
ref.statusDescription
);
if (statusRegex) {
@@ -19777,7 +19809,7 @@ speechSynthesis.getVoices();
}
if (!discord && ref.bio) {
var bioRegex =
- /(?:^|\n*)(?:(?:[^\n:]|\|)*(?::|˸|discord)[\t\v\f\r]*)?([^\n]*(#|#)(?: )?\d{4})/gi.exec(
+ /(?:^|\n*)(?:(?:[^\n:])*(?::|˸|discord)[\t\v\f\r]*)?([^\n]*(#|#)(?: )?\d{4})/gi.exec(
ref.bio
);
if (bioRegex) {
@@ -21842,11 +21874,9 @@ speechSynthesis.getVoices();
$app.methods.isRealInstance = function (instanceId) {
switch (instanceId) {
case 'offline':
- return false;
case 'private':
- return false;
case 'traveling':
- return false;
+ case 'local':
case '':
return false;
}
@@ -24567,6 +24597,16 @@ speechSynthesis.getVoices();
this.updateVRConfigVars();
};
+ API.$on('USER:FEEDBACK', function (args) {
+ if (args.params.userId === this.currentUser.id) {
+ $app.currentUserFeedbackData = buildTreeData(args.json);
+ }
+ });
+
+ $app.methods.getCurrentUserFeedback = function () {
+ return API.getUserFeedback({userId: API.currentUser.id});
+ };
+
$app = new Vue($app);
window.$app = $app;
})();
diff --git a/html/src/index.pug b/html/src/index.pug
index 66e1f9f1..24502668 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -856,7 +856,7 @@ html
el-button(type="text" icon="el-icon-delete" size="mini" style="margin-left:5px" @click="deleteNotificationLog(scope.row)")
//- profile
- .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'profile'")
+ .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'profile'" v-if="$refs.menu && $refs.menu.activeIndex === 'profile'")
div.options-container(style="margin-top:0")
span.header {{ $t('view.profile.profile.header') }}
.x-friend-list(style="margin-top:10px")
@@ -994,6 +994,17 @@ html
span
span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px")
span(v-if="!scope.data.children" v-text="scope.data.value")
+ div.options-container
+ span.header {{ $t('view.profile.feedback') }}
+ el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips")
+ el-button(type="default" @click="getCurrentUserFeedback()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px")
+ el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips")
+ el-button(type="default" @click="currentUserFeedbackData = []" size="mini" icon="el-icon-delete" circle style="margin-left:5px")
+ el-tree(v-if="currentUserFeedbackData.length > 0" :data="currentUserFeedbackData" style="margin-top:10px;font-size:12px")
+ template(#default="scope")
+ span
+ span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px")
+ span(v-if="!scope.data.children" v-text="scope.data.value")
//- friends list
.x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'friendsList'" v-if="$refs.menu && $refs.menu.activeIndex === 'friendsList'")
@@ -2722,7 +2733,7 @@ html
el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="VRCXUpdateDialog" :visible.sync="VRCXUpdateDialog.visible" :title="$t('dialog.vrcx_updater.header')" width="400px")
div(v-loading="checkingForVRCXUpdate" style="margin-top:15px")
div(v-if="VRCXUpdateDialog.updatePending" style="margin-bottom:15px")
- span(v-text="pendingVRCXUpdate")
+ span(v-text="pendingVRCXInstall")
br
span {{ $t('dialog.vrcx_updater.ready_for_update') }}
el-select(v-model="branch" @change="loadBranchVersions" style="display:inline-block;width:150px;margin-right:15px")
@@ -2732,7 +2743,7 @@ html
div(v-if="!VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release === appVersion" style="margin-top:15px")
span {{ $t('dialog.vrcx_updater.latest_version') }}
template(#footer)
- el-button(v-if="(VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release !== pendingVRCXUpdate) || VRCXUpdateDialog.release !== appVersion" type="primary" size="small" @click="installVRCXUpdate") {{ $t('dialog.vrcx_updater.download') }}
+ el-button(v-if="(VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release !== pendingVRCXInstall) || VRCXUpdateDialog.release !== appVersion" type="primary" size="small" @click="installVRCXUpdate") {{ $t('dialog.vrcx_updater.download') }}
el-button(v-if="VRCXUpdateDialog.updatePending" type="primary" size="small" @click="restartVRCX") {{ $t('dialog.vrcx_updater.install') }}
//- dialog: launch
diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json
index 137f3bf0..4fcbfe0e 100644
--- a/html/src/localization/strings/en.json
+++ b/html/src/localization/strings/en.json
@@ -163,6 +163,7 @@
"past_display_names": "Past Display Names",
"config_json": "Config JSON",
"current_user_json": "Current User JSON",
+ "feedback": "Feedback",
"refresh_tooltip": "Refresh",
"clear_results_tooltip": "Clear results"
},
@@ -202,9 +203,9 @@
},
"legal_notice": {
"header": "Legal Notice",
- "info": "VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK).",
+ "info": "VRCX is an assistant application for VRChat that provides information about and managing friendship. This application makes use of the unofficial VRChat API SDK.",
"disclaimer1": "VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc.",
- "disclaimer2": "pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk!",
+ "disclaimer2": "pypy & Natsumi are not responsible for any problems caused by VRCX. Use at your own risk!",
"open_source_software_notice": "Open Source Software Notice"
}
},
diff --git a/html/src/vr.js b/html/src/vr.js
index 9d8d7b02..e7b4e6ae 100644
--- a/html/src/vr.js
+++ b/html/src/vr.js
@@ -90,9 +90,9 @@ Vue.component('marquee-text', MarqueeText);
Vue.component('location', {
template:
- '{{ text }}' +
- '({{ groupName }})' +
- '' +
+ '{{ text }}' +
+ '({{ groupName }})' +
+ '' +
'',
props: {
location: String,
diff --git a/html/src/vr.pug b/html/src/vr.pug
index 6a05a6d0..5490d4c6 100644
--- a/html/src/vr.pug
+++ b/html/src/vr.pug
@@ -488,12 +488,12 @@ html
span(v-else-if="feed.avatar.releaseStatus === 'private'" style="margin-left:10px;color:#e6a23c") (Private)
template(v-else-if="feed.type === 'ChangeStatus'")
span(style="margin-left:10px;color:#a3a3a3") ChangeStatus
- template(v-if="feed.status !== feed.previousStatus")
- i.x-user-status(:class="statusClass(feed.previousStatus)" style="margin-left:10px;width:20px;height:20px")
- span
- i.el-icon-right
- i.x-user-status(:class="statusClass(feed.status)" style="width:20px;height:20px")
- span(v-if="feed.statusDescription !== feed.previousStatusDescription" v-text="feed.statusDescription" style="margin-left:10px")
+ span(v-if="feed.status !== feed.previousStatus")
+ i.x-user-status(:class="statusClass(feed.previousStatus)" style="margin-left:10px;width:20px;height:20px")
+ span
+ i.el-icon-right
+ i.x-user-status(:class="statusClass(feed.status)" style="width:20px;height:20px")
+ span(v-if="feed.statusDescription !== feed.previousStatusDescription" v-text="feed.statusDescription" style="margin-left:10px")
template(v-else-if="feed.type === 'ChangeGroup'")
span(style="margin-left:10px;color:#a3a3a3") ChangeGroup
span(v-text="feed.groupName" style="margin-left:10px")