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});
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) { function uploadNative(e: Event & { target: HTMLInputElement }) {
return `${version.major}.${version.minor}.${version.patch}.${version.build}`; const file = e.target.files?.[0];
} if (file) devices.uploadOsFile(props.dev, file);
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);
}
} }
</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[]];
}>();
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;
} }
const [lower, upper] = item > lastSelected ? [lastSelected, item] : [item, lastSelected];
@Watch('files') for (let i = lower; i <= upper; i++) {
onFileChange() { if (!selected.value.includes(i)) selected.value.push(i);
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);
}
} }
} }
</script> </script>