diff --git a/apps/stage-tamagotchi/package.json b/apps/stage-tamagotchi/package.json index e4da095c6..58769d836 100644 --- a/apps/stage-tamagotchi/package.json +++ b/apps/stage-tamagotchi/package.json @@ -162,7 +162,7 @@ "builder-util-runtime": "catalog:", "cac": "^6.7.14", "csstype": "^3.2.3", - "electron": "^39.2.7", + "electron": "catalog:", "electron-builder": "^26.4.0", "electron-vite": "^5.0.0", "less": "^4.5.1", diff --git a/apps/stage-tamagotchi/src/renderer/pages/devtools/screen-capture.vue b/apps/stage-tamagotchi/src/renderer/pages/devtools/screen-capture.vue index 46d34feaf..5c04a978e 100644 --- a/apps/stage-tamagotchi/src/renderer/pages/devtools/screen-capture.vue +++ b/apps/stage-tamagotchi/src/renderer/pages/devtools/screen-capture.vue @@ -3,8 +3,8 @@ import type { SerializableDesktopCapturerSource } from '@proj-airi/electron-scre import type { SourcesOptions } from 'electron' import { useElectronScreenCapture } from '@proj-airi/electron-screen-capture/vue' -import { Button } from '@proj-airi/ui' -import { onBeforeUnmount, onMounted, ref } from 'vue' +import { Button, SelectTab } from '@proj-airi/ui' +import { computed, onBeforeUnmount, onMounted, ref } from 'vue' import { useI18n } from 'vue-i18n' import WithScreenCapture from '../../components/WithScreenCapture.vue' @@ -14,9 +14,13 @@ interface ScreenCaptureSource extends SerializableDesktopCapturerSource { thumbnailURL?: string } +type SourceCategory = 'applications' | 'displays' | 'devices' + const sources = ref([]) const isRefetching = ref(false) const activeStreams = ref([]) +const sourceCategory = ref('applications') +const hasFetchedOnce = ref(false) const sourcesOptions = ref({ types: ['screen', 'window'], @@ -29,6 +33,50 @@ const { selectWithSource, } = useElectronScreenCapture(window.electron.ipcRenderer, sourcesOptions) +const categoryOptions = [ + { label: 'Applications', value: 'applications', icon: 'i-solar:window-frame-line-duotone' }, + { label: 'Displays', value: 'displays', icon: 'i-solar:screencast-2-line-duotone' }, + { label: 'Devices', value: 'devices', icon: 'i-solar:smartphone-2-line-duotone' }, +] + +const isDisplaySource = (source: ScreenCaptureSource) => source.id.startsWith('screen:') +const isWindowSource = (source: ScreenCaptureSource) => source.id.startsWith('window:') +const isDeviceSource = (source: ScreenCaptureSource) => source.id.startsWith('device:') + +const filteredSources = computed(() => { + if (sourceCategory.value === 'applications') + return sources.value.filter(isWindowSource) + if (sourceCategory.value === 'displays') + return sources.value.filter(isDisplaySource) + return sources.value.filter(isDeviceSource) +}) + +const sourceCounts = computed(() => ({ + applications: sources.value.filter(isWindowSource).length, + displays: sources.value.filter(isDisplaySource).length, + devices: sources.value.filter(isDeviceSource).length, +})) + +const isInitialLoading = computed(() => !hasFetchedOnce.value && isRefetching.value) + +const refetchLabel = computed(() => { + if (isInitialLoading.value) + return 'Loading...' + return isRefetching.value ? 'Refetching...' : 'Refetch' +}) + +const refetchIcon = computed(() => + isInitialLoading.value ? 'i-svg-spinners:ring-resize' : 'i-solar:refresh-line-duotone', +) + +function getShareLabel(source: ScreenCaptureSource) { + if (isDisplaySource(source)) + return 'Share Screen' + if (isDeviceSource(source)) + return 'Share Device' + return 'Share Window' +} + function toLocalArrayBuffer(bytes: Uint8Array) { if (typeof SharedArrayBuffer !== 'undefined' && bytes.buffer instanceof SharedArrayBuffer) { return bytes.slice().buffer @@ -86,6 +134,11 @@ async function refetchSources() { sources.value = nextSources.map(source => ({ ...source, + // NOTICE(@nekomeowww): In probability of 9/10, the window thumbnail is purely empty or black, sources printed and + // nothing is returned from the desktopCapturer API. + // NOTICE(@sumimakito): Not only thumbnail is empty, the appIcon could be empty as well with nothing returned. + // REVIEW(@sumimakito): This has nothing to do with our side, probably related to a Electron bug, you can + // read more here https://github.com/electron/electron/issues/44504 appIconURL: source.appIcon && source.appIcon.length > 0 ? toObjectUrl(source.appIcon, 'image/png') : undefined, thumbnailURL: source.thumbnail && source.thumbnail.length > 0 ? toObjectUrl(source.thumbnail, 'image/jpeg') : undefined, })) @@ -95,6 +148,7 @@ async function refetchSources() { } finally { isRefetching.value = false + hasFetchedOnce.value = true } } @@ -117,39 +171,40 @@ onBeforeUnmount(() => {