diff --git a/src/components/dialogs/UserDialog/UserDialog.vue b/src/components/dialogs/UserDialog/UserDialog.vue index 33fe0539..88c68333 100644 --- a/src/components/dialogs/UserDialog/UserDialog.vue +++ b/src/components/dialogs/UserDialog/UserDialog.vue @@ -2214,8 +2214,12 @@ } setUserDialogMutualFriendSorting(userDialog.value.mutualFriendSorting); }, - done: () => { + done: (success) => { userDialog.value.isMutualFriendsLoading = false; + if (success) { + const mutualIds = userDialog.value.mutualFriends.map((u) => u.id); + database.updateMutualsForFriend(userId, mutualIds); + } } }); } diff --git a/src/localization/en.json b/src/localization/en.json index 27ef38eb..0e59412a 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -273,7 +273,8 @@ "filter_placeholder": "Filter", "refresh_tooltip": "Refresh", "clear_tooltip": "Clear Results", - "cancel_tooltip": "Cancel" + "cancel_tooltip": "Cancel", + "load_mutual_friends": "Load Mutual Friends" }, "charts": { "header": "Charts", @@ -2201,7 +2202,8 @@ "lastActivity": "Last Activity", "lastLogin": "Last Login", "dateJoined": "Date Joined", - "unfriend": "Unfriend" + "unfriend": "Unfriend", + "mutualFriends": "Mutual Friends" }, "profile": { "invite_messages": { diff --git a/src/service/database/mutualGraph.js b/src/service/database/mutualGraph.js index 4e99fa05..2d59d249 100644 --- a/src/service/database/mutualGraph.js +++ b/src/service/database/mutualGraph.js @@ -86,6 +86,51 @@ const mutualGraph = { await sqliteService.executeNonQuery('ROLLBACK'); throw err; } + }, + + async updateMutualsForFriend(friendId, mutualIds) { + if (!dbVars.userPrefix || !friendId) { + return; + } + const friendTable = `${dbVars.userPrefix}_mutual_graph_friends`; + const linkTable = `${dbVars.userPrefix}_mutual_graph_links`; + const safeFriendId = friendId.replace(/'/g, "''"); + await sqliteService.executeNonQuery( + `INSERT OR REPLACE INTO ${friendTable} (friend_id) VALUES ('${safeFriendId}')` + ); + await sqliteService.executeNonQuery( + `DELETE FROM ${linkTable} WHERE friend_id='${safeFriendId}'` + ); + let edgeValues = ''; + for (const mutual of mutualIds) { + if (!mutual) { + continue; + } + const safeMutualId = String(mutual).replace(/'/g, "''"); + edgeValues += `('${safeFriendId}', '${safeMutualId}'),`; + } + if (edgeValues) { + edgeValues = edgeValues.slice(0, -1); + await sqliteService.executeNonQuery( + `INSERT OR REPLACE INTO ${linkTable} (friend_id, mutual_id) VALUES ${edgeValues}` + ); + } + }, + + async getMutualCountForAllUsers() { + const mutualCountMap = new Map(); + if (!dbVars.userPrefix) { + return mutualCountMap; + } + const linkTable = `${dbVars.userPrefix}_mutual_graph_links`; + await sqliteService.execute((dbRow) => { + const mutualId = dbRow[0]; + const count = dbRow[1]; + if (mutualId) { + mutualCountMap.set(mutualId, count); + } + }, `SELECT mutual_id, COUNT(*) FROM ${linkTable} GROUP BY mutual_id`); + return mutualCountMap; } }; diff --git a/src/stores/friend.js b/src/stores/friend.js index 9e5fd015..39d0f720 100644 --- a/src/stores/friend.js +++ b/src/stores/friend.js @@ -915,6 +915,16 @@ export const useFriendStore = defineStore('Friend', () => { } } + async function getAllUserMutualCount() { + const mutualCountMap = await database.getMutualCountForAllUsers(); + for (const [userId, mutualCount] of mutualCountMap.entries()) { + const ref = friends.get(userId); + if (ref?.ref) { + ref.ref.$mutualCount = mutualCount; + } + } + } + /** * * @param {string} id @@ -1625,6 +1635,7 @@ export const useFriendStore = defineStore('Friend', () => { refreshFriendsList, updateOnlineFriendCounter, getAllUserStats, + getAllUserMutualCount, initFriendLog, migrateFriendLog, getFriendLog, diff --git a/src/stores/user.js b/src/stores/user.js index e2c79166..8ae8c201 100644 --- a/src/stores/user.js +++ b/src/stores/user.js @@ -523,6 +523,7 @@ export const useUserStore = defineStore('User', () => { $joinCount: 0, $timeSpent: 0, $lastSeen: '', + $mutualCount: 0, $nickName: '', $previousLocation: '', $customTag: '', diff --git a/src/types/api/user.d.ts b/src/types/api/user.d.ts index 48446d31..f327401b 100644 --- a/src/types/api/user.d.ts +++ b/src/types/api/user.d.ts @@ -55,6 +55,7 @@ export interface VrcxUser extends GetUserResponse { $joinCount: number; $timeSpent: number; $lastSeen: string; + $mutualCount: number; $nickName: string; $previousLocation: string; $customTag: string; diff --git a/src/views/FriendList/FriendList.vue b/src/views/FriendList/FriendList.vue index d41679b1..851bf607 100644 --- a/src/views/FriendList/FriendList.vue +++ b/src/views/FriendList/FriendList.vue @@ -4,6 +4,9 @@