Files
Starlight_Lancher/apps/app-frontend/src/components/ui/settings/DownloadJavaModal.vue
T

273 lines
8.2 KiB
Vue

<script setup>
import { ArrowLeftIcon, CoffeeIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import {
commonMessages,
defineMessages,
injectNotificationManager,
NewButton as Button,
NewModal,
useVIntl,
} from '@modrinth/ui'
import { ref } from 'vue'
import AlibabaLogo from '@/assets/java-vendors/alibaba.png'
import AmazonLogo from '@/assets/java-vendors/amazon.png'
import AzulLogo from '@/assets/java-vendors/azul.png'
import BellSoftLogo from '@/assets/java-vendors/bellsoft.png'
import EclipseLogo from '@/assets/java-vendors/eclipse.png'
import GraalVmLogo from '@/assets/java-vendors/graalvm.png'
import IbmLogo from '@/assets/java-vendors/ibm.png'
import JetBrainsLogo from '@/assets/java-vendors/jetbrains.png'
import MicrosoftLogo from '@/assets/java-vendors/microsoft.png'
import OracleLogo from '@/assets/java-vendors/oracle.png'
import SapLogo from '@/assets/java-vendors/sap.png'
import { download_java, list_java_feed_vendors, list_java_feed_versions } from '@/helpers/jre'
const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl()
const messages = defineMessages({
downloadJava: { id: 'app.settings.java.download.title', defaultMessage: 'Download Java' },
selectVendor: {
id: 'app.settings.java.download.select-vendor',
defaultMessage: 'Choose a distribution:',
},
selectVersion: {
id: 'app.settings.java.download.select-version-feed',
defaultMessage: 'Select a version of {vendor}:',
},
back: { id: 'app.settings.java.download.back', defaultMessage: 'Back to distributions' },
loading: { id: 'app.settings.java.download.loading', defaultMessage: 'Loading...' },
noVendors: {
id: 'app.settings.java.download.no-vendors',
defaultMessage: 'No distributions available.',
},
noVersions: {
id: 'app.settings.java.download.no-versions',
defaultMessage: 'No versions available.',
},
versionLabel: {
id: 'app.settings.java.download.version-label',
defaultMessage: 'Java {version}',
},
})
const vendorBranding = {
Alibaba: { logo: AlibabaLogo, product: 'Dragonwell' },
Amazon: { logo: AmazonLogo, product: 'Corretto' },
Azul: { logo: AzulLogo, product: 'Zulu' },
BellSoft: { logo: BellSoftLogo, product: 'Liberica JDK' },
Eclipse: { logo: EclipseLogo, product: 'Temurin' },
GraalVM: { logo: GraalVmLogo, product: 'Community Edition' },
IBM: { logo: IbmLogo, product: 'Semeru' },
JetBrains: { logo: JetBrainsLogo, product: 'Runtime' },
Microsoft: { logo: MicrosoftLogo, product: 'OpenJDK' },
Oracle: { logo: OracleLogo, product: 'OpenJDK / GraalVM' },
SAP: { logo: SapLogo, product: 'SapMachine' },
}
const emit = defineEmits(['downloaded'])
const modal = ref(null)
const loading = ref(false)
const vendors = ref([])
const selectedVendor = ref(null)
const versions = ref([])
const downloading = ref(null)
let requestId = 0
async function show() {
const currentRequestId = ++requestId
selectedVendor.value = null
versions.value = []
downloading.value = null
loading.value = true
vendors.value = []
modal.value?.show()
const result = await list_java_feed_vendors().catch(handleError)
if (currentRequestId !== requestId) return
vendors.value = result || []
loading.value = false
}
defineExpose({ show })
async function selectVendor(vendor) {
const currentRequestId = ++requestId
selectedVendor.value = vendor
loading.value = true
versions.value = []
const result = await list_java_feed_versions(vendor).catch(handleError)
if (currentRequestId !== requestId || selectedVendor.value !== vendor) return
versions.value = result || []
loading.value = false
}
function backToVendors() {
requestId += 1
selectedVendor.value = null
versions.value = []
loading.value = false
}
async function downloadVersion(info) {
downloading.value = info.major_version
modal.value?.hide()
const job = await download_java(info.vendor, info.major_version).catch(handleError)
downloading.value = null
if (job) {
emit('downloaded', job)
}
}
</script>
<template>
<NewModal
ref="modal"
:header="formatMessage(messages.downloadJava)"
:closable="downloading === null"
max-width="720px"
width="min(720px, calc(100vw - 2rem))"
max-content-height="min(34rem, 70vh)"
scrollable
actions-divider
>
<div class="flex min-h-40 flex-col gap-4">
<template v-if="!selectedVendor">
<span class="font-semibold text-contrast">{{ formatMessage(messages.selectVendor) }}</span>
<div
v-if="loading"
class="flex min-h-32 items-center justify-center gap-2 text-sm text-secondary"
role="status"
>
<SpinnerIcon class="size-4 animate-spin" aria-hidden="true" />
{{ formatMessage(messages.loading) }}
</div>
<div
v-else-if="vendors.length === 0"
class="flex min-h-32 items-center justify-center text-sm text-secondary"
>
{{ formatMessage(messages.noVendors) }}
</div>
<div v-else class="grid grid-cols-2 gap-2 sm:grid-cols-3">
<Button
v-for="vendor in vendors"
:key="vendor"
type="base"
class="!h-16 !w-full !min-w-0 !justify-start !gap-3 !rounded-lg !px-3 !py-2 !text-left !shadow-none"
native-type="button"
@click="selectVendor(vendor)"
>
<span
class="flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-md p-1"
>
<img
v-if="vendorBranding[vendor]"
:src="vendorBranding[vendor].logo"
alt=""
class="size-full object-contain"
/>
<CoffeeIcon v-else class="size-5 text-secondary" aria-hidden="true" />
</span>
<span class="flex min-w-0 flex-1 flex-col items-start text-left leading-tight">
<span class="w-full truncate text-left text-sm font-semibold text-contrast">{{
vendor
}}</span>
<span
v-if="vendorBranding[vendor]"
class="w-full truncate text-left text-xs font-normal text-secondary"
>
{{ vendorBranding[vendor].product }}
</span>
</span>
</Button>
</div>
</template>
<template v-else>
<div class="flex items-center gap-3">
<span
class="flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-md p-1"
>
<img
v-if="vendorBranding[selectedVendor]"
:src="vendorBranding[selectedVendor].logo"
alt=""
class="size-full object-contain"
/>
<CoffeeIcon v-else class="size-5 text-secondary" aria-hidden="true" />
</span>
<span class="min-w-0 font-semibold text-contrast">
{{ formatMessage(messages.selectVersion, { vendor: selectedVendor }) }}
</span>
</div>
<div
v-if="loading"
class="flex min-h-32 items-center justify-center gap-2 text-sm text-secondary"
role="status"
>
<SpinnerIcon class="size-4 animate-spin" aria-hidden="true" />
{{ formatMessage(messages.loading) }}
</div>
<div
v-else-if="versions.length === 0"
class="flex min-h-32 items-center justify-center text-sm text-secondary"
>
{{ formatMessage(messages.noVersions) }}
</div>
<div v-else class="grid grid-cols-2 gap-2 sm:grid-cols-4">
<Button
v-for="info in versions"
:key="info.major_version"
type="base"
class="!h-12 !w-full !min-w-0 !rounded-lg !px-3 !shadow-none"
:disabled="downloading !== null"
native-type="button"
@click="downloadVersion(info)"
>
<SpinnerIcon
v-if="downloading === info.major_version"
class="animate-spin"
aria-hidden="true"
/>
<CoffeeIcon v-else aria-hidden="true" />
<span class="truncate text-sm font-semibold tabular-nums">
{{ formatMessage(messages.versionLabel, { version: info.major_version }) }}
</span>
</Button>
</div>
</template>
</div>
<template #actions>
<div class="flex flex-wrap justify-end gap-2">
<Button
v-if="selectedVendor"
type="outlined"
:disabled="downloading !== null"
native-type="button"
@click="backToVendors"
>
<ArrowLeftIcon aria-hidden="true" />
{{ formatMessage(messages.back) }}
</Button>
<Button
type="outlined"
:disabled="downloading !== null"
native-type="button"
@click="modal?.hide()"
>
<XIcon aria-hidden="true" />
{{ formatMessage(commonMessages.cancelButton) }}
</Button>
</div>
</template>
</NewModal>
</template>