mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-11 10:53:52 +02:00
feat: Limit bio display height(#1158), Toggle for display of age gated instances(#1188), fix: (#1189)(#1192) (#1195)
This commit is contained in:
51
src/app.js
51
src/app.js
@@ -6908,6 +6908,21 @@ console.log(`isLinux: ${LINUX}`);
|
||||
);
|
||||
}
|
||||
$app.data.pendingOfflineDelay = 180000;
|
||||
|
||||
// It's a mess, but it'll be fine afterward with the state manager
|
||||
$app.data.isAgeGatedInstancesVisible = await configRepository.getBool(
|
||||
'VRCX_isAgeGatedInstancesVisible',
|
||||
true
|
||||
);
|
||||
|
||||
$app.methods.toggleIsAgeGatedInstancesVisible = function () {
|
||||
this.isAgeGatedInstancesVisible = !this.isAgeGatedInstancesVisible;
|
||||
configRepository.setBool(
|
||||
'VRCX_isAgeGatedInstancesVisible',
|
||||
this.isAgeGatedInstancesVisible
|
||||
);
|
||||
};
|
||||
|
||||
if (await configRepository.getString('VRCX_avatarRemoteDatabaseProvider')) {
|
||||
// move existing provider to new list
|
||||
var avatarRemoteDatabaseProvider = await configRepository.getString(
|
||||
@@ -16694,25 +16709,6 @@ console.log(`isLinux: ${LINUX}`);
|
||||
resolution = '128',
|
||||
isUserDialogIcon = false
|
||||
) {
|
||||
function convertFileUrlToImageUrl(url) {
|
||||
/**
|
||||
* 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}`;
|
||||
}
|
||||
// return /image/file_fileId url?
|
||||
return url;
|
||||
}
|
||||
if (!user) {
|
||||
return '';
|
||||
}
|
||||
@@ -16721,7 +16717,7 @@ console.log(`isLinux: ${LINUX}`);
|
||||
(this.displayVRCPlusIconsAsAvatar && user.userIcon)
|
||||
) {
|
||||
if (isIcon) {
|
||||
return convertFileUrlToImageUrl(user.userIcon);
|
||||
return $utils.convertFileUrlToImageUrl(user.userIcon);
|
||||
}
|
||||
return user.userIcon;
|
||||
}
|
||||
@@ -16752,7 +16748,9 @@ console.log(`isLinux: ${LINUX}`);
|
||||
}
|
||||
if (user.currentAvatarImageUrl) {
|
||||
if (isIcon) {
|
||||
return convertFileUrlToImageUrl(user.currentAvatarImageUrl);
|
||||
return $utils.convertFileUrlToImageUrl(
|
||||
user.currentAvatarImageUrl
|
||||
);
|
||||
}
|
||||
return user.currentAvatarImageUrl;
|
||||
}
|
||||
@@ -19908,12 +19906,8 @@ console.log(`isLinux: ${LINUX}`);
|
||||
);
|
||||
};
|
||||
|
||||
$app.methods.getSmallThumbnailUrl = function (url, resolution = 128) {
|
||||
return (
|
||||
url
|
||||
?.replace('/file/', '/image/')
|
||||
.replace('/1/file', `/1/${resolution}`) || url
|
||||
);
|
||||
$app.methods.getSmallThumbnailUrl = function (url) {
|
||||
return $utils.convertFileUrlToImageUrl(url);
|
||||
};
|
||||
|
||||
// #endregion
|
||||
@@ -19975,7 +19969,8 @@ console.log(`isLinux: ${LINUX}`);
|
||||
groupInstances: this.groupInstances,
|
||||
inGameGroupOrder: this.inGameGroupOrder,
|
||||
groupedByGroupKeyFavoriteFriends:
|
||||
this.groupedByGroupKeyFavoriteFriends
|
||||
this.groupedByGroupKeyFavoriteFriends,
|
||||
isAgeGatedInstancesVisible: this.isAgeGatedInstancesVisible
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import configRepository from '../repository/config.js';
|
||||
import database from '../repository/database.js';
|
||||
import { baseClass, $app, API, $t, $utils } from './baseClass.js';
|
||||
import { userRequest } from './request';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export default class extends baseClass {
|
||||
constructor(_app, _API, _t) {
|
||||
@@ -168,7 +169,8 @@ export default class extends baseClass {
|
||||
if (typeof friendRef?.ref !== 'undefined') {
|
||||
friendRef.ref.$joinCount++;
|
||||
friendRef.ref.$lastSeen = new Date().toJSON();
|
||||
friendRef.ref.$timeSpent += Date.now() - ref.joinTime;
|
||||
friendRef.ref.$timeSpent +=
|
||||
dayjs(gameLog.dt) - ref.joinTime;
|
||||
if (
|
||||
this.sidebarSortMethods.includes(
|
||||
'Sort by Last Seen'
|
||||
@@ -178,7 +180,7 @@ export default class extends baseClass {
|
||||
this.sortOnlineFriends = true;
|
||||
}
|
||||
}
|
||||
var time = Date.now() - ref.joinTime;
|
||||
var time = dayjs(gameLog.dt) - ref.joinTime;
|
||||
this.lastLocation.playerList.delete(userId);
|
||||
this.lastLocation.friendList.delete(userId);
|
||||
this.photonLobbyAvatars.delete(userId);
|
||||
|
||||
@@ -402,5 +402,24 @@ export default {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
convertFileUrlToImageUrl(url, resolution = 128) {
|
||||
/**
|
||||
* 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}`;
|
||||
}
|
||||
// no match return origin url
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,18 +22,20 @@
|
||||
:key="ref.instance.id"
|
||||
class="x-friend-item"
|
||||
@click="$emit('show-group-dialog', ref.instance.ownerId)">
|
||||
<div class="avatar">
|
||||
<img v-lazy="ref.group.iconUrl" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name">
|
||||
<span v-text="ref.group.name"></span>
|
||||
<span style="font-weight: normal; margin-left: 5px"
|
||||
>({{ ref.instance.userCount }}/{{ ref.instance.capacity }})</span
|
||||
>
|
||||
</span>
|
||||
<location class="extra" :location="ref.instance.location" :link="false" />
|
||||
</div>
|
||||
<template v-if="isAgeGatedInstancesVisible || !(ref.ageGate || ref.location?.includes('~ageGate'))">
|
||||
<div class="avatar">
|
||||
<img v-lazy="getSmallGroupIconUrl(ref.group.iconUrl)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span class="name">
|
||||
<span v-text="ref.group.name"></span>
|
||||
<span style="font-weight: normal; margin-left: 5px"
|
||||
>({{ ref.instance.userCount }}/{{ ref.instance.capacity }})</span
|
||||
>
|
||||
</span>
|
||||
<location class="extra" :location="ref.instance.location" :link="false" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -42,6 +44,7 @@
|
||||
|
||||
<script>
|
||||
import Location from '../common/Location.vue';
|
||||
import utils from '../../classes/utils';
|
||||
|
||||
export default {
|
||||
name: 'GroupsSidebar',
|
||||
@@ -56,6 +59,10 @@
|
||||
groupOrder: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
isAgeGatedInstancesVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -89,6 +96,9 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getSmallGroupIconUrl(url) {
|
||||
return utils.convertFileUrlToImageUrl(url);
|
||||
},
|
||||
toggleGroupSidebarCollapse(groupId) {
|
||||
this.groupInstancesCfg[groupId].isCollapsed = !this.groupInstancesCfg[groupId].isCollapsed;
|
||||
},
|
||||
|
||||
@@ -381,6 +381,7 @@
|
||||
"zoom": "Zoom",
|
||||
"vrcplus_profile_icons": "VRCPlus Profile Icons",
|
||||
"tooltips": "Tooltips",
|
||||
"age_gated_instances": "Age Gated Instances",
|
||||
"nicknames": "Memo Nicknames",
|
||||
"sort_favorite_by": "Sort Favorites by",
|
||||
"sort_favorite_by_name": "name",
|
||||
|
||||
@@ -477,7 +477,7 @@ mixin userDialog
|
||||
.detail
|
||||
span.name {{ $t('dialog.user.info.bio') }}
|
||||
pre.extra(
|
||||
style='font-family: inherit; font-size: 12px; white-space: pre-wrap; margin: 0 0.5em 0 0') {{ userDialog.ref.bio || '-' }}
|
||||
style='font-family: inherit; font-size: 12px; white-space: pre-wrap; margin: 0 0.5em 0 0; max-height: 40vh; overflow-y: auto') {{ userDialog.ref.bio || '-' }}
|
||||
div(v-if='userDialog.id === API.currentUser.id' style='float: right')
|
||||
el-button(
|
||||
type='text'
|
||||
|
||||
@@ -6,6 +6,7 @@ mixin worldDialog
|
||||
:last-location='lastLocation'
|
||||
:instance-join-history='instanceJoinHistory'
|
||||
:update-instance-info='updateInstanceInfo'
|
||||
:is-age-gated-instances-visible='isAgeGatedInstancesVisible'
|
||||
@open-folder-generic='openFolderGeneric'
|
||||
@delete-vrchat-cache='deleteVRChatCache'
|
||||
@world-dialog-command='worldDialogCommand'
|
||||
|
||||
@@ -36,11 +36,14 @@ mixin gameLogTab
|
||||
span {{ scope.row.created_at | formatDate('short') }}
|
||||
el-table-column(:label='$t("table.gameLog.type")' prop='type' width='120')
|
||||
template(#default='scope')
|
||||
span.x-link(
|
||||
v-if='scope.row.location && scope.row.type !== "Location"'
|
||||
v-text='$t("view.game_log.filters." + scope.row.type)'
|
||||
@click='showWorldDialog(scope.row.location)')
|
||||
span(v-else v-text='$t("view.game_log.filters." + scope.row.type)')
|
||||
el-tooltip(placement='right' :open-delay='500' :disabled='hideTooltips')
|
||||
template(#content)
|
||||
span {{ $t("view.game_log.filters." + scope.row.type) }}
|
||||
span.x-link(
|
||||
v-if='scope.row.location && scope.row.type !== "Location"'
|
||||
v-text='$t("view.game_log.filters." + scope.row.type)'
|
||||
@click='showWorldDialog(scope.row.location)')
|
||||
span(v-else v-text='$t("view.game_log.filters." + scope.row.type)')
|
||||
el-table-column(:label='$t("table.gameLog.icon")' prop='isFriend' width='70' align='center')
|
||||
template(#default='scope')
|
||||
template(v-if='gameLogIsFriend(scope.row)')
|
||||
|
||||
@@ -273,6 +273,10 @@ mixin settingsTab
|
||||
:label='$t("view.settings.appearance.appearance.tooltips")'
|
||||
:value='!hideTooltips'
|
||||
@change='saveOpenVROption("VRCX_hideTooltips")')
|
||||
simple-switch(
|
||||
:label='$t("view.settings.appearance.appearance.age_gated_instances")'
|
||||
:value='isAgeGatedInstancesVisible'
|
||||
@change='toggleIsAgeGatedInstancesVisible')
|
||||
.options-container-item
|
||||
span.name {{ $t('view.settings.appearance.appearance.sort_favorite_by') }}
|
||||
el-radio-group(v-model='sortFavorites' @change='saveSortFavoritesOption')
|
||||
|
||||
@@ -2061,4 +2061,10 @@ i.x-user-status {
|
||||
background: linear-gradient(90deg, #302E34 25%, #423F46 37%, #302E34 63%);
|
||||
background-size: 400% 100%;
|
||||
animation: el-skeleton-loading 1.4s ease infinite;
|
||||
}
|
||||
.el-table .el-table__body-wrapper .el-table__row .cell > span {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -95,6 +95,7 @@
|
||||
<groups-sidebar
|
||||
:group-instances="groupInstances"
|
||||
:group-order="inGameGroupOrder"
|
||||
:is-age-gated-instances-visible="isAgeGatedInstancesVisible"
|
||||
@show-group-dialog="$emit('show-group-dialog', $event)"></groups-sidebar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -108,12 +109,12 @@
|
||||
|
||||
export default {
|
||||
name: 'SideBar',
|
||||
inject: ['API', 'userImage'],
|
||||
components: {
|
||||
FriendsSidebar,
|
||||
GroupsSidebar,
|
||||
Location
|
||||
},
|
||||
inject: ['API', 'userImage'],
|
||||
props: {
|
||||
// settings
|
||||
// remove these props when have a state manager.
|
||||
@@ -124,6 +125,7 @@
|
||||
gameLogDisabled: Boolean,
|
||||
hideNicknames: Boolean,
|
||||
isHideFriendsInSameInstance: Boolean,
|
||||
isAgeGatedInstancesVisible: Boolean,
|
||||
|
||||
isSideBarTabShow: Boolean,
|
||||
|
||||
|
||||
@@ -325,103 +325,106 @@
|
||||
}}
|
||||
</div>
|
||||
<div v-for="room in worldDialog.rooms" :key="room.id">
|
||||
<div style="margin: 5px 0">
|
||||
<location-world
|
||||
:locationobject="room.$location"
|
||||
:currentuserid="API.currentUser.id"
|
||||
:worlddialogshortname="worldDialog.$location.shortName"
|
||||
@show-launch-dialog="showLaunchDialog" />
|
||||
<launch
|
||||
:location="room.tag"
|
||||
style="margin-left: 5px"
|
||||
@show-launch-dialog="showLaunchDialog" />
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="$t('dialog.world.instances.self_invite_tooltip')"
|
||||
:disabled="hideTooltips">
|
||||
<invite-yourself
|
||||
:location="room.$location.tag"
|
||||
:shortname="room.$location.shortName"
|
||||
style="margin-left: 5px" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="$t('dialog.world.instances.refresh_instance_info')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
size="mini"
|
||||
icon="el-icon-refresh"
|
||||
<template
|
||||
v-if="isAgeGatedInstancesVisible || !(room.ageGate || room.location?.includes('~ageGate'))">
|
||||
<div style="margin: 5px 0">
|
||||
<location-world
|
||||
:locationobject="room.$location"
|
||||
:currentuserid="API.currentUser.id"
|
||||
:worlddialogshortname="worldDialog.$location.shortName"
|
||||
@show-launch-dialog="showLaunchDialog" />
|
||||
<launch
|
||||
:location="room.tag"
|
||||
style="margin-left: 5px"
|
||||
circle
|
||||
@click="refreshInstancePlayerCount(room.tag)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="instanceJoinHistory.get(room.$location.tag)"
|
||||
placement="top"
|
||||
:content="$t('dialog.previous_instances.info')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
size="mini"
|
||||
icon="el-icon-s-data"
|
||||
style="margin-left: 5px"
|
||||
plain
|
||||
circle
|
||||
@click="showPreviousInstanceInfoDialog(room.location)" />
|
||||
</el-tooltip>
|
||||
<last-join :location="room.$location.tag" :currentlocation="lastLocation.location" />
|
||||
<instance-info
|
||||
:location="room.tag"
|
||||
:instance="room.ref"
|
||||
:friendcount="room.friendCount"
|
||||
:updateelement="updateInstanceInfo" />
|
||||
<div
|
||||
v-if="room.$location.userId || room.users.length"
|
||||
class="x-friend-list"
|
||||
style="margin: 10px 0; max-height: unset">
|
||||
@show-launch-dialog="showLaunchDialog" />
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="$t('dialog.world.instances.self_invite_tooltip')"
|
||||
:disabled="hideTooltips">
|
||||
<invite-yourself
|
||||
:location="room.$location.tag"
|
||||
:shortname="room.$location.shortName"
|
||||
style="margin-left: 5px" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
:content="$t('dialog.world.instances.refresh_instance_info')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
size="mini"
|
||||
icon="el-icon-refresh"
|
||||
style="margin-left: 5px"
|
||||
circle
|
||||
@click="refreshInstancePlayerCount(room.tag)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="instanceJoinHistory.get(room.$location.tag)"
|
||||
placement="top"
|
||||
:content="$t('dialog.previous_instances.info')"
|
||||
:disabled="hideTooltips">
|
||||
<el-button
|
||||
size="mini"
|
||||
icon="el-icon-s-data"
|
||||
style="margin-left: 5px"
|
||||
plain
|
||||
circle
|
||||
@click="showPreviousInstanceInfoDialog(room.location)" />
|
||||
</el-tooltip>
|
||||
<last-join :location="room.$location.tag" :currentlocation="lastLocation.location" />
|
||||
<instance-info
|
||||
:location="room.tag"
|
||||
:instance="room.ref"
|
||||
:friendcount="room.friendCount"
|
||||
:updateelement="updateInstanceInfo" />
|
||||
<div
|
||||
v-if="room.$location.userId"
|
||||
class="x-friend-item x-friend-item-border"
|
||||
@click="showUserDialog(room.$location.userId)">
|
||||
<template v-if="room.$location.user">
|
||||
<div class="avatar" :class="userStatusClass(room.$location.user)">
|
||||
<img v-lazy="userImage(room.$location.user, true)" />
|
||||
v-if="room.$location.userId || room.users.length"
|
||||
class="x-friend-list"
|
||||
style="margin: 10px 0; max-height: unset">
|
||||
<div
|
||||
v-if="room.$location.userId"
|
||||
class="x-friend-item x-friend-item-border"
|
||||
@click="showUserDialog(room.$location.userId)">
|
||||
<template v-if="room.$location.user">
|
||||
<div class="avatar" :class="userStatusClass(room.$location.user)">
|
||||
<img v-lazy="userImage(room.$location.user, true)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span
|
||||
class="name"
|
||||
:style="{ color: room.$location.user.$userColour }"
|
||||
v-text="room.$location.user.displayName" />
|
||||
<span class="extra">
|
||||
{{ $t('dialog.world.instances.instance_creator') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<span v-else v-text="room.$location.userId" />
|
||||
</div>
|
||||
<div
|
||||
v-for="user in room.users"
|
||||
:key="user.id"
|
||||
class="x-friend-item x-friend-item-border"
|
||||
@click="showUserDialog(user.id)">
|
||||
<div class="avatar" :class="userStatusClass(user)">
|
||||
<img v-lazy="userImage(user, true)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span
|
||||
class="name"
|
||||
:style="{ color: room.$location.user.$userColour }"
|
||||
v-text="room.$location.user.displayName" />
|
||||
<span class="extra">
|
||||
{{ $t('dialog.world.instances.instance_creator') }}
|
||||
:style="{ color: user.$userColour }"
|
||||
v-text="user.displayName" />
|
||||
<span v-if="user.location === 'traveling'" class="extra">
|
||||
<i class="el-icon-loading" style="margin-right: 5px" />
|
||||
<timer :epoch="user.$travelingToTime" />
|
||||
</span>
|
||||
<span v-else class="extra">
|
||||
<timer :epoch="user.$location_at" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<span v-else v-text="room.$location.userId" />
|
||||
</div>
|
||||
<div
|
||||
v-for="user in room.users"
|
||||
:key="user.id"
|
||||
class="x-friend-item x-friend-item-border"
|
||||
@click="showUserDialog(user.id)">
|
||||
<div class="avatar" :class="userStatusClass(user)">
|
||||
<img v-lazy="userImage(user, true)" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<span
|
||||
class="name"
|
||||
:style="{ color: user.$userColour }"
|
||||
v-text="user.displayName" />
|
||||
<span v-if="user.location === 'traveling'" class="extra">
|
||||
<i class="el-icon-loading" style="margin-right: 5px" />
|
||||
<timer :epoch="user.$travelingToTime" />
|
||||
</span>
|
||||
<span v-else class="extra">
|
||||
<timer :epoch="user.$location_at" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('dialog.world.info.header')" lazy>
|
||||
@@ -756,8 +759,9 @@
|
||||
isGameRunning: Boolean,
|
||||
lastLocation: Object,
|
||||
instanceJoinHistory: Map,
|
||||
isAgeGatedInstancesVisible: Boolean,
|
||||
|
||||
// ok
|
||||
// TODO: Remove
|
||||
updateInstanceInfo: Number
|
||||
},
|
||||
data() {
|
||||
|
||||
Reference in New Issue
Block a user