feat(core): port CalcInfo and FileView to Vue 3 script setup

This commit is contained in:
Your Name 2026-07-21 20:55:52 -04:00
parent 7869a747bc
commit 3ee9925f91
2 changed files with 85 additions and 76 deletions

View file

@ -31,7 +31,7 @@
</div>
</button>
<button class="mt-4 button gray-button"
@click="nativeUpload ? $refs.upload.click() : $devices.uploadOs(dev, info.os_extension.split('.').pop())">
@click="nativeUpload ? upload?.click() : $devices.uploadOs(dev, info.os_extension.split('.').pop())">
Upload OS
</button>
<input v-if="nativeUpload" ref="upload" type="file" class="hidden" :accept="info.os_extension"
@ -39,40 +39,45 @@
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import type {Info, Version} from './devices';
import fileSize from "filesize";
<script setup lang="ts">
import {inject, ref} from 'vue';
import {DEVICES_KEY, type GenericDevices, type Info, type Version} from './devices';
import {filesize} from 'filesize';
@Component
export default class FileView extends Vue {
@Prop({type: Object, required: true}) private info!: Info;
@Prop({type: String, required: true}) private dev!: string;
@Prop({type: Boolean, default: false}) private nativeUpload!: boolean;
refreshing = false;
const props = withDefaults(defineProps<{
info: Info;
dev: string;
nativeUpload?: boolean;
}>(), {
nativeUpload: false,
});
formatSize(size: number) {
return fileSize(size, {round: 1});
const devices = inject(DEVICES_KEY) as GenericDevices;
const refreshing = ref(false);
const upload = ref<HTMLInputElement | null>(null);
function formatSize(size: number) {
return filesize(size, {round: 1});
}
function formatVersion(version: Version) {
return `${version.major}.${version.minor}.${version.patch}.${version.build}`;
}
async function refresh() {
refreshing.value = true;
try {
await devices.update(props.dev);
} catch (e) {
/* */
}
refreshing.value = false;
}
formatVersion(version: Version) {
return `${version.major}.${version.minor}.${version.patch}.${version.build}`;
}
async refresh() {
this.refreshing = true;
try {
await this.$devices.update(this.dev);
} catch (e) {
/* */
}
this.refreshing = false;
}
uploadNative(e: Event & { target: HTMLInputElement }) {
const file = e.target.files?.[0];
if (file) this.$devices.uploadOsFile(this.dev, file);
}
function uploadNative(e: Event & { target: HTMLInputElement }) {
const file = e.target.files?.[0];
if (file) devices.uploadOsFile(props.dev, file);
}
</script>

View file

@ -10,55 +10,59 @@
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue, Watch} from 'vue-property-decorator';
<script setup lang="ts">
import {computed, ref, watch} from 'vue';
import type {FileInfo} from './devices';
import FileIcon from "./FileIcon.vue";
import FileIcon from './FileIcon.vue';
@Component({
components: {FileIcon}
})
export default class FileView extends Vue {
@Prop({type: Array, default: () => ([])}) private files!: FileInfo[];
@Prop({type: Boolean, default: false}) private showHidden!: boolean;
selected: number[] = [];
const props = withDefaults(defineProps<{
files: FileInfo[];
showHidden?: boolean;
}>(), {
files: () => [],
showHidden: false,
});
@Watch('selected', {deep: true, immediate: true})
onSelect(selected: number[]) {
this.$emit('select', selected.map(file => this.filteredFiles[file]));
const emit = defineEmits<{
nav: [path: string];
select: [files: FileInfo[]];
}>();
const selected = ref<number[]>([]);
const filteredFiles = computed(() => {
if (props.showHidden) return props.files;
return props.files.filter(file => file.isDir || file.path.endsWith('.tns'));
});
watch(selected, (sel) => {
emit('select', sel.map(file => filteredFiles.value[file]));
}, {deep: true, immediate: true});
watch(() => props.files, () => {
selected.value = [];
});
function formatPath({path, isDir}: FileInfo) {
const name = path.split('/').pop() as string;
if (props.showHidden || isDir) return name;
return name.substring(0, name.length - 4);
}
function xorSelection(i: number) {
if (selected.value.includes(i)) selected.value = selected.value.filter(num => num !== i);
else selected.value.push(i);
}
function shiftSelection(item: number) {
const lastSelected = selected.value[selected.value.length - 1];
if (lastSelected === undefined) {
selected.value.push(item);
return;
}
@Watch('files')
onFileChange() {
this.selected = [];
}
get filteredFiles() {
if (this.showHidden) return this.files;
return this.files.filter(file => file.isDir || file.path.endsWith('.tns'));
}
formatPath({path, isDir}: FileInfo) {
const name = path.split('/').pop() as string;
if (this.showHidden || isDir) return name;
return name.substring(0, name.length - 4);
}
xorSelection(i: number) {
if (this.selected.includes(i)) this.selected = this.selected.filter(num => num !== i);
else this.selected.push(i);
}
shiftSelection(item: number) {
const lastSelected = this.selected[this.selected.length-1];
if(lastSelected === undefined) {
this.selected.push(item);
return;
}
const [lower, upper] = item > lastSelected ? [lastSelected, item] : [item, lastSelected];
for(let i = lower; i <= upper; i++) {
if (!this.selected.includes(i))this.selected.push(i);
}
const [lower, upper] = item > lastSelected ? [lastSelected, item] : [item, lastSelected];
for (let i = lower; i <= upper; i++) {
if (!selected.value.includes(i)) selected.value.push(i);
}
}
</script>