Files
VRCX/src/stores/settings/appearance.js

1325 lines
44 KiB
JavaScript

import { computed, ref, watch } from 'vue';
import { defineStore } from 'pinia';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import {
APP_CJK_FONT_PACK_DEFAULT_KEY,
APP_CJK_FONT_PACKS,
APP_FONT_DEFAULT_KEY,
APP_FONT_FAMILIES,
SEARCH_LIMIT_MAX,
SEARCH_LIMIT_MIN,
TABLE_MAX_SIZE_MAX,
TABLE_MAX_SIZE_MIN,
THEME_CONFIG
} from '../../shared/constants';
import {
applyAppCjkFontPack,
HueToHex,
applyAppFontFamily,
changeAppThemeStyle,
changeHtmlLangAttribute,
getThemeMode,
updateTrustColorClasses
} from '../../shared/utils/base/ui';
import { computeTrustLevel, getNameColour } from '../../shared/utils';
import { database } from '../../services/database';
import { loadLocalizedStrings } from '../../plugins';
import { useFeedStore } from '../feed';
import { useGameLogStore } from '../gameLog';
import { useUiStore } from '../ui';
import { useUserStore } from '../user';
import { useVrStore } from '../vr';
import { useVrcxStore } from '../vrcx';
import { watchState } from '../../services/watchState';
import configRepository from '../../services/config';
export const useAppearanceSettingsStore = defineStore(
'AppearanceSettings',
() => {
const vrStore = useVrStore();
const feedStore = useFeedStore();
const gameLogStore = useGameLogStore();
const vrcxStore = useVrcxStore();
const userStore = useUserStore();
const router = useRouter();
const uiStore = useUiStore();
const { locale } = useI18n();
const MAX_TABLE_PAGE_SIZE = 1000;
const DEFAULT_TABLE_PAGE_SIZES = [10, 15, 20, 25, 50, 100];
const appLanguage = ref('en');
const themeMode = ref('');
const isDarkMode = ref(false);
const lastDarkTheme = ref('dark');
const appFontFamily = ref('inter');
const customFontFamily = ref('');
const appCjkFontPack = ref(APP_CJK_FONT_PACK_DEFAULT_KEY);
const displayVRCPlusIconsAsAvatar = ref(false);
const hideNicknames = ref(false);
const showInstanceIdInLocation = ref(false);
const isAgeGatedInstancesVisible = ref(false);
const sortFavorites = ref(true);
const instanceUsersSortAlphabetical = ref(false);
const tablePageSize = ref(15);
const tablePageSizes = ref([...DEFAULT_TABLE_PAGE_SIZES]);
const dtHour12 = ref(false);
const dtIsoFormat = ref(false);
const weekStartsOn = ref(1);
const sidebarSortMethod1 = ref('Sort Private to Bottom');
const sidebarSortMethod2 = ref('Sort by Time in Instance');
const sidebarSortMethod3 = ref('Sort by Last Active');
const sidebarSortMethods = ref([
'Sort Private to Bottom',
'Sort by Time in Instance',
'Sort by Last Active'
]);
const navWidth = ref(240);
const isSidebarGroupByInstance = ref(true);
const isHideFriendsInSameInstance = ref(false);
const isSameInstanceAboveFavorites = ref(false);
const isSidebarDivideByFriendGroup = ref(false);
const sidebarFavoriteGroups = ref([]);
const sidebarFavoriteGroupOrder = ref([]);
const hideUserNotes = ref(false);
const hideUserMemos = ref(false);
const hideUnfriends = ref(false);
const randomUserColours = ref(false);
const tableDensity = ref('standard');
const TRUST_COLOR_DEFAULTS = Object.freeze({
untrusted: '#CCCCCC',
basic: '#1778FF',
known: '#2BCF5C',
trusted: '#FF7B42',
veteran: '#B18FFF',
vip: '#FF2626',
troll: '#782F2F'
});
const trustColor = ref({ ...TRUST_COLOR_DEFAULTS });
const currentCulture = ref('');
const notificationIconDot = ref(false);
const isNavCollapsed = ref(true);
const isSideBarTabShow = computed(() => {
const currentRouteName = router.currentRoute.value?.name;
return ![
'friends-locations',
'friend-list',
'charts-instance',
'charts-mutual',
'charts-hot-worlds'
].includes(currentRouteName);
});
const isDataTableStriped = ref(false);
const showPointerOnHover = ref(false);
const accessibleStatusIndicators = ref(false);
const useOfficialStatusColors = ref(true);
const showNewDashboardButton = ref(true);
const tableLimitsDialog = ref({
visible: false,
maxTableSize: 500,
searchLimit: 5000
});
const clampInt = (value, min, max) => {
const n = parseInt(value, 10);
return Math.min(max, Math.max(min, n));
};
const resolveLastDarkTheme = (value, fallback = 'dark') => {
const normalized = String(value || '').trim();
return THEME_CONFIG[normalized]?.isDark === true
? normalized
: fallback;
};
/**
*
*/
async function initAppearanceSettings() {
const { initThemeMode, isDarkMode: initDarkMode } =
await getThemeMode(configRepository);
const fallbackDarkTheme =
THEME_CONFIG[initThemeMode]?.isDark === true
? initThemeMode
: 'dark';
const [
appLanguageConfig,
displayVRCPlusIconsAsAvatarConfig,
hideNicknamesConfig,
showInstanceIdInLocationConfig,
isAgeGatedInstancesVisibleConfig,
sortFavoritesConfig,
instanceUsersSortAlphabeticalConfig,
tablePageSizeConfig,
tablePageSizesConfig,
dtHour12Config,
dtIsoFormatConfig,
weekStartsOnConfig,
sidebarSortMethodsConfig,
navWidthConfig,
isSidebarGroupByInstanceConfig,
isHideFriendsInSameInstanceConfig,
isSameInstanceAboveFavoritesConfig,
isSidebarDivideByFriendGroupConfig,
sidebarFavoriteGroupsConfig,
sidebarFavoriteGroupOrderConfig,
hideUserNotesConfig,
hideUserMemosConfig,
hideUnfriendsConfig,
randomUserColoursConfig,
tableDensityConfig,
compactTableModeConfig,
trustColorConfig,
notificationIconDotConfig,
navIsCollapsedConfig,
dataTableStripedConfig,
showPointerOnHoverConfig,
accessibleStatusIndicatorsConfig,
useOfficialStatusColorsConfig,
showNewDashboardButtonConfig,
appFontFamilyConfig,
customFontFamilyConfig,
appCjkFontPackConfig,
lastDarkThemeConfig
] = await Promise.all([
configRepository.getString('VRCX_appLanguage'),
configRepository.getBool('displayVRCPlusIconsAsAvatar', true),
configRepository.getBool('VRCX_hideNicknames', false),
configRepository.getBool(
'VRCX_showInstanceIdInLocation',
false
),
configRepository.getBool(
'VRCX_isAgeGatedInstancesVisible',
true
),
configRepository.getBool('VRCX_sortFavorites', true),
configRepository.getBool(
'VRCX_instanceUsersSortAlphabetical',
false
),
configRepository.getInt('VRCX_tablePageSize', 20),
configRepository.getString(
'VRCX_tablePageSizes',
JSON.stringify(DEFAULT_TABLE_PAGE_SIZES)
),
configRepository.getBool('VRCX_dtHour12', false),
configRepository.getBool('VRCX_dtIsoFormat', false),
configRepository.getInt('VRCX_weekStartsOn', 1),
configRepository.getString(
'VRCX_sidebarSortMethods',
JSON.stringify([
'Sort Private to Bottom',
'Sort by Time in Instance',
'Sort by Last Active'
])
),
configRepository.getInt('VRCX_navPanelWidth', 240),
configRepository.getBool('VRCX_sidebarGroupByInstance', true),
configRepository.getBool(
'VRCX_hideFriendsInSameInstance',
false
),
configRepository.getBool(
'VRCX_sameInstanceAboveFavorites',
false
),
configRepository.getBool(
'VRCX_sidebarDivideByFriendGroup',
true
),
configRepository.getString('VRCX_sidebarFavoriteGroups', '[]'),
configRepository.getString(
'VRCX_sidebarFavoriteGroupOrder',
'[]'
),
configRepository.getBool('VRCX_hideUserNotes', false),
configRepository.getBool('VRCX_hideUserMemos', false),
configRepository.getBool('VRCX_hideUnfriends', false),
configRepository.getBool('VRCX_randomUserColours', false),
configRepository.getString('VRCX_tableDensity'),
configRepository.getBool('VRCX_compactTableMode', false),
configRepository.getString(
'VRCX_trustColor',
JSON.stringify(TRUST_COLOR_DEFAULTS)
),
configRepository.getBool('VRCX_notificationIconDot', true),
configRepository.getBool('VRCX_navIsCollapsed', false),
configRepository.getBool('VRCX_dataTableStriped', false),
configRepository.getBool('VRCX_showPointerOnHover', false),
configRepository.getBool(
'VRCX_accessibleStatusIndicators',
false
),
configRepository.getBool('VRCX_useOfficialStatusColors', true),
configRepository.getBool('VRCX_showNewDashboardButton', true),
configRepository.getString(
'VRCX_fontFamily',
APP_FONT_DEFAULT_KEY
),
configRepository.getString('VRCX_customFontFamily', ''),
configRepository.getString(
'VRCX_cjkFontPack',
APP_CJK_FONT_PACK_DEFAULT_KEY
),
configRepository.getString(
'VRCX_lastDarkTheme',
fallbackDarkTheme
)
]);
if (appLanguageConfig) {
await changeAppLanguage(appLanguageConfig);
} else {
// First launch: load en in-memory only, do NOT persist.
// Login.vue detectAndPromptLanguage() will handle first-time language selection.
await loadLocalizedStrings('en');
appLanguage.value = 'en';
locale.value = 'en';
changeHtmlLangAttribute('en');
}
themeMode.value = initThemeMode;
isDarkMode.value = initDarkMode;
lastDarkTheme.value = resolveLastDarkTheme(
lastDarkThemeConfig,
fallbackDarkTheme
);
const normalizedAppFontFamily =
normalizeAppFontFamily(appFontFamilyConfig);
appFontFamily.value = normalizedAppFontFamily;
customFontFamily.value = customFontFamilyConfig || '';
appCjkFontPack.value =
normalizeAppCjkFontPack(appCjkFontPackConfig);
applyAppFontFamily(appFontFamily.value, customFontFamily.value);
applyAppCjkFontPack(appCjkFontPack.value);
if (normalizedAppFontFamily !== appFontFamilyConfig) {
configRepository.setString(
'VRCX_fontFamily',
normalizedAppFontFamily
);
}
displayVRCPlusIconsAsAvatar.value =
displayVRCPlusIconsAsAvatarConfig;
hideNicknames.value = hideNicknamesConfig;
showInstanceIdInLocation.value = showInstanceIdInLocationConfig;
isAgeGatedInstancesVisible.value = isAgeGatedInstancesVisibleConfig;
sortFavorites.value = sortFavoritesConfig;
instanceUsersSortAlphabetical.value =
instanceUsersSortAlphabeticalConfig;
tablePageSizes.value = normalizeTablePageSizes(
JSON.parse(tablePageSizesConfig)
);
setTablePageSize(tablePageSizeConfig);
dtHour12.value = dtHour12Config;
dtIsoFormat.value = dtIsoFormatConfig;
weekStartsOn.value = [0, 1, 6].includes(weekStartsOnConfig)
? weekStartsOnConfig
: 1;
currentCulture.value = await AppApi.CurrentCulture();
sidebarSortMethods.value = JSON.parse(sidebarSortMethodsConfig);
if (sidebarSortMethods.value?.length === 3) {
sidebarSortMethod1.value = sidebarSortMethods.value[0];
sidebarSortMethod2.value = sidebarSortMethods.value[1];
sidebarSortMethod3.value = sidebarSortMethods.value[2];
}
if (trustColorConfig !== JSON.stringify(TRUST_COLOR_DEFAULTS)) {
await configRepository.setString(
'VRCX_trustColor',
JSON.stringify(TRUST_COLOR_DEFAULTS)
);
}
trustColor.value = { ...TRUST_COLOR_DEFAULTS };
navWidth.value = clampInt(navWidthConfig, 64, 480);
isSidebarGroupByInstance.value = isSidebarGroupByInstanceConfig;
isHideFriendsInSameInstance.value =
isHideFriendsInSameInstanceConfig;
isSameInstanceAboveFavorites.value =
isSameInstanceAboveFavoritesConfig;
isSidebarDivideByFriendGroup.value =
isSidebarDivideByFriendGroupConfig;
sidebarFavoriteGroups.value = JSON.parse(
sidebarFavoriteGroupsConfig
);
sidebarFavoriteGroupOrder.value = JSON.parse(
sidebarFavoriteGroupOrderConfig
);
hideUserNotes.value = hideUserNotesConfig;
hideUserMemos.value = hideUserMemosConfig;
hideUnfriends.value = hideUnfriendsConfig;
randomUserColours.value = randomUserColoursConfig;
notificationIconDot.value = notificationIconDotConfig;
const resolvedTableDensity = normalizeTableDensity(
tableDensityConfig ||
(compactTableModeConfig ? 'compact' : 'standard')
);
tableDensity.value = resolvedTableDensity;
applyTableDensity(tableDensity.value);
if (!tableDensityConfig) {
configRepository.setString(
'VRCX_tableDensity',
tableDensity.value
);
}
isNavCollapsed.value = navIsCollapsedConfig;
isDataTableStriped.value = dataTableStripedConfig;
showPointerOnHover.value = showPointerOnHoverConfig;
accessibleStatusIndicators.value = accessibleStatusIndicatorsConfig;
useOfficialStatusColors.value = useOfficialStatusColorsConfig;
showNewDashboardButton.value = showNewDashboardButtonConfig;
applyPointerHoverClass();
applyAccessibleStatusClass();
applyOfficialStatusColorsClass();
await configRepository.remove('VRCX_navWidth');
// Migrate old settings
// Assume all exist if one does
await mergeOldSortMethodsSettings();
updateTrustColorClasses(trustColor.value);
vrStore.updateVRConfigVars();
}
initAppearanceSettings();
watch(
() => watchState.isFriendsLoaded,
(isFriendsLoaded) => {
if (isFriendsLoaded) {
tryInitUserColours();
}
},
{ flush: 'sync' }
);
/**
*
* @param {string} language
*/
async function changeAppLanguage(language) {
await setAppLanguage(language);
vrStore.updateVRConfigVars();
}
/**
* @param {string} language
*/
async function setAppLanguage(language) {
console.log('Language changed:', language);
await loadLocalizedStrings(language);
appLanguage.value = language;
configRepository.setString('VRCX_appLanguage', language);
locale.value = appLanguage.value;
changeHtmlLangAttribute(language);
}
/**
*
* @param {string} field
* @param {string} color
* @param {boolean} setRandomColor
* @returns {Promise<void>}
*/
async function updateTrustColor(field, color, setRandomColor = false) {
if (setRandomColor) {
setRandomUserColours();
}
if (typeof userStore.currentUser?.id === 'undefined') {
return;
}
if (field && color) {
setTrustColor({
...trustColor.value,
[field]: color
});
}
if (randomUserColours.value) {
const colour = await getNameColour(
userStore.currentUser.id,
isDarkMode.value
);
userStore.setCurrentUserColour(colour);
userColourInit();
} else {
applyUserTrustLevel(userStore.currentUser);
userStore.cachedUsers.forEach((ref) => {
applyUserTrustLevel(ref);
});
}
updateTrustColorClasses(trustColor.value);
}
/**
*
* @param customFunc
*/
async function userColourInit(customFunc) {
let dictObject = null;
if (typeof customFunc === 'function') {
dictObject = customFunc(userStore.cachedUsers.keys());
} else {
dictObject = await AppApi.GetColourBulk(
Array.from(userStore.cachedUsers.keys())
);
}
if (!dictObject) {
console.warn('No user colour data found');
return;
}
if (LINUX) {
// @ts-ignore
dictObject = Object.fromEntries(dictObject);
}
for (const [userId, hue] of Object.entries(dictObject)) {
const ref = userStore.cachedUsers.get(userId);
if (typeof ref !== 'undefined') {
ref.$userColour = HueToHex(hue, isDarkMode.value);
}
}
}
/**
*
* @param {object} ref
*/
function applyUserTrustLevel(ref) {
const trust = computeTrustLevel(ref.tags, ref.developerType);
ref.$isModerator = trust.isModerator;
ref.$isTroll = trust.isTroll;
ref.$isProbableTroll = trust.isProbableTroll;
ref.$trustLevel = trust.trustLevel;
ref.$trustClass = trust.trustClass;
ref.$trustSortNum = trust.trustSortNum;
if (randomUserColours.value && watchState.isFriendsLoaded) {
if (!ref.$userColour) {
getNameColour(ref.id, isDarkMode.value).then((colour) => {
ref.$userColour = colour;
});
}
} else {
ref.$userColour = trustColor.value[trust.trustColorKey];
}
}
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', async () => {
if (themeMode.value === 'system') {
setThemeMode(themeMode.value);
}
});
/**
* @param {string} mode
*/
function setThemeMode(mode) {
themeMode.value = mode;
configRepository.setString('VRCX_ThemeMode', mode);
if (THEME_CONFIG[mode]?.isDark === true) {
const normalized = resolveLastDarkTheme(mode);
lastDarkTheme.value = normalized;
configRepository.setString('VRCX_lastDarkTheme', normalized);
}
const { isDark } = changeAppThemeStyle(mode);
isDarkMode.value = isDark;
vrStore.updateVRConfigVars();
updateTrustColor(undefined, undefined);
}
/**
*
*/
function toggleThemeMode() {
const nextMode = isDarkMode.value
? 'light'
: resolveLastDarkTheme(lastDarkTheme.value);
setThemeMode(nextMode);
}
/**
*
* @param value
*/
function normalizeAppFontFamily(value) {
if (value === 'custom') return 'custom';
return APP_FONT_FAMILIES.includes(value)
? value
: APP_FONT_DEFAULT_KEY;
}
/**
*
* @param value
*/
function normalizeAppCjkFontPack(value) {
return APP_CJK_FONT_PACKS.includes(value)
? value
: APP_CJK_FONT_PACK_DEFAULT_KEY;
}
/**
*
* @param value
*/
function setAppFontFamily(value) {
const normalized = normalizeAppFontFamily(value);
appFontFamily.value = normalized;
configRepository.setString('VRCX_fontFamily', normalized);
applyAppFontFamily(normalized, customFontFamily.value);
}
function setCustomFontFamily(value) {
customFontFamily.value = value;
configRepository.setString('VRCX_customFontFamily', value);
if (appFontFamily.value === 'custom') {
applyAppFontFamily('custom', value);
}
}
/**
*
* @param value
*/
function setAppCjkFontPack(value) {
const normalized = normalizeAppCjkFontPack(value);
appCjkFontPack.value = normalized;
configRepository.setString('VRCX_cjkFontPack', normalized);
applyAppCjkFontPack(normalized);
}
/**
*
*/
function setDisplayVRCPlusIconsAsAvatar() {
displayVRCPlusIconsAsAvatar.value =
!displayVRCPlusIconsAsAvatar.value;
configRepository.setBool(
'displayVRCPlusIconsAsAvatar',
displayVRCPlusIconsAsAvatar.value
);
}
/**
*
*/
function setNotificationIconDot() {
notificationIconDot.value = !notificationIconDot.value;
configRepository.setBool(
'VRCX_notificationIconDot',
notificationIconDot.value
);
uiStore.updateTrayIconNotify();
}
/**
*
*/
function setHideNicknames() {
hideNicknames.value = !hideNicknames.value;
configRepository.setBool('VRCX_hideNicknames', hideNicknames.value);
}
/**
*
*/
function setShowInstanceIdInLocation() {
showInstanceIdInLocation.value = !showInstanceIdInLocation.value;
configRepository.setBool(
'VRCX_showInstanceIdInLocation',
showInstanceIdInLocation.value
);
}
/**
*
*/
function setIsAgeGatedInstancesVisible() {
isAgeGatedInstancesVisible.value =
!isAgeGatedInstancesVisible.value;
configRepository.setBool(
'VRCX_isAgeGatedInstancesVisible',
isAgeGatedInstancesVisible.value
);
}
/**
*
*/
function setSortFavorites() {
sortFavorites.value = !sortFavorites.value;
configRepository.setBool('VRCX_sortFavorites', sortFavorites.value);
}
/**
*
*/
function setInstanceUsersSortAlphabetical() {
instanceUsersSortAlphabetical.value =
!instanceUsersSortAlphabetical.value;
configRepository.setBool(
'VRCX_instanceUsersSortAlphabetical',
instanceUsersSortAlphabetical.value
);
}
/**
*
* @param size
*/
function setTablePageSize(size) {
const processedSize = clampInt(size, 1, MAX_TABLE_PAGE_SIZE);
tablePageSize.value = processedSize;
configRepository.setInt('VRCX_tablePageSize', processedSize);
return processedSize;
}
/**
*
* @param input
*/
function normalizeTablePageSizes(input) {
const values = (
Array.isArray(input) ? input : DEFAULT_TABLE_PAGE_SIZES
)
.map((v) => parseInt(v, 10))
.filter((v) => v > 0 && v <= MAX_TABLE_PAGE_SIZE);
const uniqueSorted = Array.from(new Set(values)).sort(
(a, b) => a - b
);
return uniqueSorted.length
? uniqueSorted
: [...DEFAULT_TABLE_PAGE_SIZES];
}
/**
* @param {Array<number|string>} sizes
*/
function setTablePageSizes(sizes) {
tablePageSizes.value = normalizeTablePageSizes(sizes);
configRepository.setString(
'VRCX_tablePageSizes',
JSON.stringify(tablePageSizes.value)
);
if (!tablePageSizes.value.includes(tablePageSize.value)) {
setTablePageSize(tablePageSizes.value[0]);
}
}
/**
*
*/
function setDtHour12() {
dtHour12.value = !dtHour12.value;
configRepository.setBool('VRCX_dtHour12', dtHour12.value);
}
/**
*
*/
function setDtIsoFormat() {
dtIsoFormat.value = !dtIsoFormat.value;
configRepository.setBool('VRCX_dtIsoFormat', dtIsoFormat.value);
}
/**
* @param {number} value - 0 (Sunday), 1 (Monday), or 6 (Saturday)
*/
function setWeekStartsOn(value) {
const v = [0, 1, 6].includes(value) ? value : 1;
weekStartsOn.value = v;
configRepository.setInt('VRCX_weekStartsOn', v);
}
/**
* @param {string} method
*/
function setSidebarSortMethod1(method) {
sidebarSortMethod1.value = method;
handleSaveSidebarSortOrder();
}
/**
* @param {string} method
*/
function setSidebarSortMethod2(method) {
sidebarSortMethod2.value = method;
handleSaveSidebarSortOrder();
}
/**
* @param {string} method
*/
function setSidebarSortMethod3(method) {
sidebarSortMethod3.value = method;
handleSaveSidebarSortOrder();
}
/**
* @param {Array<string>} methods
*/
function setSidebarSortMethods(methods) {
sidebarSortMethods.value = methods;
configRepository.setString(
'VRCX_sidebarSortMethods',
JSON.stringify(methods)
);
}
/**
*
* @param collapsed
*/
function setNavCollapsed(collapsed) {
isNavCollapsed.value = collapsed;
configRepository.setBool('VRCX_navIsCollapsed', collapsed);
}
/**
*
*/
function toggleNavCollapsed() {
setNavCollapsed(!isNavCollapsed.value);
}
/**
*
* @param widthOrArray
*/
function setNavWidth(widthOrArray) {
let width = null;
if (Array.isArray(widthOrArray) && widthOrArray.length) {
width = widthOrArray[widthOrArray.length - 1];
} else if (typeof widthOrArray === 'number') {
width = widthOrArray;
}
if (width) {
requestAnimationFrame(() => {
navWidth.value = clampInt(width, 64, 480);
configRepository.setInt(
'VRCX_navPanelWidth',
navWidth.value
);
});
}
}
/**
*
*/
function setIsSidebarGroupByInstance() {
isSidebarGroupByInstance.value = !isSidebarGroupByInstance.value;
configRepository.setBool(
'VRCX_sidebarGroupByInstance',
isSidebarGroupByInstance.value
);
}
/**
*
*/
function setIsHideFriendsInSameInstance() {
isHideFriendsInSameInstance.value =
!isHideFriendsInSameInstance.value;
configRepository.setBool(
'VRCX_hideFriendsInSameInstance',
isHideFriendsInSameInstance.value
);
}
/**
*
*/
function setIsSameInstanceAboveFavorites() {
isSameInstanceAboveFavorites.value =
!isSameInstanceAboveFavorites.value;
configRepository.setBool(
'VRCX_sameInstanceAboveFavorites',
isSameInstanceAboveFavorites.value
);
}
/**
*
*/
function setIsSidebarDivideByFriendGroup() {
isSidebarDivideByFriendGroup.value =
!isSidebarDivideByFriendGroup.value;
configRepository.setBool(
'VRCX_sidebarDivideByFriendGroup',
isSidebarDivideByFriendGroup.value
);
}
/**
* @param {string[]} value
*/
function setSidebarFavoriteGroups(value) {
sidebarFavoriteGroups.value = value;
configRepository.setString(
'VRCX_sidebarFavoriteGroups',
JSON.stringify(value)
);
}
/**
* @param {string[]} value
*/
function setSidebarFavoriteGroupOrder(value) {
sidebarFavoriteGroupOrder.value = value;
configRepository.setString(
'VRCX_sidebarFavoriteGroupOrder',
JSON.stringify(value)
);
}
/**
*
*/
function setHideUserNotes() {
hideUserNotes.value = !hideUserNotes.value;
configRepository.setBool('VRCX_hideUserNotes', hideUserNotes.value);
}
/**
*
*/
function setHideUserMemos() {
hideUserMemos.value = !hideUserMemos.value;
configRepository.setBool('VRCX_hideUserMemos', hideUserMemos.value);
}
/**
*
*/
function setHideUnfriends() {
hideUnfriends.value = !hideUnfriends.value;
configRepository.setBool('VRCX_hideUnfriends', hideUnfriends.value);
}
/**
*
*/
function setRandomUserColours() {
randomUserColours.value = !randomUserColours.value;
configRepository.setBool(
'VRCX_randomUserColours',
randomUserColours.value
);
}
/**
*
* @param value
*/
function normalizeTableDensity(value) {
if (
value === 'compact' ||
value === 'comfortable' ||
value === 'standard'
) {
return value;
}
return 'standard';
}
/**
*
* @param density
*/
function setTableDensity(density) {
const normalized = normalizeTableDensity(density);
tableDensity.value = normalized;
applyTableDensity(tableDensity.value);
configRepository.setString('VRCX_tableDensity', tableDensity.value);
}
/**
*
*/
function toggleStripedDataTable() {
isDataTableStriped.value = !isDataTableStriped.value;
configRepository.setBool(
'VRCX_dataTableStriped',
isDataTableStriped.value
);
}
// FIXME: this is nasty, there should be a better way of doing this
/**
*
*/
function applyPointerHoverClass() {
const classList = document.documentElement.classList;
classList.remove('force-pointer-on-hover');
if (showPointerOnHover.value) {
classList.add('force-pointer-on-hover');
}
}
/**
*
*/
function togglePointerOnHover() {
showPointerOnHover.value = !showPointerOnHover.value;
configRepository.setBool(
'VRCX_showPointerOnHover',
showPointerOnHover.value
);
applyPointerHoverClass();
}
/**
*
*/
function applyAccessibleStatusClass() {
const classList = document.documentElement.classList;
classList.remove('accessible-status-indicators');
if (accessibleStatusIndicators.value) {
classList.add('accessible-status-indicators');
}
}
/**
*
*/
function toggleAccessibleStatusIndicators() {
accessibleStatusIndicators.value =
!accessibleStatusIndicators.value;
configRepository.setBool(
'VRCX_accessibleStatusIndicators',
accessibleStatusIndicators.value
);
applyAccessibleStatusClass();
}
/**
*
*/
function applyOfficialStatusColorsClass() {
const classList = document.documentElement.classList;
classList.remove('vrcx-status-colors');
if (!useOfficialStatusColors.value) {
classList.add('vrcx-status-colors');
}
}
/**
*
*/
function toggleOfficialStatusColors() {
useOfficialStatusColors.value = !useOfficialStatusColors.value;
configRepository.setBool(
'VRCX_useOfficialStatusColors',
useOfficialStatusColors.value
);
applyOfficialStatusColorsClass();
}
/**
*
*/
function setShowNewDashboardButton() {
showNewDashboardButton.value = !showNewDashboardButton.value;
configRepository.setBool(
'VRCX_showNewDashboardButton',
showNewDashboardButton.value
);
}
/**
* @param {object} color
*/
function setTrustColor(color) {
// @ts-ignore
trustColor.value = color;
configRepository.setString(
'VRCX_trustColor',
JSON.stringify(trustColor.value)
);
}
/**
*
*/
function handleSaveSidebarSortOrder() {
if (sidebarSortMethod1.value === sidebarSortMethod2.value) {
sidebarSortMethod2.value = '';
}
if (sidebarSortMethod1.value === sidebarSortMethod3.value) {
sidebarSortMethod3.value = '';
}
if (sidebarSortMethod2.value === sidebarSortMethod3.value) {
sidebarSortMethod3.value = '';
}
if (!sidebarSortMethod1.value) {
sidebarSortMethod2.value = '';
}
if (!sidebarSortMethod2.value) {
sidebarSortMethod3.value = '';
}
const sidebarSortMethods = [
sidebarSortMethod1.value,
sidebarSortMethod2.value,
sidebarSortMethod3.value
];
setSidebarSortMethods(sidebarSortMethods);
}
/**
*
*/
async function mergeOldSortMethodsSettings() {
const orderFriendsGroupPrivate = await configRepository.getBool(
'orderFriendGroupPrivate'
);
if (orderFriendsGroupPrivate !== null) {
await configRepository.remove('orderFriendGroupPrivate');
const orderFriendsGroupStatus = await configRepository.getBool(
'orderFriendsGroupStatus'
);
await configRepository.remove('orderFriendsGroupStatus');
const orderFriendsGroupGPS = await configRepository.getBool(
'orderFriendGroupGPS'
);
await configRepository.remove('orderFriendGroupGPS');
const orderOnlineFor =
await configRepository.getBool('orderFriendGroup0');
await configRepository.remove('orderFriendGroup0');
await configRepository.remove('orderFriendGroup1');
await configRepository.remove('orderFriendGroup2');
await configRepository.remove('orderFriendGroup3');
const sortOrder = [];
if (orderFriendsGroupPrivate) {
sortOrder.push('Sort Private to Bottom');
}
if (orderFriendsGroupStatus) {
sortOrder.push('Sort by Status');
}
if (orderOnlineFor && orderFriendsGroupGPS) {
sortOrder.push('Sort by Time in Instance');
}
if (!orderOnlineFor) {
sortOrder.push('Sort Alphabetically');
}
if (sortOrder.length > 0) {
while (sortOrder.length < 3) {
sortOrder.push('');
}
sidebarSortMethods.value = sortOrder;
sidebarSortMethod1.value = sortOrder[0];
sidebarSortMethod2.value = sortOrder[1];
sidebarSortMethod3.value = sortOrder[2];
}
setSidebarSortMethods(sortOrder);
}
}
const clampLimit = (value, min, max) => {
const n = Number.parseInt(value, 10);
if (!Number.isFinite(n)) {
return null;
}
if (n < min || n > max) {
return null;
}
return n;
};
/**
*
*/
function showTableLimitsDialog() {
tableLimitsDialog.value.maxTableSize = Number(
vrcxStore.maxTableSize ?? 500
);
tableLimitsDialog.value.searchLimit = Number(
vrcxStore.searchLimit ?? 50000
);
tableLimitsDialog.value.visible = true;
}
/**
*
*/
function closeTableLimitsDialog() {
tableLimitsDialog.value.visible = false;
}
/**
*
*/
async function saveTableLimitsDialog() {
const nextMaxTableSize = clampLimit(
tableLimitsDialog.value.maxTableSize,
TABLE_MAX_SIZE_MIN,
TABLE_MAX_SIZE_MAX
);
if (nextMaxTableSize === null) {
return;
}
const nextSearchLimit = clampLimit(
tableLimitsDialog.value.searchLimit,
SEARCH_LIMIT_MIN,
SEARCH_LIMIT_MAX
);
if (nextSearchLimit === null) {
return;
}
vrcxStore.setMaxTableSize(nextMaxTableSize);
await configRepository.setInt(
'VRCX_maxTableSize_v2',
vrcxStore.maxTableSize
);
database.setMaxTableSize(vrcxStore.maxTableSize);
vrcxStore.setSearchLimit(nextSearchLimit);
await configRepository.setInt(
'VRCX_searchLimit',
vrcxStore.searchLimit
);
database.setSearchTableSize(vrcxStore.searchLimit);
feedStore.feedTableLookup();
gameLogStore.gameLogTableLookup();
tableLimitsDialog.value.visible = false;
}
/**
*
*/
async function tryInitUserColours() {
if (!randomUserColours.value) {
return;
}
const colour = await getNameColour(
userStore.currentUser.id,
isDarkMode.value
);
userStore.setCurrentUserColour(colour);
await userColourInit();
}
/**
*
* @param density
*/
function applyTableDensity(density) {
const classList = document.documentElement.classList;
classList.remove('is-compact-table', 'is-comfortable-table');
if (density === 'compact') {
classList.add('is-compact-table');
}
if (density === 'comfortable') {
classList.add('is-comfortable-table');
}
}
return {
appLanguage,
themeMode,
isDarkMode,
appFontFamily,
appCjkFontPack,
displayVRCPlusIconsAsAvatar,
hideNicknames,
showInstanceIdInLocation,
isAgeGatedInstancesVisible,
sortFavorites,
instanceUsersSortAlphabetical,
tablePageSize,
tablePageSizes,
dtHour12,
dtIsoFormat,
weekStartsOn,
sidebarSortMethod1,
sidebarSortMethod2,
sidebarSortMethod3,
sidebarSortMethods,
navWidth,
isSidebarGroupByInstance,
isHideFriendsInSameInstance,
isSameInstanceAboveFavorites,
isSidebarDivideByFriendGroup,
sidebarFavoriteGroups,
sidebarFavoriteGroupOrder,
hideUserNotes,
hideUserMemos,
hideUnfriends,
randomUserColours,
tableDensity,
trustColor,
currentCulture,
isSideBarTabShow,
notificationIconDot,
isNavCollapsed,
isDataTableStriped,
showPointerOnHover,
accessibleStatusIndicators,
useOfficialStatusColors,
showNewDashboardButton,
tableLimitsDialog,
TABLE_MAX_SIZE_MIN,
TABLE_MAX_SIZE_MAX,
SEARCH_LIMIT_MIN,
SEARCH_LIMIT_MAX,
setAppLanguage,
setDisplayVRCPlusIconsAsAvatar,
setHideNicknames,
setShowInstanceIdInLocation,
setIsAgeGatedInstancesVisible,
setSortFavorites,
setInstanceUsersSortAlphabetical,
setTablePageSize,
setTablePageSizes,
setDtHour12,
setDtIsoFormat,
setWeekStartsOn,
setSidebarSortMethod1,
setSidebarSortMethod2,
setSidebarSortMethod3,
setSidebarSortMethods,
setNavWidth,
setIsSidebarGroupByInstance,
setIsHideFriendsInSameInstance,
setIsSameInstanceAboveFavorites,
setIsSidebarDivideByFriendGroup,
setSidebarFavoriteGroups,
setSidebarFavoriteGroupOrder,
setHideUserNotes,
setHideUserMemos,
setHideUnfriends,
setRandomUserColours,
toggleStripedDataTable,
togglePointerOnHover,
toggleAccessibleStatusIndicators,
toggleOfficialStatusColors,
setShowNewDashboardButton,
setTableDensity,
setTrustColor,
tryInitUserColours,
updateTrustColor,
userColourInit,
applyUserTrustLevel,
changeAppLanguage,
showTableLimitsDialog,
closeTableLimitsDialog,
saveTableLimitsDialog,
setNotificationIconDot,
applyTableDensity,
setNavCollapsed,
toggleNavCollapsed,
setAppFontFamily,
customFontFamily,
setCustomFontFamily,
setAppCjkFontPack,
setThemeMode,
toggleThemeMode
};
}
);