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

View file

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