add local favorites friend

This commit is contained in:
pa
2026-02-11 22:38:15 +09:00
parent 6d76140e1d
commit 61a4176f47
9 changed files with 601 additions and 20 deletions
@@ -30,6 +30,27 @@
</Button>
</template>
</div>
<div v-if="favoriteDialog.type === 'friend'" style="margin-top: 20px">
<span style="display: block; text-align: center">{{ t('dialog.favorite.local_favorites') }}</span>
<template v-for="group in localFriendFavoriteGroups" :key="group">
<Button
variant="outline"
v-if="hasLocalFriendFavorite(favoriteDialog.objectId, group)"
style="width: 100%; white-space: initial"
class="my-1"
@click="removeLocalFriendFavorite(favoriteDialog.objectId, group)">
<Check />{{ group }} ({{ localFriendFavGroupLength(group) }})
</Button>
<Button
variant="outline"
v-else
style="width: 100%; white-space: initial"
class="my-1"
@click="addLocalFriendFavorite(favoriteDialog.objectId, group)">
{{ group }} ({{ localFriendFavGroupLength(group) }})
</Button>
</template>
</div>
<div v-if="favoriteDialog.type === 'world'" style="margin-top: 20px">
<span style="display: block; text-align: center">{{ t('dialog.favorite.local_favorites') }}</span>
<template v-for="group in localWorldFavoriteGroups" :key="group">
@@ -99,7 +120,8 @@
favoriteWorldGroups,
favoriteDialog,
localWorldFavoriteGroups,
localAvatarFavoriteGroups
localAvatarFavoriteGroups,
localFriendFavoriteGroups
} = storeToRefs(favoriteStore);
const {
localWorldFavGroupLength,
@@ -110,7 +132,11 @@
localAvatarFavGroupLength,
removeLocalAvatarFavorite,
removeLocalWorldFavorite,
deleteFavoriteNoConfirm
deleteFavoriteNoConfirm,
localFriendFavGroupLength,
addLocalFriendFavorite,
hasLocalFriendFavorite,
removeLocalFriendFavorite
} = favoriteStore;
const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore());
+5
View File
@@ -1,5 +1,6 @@
import { avatarFavorites } from './database/avatarFavorites.js';
import { feed } from './database/feed.js';
import { friendFavorites } from './database/friendFavorites.js';
import { friendLogCurrent } from './database/friendLogCurrent.js';
import { friendLogHistory } from './database/friendLogHistory.js';
import { gameLog } from './database/gameLog.js';
@@ -30,6 +31,7 @@ const database = {
...friendLogCurrent,
...memos,
...avatarFavorites,
...friendFavorites,
...worldFavorites,
...tableAlter,
...tableFixes,
@@ -126,6 +128,9 @@ const database = {
await sqliteService.executeNonQuery(
`CREATE TABLE IF NOT EXISTS favorite_avatar (id INTEGER PRIMARY KEY, created_at TEXT, avatar_id TEXT, group_name TEXT)`
);
await sqliteService.executeNonQuery(
`CREATE TABLE IF NOT EXISTS favorite_friend (id INTEGER PRIMARY KEY, created_at TEXT, user_id TEXT, group_name TEXT)`
);
await sqliteService.executeNonQuery(
`CREATE TABLE IF NOT EXISTS memos (user_id TEXT PRIMARY KEY, edited_at TEXT, memo TEXT)`
);
+58
View File
@@ -0,0 +1,58 @@
import sqliteService from '../sqlite.js';
const friendFavorites = {
addFriendToLocalFavorites(userId, groupName) {
sqliteService.executeNonQuery(
'INSERT OR REPLACE INTO favorite_friend (user_id, group_name, created_at) VALUES (@user_id, @group_name, @created_at)',
{
'@user_id': userId,
'@group_name': groupName,
'@created_at': new Date().toJSON()
}
);
},
removeFriendFromLocalFavorites(userId, groupName) {
sqliteService.executeNonQuery(
`DELETE FROM favorite_friend WHERE user_id = @user_id AND group_name = @group_name`,
{
'@user_id': userId,
'@group_name': groupName
}
);
},
renameFriendFavoriteGroup(newGroupName, groupName) {
sqliteService.executeNonQuery(
`UPDATE favorite_friend SET group_name = @new_group_name WHERE group_name = @group_name`,
{
'@new_group_name': newGroupName,
'@group_name': groupName
}
);
},
deleteFriendFavoriteGroup(groupName) {
sqliteService.executeNonQuery(
`DELETE FROM favorite_friend WHERE group_name = @group_name`,
{
'@group_name': groupName
}
);
},
async getFriendFavorites() {
const data = [];
await sqliteService.execute((dbRow) => {
const row = {
created_at: dbRow[1],
userId: dbRow[2],
groupName: dbRow[3]
};
data.push(row);
}, 'SELECT * FROM favorite_friend');
return data;
}
};
export { friendFavorites };
+179 -1
View File
@@ -81,6 +81,8 @@ export const useFavoriteStore = defineStore('Favorite', () => {
const localAvatarFavorites = reactive({});
const localFriendFavorites = reactive({});
const selectedFavoriteFriends = ref([]);
const selectedFavoriteWorlds = ref([]);
const selectedFavoriteAvatars = ref([]);
@@ -189,6 +191,18 @@ export const useFavoriteStore = defineStore('Favorite', () => {
return favoriteGroup.length;
});
const localFriendFavoriteGroups = computed(() =>
Object.keys(localFriendFavorites).sort()
);
const localFriendFavGroupLength = computed(() => (group) => {
const favoriteGroup = localFriendFavorites[group];
if (!favoriteGroup) {
return 0;
}
return favoriteGroup.length;
});
function syncFavoriteSelection(list, selectionRef) {
if (!Array.isArray(list)) {
selectionRef.value = [];
@@ -1514,6 +1528,157 @@ export const useFavoriteStore = defineStore('Favorite', () => {
sortLocalWorldFavorites();
}
/**
* @param {string} userId
* @param {string} group
*/
function addLocalFriendFavorite(userId, group) {
if (hasLocalFriendFavorite(userId, group)) {
return;
}
if (!localFriendFavorites[group]) {
localFriendFavorites[group] = [];
}
localFriendFavorites[group].unshift(userId);
database.addFriendToLocalFavorites(userId, group);
if (
favoriteDialog.value.visible &&
favoriteDialog.value.objectId === userId
) {
updateFavoriteDialog(userId);
}
if (
generalSettingsStore.localFavoriteFriendsGroups.includes(
`local:${group}`
)
) {
friendStore.updateLocalFavoriteFriends();
}
}
/**
* @param {string} userId
* @param {string} group
* @returns {boolean}
*/
function hasLocalFriendFavorite(userId, group) {
const favoriteGroup = localFriendFavorites[group];
if (!favoriteGroup) {
return false;
}
return favoriteGroup.includes(userId);
}
/**
* @param {string} userId
* @param {string} group
*/
function removeLocalFriendFavorite(userId, group) {
const favoriteGroup = localFriendFavorites[group];
if (favoriteGroup) {
const idx = favoriteGroup.indexOf(userId);
if (idx !== -1) {
favoriteGroup.splice(idx, 1);
}
}
database.removeFriendFromLocalFavorites(userId, group);
if (
favoriteDialog.value.visible &&
favoriteDialog.value.objectId === userId
) {
updateFavoriteDialog(userId);
}
if (
generalSettingsStore.localFavoriteFriendsGroups.includes(
`local:${group}`
)
) {
friendStore.updateLocalFavoriteFriends();
}
}
/**
* @param {string} group
*/
function deleteLocalFriendFavoriteGroup(group) {
delete localFriendFavorites[group];
database.deleteFriendFavoriteGroup(group);
if (
generalSettingsStore.localFavoriteFriendsGroups.includes(
`local:${group}`
)
) {
friendStore.updateLocalFavoriteFriends();
}
}
/**
* @param {string} newName
* @param {string} group
*/
function renameLocalFriendFavoriteGroup(newName, group) {
if (localFriendFavoriteGroups.value.includes(newName)) {
toast.error(
t('prompt.local_favorite_group_rename.message.error', {
name: newName
})
);
return;
}
localFriendFavorites[newName] = localFriendFavorites[group];
delete localFriendFavorites[group];
database.renameFriendFavoriteGroup(newName, group);
const oldKey = `local:${group}`;
const idx =
generalSettingsStore.localFavoriteFriendsGroups.indexOf(oldKey);
if (idx !== -1) {
const updated = [
...generalSettingsStore.localFavoriteFriendsGroups
];
updated[idx] = `local:${newName}`;
generalSettingsStore.setLocalFavoriteFriendsGroups(updated);
}
}
/**
* @param {string} group
*/
function newLocalFriendFavoriteGroup(group) {
if (localFriendFavoriteGroups.value.includes(group)) {
toast.error(
t('prompt.new_local_favorite_group.message.error', {
name: group
})
);
return;
}
if (!localFriendFavorites[group]) {
localFriendFavorites[group] = [];
}
}
/**
* @returns {Promise<void>}
*/
async function getLocalFriendFavorites() {
const localFavorites = Object.create(null);
const favorites = await database.getFriendFavorites();
for (let i = 0; i < favorites.length; ++i) {
const favorite = favorites[i];
if (!localFavorites[favorite.groupName]) {
localFavorites[favorite.groupName] = [];
}
localFavorites[favorite.groupName].unshift(favorite.userId);
}
if (Object.keys(localFavorites).length === 0) {
localFavorites.Favorites = [];
}
replaceReactiveObject(localFriendFavorites, localFavorites);
}
/**
*
* @param {string} objectId
@@ -1545,6 +1710,7 @@ export const useFavoriteStore = defineStore('Favorite', () => {
async function saveSortFavoritesOption() {
getLocalWorldFavorites();
getLocalFriendFavorites();
appearanceSettingsStore.setSortFavorites();
}
@@ -1552,6 +1718,7 @@ export const useFavoriteStore = defineStore('Favorite', () => {
refreshFavorites();
getLocalWorldFavorites();
getLocalAvatarFavorites();
getLocalFriendFavorites();
}
function compareByFavoriteSortOrder(a, b) {
@@ -1588,6 +1755,10 @@ export const useFavoriteStore = defineStore('Favorite', () => {
localWorldFavoritesList,
localWorldFavoriteGroups,
localFriendFavorites,
localFriendFavoriteGroups,
localFriendFavGroupLength,
groupedByGroupKeyFavoriteFriends,
selectedFavoriteFriends,
selectedFavoriteWorlds,
@@ -1632,6 +1803,13 @@ export const useFavoriteStore = defineStore('Favorite', () => {
getCachedFavoritesByObjectId,
checkInvalidLocalAvatars,
removeInvalidLocalAvatars,
getCachedFavoriteGroupsByTypeName
getCachedFavoriteGroupsByTypeName,
addLocalFriendFavorite,
hasLocalFriendFavorite,
removeLocalFriendFavorite,
deleteLocalFriendFavoriteGroup,
renameLocalFriendFavoriteGroup,
newLocalFriendFavoriteGroup,
getLocalFriendFavorites
};
});
+11
View File
@@ -317,6 +317,17 @@ export const useFriendStore = defineStore('Friend', () => {
localFavoriteFriends.add(ref.favoriteId);
}
}
for (const selectedKey of generalSettingsStore.localFavoriteFriendsGroups) {
if (selectedKey.startsWith('local:')) {
const groupName = selectedKey.slice(6);
const userIds = favoriteStore.localFriendFavorites[groupName];
if (userIds) {
for (let i = 0; i < userIds.length; ++i) {
localFavoriteFriends.add(userIds[i]);
}
}
}
}
updateSidebarFavorites();
}
+253 -6
View File
@@ -183,6 +183,86 @@
</div>
</div>
</div>
<div class="group-section">
<div class="group-section__header">
<span>{{ t('view.favorite.worlds.local_favorites') }}</span>
<Button
class="rounded-full"
size="icon-sm"
variant="ghost"
@click.stop="getLocalFriendFavorites"
><RefreshCcw />
</Button>
</div>
<div class="group-section__list">
<template v-if="localFriendFavoriteGroups.length">
<div
v-for="group in localFriendFavoriteGroups"
:key="group"
:class="[
'group-item',
{ 'is-active': !hasSearchInput && isGroupActive('local', group) }
]"
@click="handleGroupClick('local', group)">
<div class="group-item__top">
<span class="group-item__name">{{ group }}</span>
<div class="group-item__right">
<span class="group-item__count">{{
localFriendFavGroupLength(group)
}}</span>
<div class="group-item__bottom">
<DropdownMenu
:open="activeGroupMenu === localGroupMenuKey(group)"
@update:open="
handleGroupMenuVisible(localGroupMenuKey(group), $event)
">
<DropdownMenuTrigger asChild>
<Button
class="rounded-full"
size="icon-sm"
variant="ghost"
@click.stop
><Ellipsis
/></Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" class="w-50">
<DropdownMenuItem @click="handleLocalRename(group)">
<span>{{ t('view.favorite.rename_tooltip') }}</span>
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
@click="handleLocalDelete(group)">
<span>{{ t('view.favorite.delete_tooltip') }}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
</div>
</template>
<div v-else class="group-empty">
<DataTableEmpty type="nodata" />
</div>
<div
v-if="!isCreatingLocalGroup"
class="group-item group-item--new"
@click="startLocalGroupCreation">
<Plus />
<span>{{ t('view.favorite.worlds.new_group') }}</span>
</div>
<InputGroupField
v-else
ref="newLocalGroupInput"
v-model="newLocalGroupName"
size="sm"
class="group-item__input"
:placeholder="t('view.favorite.worlds.new_group')"
@keyup.enter="handleLocalGroupCreationConfirm"
@keyup.esc="cancelLocalGroupCreation"
@blur="cancelLocalGroupCreation" />
</div>
</div>
</div>
</ResizablePanel>
<ResizableHandle @dragging="setFriendSplitterDragging" />
@@ -197,11 +277,17 @@
<small>{{ activeRemoteGroup.count }}/{{ activeRemoteGroup.capacity }}</small>
</span>
</template>
<span v-else-if="activeLocalGroupName">
{{ activeLocalGroupName }}
<small>{{ activeLocalGroupCount }}</small>
</span>
<span v-else>No Group Selected</span>
</div>
<div class="favorites-content__edit">
<span>{{ t('view.favorite.edit_mode') }}</span>
<Switch v-model="friendEditMode" :disabled="isSearchActive || !activeRemoteGroup" />
<Switch
v-model="friendEditMode"
:disabled="isSearchActive || (!activeRemoteGroup && !activeLocalGroupName)" />
</div>
</div>
<div class="favorites-content__edit-actions">
@@ -259,6 +345,28 @@
</div>
</div>
</template>
<template v-else-if="!isSearchActive && activeLocalGroupName && isLocalGroupSelected">
<div class="favorites-content__scroll favorites-content__scroll--native">
<template v-if="currentLocalFriendFavorites.length">
<div
class="favorites-card-list"
:style="friendFavoritesGridStyle(currentLocalFriendFavorites.length)">
<FavoritesFriendItem
v-for="favorite in currentLocalFriendFavorites"
:key="favorite.id"
:favorite="favorite"
:group="{ key: activeLocalGroupName, type: 'local' }"
:selected="selectedFavoriteFriends.includes(favorite.id)"
:edit-mode="friendEditMode"
@toggle-select="toggleFriendSelection(favorite.id, $event)"
@click="showUserDialog(favorite.id)" />
</div>
</template>
<div v-else class="favorites-empty">
<DataTableEmpty type="nodata" />
</div>
</div>
</template>
<template v-else-if="!isSearchActive">
<div class="favorites-empty">No Group Selected</div>
</template>
@@ -309,11 +417,11 @@
</template>
<script setup>
import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
import { computed, nextTick, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue';
import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, RefreshCw } from 'lucide-vue-next';
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button';
import { DataTableEmpty } from '@/components/ui/data-table';
import { InputGroupSearch } from '@/components/ui/input-group';
import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
@@ -372,10 +480,24 @@
groupedByGroupKeyFavoriteFriends,
selectedFavoriteFriends,
friendImportDialogInput,
isFavoriteLoading
isFavoriteLoading,
localFriendFavorites,
localFriendFavoriteGroups
} = storeToRefs(favoriteStore);
const { showFriendImportDialog, refreshFavorites, getLocalWorldFavorites, handleFavoriteGroup } = favoriteStore;
const { showUserDialog } = useUserStore();
const {
showFriendImportDialog,
refreshFavorites,
getLocalWorldFavorites,
getLocalFriendFavorites,
handleFavoriteGroup,
localFriendFavGroupLength,
deleteLocalFriendFavoriteGroup,
renameLocalFriendFavoriteGroup,
newLocalFriendFavoriteGroup
} = favoriteStore;
const userStore = useUserStore();
const { showUserDialog } = userStore;
const { cachedUsers } = storeToRefs(userStore);
const { t } = useI18n();
const {
@@ -431,6 +553,9 @@
const selectedGroup = ref(null);
const activeGroupMenu = ref(null);
const friendToolbarMenuOpen = ref(false);
const isCreatingLocalGroup = ref(false);
const newLocalGroupName = ref('');
const newLocalGroupInput = ref(null);
function handleSortFavoritesChange(value) {
const next = Boolean(value);
@@ -443,6 +568,8 @@
const hasSearchInput = computed(() => friendFavoriteSearch.value.trim().length > 0);
const isSearchActive = computed(() => friendFavoriteSearch.value.trim().length >= 3);
const isRemoteGroupSelected = computed(() => selectedGroup.value?.type === 'remote');
const isLocalGroupSelected = computed(() => selectedGroup.value?.type === 'local');
const localGroupMenuKey = (key) => `local:${key}`;
const closeFriendToolbarMenu = () => {
friendToolbarMenuOpen.value = false;
@@ -603,6 +730,36 @@
return groupedByGroupKeyFavoriteFriends.value[activeRemoteGroup.value.key] || [];
});
const activeLocalGroupName = computed(() => {
if (!isLocalGroupSelected.value) {
return '';
}
return selectedGroup.value.key;
});
const activeLocalGroupCount = computed(() => {
if (!activeLocalGroupName.value) {
return 0;
}
const favorites = localFriendFavorites.value[activeLocalGroupName.value];
return favorites ? favorites.length : 0;
});
const currentLocalFriendFavorites = computed(() => {
if (!activeLocalGroupName.value) {
return [];
}
const userIds = localFriendFavorites.value[activeLocalGroupName.value] || [];
return userIds.map((userId) => {
const ref = cachedUsers.value.get(userId);
return {
id: userId,
ref: ref || undefined,
name: ref?.displayName || userId
};
});
});
const isAllFriendsSelected = computed(() => {
if (!activeRemoteGroup.value || !currentFriendFavorites.value.length) {
return false;
@@ -642,6 +799,7 @@
function handleRefreshFavorites() {
refreshFavorites();
getLocalWorldFavorites();
getLocalFriendFavorites();
}
function handleGroupMenuVisible(key, visible) {
@@ -670,6 +828,10 @@
return;
}
}
if (localFriendFavoriteGroups.value.length) {
selectGroup('local', localFriendFavoriteGroups.value[0]);
return;
}
selectedGroup.value = null;
clearSelectedFriends();
}
@@ -681,6 +843,9 @@
if (group.type === 'remote') {
return favoriteFriendGroups.value.some((item) => item.key === group.key);
}
if (group.type === 'local') {
return localFriendFavoriteGroups.value.includes(group.key);
}
return false;
}
@@ -875,6 +1040,75 @@
}
return value.charAt(0).toUpperCase() + value.slice(1);
}
function startLocalGroupCreation() {
isCreatingLocalGroup.value = true;
newLocalGroupName.value = '';
nextTick(() => {
newLocalGroupInput.value?.$el?.focus?.();
});
}
function cancelLocalGroupCreation() {
isCreatingLocalGroup.value = false;
newLocalGroupName.value = '';
}
function handleLocalGroupCreationConfirm() {
const name = newLocalGroupName.value.trim();
if (!name) {
cancelLocalGroupCreation();
return;
}
newLocalFriendFavoriteGroup(name);
isCreatingLocalGroup.value = false;
newLocalGroupName.value = '';
selectGroup('local', name);
}
function handleLocalRename(group) {
handleGroupMenuVisible(localGroupMenuKey(group), false);
modalStore
.prompt({
title: t('prompt.change_favorite_group_name.header'),
description: t('prompt.change_favorite_group_name.description'),
confirmText: t('prompt.change_favorite_group_name.change'),
cancelText: t('prompt.change_favorite_group_name.cancel'),
pattern: /\S+/,
inputValue: group,
errorMessage: t('prompt.change_favorite_group_name.input_error')
})
.then(({ ok, value }) => {
if (!ok) return;
const newName = value.trim();
if (!newName || newName === group) {
return;
}
renameLocalFriendFavoriteGroup(newName, group);
if (isGroupActive('local', group)) {
selectGroup('local', newName);
}
toast.success(t('prompt.change_favorite_group_name.message.success'));
})
.catch(() => {});
}
function handleLocalDelete(group) {
handleGroupMenuVisible(localGroupMenuKey(group), false);
modalStore
.confirm({
description: 'Continue? Delete Group',
title: 'Confirm'
})
.then(({ ok }) => {
if (!ok) return;
deleteLocalFriendFavoriteGroup(group);
if (isGroupActive('local', group)) {
selectDefaultGroup();
}
})
.catch(() => {});
}
</script>
<style scoped>
@@ -1007,6 +1241,19 @@
padding: 12px 0;
}
.group-item--new {
border-style: dashed;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
font-size: 14px;
}
.group-item__input {
width: 100%;
}
.favorites-content {
display: flex;
flex-direction: column;
@@ -24,7 +24,10 @@
<Checkbox v-model="isSelected" />
</div>
<div class="favorites-search-card__action-group">
<div class="favorites-search-card__action favorites-search-card__action--full" @click.stop>
<div
v-if="group?.type !== 'local'"
class="favorites-search-card__action favorites-search-card__action--full"
@click.stop>
<FavoritesMoveDropdown
:favoriteGroup="favoriteFriendGroups"
:currentGroup="group"
@@ -106,7 +109,7 @@
const emit = defineEmits(['click', 'toggle-select']);
const { favoriteFriendGroups } = storeToRefs(useFavoriteStore());
const { showFavoriteDialog } = useFavoriteStore();
const { showFavoriteDialog, removeLocalFriendFavorite } = useFavoriteStore();
const { t } = useI18n();
const isSelected = computed({
@@ -133,8 +136,12 @@
});
function handleDeleteFavorite() {
favoriteRequest.deleteFavorite({
objectId: props.favorite.id
});
if (props.group?.type === 'local') {
removeLocalFriendFavorite(props.favorite.id, props.group.key);
} else {
favoriteRequest.deleteFavorite({
objectId: props.favorite.id
});
}
}
</script>
@@ -119,9 +119,22 @@
<SelectValue :placeholder="t('view.settings.general.favorites.group_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="group in favoriteFriendGroups" :key="group.key" :value="group.key">
{{ group.displayName }}
</SelectItem>
<SelectGroup>
<SelectItem v-for="group in favoriteFriendGroups" :key="group.key" :value="group.key">
{{ group.displayName }}
</SelectItem>
</SelectGroup>
<template v-if="localFriendFavoriteGroups.length">
<SelectSeparator />
<SelectGroup>
<SelectItem
v-for="group in localFriendFavoriteGroups"
:key="'local:' + group"
:value="'local:' + group">
{{ group }}
</SelectItem>
</SelectGroup>
</template>
</SelectContent>
</Select>
</div>
@@ -189,7 +202,15 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../../components/ui/select';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectSeparator,
SelectTrigger,
SelectValue
} from '../../../../components/ui/select';
import { useFavoriteStore, useGeneralSettingsStore, useVRCXUpdaterStore } from '../../../../stores';
import { ToggleGroup, ToggleGroupItem } from '../../../../components/ui/toggle-group';
import { links } from '../../../../shared/constants';
@@ -231,7 +252,7 @@
promptProxySettings
} = generalSettingsStore;
const { favoriteFriendGroups } = storeToRefs(favoriteStore);
const { favoriteFriendGroups, localFriendFavoriteGroups } = storeToRefs(favoriteStore);
const { appVersion, autoUpdateVRCX, latestAppVersion, noUpdater } = storeToRefs(vrcxUpdaterStore);
const { setAutoUpdateVRCX, checkForVRCXUpdate, showVRCXUpdateDialog, showChangeLogDialog } = vrcxUpdaterStore;
@@ -101,6 +101,7 @@
useFavoriteStore,
useFriendStore,
useGameStore,
useGeneralSettingsStore,
useLocationStore,
useUserStore
} from '../../../stores';
@@ -114,6 +115,8 @@
const { t } = useI18n();
const generalSettingsStore = useGeneralSettingsStore();
const friendStore = useFriendStore();
const { vipFriends, onlineFriends, activeFriends, offlineFriends, friendsInSameInstance } =
storeToRefs(friendStore);
@@ -121,7 +124,8 @@
storeToRefs(useAppearanceSettingsStore());
const { gameLogDisabled } = storeToRefs(useAdvancedSettingsStore());
const { showUserDialog } = useUserStore();
const { favoriteFriendGroups, groupedByGroupKeyFavoriteFriends } = storeToRefs(useFavoriteStore());
const { favoriteFriendGroups, groupedByGroupKeyFavoriteFriends, localFriendFavorites } =
storeToRefs(useFavoriteStore());
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
const { isGameRunning } = storeToRefs(useGameStore());
const { currentUser } = storeToRefs(useUserStore());
@@ -191,6 +195,30 @@
}
}
for (const selectedKey of generalSettingsStore.localFavoriteFriendsGroups) {
if (selectedKey.startsWith('local:')) {
const groupName = selectedKey.slice(6);
const userIds = localFriendFavorites.value?.[groupName];
if (userIds && userIds.length) {
const filteredFriends = vipFriends.value.filter((friend) => {
if (isSidebarGroupByInstance.value && isHideFriendsInSameInstance.value) {
return userIds.includes(friend.id) && !sameInstanceFriendId.value.has(friend.id);
}
return userIds.includes(friend.id);
});
if (filteredFriends.length > 0) {
result.push(
filteredFriends.map((item) => ({
groupName,
key: selectedKey,
...item
}))
);
}
}
}
}
return result.sort((a, b) => a[0].key.localeCompare(b[0].key));
});