refactor auto change status

This commit is contained in:
pa
2026-02-14 17:07:22 +09:00
parent 64869a218e
commit 4e552bf3b9
5 changed files with 310 additions and 77 deletions

View File

@@ -537,20 +537,23 @@
"automation": { "automation": {
"auto_change_status": "Auto Change Status", "auto_change_status": "Auto Change Status",
"auto_state_change_tooltip": "Automatically change status when there are other people in the instance (Alone / Company)", "auto_state_change_tooltip": "Automatically change status when there are other people in the instance (Alone / Company)",
"alone_condition": "Alone Condition", "alone_condition": "Consider alone when",
"alone": "Alone", "alone": "No other players",
"no_friends": "No Friends", "no_friends": "No friends in instance",
"alone_status": "Alone Status", "alone_status": "Alone Status",
"company_status": "Company Status", "company_status": "Company Status",
"allowed_instance_types": "Allowed Instance Types", "allowed_instance_types": "Active in instance types",
"instance_type_placeholder": "All Instance Types", "instance_type_placeholder": "All Instance Types",
"auto_invite_request_accept": "Auto Accept Invite Requests", "auto_invite_request_accept": "Auto Accept Invite Requests",
"auto_invite_request_accept_tooltip": "Automatically accept invite requests from favorite friends", "auto_invite_request_accept_tooltip": "Automatically accept invite requests from favorite friends",
"auto_invite_request_accept_off": "Off",
"auto_invite_request_accept_favs": "All Favorites", "auto_invite_request_accept_favs": "All Favorites",
"auto_invite_request_accept_selected_favs": "VRCX Favorites", "auto_invite_request_accept_selected_favs": "VRCX Favorites",
"change_status_description": "Override status description", "change_status_description": "Override status description",
"status_description_placeholder": "Status description (max 32 characters)" "status_description_placeholder": "Status description (max 32 characters)",
"auto_change_status_groups": "Only count friends from",
"auto_change_status_groups_placeholder": "Choose Groups",
"auto_accept_invite_groups": "Only accept from",
"auto_accept_invite_groups_placeholder": "Choose Groups"
}, },
"legal_notice": { "legal_notice": {
"header": "Legal Notice", "header": "Legal Notice",

View File

@@ -247,10 +247,40 @@ export const useNotificationStore = defineStore('Notification', () => {
} }
if ( if (
generalSettingsStore.autoAcceptInviteRequests === generalSettingsStore.autoAcceptInviteRequests ===
'Selected Favorites' && 'Selected Favorites'
!friendStore.localFavoriteFriends.has(ref.senderUserId)
) { ) {
return; const groups = generalSettingsStore.autoAcceptInviteGroups;
if (groups.length === 0) {
return;
} else {
let found = false;
for (const groupKey of groups) {
if (groupKey.startsWith('local:')) {
const localGroup = groupKey.slice(6);
const localFavs =
favoriteStore.localFriendFavorites.get(localGroup);
if (localFavs && localFavs.has(ref.senderUserId)) {
found = true;
break;
}
} else {
const remoteFavs =
favoriteStore.cachedFavorites.get(groupKey);
if (
remoteFavs &&
remoteFavs.some(
(f) => f.favoriteId === ref.senderUserId
)
) {
found = true;
break;
}
}
}
if (!found) {
return;
}
}
} }
if (!checkCanInvite(currentLocation)) { if (!checkCanInvite(currentLocation)) {
return; return;

View File

@@ -39,7 +39,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
const autoStateChangeAloneDesc = ref(''); const autoStateChangeAloneDesc = ref('');
const autoStateChangeCompanyDescEnabled = ref(false); const autoStateChangeCompanyDescEnabled = ref(false);
const autoStateChangeCompanyDesc = ref(''); const autoStateChangeCompanyDesc = ref('');
const autoStateChangeGroups = ref([]);
const autoAcceptInviteRequests = ref('Off'); const autoAcceptInviteRequests = ref('Off');
const autoAcceptInviteGroups = ref([]);
async function initGeneralSettings() { async function initGeneralSettings() {
const [ const [
@@ -64,7 +66,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
autoStateChangeAloneDescConfig, autoStateChangeAloneDescConfig,
autoStateChangeCompanyDescEnabledConfig, autoStateChangeCompanyDescEnabledConfig,
autoStateChangeCompanyDescConfig, autoStateChangeCompanyDescConfig,
autoAcceptInviteRequestsConfig autoStateChangeGroupsStrConfig,
autoAcceptInviteRequestsConfig,
autoAcceptInviteGroupsStrConfig
] = await Promise.all([ ] = await Promise.all([
configRepository.getBool('VRCX_StartAtWindowsStartup', false), configRepository.getBool('VRCX_StartAtWindowsStartup', false),
VRCXStorage.Get('VRCX_StartAsMinimizedState'), VRCXStorage.Get('VRCX_StartAsMinimizedState'),
@@ -102,7 +106,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
false false
), ),
configRepository.getString('VRCX_autoStateChangeCompanyDesc', ''), configRepository.getString('VRCX_autoStateChangeCompanyDesc', ''),
configRepository.getString('VRCX_autoAcceptInviteRequests', 'Off') configRepository.getString('VRCX_autoStateChangeGroups', '[]'),
configRepository.getString('VRCX_autoAcceptInviteRequests', 'Off'),
configRepository.getString('VRCX_autoAcceptInviteGroups', '[]')
]); ]);
isStartAtWindowsStartup.value = isStartAtWindowsStartupConfig; isStartAtWindowsStartup.value = isStartAtWindowsStartupConfig;
@@ -146,7 +152,13 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
autoStateChangeCompanyDescEnabled.value = autoStateChangeCompanyDescEnabled.value =
autoStateChangeCompanyDescEnabledConfig; autoStateChangeCompanyDescEnabledConfig;
autoStateChangeCompanyDesc.value = autoStateChangeCompanyDescConfig; autoStateChangeCompanyDesc.value = autoStateChangeCompanyDescConfig;
autoStateChangeGroups.value = JSON.parse(
autoStateChangeGroupsStrConfig
);
autoAcceptInviteRequests.value = autoAcceptInviteRequestsConfig; autoAcceptInviteRequests.value = autoAcceptInviteRequestsConfig;
autoAcceptInviteGroups.value = JSON.parse(
autoAcceptInviteGroupsStrConfig
);
} }
initGeneralSettings(); initGeneralSettings();
@@ -322,6 +334,17 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
autoStateChangeCompanyDesc.value autoStateChangeCompanyDesc.value
); );
} }
/**
* @param {Array} value
*/
function setAutoStateChangeGroups(value) {
autoStateChangeGroups.value = value;
configRepository.setString(
'VRCX_autoStateChangeGroups',
JSON.stringify(autoStateChangeGroups.value)
);
}
/** /**
* @param {string} value * @param {string} value
*/ */
@@ -333,6 +356,17 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
); );
} }
/**
* @param {string[]} value
*/
function setAutoAcceptInviteGroups(value) {
autoAcceptInviteGroups.value = value;
configRepository.setString(
'VRCX_autoAcceptInviteGroups',
JSON.stringify(autoAcceptInviteGroups.value)
);
}
function promptProxySettings() { function promptProxySettings() {
// Element Plus: prompt(message, title, options) // Element Plus: prompt(message, title, options)
modalStore modalStore
@@ -398,7 +432,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
autoStateChangeAloneDesc, autoStateChangeAloneDesc,
autoStateChangeCompanyDescEnabled, autoStateChangeCompanyDescEnabled,
autoStateChangeCompanyDesc, autoStateChangeCompanyDesc,
autoStateChangeGroups,
autoAcceptInviteRequests, autoAcceptInviteRequests,
autoAcceptInviteGroups,
setIsStartAtWindowsStartup, setIsStartAtWindowsStartup,
setIsStartAsMinimizedState, setIsStartAsMinimizedState,
@@ -420,7 +456,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
setAutoStateChangeAloneDesc, setAutoStateChangeAloneDesc,
setAutoStateChangeCompanyDescEnabled, setAutoStateChangeCompanyDescEnabled,
setAutoStateChangeCompanyDesc, setAutoStateChangeCompanyDesc,
setAutoStateChangeGroups,
setAutoAcceptInviteRequests, setAutoAcceptInviteRequests,
setAutoAcceptInviteGroups,
promptProxySettings promptProxySettings
}; };
}); });

View File

@@ -1616,7 +1616,39 @@ export const useUserStore = defineStore('User', () => {
let withCompany = locationStore.lastLocation.playerList.size > 1; let withCompany = locationStore.lastLocation.playerList.size > 1;
if (generalSettingsStore.autoStateChangeNoFriends) { if (generalSettingsStore.autoStateChangeNoFriends) {
withCompany = locationStore.lastLocation.friendList.size >= 1; const selectedGroups = generalSettingsStore.autoStateChangeGroups;
if (selectedGroups.length > 0) {
const groupFriendIds = new Set();
for (const ref of favoriteStore.cachedFavorites.values()) {
if (
ref.type === 'friend' &&
selectedGroups.includes(ref.$groupKey)
) {
groupFriendIds.add(ref.favoriteId);
}
}
for (const selectedKey of selectedGroups) {
if (selectedKey.startsWith('local:')) {
const groupName = selectedKey.slice(6);
const userIds =
favoriteStore.localFriendFavorites[groupName];
if (userIds) {
for (let i = 0; i < userIds.length; ++i) {
groupFriendIds.add(userIds[i]);
}
}
}
}
withCompany = false;
for (const friendId of locationStore.lastLocation.friendList.keys()) {
if (groupFriendIds.has(friendId)) {
withCompany = true;
break;
}
}
} else {
withCompany = locationStore.lastLocation.friendList.size >= 1;
}
} }
const currentStatus = currentUser.value.status; const currentStatus = currentUser.value.status;

View File

@@ -12,6 +12,93 @@
:tooltip="t('view.settings.general.automation.auto_state_change_tooltip')" :tooltip="t('view.settings.general.automation.auto_state_change_tooltip')"
@change="setAutoStateChangeEnabled" /> @change="setAutoStateChangeEnabled" />
<Field>
<FieldLabel>{{ t('view.settings.general.automation.alone_condition') }}</FieldLabel>
<FieldContent>
<RadioGroup
:model-value="autoStateChangeNoFriends ? 'true' : 'false'"
:disabled="!autoStateChangeEnabled"
class="gap-2 flex"
@update:modelValue="handleAutoStateChangeNoFriendsRadio">
<div class="flex items-center space-x-2">
<RadioGroupItem id="autoStateChangeNoFriends-false" value="false" />
<label for="autoStateChangeNoFriends-false">
{{ t('view.settings.general.automation.alone') }}
</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem id="autoStateChangeNoFriends-true" value="true" />
<label for="autoStateChangeNoFriends-true">
{{ t('view.settings.general.automation.no_friends') }}
</label>
</div>
</RadioGroup>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('view.settings.general.automation.auto_change_status_groups') }}</FieldLabel>
<FieldContent>
<Select
:model-value="autoStateChangeGroups"
:disabled="!autoStateChangeEnabled || !autoStateChangeNoFriends"
multiple
@update:modelValue="setAutoStateChangeGroups">
<SelectTrigger size="sm">
<SelectValue
:placeholder="
t('view.settings.general.automation.auto_change_status_groups_placeholder')
" />
</SelectTrigger>
<SelectContent>
<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>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('view.settings.general.automation.allowed_instance_types') }}</FieldLabel>
<FieldContent>
<Select
:model-value="autoStateChangeInstanceTypes"
:disabled="!autoStateChangeEnabled"
multiple
@update:modelValue="setAutoStateChangeInstanceTypes">
<SelectTrigger size="sm">
<SelectValue
:placeholder="t('view.settings.general.automation.instance_type_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="instanceType in instanceTypes"
:key="instanceType"
:value="instanceType">
{{ translateAccessType(instanceType) }}
</SelectItem>
</SelectContent>
</Select>
</FieldContent>
</Field>
<Field> <Field>
<FieldLabel>{{ t('view.settings.general.automation.alone_status') }}</FieldLabel> <FieldLabel>{{ t('view.settings.general.automation.alone_status') }}</FieldLabel>
<FieldContent> <FieldContent>
@@ -96,48 +183,32 @@
</FieldContent> </FieldContent>
</Field> </Field>
<Field> <FieldSeparator></FieldSeparator>
<FieldLabel>{{ t('view.settings.general.automation.allowed_instance_types') }}</FieldLabel>
<FieldContent> <SimpleSwitch
<Select :label="t('view.settings.general.automation.auto_invite_request_accept')"
:model-value="autoStateChangeInstanceTypes" :tooltip="t('view.settings.general.automation.auto_invite_request_accept_tooltip')"
:disabled="!autoStateChangeEnabled" :value="autoAcceptInviteRequests !== 'Off'"
multiple @change="handleAutoAcceptInviteSwitch" />
@update:modelValue="setAutoStateChangeInstanceTypes">
<SelectTrigger size="sm">
<SelectValue
:placeholder="t('view.settings.general.automation.instance_type_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="instanceType in instanceTypes"
:key="instanceType"
:value="instanceType">
{{ instanceType }}
</SelectItem>
</SelectContent>
</Select>
</FieldContent>
</Field>
<Field> <Field>
<FieldLabel>{{ t('view.settings.general.automation.alone_condition') }}</FieldLabel> <FieldLabel>{{ t('view.settings.general.automation.auto_invite_request_accept') }}</FieldLabel>
<FieldContent> <FieldContent>
<RadioGroup <RadioGroup
:model-value="autoStateChangeNoFriends ? 'true' : 'false'" :model-value="autoAcceptInviteMode"
:disabled="!autoStateChangeEnabled" :disabled="autoAcceptInviteRequests === 'Off'"
class="gap-2 flex" class="gap-2 flex"
@update:modelValue="handleAutoStateChangeNoFriendsRadio"> @update:modelValue="handleAutoAcceptInviteModeChange">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="autoStateChangeNoFriends-false" value="false" /> <RadioGroupItem id="autoAcceptInvite-all" value="All Favorites" />
<label for="autoStateChangeNoFriends-false"> <label for="autoAcceptInvite-all">
{{ t('view.settings.general.automation.alone') }} {{ t('view.settings.general.automation.auto_invite_request_accept_favs') }}
</label> </label>
</div> </div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<RadioGroupItem id="autoStateChangeNoFriends-true" value="true" /> <RadioGroupItem id="autoAcceptInvite-selected" value="Selected Favorites" />
<label for="autoStateChangeNoFriends-true"> <label for="autoAcceptInvite-selected">
{{ t('view.settings.general.automation.no_friends') }} {{ t('view.settings.general.automation.auto_invite_request_accept_selected_favs') }}
</label> </label>
</div> </div>
</RadioGroup> </RadioGroup>
@@ -145,32 +216,41 @@
</Field> </Field>
<Field> <Field>
<FieldLabel> <FieldLabel>{{ t('view.settings.general.automation.auto_accept_invite_groups') }}</FieldLabel>
{{ t('view.settings.general.automation.auto_invite_request_accept') }}
<TooltipWrapper
side="top"
:content="t('view.settings.general.automation.auto_invite_request_accept_tooltip')">
<Info class="inline-block" />
</TooltipWrapper>
</FieldLabel>
<FieldContent> <FieldContent>
<ToggleGroup <Select
type="single" :model-value="autoAcceptInviteGroups"
required :disabled="autoAcceptInviteRequests !== 'Selected Favorites'"
variant="outline" multiple
size="sm" @update:modelValue="setAutoAcceptInviteGroups">
:model-value="autoAcceptInviteRequests" <SelectTrigger size="sm">
@update:model-value="setAutoAcceptInviteRequests"> <SelectValue
<ToggleGroupItem value="Off">{{ :placeholder="
t('view.settings.general.automation.auto_invite_request_accept_off') t('view.settings.general.automation.auto_accept_invite_groups_placeholder')
}}</ToggleGroupItem> " />
<ToggleGroupItem value="All Favorites">{{ </SelectTrigger>
t('view.settings.general.automation.auto_invite_request_accept_favs') <SelectContent>
}}</ToggleGroupItem> <SelectGroup>
<ToggleGroupItem value="Selected Favorites">{{ <SelectItem
t('view.settings.general.automation.auto_invite_request_accept_selected_favs') v-for="group in favoriteFriendGroups"
}}</ToggleGroupItem> :key="group.key"
</ToggleGroup> :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>
</FieldContent> </FieldContent>
</Field> </Field>
</FieldGroup> </FieldGroup>
@@ -179,18 +259,25 @@
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectSeparator,
SelectTrigger,
SelectValue
} from '@/components/ui/select';
import { Field, FieldContent, FieldGroup, FieldLabel, FieldSeparator } from '@/components/ui/field';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { Info } from 'lucide-vue-next';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { computed } from 'vue'; import { computed } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useGeneralSettingsStore } from '../../../stores'; import { useFavoriteStore, useGeneralSettingsStore } from '../../../stores';
import { accessTypeLocaleKeyMap } from '../../../shared/constants';
import SimpleSwitch from '../../Settings/components/SimpleSwitch.vue'; import SimpleSwitch from '../../Settings/components/SimpleSwitch.vue';
@@ -215,9 +302,14 @@
autoStateChangeAloneDesc, autoStateChangeAloneDesc,
autoStateChangeCompanyDescEnabled, autoStateChangeCompanyDescEnabled,
autoStateChangeCompanyDesc, autoStateChangeCompanyDesc,
autoAcceptInviteRequests autoStateChangeGroups,
autoAcceptInviteRequests,
autoAcceptInviteGroups
} = storeToRefs(generalSettingsStore); } = storeToRefs(generalSettingsStore);
const favoriteStore = useFavoriteStore();
const { favoriteFriendGroups, localFriendFavoriteGroups } = storeToRefs(favoriteStore);
const { const {
setAutoStateChangeEnabled, setAutoStateChangeEnabled,
setAutoStateChangeAloneStatus, setAutoStateChangeAloneStatus,
@@ -228,7 +320,9 @@
setAutoStateChangeAloneDesc, setAutoStateChangeAloneDesc,
setAutoStateChangeCompanyDescEnabled, setAutoStateChangeCompanyDescEnabled,
setAutoStateChangeCompanyDesc, setAutoStateChangeCompanyDesc,
setAutoAcceptInviteRequests setAutoStateChangeGroups,
setAutoAcceptInviteRequests,
setAutoAcceptInviteGroups
} = generalSettingsStore; } = generalSettingsStore;
const instanceTypes = computed(() => [ const instanceTypes = computed(() => [
@@ -242,6 +336,23 @@
'groupOnly' 'groupOnly'
]); ]);
const instanceTypeToMapKey = {
groupOnly: 'groupMembers'
};
function translateAccessType(accessTypeNameRaw) {
const mapKey = instanceTypeToMapKey[accessTypeNameRaw] || accessTypeNameRaw;
const key = accessTypeLocaleKeyMap[mapKey];
if (!key) {
return accessTypeNameRaw;
}
if (mapKey === 'groupPublic' || mapKey === 'groupPlus' || mapKey === 'groupMembers') {
const groupKey = accessTypeLocaleKeyMap['group'];
return t(groupKey) + ' ' + t(key);
}
return t(key);
}
function handleAutoStateChangeNoFriendsRadio(value) { function handleAutoStateChangeNoFriendsRadio(value) {
const nextValue = value === 'true'; const nextValue = value === 'true';
if (nextValue !== autoStateChangeNoFriends.value) { if (nextValue !== autoStateChangeNoFriends.value) {
@@ -249,6 +360,25 @@
} }
} }
const autoAcceptInviteMode = computed(() => {
if (autoAcceptInviteRequests.value === 'Off') {
return 'All Favorites';
}
return autoAcceptInviteRequests.value;
});
function handleAutoAcceptInviteSwitch(enabled) {
if (enabled) {
setAutoAcceptInviteRequests(autoAcceptInviteMode.value);
} else {
setAutoAcceptInviteRequests('Off');
}
}
function handleAutoAcceptInviteModeChange(value) {
setAutoAcceptInviteRequests(value);
}
function closeDialog() { function closeDialog() {
emit('close'); emit('close');
} }