diff --git a/html/src/app.js b/html/src/app.js
index 3983a1cc..27e0049d 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -2071,6 +2071,21 @@ speechSynthesis.getVoices();
});
};
+ API.sendInvitePhoto = function (params, receiverUserId) {
+ return this.call(`invite/${receiverUserId}/photo`, {
+ uploadImage: true,
+ postData: JSON.stringify(params),
+ imageData: $app.uploadImage
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('NOTIFICATION:INVITE:PHOTO:SEND', args);
+ return args;
+ });
+ };
+
API.sendRequestInvite = function (params, receiverUserId) {
return this.call(`requestInvite/${receiverUserId}`, {
method: 'POST',
@@ -2085,6 +2100,52 @@ speechSynthesis.getVoices();
});
};
+ API.sendRequestInvitePhoto = function (params, receiverUserId) {
+ return this.call(`requestInvite/${receiverUserId}/photo`, {
+ uploadImage: true,
+ postData: JSON.stringify(params),
+ imageData: $app.uploadImage
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('NOTIFICATION:REQUESTINVITE:PHOTO:SEND', args);
+ return args;
+ });
+ };
+
+ API.sendInviteResponse = function (params, inviteID) {
+ return this.call(`invite/${inviteID}/response`, {
+ method: 'POST',
+ params
+ }).then((json) => {
+ var args = {
+ json,
+ params,
+ inviteID
+ };
+ this.$emit('INVITE:RESPONSE:SEND', args);
+ return args;
+ });
+ };
+
+ API.sendInviteResponsePhoto = function (params, inviteID) {
+ return this.call(`invite/${inviteID}/response/photo`, {
+ uploadImage: true,
+ postData: JSON.stringify(params),
+ imageData: $app.uploadImage
+ }).then((json) => {
+ var args = {
+ json,
+ params,
+ inviteID
+ };
+ this.$emit('INVITE:RESPONSE:PHOTO:SEND', args);
+ return args;
+ });
+ };
+
/*
params: {
notificationId: string
@@ -4051,6 +4112,9 @@ speechSynthesis.getVoices();
message = noty.details[messageList[i]];
}
}
+ if (message) {
+ message = `, ${message}`;
+ }
if ((this.notificationTTS) && (this.isGameRunning)) {
this.playNotyTTS(noty, message);
}
@@ -4086,16 +4150,16 @@ speechSynthesis.getVoices();
this.speak(`${noty.displayName} status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`);
break;
case 'invite':
- this.speak(`${noty.senderUsername} has invited you to ${noty.details.worldName} ${message}`);
+ this.speak(`${noty.senderUsername} has invited you to ${noty.details.worldName}${message}`);
break;
case 'requestInvite':
- this.speak(`${noty.senderUsername} has requested an invite ${message}`);
+ this.speak(`${noty.senderUsername} has requested an invite${message}`);
break;
case 'inviteResponse':
- this.speak(`${noty.senderUsername} has responded to your invite ${message}`);
+ this.speak(`${noty.senderUsername} has responded to your invite${message}`);
break;
case 'requestInviteResponse':
- this.speak(`${noty.senderUsername} has responded to your invite request ${message}`);
+ this.speak(`${noty.senderUsername} has responded to your invite request${message}`);
break;
case 'friendRequest':
this.speak(`${noty.senderUsername} has sent you a friend request`);
@@ -4149,7 +4213,9 @@ speechSynthesis.getVoices();
}
}
}
- if (userId) {
+ if ((noty.details) && (noty.details.imageUrl)) {
+ imageURL = noty.details.imageUrl;
+ } else if (userId) {
imageURL = await API.getCachedUser({
userId: userId
}).catch((err) => {
@@ -4184,16 +4250,16 @@ speechSynthesis.getVoices();
AppApi.DesktopNotification(noty.displayName, `status is now ${noty.status[0].status} ${noty.status[0].statusDescription}`, imageURL);
break;
case 'invite':
- AppApi.DesktopNotification(noty.senderUsername, `has invited you to ${noty.details.worldName} ${message}`, imageURL);
+ AppApi.DesktopNotification(noty.senderUsername, `has invited you to ${noty.details.worldName}${message}`, imageURL);
break;
case 'requestInvite':
- AppApi.DesktopNotification(noty.senderUsername, `has requested an invite ${message}`, imageURL);
+ AppApi.DesktopNotification(noty.senderUsername, `has requested an invite${message}`, imageURL);
break;
case 'inviteResponse':
- AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite ${message}`, imageURL);
+ AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite${message}`, imageURL);
break;
case 'requestInviteResponse':
- AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite request ${message}`, imageURL);
+ AppApi.DesktopNotification(noty.senderUsername, `has responded to your invite request${message}`, imageURL);
break;
case 'friendRequest':
AppApi.DesktopNotification(noty.senderUsername, 'has sent you a friend request', imageURL);
@@ -8782,6 +8848,41 @@ speechSynthesis.getVoices();
});
};
+ $app.data.uploadImage = '';
+
+ $app.methods.inviteImageUpload = function (e) {
+ var files = e.target.files || e.dataTransfer.files;
+ if (!files.length) {
+ return;
+ }
+ if (files[0].size >= 10485760) { //10MB
+ $app.$message({
+ message: 'File size too large',
+ type: 'error'
+ });
+ return;
+ }
+ if (!files[0].type.match(/image.*/)) {
+ $app.$message({
+ message: 'File isn\'t an image',
+ type: 'error'
+ });
+ return;
+ }
+ var r = new FileReader();
+ r.onload = function () {
+ $app.uploadImage = btoa(r.result);
+ };
+ r.readAsBinaryString(files[0]);
+ };
+
+ $app.methods.clearInviteImageUpload = function () {
+ if (document.querySelector('#InviteImageUploadButton')) {
+ document.querySelector('#InviteImageUploadButton').value = '';
+ }
+ this.uploadImage = '';
+ };
+
$app.methods.userOnlineFor = function (ctx) {
if ((ctx.ref.state === 'online') && (ctx.ref.$online_for)) {
return timeToText(Date.now() - ctx.ref.$online_for);
@@ -8883,10 +8984,17 @@ speechSynthesis.getVoices();
API.editInviteMessage(params, messageType, slot).catch((err) => {
throw err;
}).then((args) => {
- this.$message('Invite message updated');
+ API.$emit(`INVITE:${messageType.toUpperCase()}`, args);
+ if (args.json[slot].message !== D.newMessage) {
+ this.$message({
+ message: 'VRChat API didn\'t update message, try again',
+ type: 'error'
+ });
+ throw new Error('VRChat API didn\'t update message, try again');
+ } else {
+ this.$message('Invite message updated');
+ }
return args;
- }).finally(() => {
- API.refreshInviteMessageTableData(messageType);
});
}
};
@@ -8926,7 +9034,7 @@ speechSynthesis.getVoices();
await API.editInviteMessage(params, messageType, slot).catch((err) => {
throw err;
}).then((args) => {
- this.$emit(`INVITE:${messageType.toUpperCase()}`, args);
+ API.$emit(`INVITE:${messageType.toUpperCase()}`, args);
if (args.json[slot].message !== D.newMessage) {
this.$message({
message: 'VRChat API didn\'t update message, try again',
@@ -8944,20 +9052,37 @@ speechSynthesis.getVoices();
responseSlot: slot,
rsvp: true
};
- API.sendInviteResponse(params, I.invite.id).catch((err) => {
- throw err;
- }).then((args) => {
- API.hideNotification({
- notificationId: I.invite.id
+ if ($app.uploadImage) {
+ API.sendInviteResponsePhoto(params, I.invite.id).catch((err) => {
+ throw err;
+ }).then((args) => {
+ API.hideNotification({
+ notificationId: I.invite.id
+ });
+ this.$message({
+ message: 'Invite response message sent',
+ type: 'success'
+ });
+ this.sendInviteResponseDialogVisible = false;
+ this.sendInviteRequestResponseDialogVisible = false;
+ return args;
});
- this.$message({
- message: 'Invite response message sent',
- type: 'success'
+ } else {
+ API.sendInviteResponse(params, I.invite.id).catch((err) => {
+ throw err;
+ }).then((args) => {
+ API.hideNotification({
+ notificationId: I.invite.id
+ });
+ this.$message({
+ message: 'Invite response message sent',
+ type: 'success'
+ });
+ this.sendInviteResponseDialogVisible = false;
+ this.sendInviteRequestResponseDialogVisible = false;
+ return args;
});
- this.sendInviteResponseDialogVisible = false;
- this.sendInviteRequestResponseDialogVisible = false;
- return args;
- });
+ }
};
$app.methods.cancelEditAndSendInviteResponse = function () {
@@ -8987,6 +9112,7 @@ speechSynthesis.getVoices();
};
API.refreshInviteMessageTableData('response');
this.$nextTick(() => adjustDialogZ(this.$refs.sendInviteResponseDialog.$el));
+ this.clearInviteImageUpload();
this.sendInviteResponseDialogVisible = true;
};
@@ -9013,38 +9139,38 @@ speechSynthesis.getVoices();
responseSlot: D.messageSlot,
rsvp: true
};
- API.sendInviteResponse(params, D.invite.id, D.messageType).catch((err) => {
- throw err;
- }).then((args) => {
- API.hideNotification({
- notificationId: D.invite.id
+ if ($app.uploadImage) {
+ API.sendInviteResponsePhoto(params, D.invite.id, D.messageType).catch((err) => {
+ throw err;
+ }).then((args) => {
+ API.hideNotification({
+ notificationId: D.invite.id
+ });
+ this.$message({
+ message: 'Invite response photo message sent',
+ type: 'success'
+ });
+ return args;
});
- this.$message({
- message: 'Invite response message sent',
- type: 'success'
+ } else {
+ API.sendInviteResponse(params, D.invite.id, D.messageType).catch((err) => {
+ throw err;
+ }).then((args) => {
+ API.hideNotification({
+ notificationId: D.invite.id
+ });
+ this.$message({
+ message: 'Invite response message sent',
+ type: 'success'
+ });
+ return args;
});
- return args;
- });
+ }
this.sendInviteResponseDialogVisible = false;
this.sendInviteRequestResponseDialogVisible = false;
this.sendInviteResponseConfirmDialog.visible = false;
};
- API.sendInviteResponse = function (params, inviteID) {
- return this.call(`invite/${inviteID}/response`, {
- method: 'POST',
- params
- }).then((json) => {
- var args = {
- json,
- params,
- inviteID
- };
- this.$emit('INVITE:RESPONSE:SEND', args);
- return args;
- });
- };
-
// App: Invite Request Response Message Dialog
$app.data.sendInviteRequestResponseDialogVisible = false;
@@ -9064,6 +9190,7 @@ speechSynthesis.getVoices();
};
API.refreshInviteMessageTableData('requestResponse');
this.$nextTick(() => adjustDialogZ(this.$refs.sendInviteRequestResponseDialog.$el));
+ this.clearInviteImageUpload();
this.sendInviteRequestResponseDialogVisible = true;
};
@@ -9098,7 +9225,7 @@ speechSynthesis.getVoices();
await API.editInviteMessage(params, messageType, slot).catch((err) => {
throw err;
}).then((args) => {
- this.$emit(`INVITE:${messageType.toUpperCase()}`, args);
+ API.$emit(`INVITE:${messageType.toUpperCase()}`, args);
if (args.json[slot].message !== D.newMessage) {
this.$message({
message: 'VRChat API didn\'t update message, try again',
@@ -9125,12 +9252,21 @@ speechSynthesis.getVoices();
var inviteLoop = () => {
if (J.userIds.length > 0) {
var receiverUserId = J.userIds.shift();
- API.sendInvite({
- instanceId: J.worldId,
- worldId: J.worldId,
- worldName: J.worldName,
- messageSlot: slot
- }, receiverUserId).finally(inviteLoop);
+ if ($app.uploadImage) {
+ API.sendInvitePhoto({
+ instanceId: J.worldId,
+ worldId: J.worldId,
+ worldName: J.worldName,
+ messageSlot: slot
+ }, receiverUserId).finally(inviteLoop);
+ } else {
+ API.sendInvite({
+ instanceId: J.worldId,
+ worldId: J.worldId,
+ worldName: J.worldName,
+ messageSlot: slot
+ }, receiverUserId).finally(inviteLoop);
+ }
} else {
J.loading = false;
J.visible = false;
@@ -9144,26 +9280,51 @@ speechSynthesis.getVoices();
} else {
if (I.messageType === 'invite') {
I.params.messageSlot = slot;
- API.sendInvite(I.params, I.userId).catch((err) => {
- throw err;
- }).then((args) => {
- this.$message({
- message: 'Invite message sent',
- type: 'success'
+ if ($app.uploadImage) {
+ API.sendInvitePhoto(I.params, I.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Invite photo message sent',
+ type: 'success'
+ });
+ return args;
});
- return args;
- });
+ } else {
+ API.sendInvite(I.params, I.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Invite message sent',
+ type: 'success'
+ });
+ return args;
+ });
+ }
} else if (I.messageType === 'requestInvite') {
I.params.requestSlot = slot;
- API.sendRequestInvite(I.params, I.userId).catch((err) => {
- throw err;
- }).then((args) => {
- this.$message({
- message: 'Request invite message sent',
- type: 'success'
+ if ($app.uploadImage) {
+ API.sendRequestInvitePhoto(I.params, I.userId).catch((err) => {
+ this.clearInviteImageUpload();
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Request invite photo message sent',
+ type: 'success'
+ });
+ return args;
});
- return args;
- });
+ } else {
+ API.sendRequestInvite(I.params, I.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Request invite message sent',
+ type: 'success'
+ });
+ return args;
+ });
+ }
}
}
this.sendInviteDialogVisible = false;
@@ -9201,6 +9362,7 @@ speechSynthesis.getVoices();
};
API.refreshInviteMessageTableData('message');
this.$nextTick(() => adjustDialogZ(this.$refs.sendInviteDialog.$el));
+ this.clearInviteImageUpload();
this.sendInviteDialogVisible = true;
};
@@ -9236,12 +9398,21 @@ speechSynthesis.getVoices();
var inviteLoop = () => {
if (J.userIds.length > 0) {
var receiverUserId = J.userIds.shift();
- API.sendInvite({
- instanceId: J.worldId,
- worldId: J.worldId,
- worldName: J.worldName,
- messageSlot: D.messageSlot
- }, receiverUserId).finally(inviteLoop);
+ if ($app.uploadImage) {
+ API.sendInvitePhoto({
+ instanceId: J.worldId,
+ worldId: J.worldId,
+ worldName: J.worldName,
+ messageSlot: D.messageSlot
+ }, receiverUserId).finally(inviteLoop);
+ } else {
+ API.sendInvite({
+ instanceId: J.worldId,
+ worldId: J.worldId,
+ worldName: J.worldName,
+ messageSlot: D.messageSlot
+ }, receiverUserId).finally(inviteLoop);
+ }
} else {
J.loading = false;
J.visible = false;
@@ -9255,24 +9426,51 @@ speechSynthesis.getVoices();
} else {
if (D.messageType === 'invite') {
D.params.messageSlot = D.messageSlot;
- API.sendInvite(D.params, D.userId).catch((err) => {
- throw err;
- }).then((args) => {
- this.$message({
- message: 'Invite message sent',
- type: 'success'
+ if ($app.uploadImage) {
+ API.sendInvitePhoto(D.params, D.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Invite photo message sent',
+ type: 'success'
+ });
+ return args;
});
- return args;
- });
+ } else {
+ API.sendInvite(D.params, D.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Invite message sent',
+ type: 'success'
+ });
+ return args;
+ });
+ }
} else if (D.messageType === 'requestInvite') {
D.params.requestSlot = D.messageSlot;
- API.sendRequestInvite(D.params, D.userId).then((args) => {
- this.$message({
- message: 'Request invite message sent',
- type: 'success'
+ if ($app.uploadImage) {
+ API.sendRequestInvitePhoto(D.params, D.userId).catch((err) => {
+ this.clearInviteImageUpload();
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Request invite photo message sent',
+ type: 'success'
+ });
+ return args;
});
- return args;
- });
+ } else {
+ API.sendRequestInvite(D.params, D.userId).catch((err) => {
+ throw err;
+ }).then((args) => {
+ this.$message({
+ message: 'Request invite message sent',
+ type: 'success'
+ });
+ return args;
+ });
+ }
}
}
this.sendInviteDialogVisible = false;
@@ -9301,6 +9499,7 @@ speechSynthesis.getVoices();
};
API.refreshInviteMessageTableData('request');
this.$nextTick(() => adjustDialogZ(this.$refs.sendInviteRequestDialog.$el));
+ this.clearInviteImageUpload();
this.sendInviteRequestDialogVisible = true;
};
diff --git a/html/src/index.pug b/html/src/index.pug
index 4ce4274e..69b834b2 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -536,12 +536,13 @@ html
template(#content)
span Clear results
el-button(type="default" @click="VRCPlusIconsTable = {}" size="mini" icon="el-icon-delete" circle style="margin-left:0")
- el-tooltip(placement="top")
- template(#content)
- span Upload icon
- div(style="display:inline-block")
- el-button(type="default" @click="displayVRCPlusIconUpload" size="mini" icon="el-icon-upload2" circle style="margin-left:0")
- input(type="file" multiple accept="image/*" @change="onFileChangeVRCPlusIcon" id="VRCPlusIconUploadButton" style="display:none")
+ template(v-if="API.currentUser.$isVRCPlus")
+ el-tooltip(placement="top")
+ template(#content)
+ span Upload icon
+ div(style="display:inline-block")
+ el-button(type="default" @click="displayVRCPlusIconUpload" size="mini" icon="el-icon-upload2" circle style="margin-left:0")
+ input(type="file" multiple accept="image/*" @change="onFileChangeVRCPlusIcon" id="VRCPlusIconUploadButton" style="display:none")
el-tooltip(placement="top")
template(#content)
span Reset icon
@@ -1511,6 +1512,8 @@ html
//- dialog Table: Send Invite Response Message
el-dialog.x-dialog(ref="sendInviteResponseDialog" :visible.sync="sendInviteResponseDialogVisible" title="Send Invite Response Message" width="800px")
+ template(v-if="API.currentUser.$isVRCPlus")
+ input(type="file" multiple accept="image/*" @change="inviteImageUpload" id="InviteImageUploadButton")
data-tables(v-bind="inviteResponseMessageTable" @row-click="showSendInviteResponseConfirmDialog" style="margin-top:10px;cursor:pointer")
el-table-column(label="Slot" prop="slot" sortable="custom" width="70")
el-table-column(label="Message" prop="message")
@@ -1526,6 +1529,8 @@ html
//- dialog Table: Send Invite Request Response Message
el-dialog.x-dialog(ref="sendInviteRequestResponseDialog" :visible.sync="sendInviteRequestResponseDialogVisible" title="Send Invite Request Response Message" width="800px")
+ template(v-if="API.currentUser.$isVRCPlus")
+ input(type="file" multiple accept="image/*" @change="inviteImageUpload" id="InviteImageUploadButton")
data-tables(v-bind="inviteRequestResponseMessageTable" @row-click="showSendInviteResponseConfirmDialog" style="margin-top:10px;cursor:pointer")
el-table-column(label="Slot" prop="slot" sortable="custom" width="70")
el-table-column(label="Message" prop="message")
@@ -1549,6 +1554,8 @@ html
//- dialog Table: Send Invite Message
el-dialog.x-dialog(ref="sendInviteDialog" :visible.sync="sendInviteDialogVisible" title="Send Invite Message" width="800px")
+ template(v-if="API.currentUser.$isVRCPlus")
+ input(type="file" multiple accept="image/*" @change="inviteImageUpload" id="InviteImageUploadButton")
data-tables(v-bind="inviteMessageTable" @row-click="showSendInviteConfirmDialog" style="margin-top:10px;cursor:pointer")
el-table-column(label="Slot" prop="slot" sortable="custom" width="70")
el-table-column(label="Message" prop="message")
@@ -1564,6 +1571,8 @@ html
//- dialog Table: Send Invite Request Message
el-dialog.x-dialog(ref="sendInviteRequestDialog" :visible.sync="sendInviteRequestDialogVisible" title="Send Invite Request Message" width="800px")
+ template(v-if="API.currentUser.$isVRCPlus")
+ input(type="file" multiple accept="image/*" @change="inviteImageUpload" id="InviteImageUploadButton")
data-tables(v-bind="inviteRequestMessageTable" @row-click="showSendInviteConfirmDialog" style="margin-top:10px;cursor:pointer")
el-table-column(label="Slot" prop="slot" sortable="custom" width="70")
el-table-column(label="Message" prop="message")