mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-06 22:46:06 +02:00
improve: Group all friends by the same instance (#1097)
* improve: Group all friends by the same instance * style
This commit is contained in:
+54
-44
@@ -23140,22 +23140,48 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
'VRCX_sidebarGroupByInstance',
|
'VRCX_sidebarGroupByInstance',
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
$app.computed.onlineFriendsInSameInstance = function () {
|
|
||||||
const groupedItems = {};
|
|
||||||
|
|
||||||
this.onlineFriends.forEach((item) => {
|
$app.methods.handleSwitchGroupByInstance = function () {
|
||||||
const key = item.ref?.$location.tag;
|
this.isSidebarGroupByInstance = !this.isSidebarGroupByInstance;
|
||||||
|
configRepository.setBool(
|
||||||
|
'VRCX_sidebarGroupByInstance',
|
||||||
|
this.isSidebarGroupByInstance
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
$app.data.isSidebarGroupByInstanceCollapsed =
|
||||||
|
await configRepository.getBool(
|
||||||
|
'VRCX_sidebarGroupByInstanceCollapsed',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
$app.methods.toggleSwitchGroupByInstanceCollapsed = function () {
|
||||||
|
this.isSidebarGroupByInstanceCollapsed =
|
||||||
|
!this.isSidebarGroupByInstanceCollapsed;
|
||||||
|
configRepository.setBool(
|
||||||
|
'VRCX_sidebarGroupByInstanceCollapsed',
|
||||||
|
this.isSidebarGroupByInstanceCollapsed
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
$app.computed.friendsInSameInstance = function () {
|
||||||
|
const friendsList = {};
|
||||||
|
|
||||||
|
const allFriends = [...this.vipFriends, ...this.onlineFriends];
|
||||||
|
|
||||||
|
allFriends.forEach((friend) => {
|
||||||
|
const key = friend.ref?.$location.tag;
|
||||||
if (!key || key === 'private' || key === 'offline') return;
|
if (!key || key === 'private' || key === 'offline') return;
|
||||||
if (!groupedItems[key]) {
|
if (!friendsList[key]) {
|
||||||
groupedItems[key] = [];
|
friendsList[key] = [];
|
||||||
}
|
}
|
||||||
groupedItems[key].push(item);
|
friendsList[key].push(friend);
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedGroups = [];
|
const sortedFriendsList = [];
|
||||||
for (const group of Object.values(groupedItems)) {
|
for (const group of Object.values(friendsList)) {
|
||||||
if (group.length > 1) {
|
if (group.length > 1) {
|
||||||
sortedGroups.push(
|
sortedFriendsList.push(
|
||||||
group.sort(
|
group.sort(
|
||||||
(a, b) => a.ref?.$location_at - b.ref?.$location_at
|
(a, b) => a.ref?.$location_at - b.ref?.$location_at
|
||||||
)
|
)
|
||||||
@@ -23163,55 +23189,39 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedGroups.sort((a, b) => b.length - a.length);
|
return sortedFriendsList.sort((a, b) => b.length - a.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
$app.computed.onlineFriendsNotInSameInstance = function () {
|
$app.computed.onlineFriendsByGroupStatus = function () {
|
||||||
const friendsInSameInstance = new Set(
|
const sameInstanceTag = new Set(
|
||||||
this.onlineFriendsInSameInstance.flat().map((friend) => friend.id)
|
this.friendsInSameInstance.flatMap((item) =>
|
||||||
|
item.map((friend) => friend.ref?.$location.tag)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.onlineFriends.filter(
|
return this.onlineFriends.filter(
|
||||||
(friend) => !friendsInSameInstance.has(friend.id)
|
(item) => !sameInstanceTag.has(item.ref?.$location.tag)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
$app.computed.vipFriendsInSameInstance = function () {
|
$app.computed.vipFriendsByGroupStatus = function () {
|
||||||
const groupedItems = {};
|
const sameInstanceTag = new Set(
|
||||||
|
this.friendsInSameInstance.flatMap((item) =>
|
||||||
this.vipFriends.forEach((item) => {
|
item.map((friend) => friend.ref?.$location.tag)
|
||||||
const key = item.ref?.$location.tag;
|
|
||||||
if (!key || key === 'private' || key === 'offline') return;
|
|
||||||
if (!groupedItems[key]) {
|
|
||||||
groupedItems[key] = [];
|
|
||||||
}
|
|
||||||
groupedItems[key].push(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortedGroups = [];
|
|
||||||
for (const group of Object.values(groupedItems)) {
|
|
||||||
if (group.length > 1) {
|
|
||||||
sortedGroups.push(
|
|
||||||
group.sort(
|
|
||||||
(a, b) => a.ref?.$location_at - b.ref?.$location_at
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortedGroups.sort((a, b) => b.length - a.length);
|
|
||||||
};
|
|
||||||
|
|
||||||
$app.computed.vipFriendsNotInSameInstance = function () {
|
|
||||||
const friendsInSameInstance = new Set(
|
|
||||||
this.vipFriendsInSameInstance.flat().map((friend) => friend.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.vipFriends.filter(
|
return this.vipFriends.filter(
|
||||||
(friend) => !friendsInSameInstance.has(friend.id)
|
(item) => !sameInstanceTag.has(item.ref?.$location.tag)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$app.methods.getFriendsLocations = function (friendsArr) {
|
||||||
|
// prevent the instance title display as "Traveling".
|
||||||
|
return friendsArr.find((friend) => !friend.ref?.$location?.isTraveling)
|
||||||
|
?.ref?.location;
|
||||||
|
};
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region | Electron
|
// #region | Electron
|
||||||
|
|||||||
@@ -633,6 +633,7 @@
|
|||||||
"friends": "Friends",
|
"friends": "Friends",
|
||||||
"me": "ME",
|
"me": "ME",
|
||||||
"favorite": "FAVORITES",
|
"favorite": "FAVORITES",
|
||||||
|
"same_instance": "Same Instance",
|
||||||
"online": "ONLINE",
|
"online": "ONLINE",
|
||||||
"active": "ACTIVE",
|
"active": "ACTIVE",
|
||||||
"offline": "OFFLINE",
|
"offline": "OFFLINE",
|
||||||
|
|||||||
@@ -633,6 +633,7 @@
|
|||||||
"friends": "好友",
|
"friends": "好友",
|
||||||
"me": "我",
|
"me": "我",
|
||||||
"favorite": "星标好友",
|
"favorite": "星标好友",
|
||||||
|
"same_instance": "同一房间",
|
||||||
"online": "在线",
|
"online": "在线",
|
||||||
"active": "活跃中(仅登录网页端)",
|
"active": "活跃中(仅登录网页端)",
|
||||||
"offline": "离线",
|
"offline": "离线",
|
||||||
|
|||||||
@@ -70,21 +70,12 @@ mixin friendsListSidebar
|
|||||||
span.extra(v-else v-text='API.currentUser.statusDescription')
|
span.extra(v-else v-text='API.currentUser.statusDescription')
|
||||||
.x-friend-group.x-link(
|
.x-friend-group.x-link(
|
||||||
@click='isVIPFriends = !isVIPFriends; saveFriendsGroupStates()'
|
@click='isVIPFriends = !isVIPFriends; saveFriendsGroupStates()'
|
||||||
v-show='vipFriends.length')
|
v-show='vipFriendsByGroupStatus.length')
|
||||||
i.el-icon-arrow-right(:class='{ rotate: isVIPFriends }')
|
i.el-icon-arrow-right(:class='{ rotate: isVIPFriends }')
|
||||||
span(style='margin-left: 5px') {{ $t('side_panel.favorite') }} ― {{ vipFriends.length }}
|
span(style='margin-left: 5px') {{ $t('side_panel.favorite') }} ― {{ vipFriendsByGroupStatus.length }}
|
||||||
div(v-show='isVIPFriends')
|
div(v-show='isVIPFriends')
|
||||||
template(v-if='isSidebarGroupByInstance')
|
|
||||||
div(
|
|
||||||
v-for='(friendArr, idx) in vipFriendsInSameInstance'
|
|
||||||
:key='friendArr[0].ref?.location.tag')
|
|
||||||
div(style='margin-bottom: 3px')
|
|
||||||
location.extra(:location='friendArr[0].ref?.location' style='color: #c7c7c7')
|
|
||||||
span(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
|
||||||
div(style='margin-bottom: 10px')
|
|
||||||
.x-friend-item(
|
.x-friend-item(
|
||||||
v-if='friendArr && friendArr.length'
|
v-for='friend in vipFriendsByGroupStatus'
|
||||||
v-for='friend in friendArr'
|
|
||||||
:key='friend.id'
|
:key='friend.id'
|
||||||
@click='showUserDialog(friend.id)')
|
@click='showUserDialog(friend.id)')
|
||||||
template(v-if='friend.ref')
|
template(v-if='friend.ref')
|
||||||
@@ -99,6 +90,53 @@ mixin friendsListSidebar
|
|||||||
v-text='friend.ref.displayName'
|
v-text='friend.ref.displayName'
|
||||||
:style='{ color: friend.ref.$userColour }')
|
:style='{ color: friend.ref.$userColour }')
|
||||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||||
|
location.extra(
|
||||||
|
v-else
|
||||||
|
:location='friend.ref.location'
|
||||||
|
:traveling='friend.ref.travelingToLocation'
|
||||||
|
:link='false')
|
||||||
|
template(v-else)
|
||||||
|
span(v-text='friend.name || friend.id')
|
||||||
|
el-button(
|
||||||
|
type='text'
|
||||||
|
icon='el-icon-close'
|
||||||
|
size='mini'
|
||||||
|
@click.stop='confirmDeleteFriend(friend.id)'
|
||||||
|
style='margin-left: 5px')
|
||||||
|
|
||||||
|
//- Group By Instance
|
||||||
|
template(v-if='isSidebarGroupByInstance && friendsInSameInstance.length')
|
||||||
|
.x-friend-group.x-link(@click='toggleSwitchGroupByInstanceCollapsed')
|
||||||
|
i.el-icon-arrow-right(:class='{ rotate: isSidebarGroupByInstanceCollapsed }')
|
||||||
|
span(style='margin-left: 5px') {{ $t('side_panel.same_instance') }} ― {{ friendsInSameInstance.length }}
|
||||||
|
div(v-show='!isSidebarGroupByInstanceCollapsed')
|
||||||
|
div(v-for='friendArr in friendsInSameInstance' :key='friendArr[0].ref?.location.tag')
|
||||||
|
div(style='margin-bottom: 3px')
|
||||||
|
location.extra(:location='getFriendsLocations(friendArr)' style='color: #c7c7c7')
|
||||||
|
span(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
||||||
|
div
|
||||||
|
.x-friend-item(
|
||||||
|
v-if='friendArr && friendArr.length'
|
||||||
|
v-for='(friend, idx) in friendArr'
|
||||||
|
:key='friend.id'
|
||||||
|
@click='showUserDialog(friend.id)'
|
||||||
|
:style='{ "margin-bottom": idx === friendArr.length - 1 ? "5px" : undefined }')
|
||||||
|
template(v-if='friend.ref')
|
||||||
|
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
||||||
|
img(v-lazy='userImage(friend.ref)')
|
||||||
|
.detail
|
||||||
|
div(style='display: flex; align-items: center')
|
||||||
|
span.name(
|
||||||
|
v-if='!hideNicknames && friend.$nickName'
|
||||||
|
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
||||||
|
span.name(
|
||||||
|
v-else
|
||||||
|
v-text='friend.ref.displayName'
|
||||||
|
:style='{ color: friend.ref.$userColour }')
|
||||||
|
i.el-icon-star-on(
|
||||||
|
v-if='friend.isVIP'
|
||||||
|
style='color: #ffd700; margin: 1px 0 0 2px')
|
||||||
|
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
||||||
template(v-else)
|
template(v-else)
|
||||||
i.el-icon.el-icon-loading(
|
i.el-icon.el-icon-loading(
|
||||||
v-if='friend.ref.travelingToLocation'
|
v-if='friend.ref.travelingToLocation'
|
||||||
@@ -112,143 +150,15 @@ mixin friendsListSidebar
|
|||||||
size='mini'
|
size='mini'
|
||||||
@click.stop='confirmDeleteFriend(friend.id)'
|
@click.stop='confirmDeleteFriend(friend.id)'
|
||||||
style='margin-left: 5px')
|
style='margin-left: 5px')
|
||||||
div(v-if='idx === vipFriendsInSameInstance.length - 1' style='color: #c7c7c7') {{ 'Others' }}
|
|
||||||
.x-friend-item(
|
|
||||||
v-for='friend in vipFriendsNotInSameInstance'
|
|
||||||
:key='friend.id'
|
|
||||||
@click='showUserDialog(friend.id)')
|
|
||||||
template(v-if='friend.ref')
|
|
||||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
|
||||||
img(v-lazy='userImage(friend.ref)')
|
|
||||||
.detail
|
|
||||||
span.name(
|
|
||||||
v-if='!hideNicknames && friend.$nickName'
|
|
||||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
|
||||||
span.name(
|
|
||||||
v-else
|
|
||||||
v-text='friend.ref.displayName'
|
|
||||||
:style='{ color: friend.ref.$userColour }')
|
|
||||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
|
||||||
location.extra(
|
|
||||||
v-else
|
|
||||||
:location='friend.ref.location'
|
|
||||||
:traveling='friend.ref.travelingToLocation'
|
|
||||||
:link='false')
|
|
||||||
template(v-else)
|
|
||||||
span(v-text='friend.name || friend.id')
|
|
||||||
el-button(
|
|
||||||
type='text'
|
|
||||||
icon='el-icon-close'
|
|
||||||
size='mini'
|
|
||||||
@click.stop='confirmDeleteFriend(friend.id)'
|
|
||||||
style='margin-left: 5px')
|
|
||||||
template(v-else)
|
|
||||||
.x-friend-item(
|
|
||||||
v-for='friend in vipFriends'
|
|
||||||
:key='friend.id'
|
|
||||||
@click='showUserDialog(friend.id)')
|
|
||||||
template(v-if='friend.ref')
|
|
||||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
|
||||||
img(v-lazy='userImage(friend.ref)')
|
|
||||||
.detail
|
|
||||||
span.name(
|
|
||||||
v-if='!hideNicknames && friend.$nickName'
|
|
||||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
|
||||||
span.name(
|
|
||||||
v-else
|
|
||||||
v-text='friend.ref.displayName'
|
|
||||||
:style='{ color: friend.ref.$userColour }')
|
|
||||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
|
||||||
location.extra(
|
|
||||||
v-else
|
|
||||||
:location='friend.ref.location'
|
|
||||||
:traveling='friend.ref.travelingToLocation'
|
|
||||||
:link='false')
|
|
||||||
template(v-else)
|
|
||||||
span(v-text='friend.name || friend.id')
|
|
||||||
el-button(
|
|
||||||
type='text'
|
|
||||||
icon='el-icon-close'
|
|
||||||
size='mini'
|
|
||||||
@click.stop='confirmDeleteFriend(friend.id)'
|
|
||||||
style='margin-left: 5px')
|
|
||||||
.x-friend-group.x-link(
|
.x-friend-group.x-link(
|
||||||
@click='isOnlineFriends = !isOnlineFriends; saveFriendsGroupStates()'
|
@click='isOnlineFriends = !isOnlineFriends; saveFriendsGroupStates()'
|
||||||
v-show='onlineFriends.length')
|
v-show='onlineFriendsByGroupStatus.length')
|
||||||
i.el-icon-arrow-right(:class='{ rotate: isOnlineFriends }')
|
i.el-icon-arrow-right(:class='{ rotate: isOnlineFriends }')
|
||||||
span(style='margin-left: 5px') {{ $t('side_panel.online') }} ― {{ onlineFriends.length }}
|
span(style='margin-left: 5px') {{ $t('side_panel.online') }} ― {{ onlineFriendsByGroupStatus.length }}
|
||||||
div(v-show='isOnlineFriends')
|
div(v-show='isOnlineFriends')
|
||||||
template(v-if='isSidebarGroupByInstance')
|
|
||||||
div(
|
|
||||||
v-for='(friendArr, idx) in onlineFriendsInSameInstance'
|
|
||||||
:key='friendArr[0].ref?.location.tag')
|
|
||||||
div(style='margin-bottom: 3px')
|
|
||||||
location.extra(:location='friendArr[0].ref?.location' style='color: #c7c7c7')
|
|
||||||
span(style='margin-left: 5px') {{ `(${friendArr.length})` }}
|
|
||||||
div(style='margin-bottom: 10px')
|
|
||||||
.x-friend-item(
|
.x-friend-item(
|
||||||
v-if='friendArr && friendArr.length'
|
v-for='friend in onlineFriendsByGroupStatus'
|
||||||
v-for='friend in friendArr'
|
|
||||||
:key='friend.id'
|
|
||||||
@click='showUserDialog(friend.id)')
|
|
||||||
template(v-if='friend.ref')
|
|
||||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
|
||||||
img(v-lazy='userImage(friend.ref)')
|
|
||||||
.detail
|
|
||||||
span.name(
|
|
||||||
v-if='!hideNicknames && friend.$nickName'
|
|
||||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
|
||||||
span.name(
|
|
||||||
v-else
|
|
||||||
v-text='friend.ref.displayName'
|
|
||||||
:style='{ color: friend.ref.$userColour }')
|
|
||||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
|
||||||
template(v-else)
|
|
||||||
i.el-icon.el-icon-loading(
|
|
||||||
v-if='friend.ref.travelingToLocation'
|
|
||||||
style='display: inline-block; margin-right: 5px')
|
|
||||||
timer(:epoch='friend.ref?.$location_at' style='color: #c7c7c7')
|
|
||||||
template(v-else)
|
|
||||||
span(v-text='friend.name || friend.id')
|
|
||||||
el-button(
|
|
||||||
type='text'
|
|
||||||
icon='el-icon-close'
|
|
||||||
size='mini'
|
|
||||||
@click.stop='confirmDeleteFriend(friend.id)'
|
|
||||||
style='margin-left: 5px')
|
|
||||||
div(v-if='idx === onlineFriendsInSameInstance.length - 1' style='color: #c7c7c7') {{ 'Others' }}
|
|
||||||
.x-friend-item(
|
|
||||||
v-for='friend in onlineFriendsNotInSameInstance'
|
|
||||||
:key='friend.id'
|
|
||||||
@click='showUserDialog(friend.id)')
|
|
||||||
template(v-if='friend.ref')
|
|
||||||
.avatar(:class='userStatusClass(friend.ref, friend.pendingOffline)')
|
|
||||||
img(v-lazy='userImage(friend.ref)')
|
|
||||||
.detail
|
|
||||||
span.name(
|
|
||||||
v-if='!hideNicknames && friend.$nickName'
|
|
||||||
:style='{ color: friend.ref.$userColour }') {{ friend.ref.displayName }} ({{ friend.$nickName }})
|
|
||||||
span.name(
|
|
||||||
v-else
|
|
||||||
v-text='friend.ref.displayName'
|
|
||||||
:style='{ color: friend.ref.$userColour }')
|
|
||||||
span.extra(v-if='friend.pendingOffline') #[i.el-icon-warning-outline] {{ $t('side_panel.pending_offline') }}
|
|
||||||
location.extra(
|
|
||||||
v-else
|
|
||||||
:location='friend.ref.location'
|
|
||||||
:traveling='friend.ref.travelingToLocation'
|
|
||||||
:link='false')
|
|
||||||
template(v-else)
|
|
||||||
span(v-text='friend.name || friend.id')
|
|
||||||
el-button(
|
|
||||||
type='text'
|
|
||||||
icon='el-icon-close'
|
|
||||||
size='mini'
|
|
||||||
@click.stop='confirmDeleteFriend(friend.id)'
|
|
||||||
style='margin-left: 5px')
|
|
||||||
template(v-else)
|
|
||||||
.x-friend-item(
|
|
||||||
v-for='friend in onlineFriends'
|
|
||||||
:key='friend.id'
|
:key='friend.id'
|
||||||
@click='showUserDialog(friend.id)')
|
@click='showUserDialog(friend.id)')
|
||||||
template(v-if='friend.ref')
|
template(v-if='friend.ref')
|
||||||
|
|||||||
Reference in New Issue
Block a user