Add:iOS audio player

This commit is contained in:
advplyr
2021-12-31 16:57:53 -06:00
parent 4496b1170c
commit 4bf75c606a
24 changed files with 467 additions and 129 deletions
+6 -2
View File
@@ -15,7 +15,8 @@
<h3 v-if="series" class="font-book text-gray-300 text-lg leading-7">{{ seriesText }}</h3>
<p class="text-sm text-gray-400">by {{ author }}</p>
<p v-if="numTracks" class="text-gray-300 text-sm my-1">
{{ $elapsedPretty(duration) }}<span class="px-4">{{ $bytesPretty(size) }}</span>
{{ $elapsedPretty(duration) }}
<span class="px-4">{{ $bytesPretty(size) }}</span>
</p>
<div v-if="progressPercent > 0" class="px-4 py-2 bg-primary text-sm font-semibold rounded-md text-gray-200 mt-4 relative" :class="resettingProgress ? 'opacity-25' : ''">
@@ -35,7 +36,7 @@
<span class="material-icons">auto_stories</span>
<span v-if="!showPlay" class="px-2 text-base">Read {{ ebookFormat }}</span>
</ui-btn>
<ui-btn v-if="isConnected && showPlay" color="primary" class="flex items-center justify-center" :padding-x="2" @click="downloadClick">
<ui-btn v-if="isConnected && showPlay && !isIos" color="primary" class="flex items-center justify-center" :padding-x="2" @click="downloadClick">
<span class="material-icons" :class="downloadObj ? 'animate-pulse' : ''">{{ downloadObj ? (isDownloading || isDownloadPreparing ? 'downloading' : 'download_done') : 'download' }}</span>
</ui-btn>
</div>
@@ -84,6 +85,9 @@ export default {
}
},
computed: {
isIos() {
return this.$platform === 'ios'
},
isConnected() {
return this.$store.state.socketConnected
},
+3 -1
View File
@@ -7,7 +7,7 @@
<!-- <div v-if="isLoading" class="absolute top-0 left-0 w-full h-full flex items-center justify-center">
<ui-loading-indicator />
</div> -->
</div>-->
</div>
</div>
</template>
@@ -27,11 +27,13 @@ export default {
<style>
.main-content {
height: calc(100% - 72px);
max-height: calc(100% - 72px);
min-height: calc(100% - 72px);
max-width: 100vw;
}
.main-content.home-page {
height: calc(100% - 36px);
max-height: calc(100% - 36px);
min-height: calc(100% - 36px);
}
+11 -6
View File
@@ -1,5 +1,5 @@
<template>
<div class="w-full h-full">
<div class="w-full h-full min-h-full relative">
<template v-for="(shelf, index) in shelves">
<bookshelf-shelf :key="shelf.id" :label="shelf.label" :entities="shelf.entities" :type="shelf.type" :style="{ zIndex: shelves.length - index }" />
</template>
@@ -7,19 +7,24 @@
<div v-if="!shelves.length" class="absolute top-0 left-0 w-full h-full flex items-center justify-center">
<div>
<p class="mb-4 text-center text-xl">
Bookshelf empty<span v-show="isSocketConnected">
for library <strong>{{ currentLibraryName }}</strong></span
>
Bookshelf empty
<span v-show="isSocketConnected">
for library
<strong>{{ currentLibraryName }}</strong>
</span>
</p>
<div class="w-full" v-if="!isSocketConnected">
<div class="flex justify-center items-center mb-3">
<span class="material-icons text-error text-lg">cloud_off</span>
<p class="pl-2 text-error text-sm">Audiobookshelf server not connected.</p>
</div>
<p class="px-4 text-center text-error absolute bottom-12 left-0 right-0 mx-auto"><strong>Important!</strong> This app requires that you are running <u>your own server</u> and does not provide any content.</p>
<p class="px-4 text-center text-error absolute bottom-12 left-0 right-0 mx-auto">
<strong>Important!</strong> This app requires that you are running
<u>your own server</u> and does not provide any content.
</p>
</div>
<div class="flex justify-center">
<ui-btn v-if="!isSocketConnected" small @click="$router.push('/connect')" class="w-32"> Connect </ui-btn>
<ui-btn v-if="!isSocketConnected" small @click="$router.push('/connect')" class="w-32">Connect</ui-btn>
</div>
</div>
</div>
+84 -76
View File
@@ -2,91 +2,96 @@
<div class="w-full h-full py-6">
<h1 class="text-2xl px-4">Downloads</h1>
<div class="w-full px-2 py-2" :class="hasStoragePermission ? '' : 'text-error'">
<div class="flex items-center">
<span class="material-icons" @click="changeDownloadFolderClick">{{ hasStoragePermission ? 'folder' : 'error' }}</span>
<p v-if="hasStoragePermission" class="text-sm px-4" @click="changeDownloadFolderClick">{{ downloadFolderSimplePath || 'No Download Folder Selected' }}</p>
<p v-else class="text-sm px-4" @click="changeDownloadFolderClick">No Storage Permissions. Click here</p>
</div>
<!-- <p v-if="hasStoragePermission" class="text-xs text-gray-400 break-all max-w-full">{{ downloadFolderUri }}</p> -->
<template v-if="isIos"></template>
</div>
</template>
<template v-else>
<div class="w-full px-2 py-2" :class="hasStoragePermission ? '' : 'text-error'">
<div class="flex items-center">
<span class="material-icons" @click="changeDownloadFolderClick">{{ hasStoragePermission ? 'folder' : 'error' }}</span>
<p v-if="hasStoragePermission" class="text-sm px-4" @click="changeDownloadFolderClick">{{ downloadFolderSimplePath || 'No Download Folder Selected' }}</p>
<p v-else class="text-sm px-4" @click="changeDownloadFolderClick">No Storage Permissions. Click here</p>
</div>
<!-- <p v-if="hasStoragePermission" class="text-xs text-gray-400 break-all max-w-full">{{ downloadFolderUri }}</p> -->
</div>
<div class="w-full h-10 relative">
<div class="absolute top-px left-0 z-10 w-full h-full flex">
<div class="flex-grow h-full bg-primary rounded-t-md mr-px" @click="showingDownloads = true">
<div class="flex items-center justify-center rounded-t-md border-t border-l border-r border-white border-opacity-20 h-full" :class="showingDownloads ? 'text-gray-100' : 'border-b bg-black bg-opacity-20 text-gray-400'">
<p>Downloads</p>
</div>
<div class="w-full h-10 relative">
<div class="absolute top-px left-0 z-10 w-full h-full flex">
<div class="flex-grow h-full bg-primary rounded-t-md mr-px" @click="showingDownloads = true">
<div class="flex items-center justify-center rounded-t-md border-t border-l border-r border-white border-opacity-20 h-full" :class="showingDownloads ? 'text-gray-100' : 'border-b bg-black bg-opacity-20 text-gray-400'">
<p>Downloads</p>
</div>
<div class="flex-grow h-full bg-primary rounded-t-md ml-px" @click="showingDownloads = false">
<div class="flex items-center justify-center h-full rounded-t-md border-t border-l border-r border-white border-opacity-20" :class="!showingDownloads ? 'text-gray-100' : 'border-b bg-black bg-opacity-20 text-gray-400'">
<p>Files</p>
</div>
</div>
<div class="flex-grow h-full bg-primary rounded-t-md ml-px" @click="showingDownloads = false">
<div class="flex items-center justify-center h-full rounded-t-md border-t border-l border-r border-white border-opacity-20" :class="!showingDownloads ? 'text-gray-100' : 'border-b bg-black bg-opacity-20 text-gray-400'">
<p>Files</p>
</div>
</div>
</div>
<div class="list-content-body relative w-full overflow-x-hidden bg-primary">
<template v-if="showingDownloads">
<div v-if="!totalDownloads" class="flex items-center justify-center h-40">
<p>No Downloads</p>
</div>
<ul v-else class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
<template v-for="download in downloadsDownloading">
<li :key="download.id" class="text-gray-400 select-none relative px-4 py-5 border-b border-white border-opacity-10 bg-black bg-opacity-10">
<div class="flex items-center justify-center">
<div class="w-3/4">
<span class="text-xs">({{ downloadingProgress[download.id] || 0 }}%) {{ download.isPreparing ? 'Preparing' : 'Downloading' }}...</span>
<p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p>
</div>
<div class="flex-grow" />
</div>
<div class="list-content-body relative w-full overflow-x-hidden bg-primary">
<template v-if="showingDownloads">
<div v-if="!totalDownloads" class="flex items-center justify-center h-40">
<p>No Downloads</p>
</div>
<ul v-else class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
<template v-for="download in downloadsDownloading">
<li :key="download.id" class="text-gray-400 select-none relative px-4 py-5 border-b border-white border-opacity-10 bg-black bg-opacity-10">
<div class="flex items-center justify-center">
<div class="w-3/4">
<span class="text-xs">({{ downloadingProgress[download.id] || 0 }}%) {{ download.isPreparing ? 'Preparing' : 'Downloading' }}...</span>
<p class="font-normal truncate text-sm">{{ download.audiobook.book.title }}</p>
</div>
<div class="flex-grow" />
<div class="shadow-sm text-white flex items-center justify-center rounded-full animate-spin">
<span class="material-icons">refresh</span>
</div>
<div class="shadow-sm text-white flex items-center justify-center rounded-full animate-spin">
<span class="material-icons">refresh</span>
</div>
</li>
</template>
<template v-for="download in downloadsReady">
<li :key="download.id" class="text-gray-50 select-none relative pr-4 pl-2 py-5 border-b border-white border-opacity-10" @click="jumpToAudiobook(download)">
<modals-downloads-download-item :download="download" @play="playDownload" @delete="clickDeleteDownload" />
</li>
</template>
</ul>
</template>
<template v-else>
<div class="w-full h-full">
<div class="w-full flex justify-around py-4 px-2">
<ui-btn small @click="searchFolder">Re-Scan</ui-btn>
<ui-btn small @click="changeDownloadFolderClick">Change Folder</ui-btn>
<ui-btn small color="error" @click="resetFolder">Reset</ui-btn>
</div>
<p v-if="isScanning" class="text-center my-8">Scanning Folder..</p>
<p v-else-if="!mediaScanResults" class="text-center my-8">No Files Found</p>
<template v-else>
<template v-for="mediaFolder in mediaScanResults.folders">
<div :key="mediaFolder.uri" class="w-full px-2 py-2">
<div class="flex items-center">
<span class="material-icons text-base text-white text-opacity-50">folder</span>
<p class="ml-1 py-0.5">{{ mediaFolder.name }}</p>
</div>
<div v-for="mediaFile in mediaFolder.files" :key="mediaFile.uri" class="ml-3 flex items-center">
<span class="material-icons text-base text-white text-opacity-50">{{ mediaFile.isAudio ? 'music_note' : 'image' }}</span>
<p class="ml-1 py-0.5">{{ mediaFile.name }}</p>
</div>
</div>
</template>
<template v-for="mediaFile in mediaScanResults.files">
<div :key="mediaFile.uri" class="w-full px-2 py-2">
<div class="flex items-center">
<span class="material-icons text-base text-white text-opacity-50">{{ mediaFile.isAudio ? 'music_note' : 'image' }}</span>
<p class="ml-1 py-0.5">{{ mediaFile.name }}</p>
</div>
</div>
</template>
</template>
</div>
</li>
</template>
<template v-for="download in downloadsReady">
<li :key="download.id" class="text-gray-50 select-none relative pr-4 pl-2 py-5 border-b border-white border-opacity-10" @click="jumpToAudiobook(download)">
<modals-downloads-download-item :download="download" @play="playDownload" @delete="clickDeleteDownload" />
</li>
</template>
</ul>
</template>
<template v-else>
<div class="w-full h-full">
<div class="w-full flex justify-around py-4 px-2">
<ui-btn small @click="searchFolder">Re-Scan</ui-btn>
<ui-btn small @click="changeDownloadFolderClick">Change Folder</ui-btn>
<ui-btn small color="error" @click="resetFolder">Reset</ui-btn>
</div>
</template>
</div>
<p v-if="isScanning" class="text-center my-8">Scanning Folder..</p>
<p v-else-if="!mediaScanResults" class="text-center my-8">No Files Found</p>
<template v-else>
<template v-for="mediaFolder in mediaScanResults.folders">
<div :key="mediaFolder.uri" class="w-full px-2 py-2">
<div class="flex items-center">
<span class="material-icons text-base text-white text-opacity-50">folder</span>
<p class="ml-1 py-0.5">{{ mediaFolder.name }}</p>
</div>
<div v-for="mediaFile in mediaFolder.files" :key="mediaFile.uri" class="ml-3 flex items-center">
<span class="material-icons text-base text-white text-opacity-50">{{ mediaFile.isAudio ? 'music_note' : 'image' }}</span>
<p class="ml-1 py-0.5">{{ mediaFile.name }}</p>
</div>
</div>
</template>
<template v-for="mediaFile in mediaScanResults.files">
<div :key="mediaFile.uri" class="w-full px-2 py-2">
<div class="flex items-center">
<span class="material-icons text-base text-white text-opacity-50">{{ mediaFile.isAudio ? 'music_note' : 'image' }}</span>
<p class="ml-1 py-0.5">{{ mediaFile.name }}</p>
</div>
</div>
</template>
</template>
</div>
</template>
</div>
</template>
</div>
</template>
@@ -105,6 +110,9 @@ export default {
}
},
computed: {
isIos() {
return this.$platform === 'ios'
},
isSocketConnected() {
return this.$store.state.socketConnected
},