1
0
Fork 0
mirror of https://github.com/VueTorrent/VueTorrent.git synced 2025-05-03 13:55:05 +03:00
This commit is contained in:
Daan Wijns 2021-01-23 11:59:02 +01:00 committed by GitHub
parent 9ec4b09b28
commit c3dfddf12f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 1546 additions and 1227 deletions

View file

@ -19,10 +19,9 @@
v-model="files"
color="deep-purple accent-4"
counter
label="File input"
label="Select your files"
multiple
placeholder="Select your files"
prepend-icon="mdi-paperclip"
:prepend-icon="mdiPaperclip"
:rules="fileInputRules"
outlined
:show-size="1000"
@ -55,7 +54,7 @@
v-if="files.length == 0"
v-model="urls"
label="URL"
prepend-icon="mdi-link"
:prepend-icon="mdiLink"
rows="1"
required
:autofocus="!phoneLayout"
@ -71,7 +70,7 @@
:items="availableCategories"
clearable
label="Category"
prepend-icon="tag"
:prepend-icon="mdiTag"
@input="categoryChanged"
/>
@ -79,7 +78,9 @@
v-model="directory"
:disabled="autoTMM"
label="Download Directory"
prepend-icon="folder"
:prepend-icon="mdiFolder"
autocomplete="download-directory"
name="download-directory"
/>
<v-row no-gutters>
<v-flex xs12 sm6>
@ -117,7 +118,7 @@
<v-btn
text
:disabled="!valid"
class="blue_accent white--text mx-0 mt-3"
class="accent white--text mx-0 mt-3"
@click="submit"
>
Add Torrent
@ -133,6 +134,7 @@
import { mapGetters } from 'vuex'
import Modal from '@/mixins/Modal'
import qbit from '@/services/qbit'
import { mdiFolder, mdiTag, mdiPaperclip, mdiLink } from '@mdi/js'
export default {
name: 'AddModal',
mixins: [Modal],
@ -158,7 +160,8 @@ export default {
],
loading: false,
urls: null,
valid: false
valid: false,
mdiFolder, mdiTag, mdiPaperclip, mdiLink
}
},
computed: {

View file

@ -27,14 +27,14 @@
</v-btn>
<v-btn
text
class="green_accent white--text mt-3"
class="accent white--text mt-3"
@click="deleteWithoutFiles()"
>
Delete
</v-btn>
<v-btn
text
class="green_accent white--text mt-3"
class="accent white--text mt-3"
@click="deleteWithFiles()"
>
Delete with files

View file

@ -1,7 +1,7 @@
<template>
<div>
<v-btn @click="opened = true">
<v-icon>mdi-cog</v-icon> Plugin manager
<v-icon>{{ mdiCog }}</v-icon> Plugin manager
</v-btn>
<v-bottom-sheet
@ -12,7 +12,7 @@
>
<v-sheet>
<v-card>
<v-card-title> <v-icon>mdi-toy-brick</v-icon> Plugin manager </v-card-title>
<v-card-title> <v-icon>{{ mdiToyBrick }}</v-icon> Plugin manager </v-card-title>
<v-card-text>
<v-switch
v-for="(plugin, key) in searchPlugins"
@ -27,7 +27,7 @@
</v-bottom-sheet>
<v-dialog v-else v-model="opened" width="50%">
<v-card>
<v-card-title> <v-icon>mdi-toy-brick</v-icon> Plugin manager </v-card-title>
<v-card-title> <v-icon>{{ mdiToyBrick }}</v-icon> Plugin manager </v-card-title>
<v-card-text>
<v-switch
v-for="(plugin, key) in searchPlugins"
@ -45,10 +45,12 @@
<script>
import { mapState } from 'vuex'
import qbit from '@/services/qbit'
import { mdiCog, mdiToyBrick } from '@mdi/js'
export default {
name: 'PluginsManager',
data: () => ({
opened: false
opened: false,
mdiCog, mdiToyBrick
}),
computed: {
...mapState(['searchPlugins'])

View file

@ -16,10 +16,10 @@
v-model="searchForm.valid"
>
<v-container fluid>
<v-flex row class="col-12 col-sm-6 col-md-8 mx-auto">
<v-flex row class="mx-auto">
<v-text-field
v-model="searchForm.pattern"
prepend-inner-icon="mdi-magnify"
:prepend-inner-icon="mdiMagnify"
label="Search"
:rules="[v => !!v || 'Searchterm is required']"
clearable
@ -58,7 +58,7 @@
</template>
<template #[`item.actions`]="{ item }">
<v-icon @click="downloadTorrent(item)">
mdi-download
{{ mdiDownload }}
</v-icon>
</template>
</v-data-table>
@ -76,7 +76,7 @@
right
@click="close"
>
<v-icon>close</v-icon>
<v-icon>{{ mdiClose }}</v-icon>
</v-btn>
</v-fab-transition>
</v-card>
@ -88,6 +88,7 @@ import { mapGetters } from 'vuex'
import qbit from '@/services/qbit'
import { Modal, FullScreenModal, General } from '@/mixins'
import PluginManager from './PluginManager'
import { mdiClose, mdiMagnify, mdiDownload } from '@mdi/js'
export default {
name: 'SearchModal',
@ -115,7 +116,8 @@ export default {
searchForm: {
valid: false,
pattern: ''
}
},
mdiClose, mdiMagnify, mdiDownload
}
},
computed: {

View file

@ -68,7 +68,7 @@
right
@click="close"
>
<v-icon>close</v-icon>
<v-icon>{{ mdiClose }}</v-icon>
</v-btn>
</v-fab-transition>
</v-card-actions>
@ -78,6 +78,7 @@
<script>
import { Modal, FullScreenModal, SettingsTab } from '@/mixins'
import { mdiClose } from '@mdi/js'
import {
WebUI,
BitTorrent,
@ -94,7 +95,8 @@ export default {
return {
tab: null,
items: [],
peers: []
peers: [],
mdiClose
}
},
created() {

View file

@ -2,7 +2,7 @@
<v-container>
<v-card flat>
<perfect-scrollbar>
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-card-text class="pa-1" :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<h3>Privacy</h3>
<div class="settings_content ml-5 mr-5">
<v-checkbox
@ -155,5 +155,5 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
</style>
@import '~@/styles/SettingsTab.scss';
</style>

View file

@ -2,7 +2,7 @@
<v-container>
<v-card flat>
<perfect-scrollbar>
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-card-text class="pa-1" :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<h3>When adding a torrent</h3>
<div class="settings_content ml-5 mr-5">
<v-checkbox
@ -55,7 +55,7 @@
</v-col>
</v-row>
<v-row dense>
<v-col cols="5">
<v-col cols="12" md="5">
<v-checkbox
v-model="settings.temp_path_enabled"
dense
@ -90,5 +90,5 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
@import '~@/styles/SettingsTab.scss';
</style>

View file

@ -1,88 +1,105 @@
<template>
<v-container>
<v-card flat>
<v-card-text
class="mx-auto mt-5"
style="font-size: 1.1em;"
:style="{ minHeight: phoneLayout ? '' : '64vh'}"
>
<v-layout row wrap>
<v-flex class="mx-auto text-center" xs12 md6>
<div>
<h3>Available Tags:</h3>
</div>
<div class="mt-3 d-flex flex-wrap justify-center">
<v-chip
v-for="tag in availableTags"
:key="tag"
small
class="download white--text caption mx-2 my-1"
style="font-size: 0.95em !important"
>
{{ tag }}
</v-chip>
</div>
<v-card-actions class="justify-center pb-5">
<v-btn
text
class="error white--text mt-3"
@click="deleteTag"
>
Delete
</v-btn>
<v-btn
text
class="green_accent white--text mt-3"
@click="createTag"
>
Create new
</v-btn>
</v-card-actions>
</v-flex>
<v-flex class="mx-auto text-center" xs12 md6>
<div>
<h3>Available Categories:</h3>
</div>
<div class="d-flex flex-wrap mt-3 justify-center" xs12 sm12>
<v-chip
v-for="cat in availableCategories"
:key="cat.name"
small
class="upload white--text caption mx-2 my-1"
style="font-size: 0.95em !important"
@click="editCategory(cat)"
@click:close="editCategory(cat)"
>
{{ cat.name }}
</v-chip>
</div>
<v-card-actions class="justify-center pb-5">
<v-btn
text
class="error white--text mt-3"
@click="deleteCategory"
>
Delete
</v-btn>
<v-btn
text
class="green_accent white--text mt-3"
@click="createCategory"
>
Create new
</v-btn>
</v-card-actions>
</v-flex>
</v-layout>
</v-card-text>
<perfect-scrollbar>
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-layout row wrap>
<v-flex class="mx-auto" xs12 md6>
<v-card flat class="ma-1">
<v-card-title>
<h3 class="mx-auto">
Available Tags:
</h3>
</v-card-title>
<v-card-text>
<v-list>
<template v-for="(item, index) in availableTags">
<v-list-item :key="item.title">
<v-list-item-content>
<v-list-item-title v-text="item" />
</v-list-item-content>
<v-list-item-action>
<v-icon color="red" @click="deleteTag(item)">
{{ mdiDelete }}
</v-icon>
</v-list-item-action>
</v-list-item>
<v-divider
v-if="index < availableTags.length - 1"
:key="index"
/>
</template>
</v-list>
</v-card-text>
<v-card-actions>
<v-btn
text
class="accent white--text mx-auto"
@click="createTag"
>
Create new
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
<v-flex class="mx-auto" xs12 md6>
<v-card flat class="ma-1">
<v-card-title>
<h3 class="mx-auto">
Available Categories:
</h3>
</v-card-title>
<v-card-text>
<v-list>
<template v-for="(item, index) in availableCategories">
<v-list-item :key="item.title">
<v-list-item-content>
<v-list-item-title v-text="item.name" />
</v-list-item-content>
<v-list-item-action>
<v-icon @click="editCategory(item)">
{{ mdiPencil }}
</v-icon>
</v-list-item-action>
<v-list-item-action>
<v-icon color="red" @click="deleteCategory(item)">
{{ mdiDelete }}
</v-icon>
</v-list-item-action>
</v-list-item>
<v-divider
v-if="index < availableCategories.length - 1"
:key="index"
/>
</template>
</v-list>
</v-card-text>
<v-card-actions>
<v-btn
text
class="accent white--text mx-auto"
@click="createCategory"
>
Create new
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-card-text>
</perfect-scrollbar>
</v-card>
</v-container>
</template>
<script>
import { mapGetters } from 'vuex'
import qbit from '@/services/qbit'
import { mdiDelete, mdiPencil } from '@mdi/js'
import { Tab, General, FullScreenModal } from '@/mixins'
@ -93,11 +110,12 @@ export default {
hash: String
},
data: () => ({
selectedCategory: null
selectedCategory: null,
mdiDelete,
mdiPencil
}),
computed: {
...mapGetters(['getTorrent', 'getAvailableTags', 'getCategories']),
availableTags() {
return this.getAvailableTags()
},
@ -110,14 +128,10 @@ export default {
},
methods: {
activeMethod() {
this.fetchCategories()
this.$store.commit('FETCH_CATEGORIES')
},
async fetchCategories() {
const { data } = await qbit.getCategories()
this.categories = data
},
deleteTag() {
this.createModal('DeleteTagDialog')
deleteTag(item) {
qbit.deleteTag(item)
},
createTag() {
this.createModal('CreateTagDialog')
@ -125,8 +139,9 @@ export default {
createCategory() {
this.createModal('CreateCategoryDialog')
},
deleteCategory() {
this.createModal('DeleteCategoryDialog')
deleteCategory(category) {
qbit.deleteCategory(category.name)
this.$store.commit('FETCH_CATEGORIES')
},
editCategory(cat) {
this.createModal('CreateCategoryDialog', { initialCategory: cat })
@ -135,6 +150,3 @@ export default {
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
</style>

View file

@ -1,7 +1,7 @@
<template>
<v-card flat>
<perfect-scrollbar>
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-card-text class="pa-1" :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-tabs v-model="tab">
<v-tab href="#general">
General

View file

@ -86,5 +86,5 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
</style>
@import '~@/styles/SettingsTab.scss';
</style>

View file

@ -1,19 +1,19 @@
<template>
<v-container class="mx-1 px-1">
<v-card flat>
<v-card-text class="pa-0" style="font-size: 1.1em">
<v-card-text class="pa-0 px-1" style="font-size: 1.1em">
<div class="box">
<v-subheader>
These settings are for the custom WebUI
itself
</v-subheader>
<v-form class="px-6 mt-3">
<v-form class="px-4 mt-3">
<v-container>
<v-switch
v-model="showCurrentSpeed"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Current Speed
@ -23,7 +23,7 @@
v-model="showSpeedGraph"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Speed Graph
@ -33,7 +33,7 @@
v-model="showSessionStat"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Session Stats
@ -43,37 +43,17 @@
v-model="freeSpace"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Free Space
</template>
</v-switch>
<v-switch
v-model="showGlobalRemoveResumePause"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
>
<template #label>
Global Remove/Resume/Pause Buttons
</template>
</v-switch>
<v-switch
v-model="denseDashboard"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
>
<template #label>
Dense version of the dashboard
</template>
</v-switch>
<v-switch
v-model="showTrackerFilter"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Tracker Filter
@ -83,12 +63,22 @@
v-model="showSpeedInTitle"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
>
<template #label>
Show Speed in Title
</template>
</v-switch>
<v-switch
v-model="useDeviceDarkMode"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="accent"
>
<template #label>
Use device dark/light mode
</template>
</v-switch>
<v-row dense>
<v-col cols="8" sm="8" md="10">
<p class="subtitle-1">
@ -99,7 +89,7 @@
<v-select
v-model="paginationSize"
class="pa-0 ma-0"
color="green_accent"
color="accent"
:items="paginationSizes"
/>
</v-col>
@ -184,22 +174,6 @@ export default {
this.webuiSettings.showSessionStat = val
}
},
showGlobalRemoveResumePause: {
get() {
return this.webuiSettings.showGlobalRemoveResumePause
},
set(val) {
this.webuiSettings.showGlobalRemoveResumePause = val
}
},
denseDashboard: {
get() {
return this.webuiSettings.denseDashboard
},
set(val) {
this.webuiSettings.denseDashboard = val
}
},
showTrackerFilter: {
get() {
return this.webuiSettings.showTrackerFilter
@ -208,6 +182,14 @@ export default {
this.webuiSettings.showTrackerFilter = val
}
},
useDeviceDarkMode: {
get() {
return this.webuiSettings.useDeviceDarkMode
},
set(val) {
this.webuiSettings.useDeviceDarkMode = val
}
},
showSpeedInTitle: {
get() {
return this.webuiSettings.showSpeedInTitle
@ -241,10 +223,6 @@ export default {
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
</style>
<style lang="scss" scoped>
// Reversed input variant
::v-deep .v-input--reverse .v-input__slot {
@ -264,3 +242,7 @@ export default {
}
}
</style>
<style lang="scss" scoped>
@import '~@/styles/SettingsTab.scss';
</style>

View file

@ -25,11 +25,11 @@
</div>
</div>
<div class="box">
<v-subheader>
<v-subheader class="pb-4">
Web User Interface (Remote Control)
</v-subheader>
<v-row class="ml-5 mr-5">
<v-col cols="10">
<v-row class="ml-5 mr-5 pb-4">
<v-col cols="9" class="pa-0">
<v-text-field
v-model="settings.web_ui_address"
class="mr-1"
@ -39,7 +39,7 @@
:label="`IP Address:`"
/>
</v-col>
<v-col>
<v-col cols="3" class="pa-0">
<v-text-field
v-model="settings.web_ui_port"
class="ml-1"
@ -66,5 +66,5 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/styles/SettingsTab.scss';
@import '~@/styles/SettingsTab.scss';
</style>

View file

@ -18,14 +18,13 @@
item-value="value"
dense
solo
background-color="select"
height="55"
/>
<v-switch
v-model="sort_options.reverse"
class="v-input--reverse v-input--expand pa-0 ma-0"
inset
color="green_accent"
color="accent"
style="padding-left: 10px !important"
>
<template #label>

View file

@ -16,6 +16,7 @@
:counter="15"
label="Category name"
required
:disabled="hasInitialCategory"
/>
<v-text-field
v-model="category.savePath"
@ -40,7 +41,7 @@
<v-btn
v-if="!hasInitialCategory"
text
class="green_accent white--text mt-3"
class="accent white--text mt-3"
@click="create"
>
Save
@ -48,7 +49,7 @@
<v-btn
v-else
text
class="green_accent white--text mt-3"
class="accent white--text mt-3"
@click="edit"
>
Edit
@ -86,10 +87,8 @@ export default {
computed: {
...mapGetters(['getSelectedCategory']),
hasInitialCategory() {
return (
this.initialCategory &&
this.initialCategory.name
)
return !!(this.initialCategory &&
this.initialCategory.name)
}
},
created() {
@ -104,9 +103,6 @@ export default {
this.cancel()
},
cancel() {
this.category.name = ''
this.category.savePath = ''
this.$refs.categoryForm.reset()
this.$store.commit('FETCH_CATEGORIES')
this.deleteModal()
},

View file

@ -30,7 +30,7 @@
</v-btn>
<v-btn
text
class="green_accent white--text mt-3"
class="accent white--text mt-3"
@click="create"
>
Save
@ -59,7 +59,6 @@ export default {
this.cancel()
},
cancel() {
this.tagname = ''
this.deleteModal()
}
}

View file

@ -1,74 +0,0 @@
<template>
<v-dialog :value="dialog" max-width="600px">
<v-card>
<v-container style="min-height: 200px" :class="`pa-0 project done`">
<v-card-title class="justify-center">
<h2>Delete Category</h2>
</v-card-title>
<v-list
v-if="categories"
rounded
class="text-center mx-auto"
style="max-width: 200px"
>
<v-list-item
v-for="(t, i) in categories"
:key="i"
@click="deleteCategory(t)"
>
<v-list-item-content>
<v-list-item-title
v-text="t.name"
/>
</v-list-item-content>
</v-list-item>
</v-list>
<v-card-subtitle
v-else
class="text-center mx-auto"
style="font-size: 1.5em; margin-top: 20px"
>
No categories found
</v-card-subtitle>
</v-container>
<v-card-actions class="justify-center pb-5 project done">
<v-btn
text
class="error white--text mt-3"
@click="cancel"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import qbit from '@/services/qbit'
import { Modal } from '@/mixins'
import { mapGetters } from 'vuex'
export default {
name: 'DeleteCategoryDialog',
mixins: [Modal],
computed: {
...mapGetters(['getCategories']),
categories() {
return this.getCategories()
}
},
methods: {
deleteCategory(cat) {
qbit.deleteCategory(cat.name)
this.cancel()
},
cancel() {
this.$store.commit('FETCH_CATEGORIES')
this.deleteModal()
}
}
}
</script>
<style></style>

View file

@ -1,71 +0,0 @@
<template>
<v-dialog v-model="dialog" max-width="600px">
<v-card>
<v-container style="min-height: 200px" :class="`pa-0 project done`">
<v-card-title class="justify-center">
<h2>Delete Tag</h2>
</v-card-title>
<v-list
v-if="availableTags && availableTags.length"
rounded
class="text-center mx-auto"
style="max-width: 200px"
>
<v-list-item
v-for="(t, i) in availableTags"
:key="i"
@click="deleteTag(t)"
>
<v-list-item-content>
<v-list-item-title v-text="t" />
</v-list-item-content>
</v-list-item>
</v-list>
<v-card-subtitle
v-else
class="text-center mx-auto"
style="font-size: 1.5em; margin-top: 20px"
>
No tags found
</v-card-subtitle>
</v-container>
<v-card-actions class="justify-center pb-5 project done">
<v-btn
text
class="error white--text mt-3"
@click="cancel"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import qbit from '@/services/qbit'
import { Modal } from '@/mixins'
import { mapGetters } from 'vuex'
export default {
name: 'DeleteTagDialog',
mixins: [Modal],
computed: {
...mapGetters(['getTorrent', 'getAvailableTags']),
availableTags() {
return this.getAvailableTags()
}
},
methods: {
deleteTag(tag) {
qbit.deleteTag(tag)
this.cancel()
},
cancel() {
this.deleteModal()
}
}
}
</script>
<style></style>

View file

@ -1,11 +1,7 @@
import CreateNewTagDialog from './CreateTagDialog.vue'
import DeleteTagDialog from './DeleteTagDialog.vue'
import CreateNewCategoryDialog from './CreateCategoryDialog.vue'
import DeleteCategoryDialog from './DeleteCategoryDialog'
export {
CreateNewTagDialog,
DeleteTagDialog,
CreateNewCategoryDialog,
DeleteCategoryDialog
CreateNewCategoryDialog
}

View file

@ -13,7 +13,7 @@
>
<template #prepend="{ item, open }">
<v-icon v-if="!item.icon">
{{ open ? "mdi-folder-open" : "mdi-folder" }}
{{ open ? mdiFolderOpen : mdiFolderOpen }}
</v-icon>
<v-icon v-else>
{{ item.icon }}
@ -44,7 +44,7 @@
fab
v-on="on"
>
<v-icon>trending_up</v-icon>
<v-icon>{{ mdiTrendingUp }}</v-icon>
</v-btn>
</template>
<v-list dense rounded>
@ -69,7 +69,7 @@
fab
@click="edit(item)"
>
<v-icon>mdi-pencil</v-icon>
<v-icon>{{ mdiPencil }}</v-icon>
</v-btn>
<v-btn
v-if="item.editing"
@ -78,7 +78,7 @@
fab
@click="renameFile(item)"
>
<v-icon>save</v-icon>
<v-icon>{{ mdiContentSave }}</v-icon>
</v-btn>
<v-btn
v-if="item.editing"
@ -87,7 +87,7 @@
fab
@click="togleEditing(item)"
>
<v-icon>close</v-icon>
<v-icon>{{ mdiClose }}</v-icon>
</v-btn>
</div>
</template>
@ -101,12 +101,17 @@
import qbit from '@/services/qbit'
import { treeify } from '@/helpers'
import { FullScreenModal } from '@/mixins'
import {
mdiClose, mdiContentSave, mdiPencil, mdiFolderOpen,
mdiFolder, mdiFile, mdiTrendingUp, mdiPriorityHigh,
mdiArrowUp, mdiArrowDown, mdiPriorityLow
} from '@mdi/js'
const FILE_PRIORITY_OPTIONS = [
{ name: 'max', icon: 'upgrade', value: 7 },
{ name: 'high', icon: 'arrow_drop_up', value: 6 },
{ name: 'normal', icon: 'trending_flat', value: 1 },
{ name: 'unwanted', icon: 'file_download_off', value: 0 }
{ name: 'max', icon: mdiPriorityHigh, value: 7 },
{ name: 'high', icon: mdiArrowUp, value: 6 },
{ name: 'normal', icon: mdiArrowDown, value: 1 },
{ name: 'unwanted', icon: mdiPriorityLow, value: 0 }
]
export default {
@ -129,7 +134,14 @@ export default {
opened: null,
selected: [],
treeData: null,
priority_options: FILE_PRIORITY_OPTIONS
priority_options: FILE_PRIORITY_OPTIONS,
mdiFolderOpen,
mdiFolder,
mdiFile,
mdiTrendingUp,
mdiPencil,
mdiContentSave,
mdiClose
}
},
computed: {

View file

@ -127,7 +127,7 @@ export default {
}
</style>
<style lang="scss" scoped>
@import "~@/assets/styles.scss";
@import "~@/styles/colors.scss";
::v-deep .v-data-table thead th,
::v-deep .v-data-table tbody td {

View file

@ -1,116 +1,70 @@
<template>
<v-card flat>
<v-card-text
class="mx-auto mt-4"
style="font-size: 1.1em"
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
>
<v-row>
<v-col
:cols="12"
:lg="6"
:md="6"
:sm="12"
>
<v-layout class="mx-auto" row wrap>
<v-flex xs12 sm12>
<h3>Available Tags:</h3>
</v-flex>
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
<v-chip
v-for="tag in availableTags"
:key="tag"
small
class="download white--text caption mx-2 my-1"
style="font-size: 0.95em !important"
@click="addTag(tag)"
>
{{ tag }}
</v-chip>
</v-flex>
</v-layout>
<v-layout class="mx-auto mt-12" row wrap>
<v-flex xs12 sm12>
<h3>Current Tags:</h3>
</v-flex>
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
<div v-if="torrent.tags">
<v-chip
v-for="tag in torrent.tags"
:key="tag"
small
close
class="download white--text caption mx-2 my-1"
style="font-size: 0.95em !important"
@click="deleteTag(tag)"
@click:close="deleteTag(tag)"
<perfect-scrollbar>
<v-card-text :style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh'}">
<v-layout class="mx-auto" row wrap>
<v-flex xs12 sm12 md6>
<v-card flat class="ma-1">
<v-card-title>
<h3 class="mx-auto">
Available Tags:
</h3>
</v-card-title>
<v-card-text>
<v-list-item-group
:value="activeTags"
active-class="accent--text"
multiple
>
{{ tag }}
</v-chip>
</div>
<div v-else>
None
</div>
</v-flex>
</v-layout>
</v-col>
<v-col
:cols="12"
:lg="6"
:md="6"
:sm="12"
>
<v-layout
class="mx-auto"
:class="this.$vuetify.breakpoint.smAndDown ? 'mt-12' : ''"
row
wrap
>
<v-flex xs12 sm12>
<h3>Available Categories:</h3>
</v-flex>
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
<v-chip
v-for="cat in availableCategories"
:key="cat.name"
small
class="upload white--text caption mx-2 my-1"
style="font-size: 0.95em !important"
@click="setCategory(cat.name)"
>
{{ cat.name }}
</v-chip>
</v-flex>
</v-layout>
<v-layout class="mx-auto mt-12" row wrap>
<v-flex xs12 sm12>
<h3>Current Category:</h3>
</v-flex>
<v-flex class="mt-3 d-flex justify-center" xs12 sm12>
<v-chip
v-if="torrent.category"
small
close
class="upload white--text caption mx-2"
style="font-size: 0.95em !important"
@click="deleteCategory"
@click:close="deleteCategory"
>
{{ torrent.category }}
</v-chip>
<div v-else>
None
</div>
</v-flex>
</v-layout>
</v-col>
</v-row>
</v-card-text>
<template v-for="(item, index) in availableTags">
<v-list-item :key="item" @click="addTag(item)">
<v-list-item-content>
<v-list-item-title v-text="item" />
</v-list-item-content>
</v-list-item>
<v-divider
v-if="index < availableTags.length - 1"
:key="index"
/>
</template>
</v-list-item-group>
</v-card-text>
</v-card>
</v-flex>
<v-flex xs12 sm12 md6>
<v-card flat class="ma-1">
<v-card-title>
<h3 class="mx-auto">
Available Categories:
</h3>
</v-card-title>
<v-card-text>
<v-list-item-group
:value="activeCategory"
active-class="accent--text"
>
<template v-for="(item, index) in availableCategories">
<v-list-item :key="item.title" @click="setCategory(item)">
<v-list-item-content>
<v-list-item-title v-text="item.name" />
</v-list-item-content>
</v-list-item>
<v-divider
v-if="index < availableCategories.length - 1"
:key="index"
/>
</template>
</v-list-item-group>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-card-text>
</perfect-scrollbar>
</v-card>
</template>
<script>
import { difference } from 'lodash'
import { mapGetters } from 'vuex'
import qbit from '@/services/qbit'
import { FullScreenModal } from '@/mixins'
@ -130,13 +84,25 @@ export default {
return this.getTorrent(this.hash)
},
availableTags() {
const availableTags = this.getAvailableTags()
const currentTags = this.getTorrent(this.hash).tags
return difference(availableTags, currentTags)
return this.getAvailableTags()
},
availableCategories() {
return this.getCategories()
},
activeCategory() {
return this.availableCategories.map(el => el.name).indexOf(this.torrent.category)
},
activeTags() {
const active = []
const tags = this.torrent.tags
if (tags && tags.length) {
tags.forEach(t => {
const index = this.availableTags.indexOf(t)
if (index !== -1) active.push(index)
})
}
return active
}
},
created() {
@ -144,16 +110,22 @@ export default {
},
methods: {
addTag(tag) {
if (this.activeTags.includes(this.availableTags.indexOf(tag))) {
return this.deleteTag(tag)
}
qbit.addTorrentTag(this.hash, tag)
},
deleteTag(tag) {
qbit.removeTorrentTag(this.hash, tag)
},
setCategory(cat) {
qbit.setCategory(this.hash, cat)
if (this.torrent.category === cat.name) {
return qbit.setCategory([this.hash], '')
}
qbit.setCategory([this.hash], cat.name)
},
deleteCategory() {
qbit.setCategory(this.hash, '')
qbit.setCategory([this.hash], '')
}
}
}

View file

@ -1,26 +1,93 @@
<template>
<perfect-scrollbar>
<v-data-table
v-if="trackers"
:headers="headers"
:items="trackers"
:hide-default-footer="true"
:style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh'}"
>
<template #item="row">
<tr>
<td>{{ row.item.tier }}</td>
<td>{{ row.item.url }}</td>
<td>{{ row.item.status | formatTrackerStatus }}</td>
<td>{{ row.item.num_peers | formatTrackerNum }}</td>
<td>{{ row.item.num_seeds | formatTrackerNum }}</td>
<td>{{ row.item.num_leeches | formatTrackerNum }}</td>
<td>{{ row.item.num_downloaded | formatTrackerNum }}</td>
<td>{{ row.item.msg }}</td>
</tr>
</template>
</v-data-table>
</perfect-scrollbar>
<v-card
flat
:style="{ minHeight: phoneLayout ? '' : '75vh', maxHeight: '75vh' }"
>
<v-card-text class="pa-0">
<perfect-scrollbar>
<v-data-table
v-if="trackers"
v-model="selectedTrackers"
show-select
:headers="headers"
:items="trackers"
item-key="url"
:style="{ minHeight: phoneLayout ? '' : '70vh', maxHeight: '70vh' }"
>
<template #body="{ items }">
<tbody>
<tr v-for="item in items" :key="item.url">
<td>
<v-checkbox
v-if="typeof item.tier === 'number'"
v-model="selectedTrackers"
:value="item"
class="pa-0 mb-0"
color="accent"
/>
</td>
<td>{{ item.tier }}</td>
<td>{{ item.url }}</td>
<td>{{ item.status | formatTrackerStatus }}</td>
<td>{{ item.num_peers | formatTrackerNum }}</td>
<td>{{ item.num_seeds | formatTrackerNum }}</td>
<td>{{ item.num_leeches | formatTrackerNum }}</td>
<td>{{ item.num_downloaded | formatTrackerNum }}</td>
<td>{{ item.msg }}</td>
</tr>
</tbody>
</template>
</v-data-table>
</perfect-scrollbar>
</v-card-text>
<v-card-actions class="justify-center">
<v-btn
class="error mx-2"
dark
@click="DeleteTrackers"
>
Delete
</v-btn>
<v-dialog v-model="dialog" persistent max-width="290">
<template #activator="{ on, attrs }">
<v-btn
color="accent"
dark
v-bind="attrs"
v-on="on"
>
Add
</v-btn>
</template>
<v-card>
<v-card-title class="justify-center">
Add Trackers
</v-card-title>
<v-card-text>
<v-textarea
v-model="newTrackers"
label="Trackers"
rows="1"
required
autofocus
auto-grow
clearable
hint="One link per line"
/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn color="red darken-1" text @click="addTrackers">
Cancel
</v-btn>
<v-btn color="green darken-1" text @click="addTrackers">
Add
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-card-actions>
</v-card>
</template>
<script>
@ -61,11 +128,14 @@ export default {
{ text: 'Downloaded', value: 'num_downloaded' },
{ text: 'Message', value: 'msg' }
],
tempTrackers: []
tempTrackers: [],
dialog: false,
newTrackers: '',
selectedTrackers: []
}),
computed: {
trackers() {
return this.tempTrackers
return this.tempTrackers.map(x => ({ ...x, isSelectable: typeof x.tier === 'number' }))
}
},
watch: {
@ -82,13 +152,27 @@ export default {
async getTorrentTrackers() {
const { data } = await qbit.getTorrentTrackers(this.hash)
this.tempTrackers = data
},
async addTrackers() {
if (!this.newTrackers.length) return (this.dialog = false)
qbit.addTorrenTrackers(this.hash, this.newTrackers)
this.newTrackers = ''
await this.getTorrentTrackers()
this.dialog = false
},
async DeleteTrackers() {
if (!this.selectedTrackers.length) return
qbit.removeTorrentTrackers(this.hash, this.selectedTrackers.map(t => t.url))
this.selectedTrackers = []
await this.getTorrentTrackers()
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/assets/styles.scss";
@import "~@/styles/colors.scss";
::v-deep .v-data-table thead th,
::v-deep .v-data-table tbody td {

View file

@ -73,7 +73,7 @@
right
@click="close"
>
<v-icon>close</v-icon>
<v-icon>{{ mdiClose }}</v-icon>
</v-btn>
</v-fab-transition>
</v-card>
@ -82,9 +82,9 @@
<script>
import { mapGetters } from 'vuex'
import { Modal, FullScreenModal } from '@/mixins'
import { Content, Info, Peers, Trackers, TagsAndCategories } from './Tabs'
import { mdiClose } from '@mdi/js'
export default {
name: 'TorrentDetailModal',
@ -97,7 +97,8 @@ export default {
return {
tab: null,
items: [{ tab: 'Info' }, { tab: 'Content' }],
peers: []
peers: [],
mdiClose
}
},
computed: {