refactor: app.js (#1291)

* refactor: frontend

* Fix avatar gallery sort

* Update .NET dependencies

* Update npm dependencies

electron v37.1.0

* bulkRefreshFriends

* fix dark theme

* Remove crowdin

* Fix config.json dialog not updating

* VRCX log file fixes & add Cef log

* Remove SharedVariable, fix startup

* Revert init theme change

* Logging date not working? Fix WinformThemer designer error

* Add Cef request hander, no more escaping main page

* clean

* fix

* fix

* clean

* uh

* Apply thememode at startup, fixes random user colours

* Split database into files

* Instance info remove empty lines

* Open external VRC links with VRCX

* Electron fixes

* fix userdialog style

* ohhhh

* fix store

* fix store

* fix: load all group members after kicking a user

* fix: world dialog favorite button style

* fix: Clear VRCX Cache Timer input value

* clean

* Fix VR overlay

* Fix VR overlay 2

* Fix Discord discord rich presence for RPC worlds

* Clean up age verified user tags

* Fix playerList being occupied after program reload

* no `this`

* Fix login stuck loading

* writable: false

* Hide dialogs on logout

* add flush sync option

* rm LOGIN event

* rm LOGOUT event

* remove duplicate event listeners

* remove duplicate event listeners

* clean

* remove duplicate event listeners

* clean

* fix theme style

* fix t

* clearable

* clean

* fix ipcEvent

* Small changes

* Popcorn Palace support

* Remove checkActiveFriends

* Clean up

* Fix dragEnterCef

* Block API requests when not logged in

* Clear state on login & logout

* Fix worldDialog instances not updating

* use <script setup>

* Fix avatar change event, CheckGameRunning at startup

* Fix image dragging

* fix

* Remove PWI

* fix updateLoop

* add webpack-dev-server to dev environment

* rm unnecessary chunks

* use <script setup>

* webpack-dev-server changes

* use <script setup>

* use <script setup>

* Fix UGC text size

* Split login event

* t

* use <script setup>

* fix

* Update .gitignore and enable checkJs in jsconfig

* fix i18n t

* use <script setup>

* use <script setup>

* clean

* global types

* fix

* use checkJs for debugging

* Add watchState for login watchers

* fix .vue template

* type fixes

* rm Vue.filter

* Cef v138.0.170, VC++ 2022

* Settings fixes

* Remove 'USER:CURRENT'

* clean up 2FA callbacks

* remove userApply

* rm i18n import

* notification handling to use notification store methods

* refactor favorite handling to use favorite store methods and clean up event emissions

* refactor moderation handling to use dedicated functions for player moderation events

* refactor friend handling to use dedicated functions for friend events

* Fix program startup, move lang init

* Fix friend state

* Fix status change error

* Fix user notes diff

* fix

* rm group event

* rm auth event

* rm avatar event

* clean

* clean

* getUser

* getFriends

* getFavoriteWorlds, getFavoriteAvatars

* AvatarGalleryUpload btn style & package.json update

* Fix friend requests

* Apply user

* Apply world

* Fix note diff

* Fix VR overlay

* Fixes

* Update build scripts

* Apply avatar

* Apply instance

* Apply group

* update hidden VRC+ badge

* Fix sameInstance "private"

* fix 502/504 API errors

* fix 502/504 API errors

* clean

* Fix friend in same instance on orange showing twice in friends list

* Add back in broken friend state repair methods

* add types

---------

Co-authored-by: Natsumi <cmcooper123@hotmail.com>
This commit is contained in:
pa
2025-07-14 12:00:08 +09:00
committed by GitHub
parent 952fd77ed5
commit f4f78bb5ec
323 changed files with 47745 additions and 43326 deletions
+145 -138
View File
@@ -1,5 +1,5 @@
<template>
<safe-dialog :visible.sync="isDialogVisible" :title="$t('dialog.avatar_export.header')" width="650px">
<safe-dialog :visible.sync="isDialogVisible" :title="t('dialog.avatar_export.header')" width="650px">
<el-checkbox-group
v-model="exportSelectedOptions"
style="margin-bottom: 10px"
@@ -26,7 +26,7 @@
<el-dropdown-item style="display: block; margin: 10px 0" @click.native="selectAvatarExportGroup(null)">
All Favorites
</el-dropdown-item>
<template v-for="groupAPI in API.favoriteAvatarGroups">
<template v-for="groupAPI in favoriteAvatarGroups">
<el-dropdown-item
:key="groupAPI.name"
style="display: block; margin: 10px 0"
@@ -79,145 +79,152 @@
</safe-dialog>
</template>
<script>
export default {
name: 'AvatarExportDialog',
inject: ['API'],
props: {
avatarExportDialogVisible: Boolean,
favoriteAvatars: Array,
localAvatarFavoriteGroups: Array,
localAvatarFavorites: Object,
localAvatarFavoritesList: Array
},
data() {
return {
avatarExportContent: '',
avatarExportFavoriteGroup: null,
avatarExportLocalFavoriteGroup: null,
exportSelectedOptions: ['ID', 'Name'],
exportSelectOptions: [
{ label: 'ID', value: 'id' },
{ label: 'Name', value: 'name' },
{ label: 'Author ID', value: 'authorId' },
{ label: 'Author Name', value: 'authorName' },
{ label: 'Thumbnail', value: 'thumbnailImageUrl' }
]
};
},
computed: {
isDialogVisible: {
get() {
return this.avatarExportDialogVisible;
},
set(value) {
this.$emit('update:avatar-export-dialog-visible', value);
}
}
},
watch: {
avatarExportDialogVisible(visible) {
if (visible) {
this.showAvatarExportDialog();
}
}
},
methods: {
showAvatarExportDialog() {
this.avatarExportFavoriteGroup = null;
this.avatarExportLocalFavoriteGroup = null;
this.updateAvatarExportDialog();
},
handleCopyAvatarExportData(event) {
if (event.target.tagName === 'TEXTAREA') {
event.target.select();
}
navigator.clipboard
.writeText(this.avatarExportContent)
.then(() => {
this.$message({
message: 'Copied successfully!',
type: 'success',
duration: 2000
});
})
.catch((err) => {
console.error('Copy failed:', err);
this.$message.error('Copy failed!');
});
},
updateAvatarExportDialog() {
const formatter = function (str) {
if (/[\x00-\x1f,"]/.test(str) === true) {
return `"${str.replace(/"/g, '""')}"`;
}
return str;
};
const propsForQuery = this.exportSelectOptions
.filter((option) => this.exportSelectedOptions.includes(option.label))
.map((option) => option.value);
<script setup>
import { ref, computed, watch, getCurrentInstance } from 'vue';
import { useI18n } from 'vue-i18n-bridge';
import { storeToRefs } from 'pinia';
import { useAvatarStore, useFavoriteStore } from '../../../stores';
function resText(ref) {
let resArr = [];
propsForQuery.forEach((e) => {
resArr.push(formatter(ref?.[e]));
});
return resArr.join(',');
}
const { t } = useI18n();
const { proxy } = getCurrentInstance();
const lines = [this.exportSelectedOptions.join(',')];
const props = defineProps({
avatarExportDialogVisible: {
type: Boolean,
required: true
}
});
if (this.avatarExportFavoriteGroup) {
this.API.favoriteAvatarGroups.forEach((group) => {
if (!this.avatarExportFavoriteGroup || this.avatarExportFavoriteGroup === group) {
this.favoriteAvatars.forEach((ref) => {
if (group.key === ref.groupKey) {
lines.push(resText(ref.ref));
}
});
}
});
} else if (this.avatarExportLocalFavoriteGroup) {
const favoriteGroup = this.localAvatarFavorites[this.avatarExportLocalFavoriteGroup];
if (!favoriteGroup) {
return;
}
for (let i = 0; i < favoriteGroup.length; ++i) {
const ref = favoriteGroup[i];
lines.push(resText(ref));
}
} else {
// export all
this.favoriteAvatars.forEach((ref) => {
lines.push(resText(ref.ref));
});
for (let i = 0; i < this.localAvatarFavoritesList.length; ++i) {
const avatarId = this.localAvatarFavoritesList[i];
const ref = this.API.cachedAvatars.get(avatarId);
if (typeof ref !== 'undefined') {
lines.push(resText(ref));
}
}
}
this.avatarExportContent = lines.join('\n');
},
selectAvatarExportGroup(group) {
this.avatarExportFavoriteGroup = group;
this.avatarExportLocalFavoriteGroup = null;
this.updateAvatarExportDialog();
},
selectAvatarExportLocalGroup(group) {
this.avatarExportLocalFavoriteGroup = group;
this.avatarExportFavoriteGroup = null;
this.updateAvatarExportDialog();
},
getLocalAvatarFavoriteGroupLength(group) {
const favoriteGroup = this.localAvatarFavorites[group];
if (!favoriteGroup) {
return 0;
}
return favoriteGroup.length;
const emit = defineEmits(['update:avatarExportDialogVisible']);
const favoriteStore = useFavoriteStore();
const {
favoriteAvatars,
favoriteAvatarGroups,
localAvatarFavorites,
localAvatarFavoritesList,
localAvatarFavoriteGroups
} = storeToRefs(favoriteStore);
const { getLocalAvatarFavoriteGroupLength } = favoriteStore;
const avatarStore = useAvatarStore();
const { cachedAvatars } = storeToRefs(avatarStore);
const avatarExportContent = ref('');
const avatarExportFavoriteGroup = ref(null);
const avatarExportLocalFavoriteGroup = ref(null);
const exportSelectedOptions = ref(['ID', 'Name']);
const exportSelectOptions = ref([
{ label: 'ID', value: 'id' },
{ label: 'Name', value: 'name' },
{ label: 'Author ID', value: 'authorId' },
{ label: 'Author Name', value: 'authorName' },
{ label: 'Thumbnail', value: 'thumbnailImageUrl' }
]);
const isDialogVisible = computed({
get() {
return props.avatarExportDialogVisible;
},
set(value) {
emit('update:avatarExportDialogVisible', value);
}
});
watch(
() => props.avatarExportDialogVisible,
(value) => {
if (value) {
showAvatarExportDialog();
}
}
};
);
function showAvatarExportDialog() {
avatarExportFavoriteGroup.value = null;
avatarExportLocalFavoriteGroup.value = null;
updateAvatarExportDialog();
}
function handleCopyAvatarExportData(event) {
if (event.target.tagName === 'TEXTAREA') {
event.target.select();
}
navigator.clipboard
.writeText(avatarExportContent.value)
.then(() => {
proxy.$message({
message: 'Copied successfully!',
type: 'success',
duration: 2000
});
})
.catch((err) => {
console.error('Copy failed:', err);
proxy.$message.error('Copy failed!');
});
}
function updateAvatarExportDialog() {
const formatter = function (str) {
if (/[\x00-\x1f,"]/.test(str) === true) {
return `"${str.replace(/"/g, '""')}"`;
}
return str;
};
const propsForQuery = exportSelectOptions.value
.filter((option) => exportSelectedOptions.value.includes(option.label))
.map((option) => option.value);
function resText(ref) {
let resArr = [];
propsForQuery.forEach((e) => {
resArr.push(formatter(ref?.[e]));
});
return resArr.join(',');
}
const lines = [exportSelectedOptions.value.join(',')];
if (avatarExportFavoriteGroup.value) {
favoriteAvatarGroups.value.forEach((group) => {
if (!avatarExportFavoriteGroup.value || avatarExportFavoriteGroup.value === group) {
favoriteAvatars.value.forEach((ref) => {
if (group.key === ref.groupKey) {
lines.push(resText(ref.ref));
}
});
}
});
} else if (avatarExportLocalFavoriteGroup.value) {
const favoriteGroup = localAvatarFavorites.value[avatarExportLocalFavoriteGroup.value];
if (!favoriteGroup) {
return;
}
for (let i = 0; i < favoriteGroup.length; ++i) {
const ref = favoriteGroup[i];
lines.push(resText(ref));
}
} else {
// export all
favoriteAvatars.value.forEach((ref) => {
lines.push(resText(ref.ref));
});
for (let i = 0; i < localAvatarFavoritesList.value.length; ++i) {
const avatarId = localAvatarFavoritesList.value[i];
const ref = cachedAvatars.value.get(avatarId);
if (typeof ref !== 'undefined') {
lines.push(resText(ref));
}
}
}
avatarExportContent.value = lines.join('\n');
}
function selectAvatarExportGroup(group) {
avatarExportFavoriteGroup.value = group;
avatarExportLocalFavoriteGroup.value = null;
updateAvatarExportDialog();
}
function selectAvatarExportLocalGroup(group) {
avatarExportLocalFavoriteGroup.value = group;
avatarExportFavoriteGroup.value = null;
updateAvatarExportDialog();
}
</script>