Implement loading

This commit is contained in:
CodexAdrian
2023-05-02 13:54:40 -04:00
parent 713a915161
commit 8767927646
6 changed files with 251 additions and 29 deletions

View File

@@ -1,35 +1,29 @@
<script setup>
import { ref, onMounted } from 'vue'
import { ref } from 'vue'
import { RouterView, RouterLink } from 'vue-router'
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon } from 'omorphia'
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon, AnimatedLogo } from 'omorphia'
import { useTheming } from '@/store/state'
import AccountsCard from '@/components/ui/AccountsCard.vue'
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
import { list } from '@/helpers/profile'
import { get } from '@/helpers/settings'
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
const themeStore = useTheming()
onMounted(async () => {
const { theme } = await get()
themeStore.setThemeState(theme)
})
const loading = ref(true)
const installedMods = ref(0)
list().then(
(profiles) =>
(installedMods.value = Object.values(profiles).reduce(
(acc, val) => acc + Object.keys(val.projects).length,
0
))
)
// TODO: add event when profiles update to update installed mods count
defineExpose({
initialize: async () => {
loading.value = false
const { theme } = await get()
themeStore.setThemeState(theme)
},
})
</script>
<template>
<div class="container">
<div v-if="!loading" class="container">
<div class="nav-container">
<div class="nav-section">
<suspense>
@@ -74,6 +68,9 @@ list().then(
</div>
</div>
</div>
<div v-else class="loading-page">
<AnimatedLogo class="initializing-icon" />
</div>
</template>
<style lang="scss" scoped>
@@ -316,4 +313,23 @@ list().then(
height: 100%;
gap: 1rem;
}
.loading-page {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #16181c;
height: 100vh;
.initializing-icon {
width: 12rem;
height: 12rem;
:deep(svg) {
width: 12rem;
height: 12rem;
}
}
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup>
import { RouterLink } from 'vue-router'
import { Card } from 'omorphia'
import { AnimatedLogo, Card } from 'omorphia'
import { PlayIcon } from '@/assets/icons'
import { convertFileSrc } from '@tauri-apps/api/tauri'
@@ -25,7 +25,10 @@ const props = defineProps({
{{ props.instance.metadata.loader }} {{ props.instance.metadata.game_version }}
</p>
</div>
<div class="cta"><PlayIcon /></div>
<div class="cta" :class="{ loading: !instance.installed }">
<PlayIcon v-if="instance.installed" />
<AnimatedLogo v-else class="loading-icon" />
</div>
</Card>
</RouterLink>
</div>
@@ -63,11 +66,27 @@ const props = defineProps({
opacity: 0;
transition: 0.3s ease-in-out bottom, 0.1s ease-in-out opacity;
cursor: pointer;
&.loading {
background: var(--color-button-bg);
}
svg {
color: var(--color-accent-contrast);
width: 1.5rem;
height: 1.5rem;
}
.loading-icon {
width: 2rem;
height: 2rem;
:deep(svg) {
width: 2rem;
height: 2rem;
}
}
&:hover {
filter: brightness(0.75);
box-shadow: var(--shadow-floating);

View File

@@ -10,26 +10,59 @@
<Button icon-only class="icon-button" @click="goToTerminal()">
<TerminalIcon />
</Button>
<Button
v-if="currentLoadingBars.length > 0"
ref="infoButton"
icon-only
class="icon-button show-card-icon"
@click="toggleCard()"
>
<DownloadIcon />
</Button>
</div>
<div v-else class="status">
<span class="circle stopped" />
<span class="running-text"> No running profiles </span>
<Button
v-if="currentLoadingBars.length > 0"
ref="infoButton"
icon-only
class="icon-button show-card-icon"
@click="toggleCard()"
>
<DownloadIcon />
</Button>
</div>
<Card v-if="showCard === true" ref="card" class="info-card">
<div v-for="loadingBar in currentLoadingBars" :key="loadingBar.id" class="loading-option">
<AnimatedLogo class="loading-icon" />
<div class="loading-text">
<div class="row">
{{ loadingBar.bar_type.PackDownload.pack_name }}
</div>
<div class="row">{{ Math.round(loadingBar.current) }} % {{ loadingBar.message }}</div>
</div>
</div>
</Card>
</template>
<script setup>
import { Button } from 'omorphia'
import { Button, DownloadIcon, Card, AnimatedLogo } from 'omorphia'
import { StopIcon, TerminalIcon } from '@/assets/icons'
import { ref } from 'vue'
import { onBeforeUnmount, onMounted, ref } from 'vue'
import {
get_all_running_profiles as getRunningProfiles,
kill_by_uuid as killProfile,
get_uuids_by_profile_path as getProfileProcesses,
} from '@/helpers/process'
import { process_listener } from '@/helpers/events'
import { loading_listener, process_listener } from '@/helpers/events'
import { useRouter } from 'vue-router'
import { progress_bars_list } from '@/helpers/state.js'
const router = useRouter()
const card = ref(null)
const infoButton = ref(null)
const showCard = ref(false)
const currentProcesses = ref(await getRunningProfiles())
@@ -55,6 +88,52 @@ const stop = async () => {
const goToTerminal = () => {
router.push(`/instance/${encodeURIComponent(currentProcesses.value[0].path)}/logs`)
}
const currentLoadingBars = ref(
Object.values(await progress_bars_list()).filter(
(bar) => bar.bar_type !== 'StateInit' && Object.keys(bar.bar_type)[0] === 'PackDownload'
)
)
await loading_listener(async (event) => {
console.log('loading listener', event.message, event)
await refreshInfo()
})
const refreshInfo = async () => {
currentLoadingBars.value = Object.values(await progress_bars_list()).filter(
(bar) => bar.bar_type !== 'StateInit' && Object.keys(bar.bar_type)[0] === 'PackDownload'
)
if (currentLoadingBars.value.length === 0) {
showCard.value = false
}
}
const handleClickOutside = (event) => {
console.log('clicked outside from appbar')
if (
card.value &&
infoButton.value.$el !== event.target &&
card.value.$el !== event.target &&
!document.elementsFromPoint(event.clientX, event.clientY).includes(card.value.$el) &&
!document.elementsFromPoint(event.clientX, event.clientY).includes(infoButton.value.$el)
) {
showCard.value = false
}
}
const toggleCard = async () => {
showCard.value = !showCard.value
await refreshInfo()
}
onMounted(() => {
window.addEventListener('click', handleClickOutside)
})
onBeforeUnmount(() => {
window.removeEventListener('click', handleClickOutside)
})
</script>
<style scoped lang="scss">
@@ -100,4 +179,68 @@ const goToTerminal = () => {
--text-color: var(--color-red) !important;
}
}
.info-card {
position: absolute;
top: 3.25rem;
right: 0;
z-index: 100;
width: 20rem;
background-color: var(--color-raised-bg);
box-shadow: var(--shadow-raised);
padding: 1rem;
display: flex;
flex-direction: column;
gap: 1rem;
overflow: auto;
transition: all 0.2s ease-in-out;
border: 1px solid var(--color-button-bg);
&.hidden {
transform: translateY(-100%);
}
}
.loading-option {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
margin: 0;
padding: 0;
:hover {
background-color: var(--color-raised-bg-hover);
}
}
.loading-text {
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
.row {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
}
}
.loading-icon {
width: 2.25rem;
height: 2.25rem;
display: block;
:deep(svg) {
left: 1rem;
width: 2.25rem;
height: 2.25rem;
}
}
.show-card-icon {
color: var(--color-brand);
}
</style>

View File

@@ -16,8 +16,10 @@ app.use(pinia)
app.use(FloatingVue)
app.mixin(loadCssMixin)
const mountedApp = app.mount('#app')
initialize_state()
.then(() => app.mount('#app'))
.then(() => mountedApp.initialize())
.catch((err) => {
console.error(err)
})

View File

@@ -4,14 +4,21 @@ import { shallowRef } from 'vue'
import { list } from '@/helpers/profile.js'
import { useRoute } from 'vue-router'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { loading_listener } from '@/helpers/events.js'
import { progress_bars_list } from '@/helpers/state.js'
const route = useRoute()
const breadcrumbs = useBreadcrumbs()
const profiles = await list()
const instances = shallowRef(Object.values(profiles))
const instances = shallowRef(Object.values(await list()))
const loadingInstances = shallowRef(Object.values(await progress_bars_list()))
breadcrumbs.setRootContext({ name: 'Library', link: route.path })
loading_listener(async (profile) => {
console.log(profile)
instances.value = Object.values(await list())
loadingInstances.value = Object.values(await progress_bars_list())
})
</script>
<template>

View File

@@ -10,9 +10,15 @@
</span>
</div>
<span class="button-group">
<Button color="primary" class="instance-button" @click="run($route.params.id)">
<PlayIcon />
Play
<Button
:color="instance.installed ? 'primary' : ''"
class="instance-button"
:disabled="!instance.installed"
@click="run($route.params.id)"
>
<PlayIcon v-if="instance.installed" />
<AnimatedLogo v-else class="loading-icon" />
{{ instance.installed ? 'Play' : 'Installing' }}
</Button>
<Button class="instance-button" icon-only>
<OpenFolderIcon />
@@ -41,13 +47,23 @@
</div>
</template>
<script setup>
import { BoxIcon, SettingsIcon, FileIcon, Button, Avatar, Card, Promotion } from 'omorphia'
import {
BoxIcon,
SettingsIcon,
FileIcon,
Button,
Avatar,
Card,
Promotion,
AnimatedLogo,
} from 'omorphia'
import { PlayIcon, OpenFolderIcon } from '@/assets/icons'
import { get, run } from '@/helpers/profile'
import { useRoute } from 'vue-router'
import { shallowRef } from 'vue'
import { convertFileSrc } from '@tauri-apps/api/tauri'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { profile_listener } from '@/helpers/events.js'
const breadcrumbs = useBreadcrumbs()
@@ -58,6 +74,12 @@ breadcrumbs.setContext({
name: instance.value.metadata.name,
link: route.path,
})
profile_listener(async (event) => {
if (event.profile_path === route.params.id) {
instance.value = await get(route.params.id)
}
})
</script>
<style scoped lang="scss">
@@ -274,4 +296,17 @@ Button {
height: 1px;
margin: var(--gap-xl) 0;
}
.loading-icon {
width: 1.5rem;
height: 1.5rem;
animation: spin 1s linear infinite;
:deep(svg) {
left: 2rem;
width: 1.5rem;
height: 1.5rem;
fill: var(--color-contrast);
}
}
</style>