FEATURE - New settings modal (#24)

Co-authored-by: Tyler Mayoff <tyler@tylermayoff.com>
This commit is contained in:
Daan Wijns 2020-08-27 19:33:32 +02:00 committed by GitHub
parent a00a6d539e
commit 9463d83752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 566 additions and 30 deletions

View file

@ -42,6 +42,8 @@ The sleekest looking WEBUI for qBittorrent made with Vuejs!
- searching for new torrents straight from the WEBUI! - searching for new torrents straight from the WEBUI!
- changing the most common settings
* works on QBittorrent V4.2 and later * works on QBittorrent V4.2 and later
### Sorting/Filtring ### Sorting/Filtring

View file

@ -1,6 +1,6 @@
{ {
"name": "vuetorrent", "name": "vuetorrent",
"version": "0.1.2", "version": "0.1.3",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",

View file

@ -0,0 +1,103 @@
<template>
<v-dialog
v-model="dialog"
scrollable
:width="dialogWidth"
:fullscreen="phoneLayout"
>
<v-card style="min-height: 400px; overflow: hidden !important">
<div :style="{ height: phoneLayout ? '100vh' : '' }">
<v-card-title class="pb-0 justify-center primary">
<h2 class="white--text">Settings</h2>
</v-card-title>
<v-tabs v-model="tab" background-color="primary" center-active>
<v-tab href="#downloads">Downloads</v-tab>
<v-tab href="#bittorrent">BitTorrent</v-tab>
<v-tab href="#webui">WebUI</v-tab>
<v-tab href="#vuetorrent">VueTorrent</v-tab>
</v-tabs>
<perfect-scrollbar>
<v-tabs-items
v-model="tab"
touchless
:style="{ maxHeight: dialogHeight }"
>
<v-tab-item value="webui">
<WebUI :is-active="tab === 'webui'" />
</v-tab-item>
<v-tab-item value="bittorrent">
<BitTorrent :is-active="tab === 'bittorrent'" />
</v-tab-item>
<v-tab-item value="downloads">
<Downloads :is-active="tab === 'downloads'" />
</v-tab-item>
<v-tab-item value="vuetorrent">
<VueTorrent :is-active="tab === 'vuetorrent'" />
</v-tab-item>
</v-tabs-items>
</perfect-scrollbar>
</div>
<v-card-actions class="d-flex justify-center">
<v-btn color="success" @click="save_settings">Save</v-btn>
<v-fab-transition v-if="phoneLayout">
<v-btn
@click="close"
color="red"
dark
absolute
bottom
right
>
<v-icon>close</v-icon>
</v-btn>
</v-fab-transition>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import Vue from 'vue'
import { mapGetters } from 'vuex'
import qbit from '@/services/qbit'
import { Modal, FullScreenModal } from '@/mixins'
import { WebUI, BitTorrent, Downloads, VueTorrent } from './Tabs'
export default {
name: 'SettingsModal',
mixins: [Modal, FullScreenModal],
components: { WebUI, BitTorrent, Downloads, VueTorrent },
data() {
return {
tab: null,
items: [],
peers: []
}
},
methods: {
close() {
this.$store.commit('TOGGLE_MODAL', 'SettingsModal')
},
save_settings() {
qbit.setPreferences(this.getSettings()).then(() => {
Vue.$toast.success('Settings saved successfully!')
})
}
},
computed: {
...mapGetters(['getSettings']),
dialogWidth() {
return this.phoneLayout ? '100%' : '750px'
},
dialogHeight() {
return this.phoneLayout ? '79vh' : '70vh'
}
},
watch: {
dialog(visible) {
!visible ? (this.tab = null) : this.$store.commit('SET_SETTINGS')
}
}
}
</script>

View file

@ -0,0 +1,171 @@
<template>
<v-container>
<v-card flat>
<v-card-text>
<h3>Privacy</h3>
<div class="settings_content ml-5 mr-5">
<v-checkbox
dense
:label="`Enable DHT (decentralized network) to find more peers`"
v-model="settings.dht"
/>
<v-checkbox
dense
:label="`Enable Peer Exchange (PeX) to find more peers`"
v-model="settings.pex"
/>
<v-checkbox
dense
:label="`Enable Local Peer Discovery to find more peers`"
v-model="settings.lsd"
/>
<v-checkbox
dense
:label="`Enable anonymous mode`"
v-model="settings.anonymous_mode"
/>
</div>
<v-checkbox
dense
:label="`Torrent Queueing`"
v-model="settings.queueing_enabled"
/>
<div class="settings_content ml-5 mr-5">
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Maximum active downloads`"
:disabled="!settings.queueing_enabled"
v-model="settings.max_active_downloads"
/>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Maximum active uploads`"
:disabled="!settings.queueing_enabled"
v-model="settings.max_active_uploads"
/>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Maximum active torrents`"
:disabled="!settings.queueing_enabled"
v-model="settings.max_active_torrents"
/>
<v-checkbox
dense
:label="`Do not count slow torrents in these limits`"
v-model="settings.dont_count_slow_torrents"
/>
<div class="settings_content">
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Download rate threshold KiB/s`"
:disabled="!settings.dont_count_slow_torrents"
v-model="settings.slow_torrent_dl_rate_threshold"
/>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Upload rate threshold KiB/s`"
:disabled="!settings.dont_count_slow_torrents"
v-model="settings.slow_torrent_ul_rate_threshold"
/>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:label="`Torrent inactivity timer`"
:disabled="!settings.dont_count_slow_torrents"
v-model="settings.slow_torrent_inactive_timer"
/>
</div>
</div>
<h3>Seeding Limits</h3>
<div class="settings_content ml-5 mr-5">
<v-row dense>
<v-col cols="10">
<v-checkbox
dense
:label="`When ratio reaches`"
v-model="settings.max_ratio_enabled"
/>
</v-col>
<v-col>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:disabled="!settings.max_ratio_enabled"
v-model="settings.max_ratio"
/>
</v-col>
</v-row>
<v-row dense>
<v-col cols="10">
<v-checkbox
dense
:label="`When seeding time reaches`"
v-model="settings.max_seeding_time_enabled"
/>
</v-col>
<v-col>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:disabled="!settings.max_seeding_time_enabled"
v-model="settings.max_seeding_time"
/>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
import SettingsTab from '@/mixins/SettingsTab'
export default {
name: 'BitTorrent',
mixins: [SettingsTab]
}
</script>
<style lang="scss" scoped>
.v-input--selection-controls {
padding-top: 0px;
}
.settings_content {
border-left: 2px solid black;
padding-left: 8px;
}
.box {
margin: 2px;
padding: 5px;
border-radius: 4px;
border: 1px solid black;
}
</style>

View file

@ -0,0 +1,101 @@
<template>
<v-container>
<v-card flat>
<v-card-text>
<h3>When adding a torrent</h3>
<div class="settings_content ml-5 mr-5">
<v-checkbox
dense
:label="`Create subfolder for torrents with multiple files`"
v-model="settings.create_subfolder_enabled"
/>
<v-checkbox
dense
:label="`Do not start the download automatically`"
v-model="settings.start_paused_enabled"
/>
<!-- <v-checkbox
dense
:label="`Delete .torrent files afterwards`"
v-model="settings.lsd"
/> -->
</div>
<v-checkbox
dense
:label="`Pre-allocate disk space for all files`"
v-model="settings.preallocate_all"
/>
<v-checkbox
dense
:label="` Append .!qB extension to incomplete files`"
v-model="settings.incomplete_files_ext"
/>
<h3>Saving Management</h3>
<div class="settings_content ml-5 mr-5">
<v-row dense>
<v-col cols="5" class="d-flex align-center">
<h4>Default Save Path</h4>
</v-col>
<v-col>
<v-text-field
class="mb-2"
outlined
dense
hide-details
v-model="settings.save_path"
/>
</v-col>
</v-row>
<v-row dense>
<v-col cols="5">
<v-checkbox
dense
:label="`Keep incomplete torrents in:`"
v-model="settings.temp_path_enabled"
/>
</v-col>
<v-col>
<v-text-field
class="mb-2"
outlined
dense
hide-details
:disabled="!settings.temp_path_enabled"
v-model="settings.temp_path"
/>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
import SettingsTab from '@/mixins/SettingsTab'
export default {
name: 'BitTorrent',
mixins: [SettingsTab]
}
</script>
<style lang="scss" scoped>
.v-input--selection-controls {
padding-top: 0px;
}
.settings_content {
border-left: 2px solid black;
padding-left: 8px;
}
.box {
margin: 2px;
padding: 5px;
border-radius: 4px;
border: 1px solid black;
}
</style>

View file

@ -0,0 +1,68 @@
<template>
<v-container>
<v-card flat>
<v-card-text class="pa-0" 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-container>
<v-switch
class="v-input--reverse v-input--expand"
inset
v-model="freeSpace"
color="green_accent"
>
<template #label>
<span class="grey--text">
Show Free Space
</span>
</template>
</v-switch>
</v-container>
</v-form>
</div>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'VueTorrent',
computed: {
...mapState(['webuiSettings']),
freeSpace: {
get() {
return this.webuiSettings.showFreeSpace
},
set(val) {
this.webuiSettings.showFreeSpace = val
}
}
}
}
</script>
<style lang="scss" scoped>
// Reversed input variant
::v-deep .v-input--reverse .v-input__slot {
flex-direction: row-reverse;
justify-content: flex-end;
.v-application--is-ltr & {
.v-input--selection-controls__input {
margin-right: 0;
margin-left: 8px;
}
}
.v-application--is-rtl & {
.v-input--selection-controls__input {
margin-left: 0;
margin-right: 8px;
}
}
}
</style>

View file

@ -0,0 +1,71 @@
<template>
<v-container>
<v-card flat>
<v-card-text class="pa-0" style="font-size: 1.1em">
<div class="box">
<v-subheader>Use Alternative WebUI</v-subheader>
<div class="ml-5 mr-5">
<v-checkbox
dense
:label="`Use Alternative WebUI`"
v-model="settings.alternative_webui_enabled"
/>
<v-text-field
outlined
dense
hide-details="true"
:label="`Files location`"
:disabled="!settings.alternative_webui_enabled"
v-model="settings.alternative_webui_path"
/>
</div>
</div>
<div class="box">
<v-subheader
>Web User Interface (Remote Control)</v-subheader
>
<v-row class="ml-5 mr-5">
<v-col cols="10">
<v-text-field
class="mr-1"
outlined
dense
hide-details="true"
:label="`IP Address:`"
v-model="settings.web_ui_address"
/>
</v-col>
<v-col>
<v-text-field
class="ml-1"
outlined
dense
hide-details="true"
:label="`Port`"
v-model="settings.web_ui_port"
/>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
import SettingsTab from '@/mixins/SettingsTab'
export default {
name: 'WebUI',
mixins: [SettingsTab]
}
</script>
<style lang="scss" scoped>
.box {
margin: 2px;
padding: 5px;
border-radius: 4px;
border: 1px solid black;
}
</style>

View file

@ -0,0 +1,6 @@
import WebUI from '@/components/Modals/SettingsModal/Tabs/WebUI.vue'
import BitTorrent from '@/components/Modals/SettingsModal/Tabs/BitTorrent.vue'
import Downloads from '@/components/Modals/SettingsModal/Tabs/Downloads.vue'
import VueTorrent from '@/components/Modals/SettingsModal/Tabs/VueTorrent.vue'
export { WebUI, BitTorrent, Downloads, VueTorrent }

View file

@ -219,11 +219,9 @@ export default {
.v-chip.queued { .v-chip.queued {
background: #2e5eaa !important; background: #2e5eaa !important;
} }
.noselect { .noselect {
-webkit-touch-callout: none; /* iOS Safari */ -webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */ -webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */ -moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */ -ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently user-select: none; /* Non-prefixed version, currently

View file

@ -6,7 +6,7 @@
:items="peers" :items="peers"
:items-per-page="-1" :items-per-page="-1"
:hide-default-footer="true" :hide-default-footer="true"
style="max-height: 500px; min-height: 400px;" style="max-height: 500px; min-height: 400px"
> >
<template v-slot:item="row"> <template v-slot:item="row">
<tr> <tr>
@ -45,7 +45,6 @@
<script> <script>
import { map, merge, cloneDeep } from 'lodash' import { map, merge, cloneDeep } from 'lodash'
import qbit from '@/services/qbit' import qbit from '@/services/qbit'
// eslint-disable-next-line no-unused-vars
import { codeToFlag, isWindows } from '@/helpers' import { codeToFlag, isWindows } from '@/helpers'
export default { export default {

View file

@ -0,0 +1,7 @@
import Content from '@/components/TorrentDetailModal/Tabs/Content'
import Info from '@/components/TorrentDetailModal/Tabs/Info'
import Peers from '@/components/TorrentDetailModal/Tabs/Peers'
import Trackers from '@/components/TorrentDetailModal/Tabs/Trackers'
import Tags from '@/components/TorrentDetailModal/Tabs/Tags'
export { Content, Info, Peers, Trackers, Tags }

View file

@ -7,7 +7,7 @@
> >
<v-card <v-card
v-if="torrent" v-if="torrent"
style="min-height: 400px; overflow: hidden !important;" style="min-height: 400px; overflow: hidden !important"
> >
<div <div
:class="`pa-0 project ${torrent.state}`" :class="`pa-0 project ${torrent.state}`"
@ -54,19 +54,14 @@
</template> </template>
<script> <script>
/* eslint-disable vue/no-unused-components */
import Modal from '@/mixins/Modal'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Content from '@/components/TorrentDetailModal/Content' import { Modal, FullScreenModal } from '@/mixins'
import Info from '@/components/TorrentDetailModal/Info' import { Content, Info, Peers, Trackers, Tags } from './Tabs'
import Peers from '@/components/TorrentDetailModal/Peers'
import Trackers from '@/components/TorrentDetailModal/Trackers'
import Tags from '@/components/TorrentDetailModal/Tags'
export default { export default {
name: 'TorrentDetailModal', name: 'TorrentDetailModal',
mixins: [Modal], mixins: [Modal, FullScreenModal],
components: { Content, Info, Peers, Trackers, Tags }, components: { Content, Info, Peers, Trackers, Tags },
data() { data() {
return { return {
@ -87,19 +82,6 @@ export default {
}, },
torrent() { torrent() {
return this.getTorrent(this.hash) return this.getTorrent(this.hash)
},
phoneLayout() {
return this.$vuetify.breakpoint.xsOnly
},
dialogWidth() {
return this.phoneLayout ? '100%' : '80%'
}
},
watch: {
dialog(visible) {
if (!visible) {
this.tab = null
}
} }
} }
} }

View file

@ -0,0 +1,17 @@
export default {
computed: {
phoneLayout() {
return this.$vuetify.breakpoint.xsOnly
},
dialogWidth() {
return this.phoneLayout ? '100%' : '80%'
}
},
watch: {
dialog(visible) {
if (!visible) {
this.tab = null
}
}
}
}

View file

@ -0,0 +1,9 @@
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['getSettings']),
settings() {
return this.getSettings()
}
}
}

5
src/mixins/index.js Normal file
View file

@ -0,0 +1,5 @@
import FullScreenModal from '@/mixins/FullScreenModal'
import Modal from '@/mixins/Modal'
import SettingsTab from '@/mixins/SettingsTab'
export { FullScreenModal, Modal, SettingsTab }

View file

@ -53,9 +53,6 @@ export default {
SET_SETTINGS: async state => { SET_SETTINGS: async state => {
const { data } = await qbit.getAppPreferences() const { data } = await qbit.getAppPreferences()
state.settings = data state.settings = data
// state.settings.savePath = data.save_path
// state.settings.alternative_webui_enabled = data.alternative_webui_enabled
// state.settings.alternative_webui_path = data.alternative_webui_path
}, },
SET_SELECTED_TORRENT_DETAIL: (state, hash) => { SET_SELECTED_TORRENT_DETAIL: (state, hash) => {
state.selectedDetailTorrent = hash state.selectedDetailTorrent = hash