Group Dialog

This commit is contained in:
Natsumi
2022-12-02 12:13:11 +13:00
parent e3c09f78cb
commit 7b42ef8afc
3 changed files with 525 additions and 15 deletions

View File

@@ -13275,8 +13275,7 @@ speechSynthesis.getVoices();
if (this.directAccessWorld(input.trim())) {
return true;
}
var testUrl = input.substring(0, 15);
if (testUrl === 'https://vrchat.') {
if (input.startsWith('https://vrchat.')) {
var url = new URL(input);
var urlPath = url.pathname;
if (urlPath.substring(5, 11) === '/user/') {
@@ -13287,7 +13286,14 @@ speechSynthesis.getVoices();
var avatarId = urlPath.substring(13);
this.showAvatarDialog(avatarId);
return true;
} else if (urlPath.substring(5, 12) === '/group/') {
var groupId = urlPath.substring(12);
this.showGroupDialog(groupId);
return true;
}
} else if (input.startsWith('https://vrc.group/')) {
// var shortCode = input.substring(18);
// resolve short code? A
} else if (
input.substring(0, 4) === 'usr_' ||
/^[A-Za-z0-9]{10}$/g.test(input)
@@ -13297,6 +13303,9 @@ speechSynthesis.getVoices();
} else if (input.substring(0, 5) === 'avtr_') {
this.showAvatarDialog(input.trim());
return true;
} else if (input.substring(0, 4) === 'grp_') {
this.showGroupDialog(input.trim());
return true;
}
return false;
};
@@ -13695,6 +13704,20 @@ speechSynthesis.getVoices();
avatarName: '',
fileCreatedAt: ''
},
representedGroup: {
bannerUrl: '',
description: '',
discriminator: '',
groupId: '',
iconUrl: '',
isRepresenting: false,
memberCount: 0,
memberVisibility: '',
name: '',
ownerId: '',
privacy: '',
shortCode: ''
},
joinCount: 0,
timeSpent: 0,
lastSeen: '',
@@ -13923,6 +13946,20 @@ speechSynthesis.getVoices();
occupants: 0,
friendCount: 0
};
D.representedGroup = {
bannerUrl: '',
description: '',
discriminator: '',
groupId: '',
iconUrl: '',
isRepresenting: false,
memberCount: 0,
memberVisibility: '',
name: '',
ownerId: '',
privacy: '',
shortCode: ''
};
D.lastSeen = '';
D.joinCount = 0;
D.timeSpent = 0;
@@ -14070,6 +14107,7 @@ speechSynthesis.getVoices();
);
});
}
API.getRepresentedGroup({userId});
}
return args;
});
@@ -16716,6 +16754,22 @@ speechSynthesis.getVoices();
this.copyToClipboard(`https://vrchat.com/home/user/${userId}`);
};
$app.methods.copyGroupId = function (groupId) {
this.$message({
message: 'Group ID copied to clipboard',
type: 'success'
});
this.copyToClipboard(groupId);
};
$app.methods.copyGroupUrl = function (groupUrl) {
this.$message({
message: 'Group URL copied to clipboard',
type: 'success'
});
this.copyToClipboard(groupUrl);
};
$app.methods.copyText = function (text) {
this.$message({
message: 'Text copied to clipboard',
@@ -20403,6 +20457,9 @@ speechSynthesis.getVoices();
case 'user':
this.showUserDialog(commandArg);
break;
case 'group':
this.showGroupDialog(commandArg);
break;
case 'addavatardb':
this.addAvatarProvider(input.replace('addavatardb/', ''));
break;
@@ -22278,11 +22335,64 @@ speechSynthesis.getVoices();
};
API.$on('GROUP', function (args) {
var group = args.json;
console.log(args);
args.ref = this.applyGroup(args.json);
});
API.$on('GROUP', function (args) {
console.log('group', args);
var group = args.ref;
this.cachedGroups.set(group.id, group);
});
API.$on('GROUP', function (args) {
if ($app.groupDialog.visible && $app.groupDialog.id === args.ref.id) {
// update group dialog
}
if (
$app.userDialog.visible &&
($app.userDialog.representedGroup.id === args.ref.id ||
$app.userDialog.id === args.params.userId)
) {
$app.userDialog.representedGroup = args.ref;
}
});
/*
params: {
userId: string
}
*/
API.getRepresentedGroup = function (params) {
return this.call(`users/${params.userId}/groups/represented`, {
method: 'GET'
}).then((json) => {
var args = {
json,
params
};
this.$emit('GROUP:REPRESENTED', args);
return args;
});
};
API.$on('GROUP:REPRESENTED', function (args) {
console.log('represented', args.json);
var json = args.json;
if (!json.id) {
// no group
return;
}
json.$memberId = json.id;
json.id = json.groupId;
this.$emit('GROUP', {
json,
params: {
groupId: json.id,
userId: args.params.userId
}
});
});
/*
params: {
userId: string
@@ -22302,24 +22412,329 @@ speechSynthesis.getVoices();
};
API.$on('GROUP:LIST', function (args) {
console.log(args.json);
for (var i = 0; i < args.json.length; ++i) {
var group = args.json[i];
this.cachedGroups.set(group.id, group);
console.log('groups', args.json);
for (var json of args.json) {
json.$memberId = json.id;
json.id = json.groupId;
this.$emit('GROUP', {
json,
params: {
groupId: json.id,
userId: args.params.userId
}
});
}
});
/*
params: {
groupId: string
}
*/
API.joinGroup = function (params) {
return this.call(`groups/${params.groupId}/join`, {
method: 'POST'
}).then((json) => {
var args = {
json,
params
};
this.$emit('GROUP:JOIN', args);
return args;
});
};
API.$on('GROUP:JOIN', function (args) {
console.log('join', args.json);
var json = {
$memberId: args.json.id,
id: args.json.groupId,
membershipStatus: args.json.membershipStatus,
myMember: {
isRepresenting: args.json.isRepresenting,
id: args.json.id,
roleIds: args.json.roleIds,
joinedAt: args.json.joinedAt,
membershipStatus: args.json.membershipStatus,
visibility: args.json.visibility,
isSubscribedToAnnouncements:
args.json.isSubscribedToAnnouncements
}
};
var groupId = json.id;
this.$emit('GROUP', {
json,
params: {
groupId,
userId: args.params.userId
}
});
if ($app.groupDialog.visible && $app.groupDialog.id === groupId) {
if (json.membershipStatus === 'member') {
$app.groupDialog.inGroup = true;
}
}
});
/*
params: {
groupId: string
}
*/
API.leaveGroup = function (params) {
return this.call(`groups/${params.groupId}/leave`, {
method: 'POST'
}).then((json) => {
var args = {
json,
params
};
this.$emit('GROUP:LEAVE', args);
return args;
});
};
API.$on('GROUP:LEAVE', function (args) {
console.log('leave', args);
var groupId = args.params.groupId;
if ($app.groupDialog.visible && $app.groupDialog.id === groupId) {
$app.groupDialog.inGroup = false;
}
});
/*
params: {
groupId: string
}
*/
API.cancelGroupRequest = function (params) {
return this.call(`groups/${params.groupId}/requests`, {
method: 'DELETE'
}).then((json) => {
var args = {
json,
params
};
this.$emit('GROUP:CANCELJOINREQUEST', args);
return args;
});
};
API.$on('GROUP:CANCELJOINREQUEST', function (args) {
console.log('CANCELJOINREQUEST', args);
var groupId = args.params.groupId;
if ($app.groupDialog.visible && $app.groupDialog.id === groupId) {
$app.groupDialog.ref.membershipStatus = 'inactive';
}
});
/*
params: {
groupId: string
}
*/
API.getCachedGroup = function (params) {
return new Promise((resolve, reject) => {
var ref = this.cachedGroups.get(params.groupId);
if (typeof ref === 'undefined') {
this.getGroup(params).catch(reject).then(resolve);
} else {
resolve({
cache: true,
json: ref,
params,
ref
});
}
});
};
API.applyGroup = function (json) {
var ref = this.cachedGroups.get(json.id);
if (typeof ref === 'undefined') {
ref = {
id: '',
name: '',
shortCode: '',
description: '',
bannerId: '',
bannerUrl: '',
createdAt: '',
discriminator: '',
galleries: [],
iconId: '',
iconUrl: '',
isVerified: false,
joinState: '',
languages: [],
links: [],
memberCount: 0,
memberCountSyncedAt: '',
membershipStatus: '',
onlineMemberCount: 0,
ownerId: '',
privacy: '',
rules: null,
tags: [],
// in group
initialRoleIds: [],
myMember: {
bannedAt: null,
groupId: '',
has2FA: false,
id: '',
isRepresenting: false,
isSubscribedToAnnouncements: false,
joinedAt: '',
managerNotes: '',
membershipStatus: '',
permissions: [],
roleIds: [],
userId: '',
visibility: '',
_created_at: '',
_id: '',
_updated_at: ''
},
updatedAt: '',
// group list
$memberId: '',
groupId: '',
isRepresenting: false,
memberVisibility: false,
mutualGroup: false,
// VRCX
$languages: [],
...json
};
this.cachedGroups.set(ref.id, ref);
} else {
Object.assign(ref, json);
}
ref.$url = `https://vrc.group/${ref.shortCode}.${ref.discriminator}`;
this.applyGroupLanguage(ref);
return ref;
};
API.applyGroupLanguage = function (ref) {
ref.$languages = [];
var {languages} = ref;
if (!languages) {
return;
}
for (var language of languages) {
var value = subsetOfLanguages[language];
if (typeof value === 'undefined') {
continue;
}
ref.$languages.push({
key: language,
value
});
}
};
$app.data.groupDialog = {
visible: false,
loading: false,
treeData: [],
id: '',
group: null
inGroup: false,
ref: {}
};
$app.methods.showGroupDialog = function (groupId) {
// this.$nextTick(() => adjustDialogZ(this.$refs.groupDialog.$el));
this.groupDialog.visible = true;
this.groupDialog.id = groupId;
if (!groupId) {
return;
}
this.$nextTick(() => adjustDialogZ(this.$refs.groupDialog.$el));
var D = this.groupDialog;
D.visible = true;
D.loading = true;
D.id = groupId;
D.inGroup = false;
D.treeData = [];
API.getCachedGroup({
groupId
})
.catch((err) => {
D.loading = false;
D.visible = false;
this.$message({
message: 'Failed to load group',
type: 'error'
});
throw err;
})
.then((args) => {
if (D.id === args.ref.id) {
D.loading = false;
D.ref = args.ref;
D.inGroup = args.ref.membershipStatus === 'member';
if (args.cache) {
API.getGroup(args.params)
.catch((err) => {
throw err;
})
.then((args1) => {
if (D.id === args1.ref.id) {
D.ref = args1.ref;
D.inGroup =
args.ref.membershipStatus === 'member';
}
return args1;
});
}
}
});
};
$app.methods.groupDialogCommand = function (command) {
var D = this.groupDialog;
if (D.visible === false) {
return;
}
switch (command) {
case 'Refresh':
this.showGroupDialog(D.id);
break;
}
};
$app.methods.refreshGroupDialogTreeData = function () {
var D = this.groupDialog;
D.treeData = buildTreeData(D.ref);
};
$app.methods.joinGroup = function (groupId) {
return API.joinGroup({
groupId
}).then((args) => {
if (args.json.membershipStatus === 'member') {
this.$message({
message: 'Group joined',
type: 'success'
});
} else if (args.json.membershipStatus === 'requested') {
this.$message({
message: 'Group join request sent',
type: 'success'
});
}
return args;
});
};
$app.methods.leaveGroup = function (groupId) {
return API.leaveGroup({
groupId
});
};
$app.methods.cancelGroupRequest = function (groupId) {
return API.cancelGroupRequest({
groupId
});
};
$app = new Vue($app);

View File

@@ -100,7 +100,7 @@
.el-dialog__body {
padding: 20px;
word-break: unset;
word-break: break-word;
}
.el-dialog__footer > .el-button + .el-button {

View File

@@ -1694,6 +1694,19 @@ html
span.name(v-else) Avatar Info
.extra
avatar-info(:imageurl="userDialog.ref.currentAvatarImageUrl" :userid="userDialog.id")
.x-friend-item(style="width:100%;cursor:default")
.detail
span.name Represented Group
.extra(v-if="userDialog.representedGroup.id")
div(style="display:inline-block;flex:none;margin-right:5px")
el-popover(placement="right" width="500px" trigger="click")
img.x-link(slot="reference" v-lazy="userDialog.representedGroup.iconUrl" style="flex:none;width:60px;height:60px;border-radius:4px;object-fit:cover")
img.x-link(v-lazy="userDialog.representedGroup.iconUrl" style="height:500px" @click="openExternalLink(userDialog.representedGroup.iconUrl)")
span(style="vertical-align:top;cursor:pointer" @click="showGroupDialog(userDialog.representedGroup.id)")
span(v-if="userDialog.representedGroup.ownerId === userDialog.id" style="margin-right:5px") 👑
span(v-text="userDialog.representedGroup.name" style="margin-right:5px")
span ({{ userDialog.representedGroup.memberCount }})
.extra(v-else) -
.x-friend-item(style="width:100%;cursor:default")
.detail
span.name Bio
@@ -1791,7 +1804,7 @@ html
template(v-if="userGroups.mutualGroups.length > 0")
span(style="font-weight:bold;font-size:16px") Mutual Groups
span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.mutualGroups.length }}
.x-friend-list(v-if="userGroups.mutualGroups.length > 0" style="margin-top:10px;margin-bottom:15px;min-height:60px")
.x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px")
.x-friend-item(v-for="group in userGroups.mutualGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border")
.avatar
img(v-lazy="group.iconUrl")
@@ -1801,7 +1814,7 @@ html
template(v-if="userGroups.remainingGroups.length > 0")
span(style="font-weight:bold;font-size:16px") Groups
span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.remainingGroups.length }}
.x-friend-list(v-if="userGroups.remainingGroups.length > 0" style="margin-top:10px;margin-bottom:15px;min-height:60px")
.x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px")
.x-friend-item(v-for="group in userGroups.remainingGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border")
.avatar
img(v-lazy="group.iconUrl")
@@ -2128,6 +2141,88 @@ html
span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px")
span(v-if="!scope.data.children" v-text="scope.data.value")
//- dialog: group
el-dialog.x-dialog.x-world-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="groupDialog" :visible.sync="groupDialog.visible" :show-close="false" width="770px")
div(v-loading="groupDialog.loading")
div(style="display:flex")
el-popover(placement="right" width="500px" trigger="click")
img.x-link(slot="reference" v-lazy="groupDialog.ref.iconUrl" style="flex:none;width:120px;height:120px;border-radius:4px")
img.x-link(v-lazy="groupDialog.ref.iconUrl" style="width:500px;height:500px" @click="openExternalLink(groupDialog.ref.iconUrl)")
div(style="flex:1;display:flex;align-items:center;margin-left:15px")
div(style="flex:1")
div
span(v-if="groupDialog.ref.ownerId === API.currentUser.id" style="margin-right:5px") 👑
span.dialog-title(v-text="groupDialog.ref.name" style="margin-right:5px")
el-tooltip(v-for="item in groupDialog.ref.$languages" :key="item.key" placement="top")
template(#content)
span {{ item.value }} ({{ item.key }})
span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px")
div(style="margin-top:5px")
span.x-link(v-text="groupDialog.ref.ownerId" @click="showUserDialog(groupDialog.ref.ownerId)" style="color:#909399;font-family:monospace")
//- display-name(:userid="groupDialog.ref.ownerId" style="color:#909399;font-family:monospace")
div(style="margin-top:5px")
span(v-show="groupDialog.ref.name !== groupDialog.ref.description" v-text="groupDialog.ref.description" style="font-size:12px")
div(style="flex:none;margin-left:10px")
el-tooltip(v-if="groupDialog.inGroup" placement="top" content="Leave Group" :disabled="hideTooltips")
el-button(type="default" icon="el-icon-star-on" circle @click="leaveGroup(groupDialog.id)" style="margin-left:5px")
el-tooltip(v-else-if="groupDialog.ref.membershipStatus === 'requested'" placement="top" content="Cancel join request" :disabled="hideTooltips")
el-button(type="default" icon="el-icon-close" circle @click="cancelGroupRequest(groupDialog.id)" style="margin-left:5px")
el-tooltip(v-else-if="groupDialog.ref.joinState === 'request'" placement="top" content="Request to join" :disabled="hideTooltips")
el-button(type="default" icon="el-icon-message" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px")
el-tooltip(v-else placement="top" content="Join Group" :disabled="hideTooltips")
el-button(type="default" icon="el-icon-star-off" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px")
el-dropdown(trigger="click" @command="groupDialogCommand" size="small" style="margin-left:5px")
el-button(type="default" icon="el-icon-more" circle)
el-dropdown-menu(#default="dropdown")
el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh
el-tabs
el-tab-pane(label="Info")
.x-friend-list(style="max-height:none")
.x-friend-item(style="width:100%;cursor:default")
.detail
span.name Links
div(v-if="groupDialog.ref.links && groupDialog.ref.links.length > 0" style="margin-top:5px")
el-tooltip(v-if="link" v-for="(link, index) in groupDialog.ref.links" :key="index")
template(#content)
span(v-text="link")
img(:src="getFaviconUrl(link)" style="width:16px;height:16px;vertical-align:middle;margin-right:5px;cursor:pointer" @click.stop="openExternalLink(link)")
.extra(v-else) -
.x-friend-item(style="width:100%;cursor:default")
.detail
span.name Rules
pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ groupDialog.ref.rules || '-' }}
.x-friend-item(style="width:350px;cursor:default")
.detail
span.name Group ID
span.extra {{ groupDialog.id }}
el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips")
el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px")
el-button(type="default" icon="el-icon-s-order" size="mini" circle)
el-dropdown-menu(#default="dropdown")
el-dropdown-item(@click.native="copyGroupId(groupDialog.id)") Copy ID
el-dropdown-item(@click.native="copyGroupUrl(groupDialog.ref.$url)") Copy URL
template(v-if="groupDialog.ref.membershipStatus === 'member'")
div(style="width:100%;display:flex")
.x-friend-item(style="cursor:default")
.detail
span.name Joined At
span.extra {{ groupDialog.ref.myMember.joinedAt | formatDate('long') }}
.x-friend-item(style="cursor:default")
.detail
span.name Announcements
span.extra {{ groupDialog.ref.myMember.isSubscribedToAnnouncements }}
.x-friend-item(style="cursor:default")
.detail
span.name Visibility
span.extra {{ groupDialog.ref.myMember.visibility }}
el-tab-pane(label="JSON")
el-button(type="default" @click="refreshGroupDialogTreeData()" size="mini" icon="el-icon-refresh" circle)
el-tree(:data="groupDialog.treeData" style="margin-top:5px;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")
//- dialog: favorite
el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="favoriteDialog" :visible.sync="favoriteDialog.visible" title="Choose Group" width="300px")
div(v-if="favoriteDialog.visible" v-loading="favoriteDialog.loading")