refactor(upload): [WIP] rebuild upload modal functionality

This commit is contained in:
upsiflu 2025-02-03 14:38:18 +01:00
parent 5a39323e11
commit a23996bbdd
3 changed files with 93 additions and 146 deletions

View File

@ -40,6 +40,7 @@ const fetchData = async () => {
} }
}) })
console.log("I found another album with artist", props.channel?.artist.name, ":", response.data.results)
albums.push(...response.data.results) albums.push(...response.data.results)
isLoading.value = false isLoading.value = false
} }
@ -57,6 +58,7 @@ watch(() => props.channel, fetchData, { immediate: true })
{{ t('components.channels.AlbumSelect.label.album') }} {{ t('components.channels.AlbumSelect.label.album') }}
</span> </span>
</label> </label>
{{ albums }}
<select <select
id="album-dropdown" id="album-dropdown"
v-model="value" v-model="value"

View File

@ -89,7 +89,7 @@ const fetchChannels = async () => {
availableChannels.loading = false availableChannels.loading = false
} }
const selectedChannel = computed(() => availableChannels.channels.find((channel) => channel.uuid === values.channel) ?? null) const selectedChannel = computed(() => availableChannels.channels[0])
// //
// Quota and space // Quota and space
@ -302,49 +302,6 @@ const retry = async (file: VueUploadItem) => {
fetchChannels() fetchChannels()
fetchQuota() fetchQuota()
//
// Dropdown
//
const el = useCurrentElement()
watch(() => availableChannels.channels, () => {
$(el.value).find('#channel-dropdown').dropdown({
onChange (value) {
values.channel = value
},
values: availableChannels.channels.map((channel) => {
const value = {
name: channel.artist?.name ?? '',
value: channel.uuid,
selected: props.channel?.uuid === channel.uuid
} as {
name: string
value: string
selected: boolean
image?: string
imageClass?: string
icon?: string
iconClass?: string
}
if (channel.artist?.cover?.urls.medium_square_crop) {
value.image = store.getters['instance/absoluteUrl'](channel.artist.cover.urls.medium_square_crop)
value.imageClass = channel.artist.content_category !== 'podcast'
? 'ui image avatar'
: 'ui image'
} else {
value.icon = 'user'
value.iconClass = channel.artist?.content_category !== 'podcast'
? 'circular icon'
: 'bordered icon'
}
return value
})
})
$(el.value).find('#channel-dropdown').dropdown('hide')
})
// //
// Step // Step
// //
@ -454,15 +411,8 @@ defineExpose({
</div> </div>
<div :class="['ui', 'required', {hidden: step > 1}, 'field']"> <div :class="['ui', 'required', {hidden: step > 1}, 'field']">
<label for="channel-dropdown"> <label for="channel-dropdown">
{{ t('components.channels.UploadForm.label.channel') }} {{ t('components.channels.UploadForm.label.channel') }}: {{ selectedChannel?.artist.name }}
</label> </label>
<div
id="channel-dropdown"
class="ui search normal selection dropdown"
>
<div class="text" />
<i class="dropdown icon" />
</div>
</div> </div>
<album-select <album-select
v-model.number="values.album" v-model.number="values.album"

View File

@ -18,6 +18,7 @@ import FileUploadWidget from '~/components/library/FileUploadWidget.vue';
import type { VueUploadItem } from 'vue-upload-component'; import type { VueUploadItem } from 'vue-upload-component';
import ChannelUpload from '~/components/channels/UploadForm.vue'; import ChannelUpload from '~/components/channels/UploadForm.vue';
import LibraryUpload from '~/components/library/FileUpload.vue'; import LibraryUpload from '~/components/library/FileUpload.vue';
import LibraryWidget from '~/components/federation/LibraryWidget.vue'
const { t } = useI18n() const { t } = useI18n()
const store = useStore() const store = useStore()
@ -29,40 +30,23 @@ const isOpen = computed({
return store.state.ui.modalsOpen.has(modalName); return store.state.ui.modalsOpen.has(modalName);
}, },
set(value) { set(value) {
store.commit('ui/setModal', [modalName, value]); if (value===false) {
state.value = init()
}
store.commit('ui/setModal', [modalName, value])
} }
}) })
onKeyboardShortcut('u', () => store.commit('ui/toggleModal', modalName)) onKeyboardShortcut('u', () => store.commit('ui/toggleModal', modalName))
const dummyActor = (number:number) : Actor => ({
id: number,
summary: "actor summary",
preferred_username: `actor ${number}`,
full_username: "actor full username",
is_local: false,
domain: "domain"
})
const dummyChannel=(number:number) : Channel=>
({
id : number,
uuid : 'uuid',
actor: dummyActor(number),
attributed_to: dummyActor(number),
rss_url: "rss url string",
subscriptions_count: 10,
downloads_count: 10,
content_category: 'music'
})
type UploadDestination = 'channel' | 'library' | 'podcast' type UploadDestination = 'channel' | 'library' | 'podcast'
type State = type State =
{ uploadDestination? : UploadDestination, page: typeof pages[number], files?: string[] } { uploadDestination? : UploadDestination, page: typeof pages[number], files?: string[] }
// initial state // initial state
const state = ref<State>({page : 'selectDestination'}); const init = () => ({ page : 'selectDestination' } as const)
const state = ref<State>(init())
const pages = ['selectDestination', 'uploadFiles', 'uploadsInProgress'] as const const pages = ['selectDestination', 'uploadFiles', 'uploadsInProgress'] as const
@ -70,6 +54,20 @@ const pages = ['selectDestination', 'uploadFiles', 'uploadsInProgress'] as const
const destinationSelected = (destination: UploadDestination) => const destinationSelected = (destination: UploadDestination) =>
state.value = {...state.value, uploadDestination:destination, page:'uploadFiles' } state.value = {...state.value, uploadDestination:destination, page:'uploadFiles' }
// Wait for pablo: If no channel exists, auto-create an empty channel
// Step 1.1
/*
- Load the library for the chosen privacy level
-
*/
// Lade User
const url="`federation/actors/${object.full_username}/libraries/`"
//
// Step 2 // Step 2
const filesSelected = (e: InputEvent)=>{ const filesSelected = (e: InputEvent)=>{
state.value = {...state.value, files: [] } state.value = {...state.value, files: [] }
@ -79,18 +77,6 @@ const modalTitle = computed(()=>
({ 'selectDestination' : 'Upload', 'uploadFiles' : 'Select files for upload', 'uploadsInProgress': 'Uploading...'} ({ 'selectDestination' : 'Upload', 'uploadFiles' : 'Select files for upload', 'uploadsInProgress': 'Uploading...'}
[state.value.page]) [state.value.page])
) )
// Upload input metadata
const values = reactive({
channel: null,
license: null,
album: null
})
const channels = [0,1,2,3,4].map(dummyChannel)
</script> </script>
<template> <template>
@ -98,83 +84,92 @@ const channels = [0,1,2,3,4].map(dummyChannel)
:title="modalTitle" :title="modalTitle"
v-model="isOpen" v-model="isOpen"
> >
<!-- Alert -->
<template #alert v-if="state.page === 'selectDestination'"> <template #alert v-if="state.page === 'selectDestination'">
<Alert yellow> <Alert blue>
Before uploading, please ensure your files are tagged properly. Before uploading, please ensure your files are tagged properly.
We recommend using Picard for that purpose. We recommend using Picard for that purpose.
</Alert> </Alert>
</template> </template>
<Layout flex style="place-content:center" v-if="state.page === 'selectDestination'"> <!-- Page content -->
<Card small solid secondary title="Music" <!-- Page 1 -->
@click="destinationSelected('channel')"
icon="bi-upload primary solid"
>
<template #image>
<i class="bi bi-music-note-beamed solid primary" :class="$style.icon"></i>
</template>
Publish music you make
</Card>
<Card small solid secondary title="Podcast"
@click="destinationSelected('podcast')"
icon="bi-upload primary solid"
>
<template #image>
<i class="bi bi-mic-fill solid primary" :class="$style.icon"></i>
</template>
Publish podcasts you make
</Card>
<Card small solid secondary title="Mix & Share"
@click="destinationSelected('library')"
icon="bi-upload"
>
<template #image>
<i class="bi bi-headphones solid secondary raised" :class="$style.icon"></i>
</template>
Host music you listen to
</Card>
</Layout>
<Layout stack v-if="state.page === 'uploadFiles'"> <Layout flex style="place-content:center" v-if="state.page === 'selectDestination'">
UPLOAD FILES <Card small title="Music"
<!-- <Input icon="bi-upload primary solid"
type="file" @click="destinationSelected('channel')"
:accept="['.flac', '.ogg', '.opus', '.mp3', '.aac', '.aif', '.aiff', '.m4a'].join(', ')" >
multiple <template #image>
auto-reset <i class="bi bi-music-note-beamed solid primary" :class="$style.icon"></i>
@input="filesSelected" </template>
/> --> {{ "Publish music you make" /* TODO: Translate */ }}
</Card>
<Card small title="Podcast"
icon="bi-upload primary solid"
@click="destinationSelected('podcast')"
>
<template #image>
<i class="bi bi-mic-fill solid primary" :class="$style.icon"></i>
</template>
{{ "Publish podcasts you make" /* TODO: Translate */ }}
</Card>
<Card small title="Mix & Share"
icon="bi-upload"
@click="destinationSelected('library')"
>
<template #image>
<i class="bi bi-headphones solid secondary raised" :class="$style.icon"></i>
</template>
{{ "Host music you listen to" /* TODO: Translate */ }}
</Card>
</Layout>
<!-- <UploadForm></UploadForm> --> <!-- Page 2 -->
<LibraryUpload v-if="state.uploadDestination==='library'"
:library="{uuid: 'string'}">
</LibraryUpload>
{{ state.files }}
<ChannelUpload v-if="state.uploadDestination==='channel'" /> <Layout stack v-if="state.page === 'uploadFiles'">
</Layout>
<!-- -->
<ChannelUpload v-if="state.uploadDestination === 'channel'" />
<!-- -->
<!-- Privacy Slider -->
<LibraryUpload v-if="state.uploadDestination === 'library'"
:library="{uuid: 'string'} /* Get corresponding library from user */">
</LibraryUpload>
{{ state.files }}
</Layout>
<template #actions> <template #actions>
<Button secondary> <Button secondary
Cancel v-if="state.page !== pages[0]"
:onClick="() => { state.page = pages[(pages.indexOf(state.page) || 1) - 1] }">
{{ t('components.channels.UploadModal.button.previous') }}
</Button> </Button>
<Button disabled v-if="state.page === 'selectDestination'"> <Spacer h grow />
Continue in background' : 'Save and close' <Button secondary :onClick="() => { isOpen = false }">
{{ t('components.channels.UploadModal.button.cancel') }}
</Button> </Button>
<Spacer size-16 />
<Button primary v-if="state.page === 'uploadFiles'"> <Button primary v-if="state.page === 'uploadFiles'">
Continue in background' : 'Save and close' {{ t('components.channels.UploadModal.button.finishLater') }} /
{{ t('components.channels.UploadModal.button.publish') }} /
{{ t('components.channels.UploadModal.button.update') }}
</Button> </Button>
</template> </template>
</Modal> </Modal>
</template> </template>
<style module> <style module>
.icon { .icon {
font-size:100px; font-size:100px;
padding:28px; padding:28px;
inset:0; inset:0;
display:block; display:block;
text-align: center; text-align: center;
} }
</style> </style>