Browse Source

A lot of changes.

tags/v1.5.0-rc2.2
Ivan Bravo Bravo 1 month ago
parent
commit
3c2edfb33f
90 changed files with 3535 additions and 2027 deletions
  1. 1
    1
      src/.env-cmdrc.js
  2. 51
    85
      src/.eslintrc.js
  3. 10
    20
      src/assets/css/components/_box.scss
  4. 37
    50
      src/assets/css/components/_button.scss
  5. 5
    5
      src/assets/css/components/_container.scss
  6. 19
    7
      src/assets/css/components/_form.scss
  7. 3
    11
      src/assets/css/reset/_base.scss
  8. 4
    4
      src/assets/css/reset/_libs.scss
  9. 0
    0
      src/components/Form/FormInlineField.vue
  10. 0
    4
      src/components/Form/index.js
  11. 0
    0
      src/components/Help/HelpLesson.vue
  12. 0
    4
      src/components/Help/index.js
  13. 33
    45
      src/components/Layout/Menubar.vue
  14. 26
    104
      src/components/Layout/Navbar.vue
  15. 110
    15
      src/components/Layout/Titlebar.vue
  16. 0
    9
      src/components/Layout/index.js
  17. 70
    0
      src/components/Nudify/NudifyMaskPhoto.vue
  18. 0
    0
      src/components/Nudify/NudifyPhotoRun.vue
  19. 0
    0
      src/components/Nudify/NudifyUpload.vue
  20. 0
    6
      src/components/Nudity/index.js
  21. 21
    22
      src/components/Page/PageHeader.vue
  22. 0
    4
      src/components/Page/index.js
  23. 6
    11
      src/components/Queue/QueueBar.vue
  24. 39
    38
      src/components/Queue/QueuePhoto.vue
  25. 0
    15
      src/components/Queue/index.js
  26. 42
    23
      src/components/Settings/Preference.vue
  27. 163
    0
      src/components/Settings/SettingsField.vue
  28. 51
    125
      src/components/Settings/SettingsPreferences.vue
  29. 0
    17
      src/components/Settings/index.js
  30. 135
    0
      src/components/UI/AppAds.vue
  31. 1
    1
      src/components/UI/AppPhoto.vue
  32. 104
    0
      src/components/UI/AppStats.vue
  33. 26
    0
      src/components/UI/AppTip.vue
  34. 14
    30
      src/components/UI/AppUpdate.vue
  35. 6
    11
      src/components/UI/BoxItem.vue
  36. 33
    32
      src/components/UI/MenuItem.vue
  37. 0
    26
      src/components/UI/index.js
  38. 0
    8
      src/components/index.js
  39. 34
    8
      src/electron/src/index.js
  40. 21
    1
      src/electron/src/modules/tools/paths.js
  41. 70
    31
      src/layouts/default.vue
  42. 17
    0
      src/mixins/BaseMixin.js
  43. 12
    10
      src/mixins/VModel.js
  44. 5
    5
      src/modules/config/help.yml
  45. 241
    0
      src/modules/config/settings.yml
  46. 2
    2
      src/modules/file.js
  47. 2
    9
      src/modules/help.js
  48. 6
    4
      src/modules/nudify/nudify.js
  49. 35
    0
      src/modules/nudify/photo-mask.js
  50. 64
    45
      src/modules/nudify/photo-run.js
  51. 213
    96
      src/modules/nudify/photo.js
  52. 52
    0
      src/modules/projects/checkpoints.js
  53. 47
    0
      src/modules/projects/community.js
  54. 67
    0
      src/modules/projects/dreampower.js
  55. 72
    0
      src/modules/projects/dreamtime.js
  56. 4
    0
      src/modules/projects/index.js
  57. 1
    0
      src/modules/services/dreamtrack.js
  58. 41
    9
      src/modules/system/settings.js
  59. 26
    16
      src/nuxt.config.js
  60. 23
    11
      src/package.json
  61. 1
    1
      src/package.min.json
  62. 49
    344
      src/pages/about.vue
  63. 55
    0
      src/pages/about/developers.vue
  64. 97
    0
      src/pages/about/dreamnet.vue
  65. 72
    0
      src/pages/about/dreampower.vue
  66. 75
    0
      src/pages/about/dreamtime.vue
  67. 140
    0
      src/pages/about/supporters.vue
  68. 7
    12
      src/pages/index.vue
  69. 92
    78
      src/pages/nudify/_id.vue
  70. 36
    93
      src/pages/nudify/_id/crop.vue
  71. 5
    3
      src/pages/nudify/_id/editor.vue
  72. 38
    97
      src/pages/nudify/_id/overlay.vue
  73. 15
    11
      src/pages/nudify/_id/preferences.vue
  74. 152
    0
      src/pages/nudify/_id/results.legacy.vue
  75. 67
    96
      src/pages/nudify/_id/results.vue
  76. 7
    6
      src/pages/settings.vue
  77. 36
    45
      src/pages/settings/app.vue
  78. 36
    36
      src/pages/settings/folders.vue
  79. 14
    39
      src/pages/settings/notifications.vue
  80. 12
    5
      src/pages/settings/preferences.vue
  81. 21
    55
      src/pages/settings/processing.vue
  82. 318
    0
      src/pages/settings/share.vue
  83. 14
    27
      src/pages/settings/telemetry.vue
  84. 13
    0
      src/patches/@adonisjs+websocket-client+1.0.9.patch
  85. 0
    22
      src/patches/tui-image-editor+3.8.0.patch
  86. 22
    0
      src/patches/tui-image-editor+3.9.0.patch
  87. 21
    13
      src/plugins/boot.js
  88. 1
    14
      src/plugins/setup.js
  89. 17
    0
      src/store/app.js
  90. 37
    50
      src/tailwind.config.js

+ 1
- 1
src/.env-cmdrc.js View File

@@ -12,7 +12,7 @@ module.exports = {
"NODE_ENV": "development",
"ROLLBAR_ACCESS_TOKEN": "e62c909ec771492fa7f371dc61eea092",
"LOGROCKET_ACCESS_TOKEN": "of2lox/dreamtime",
"DREAMTRACK_HOST": "track.dreamnet.tech",
"DREAMTRACK_HOST": "localhost:3333",
...development
},
"production": {

+ 51
- 85
src/.eslintrc.js View File

@@ -1,20 +1,10 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
mocha: true,
},
extends: [
'@nuxtjs',
'airbnb-base',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:promise/recommended',
'plugin:lodash/recommended',
'plugin:vue/recommended',
'plugin:nuxt/recommended',
'plugin:mocha/recommended',
],
globals: {
$provider: false,
AppError: false,
@@ -25,37 +15,37 @@ module.exports = {
},
parserOptions: {
parser: 'babel-eslint',
ecmaVersion: 2020,
allowImportExportEverywhere: true,
},
extends: [
'@nuxtjs',
'plugin:nuxt/recommended',
'airbnb-base',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:promise/recommended',
'plugin:lodash/recommended',
'plugin:vue/recommended',
'plugin:mocha/recommended',
],
plugins: [
'nuxt',
'import',
'promise',
'lodash',
'vue',
'mocha',
],
root: true,
rules: {
'no-param-reassign': 'off',
'class-methods-use-this': 'off',
'no-trailing-spaces': 'warn',
'comma-dangle': 'warn',
'global-require': 'off',
'import/default': 'warn',
'import/named': 'error',
'import/no-cycle': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-webpack-loader-syntax': 'off',
'import/order': ['error'],
'import/order': 'error',
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'import/named': 'warn',
'import/no-cycle': 'off',
'promise/no-callback-in-promise': 'off',
'promise/catch-or-return': 'off',
'linebreak-style': 'warn',
'new-parens': 'off',
'lodash/import-scope': [
'off',
'member',
],
'import/no-duplicates': 'off',
'lodash/import-scope': ['error', 'member'],
'lodash/prefer-constant': 'off',
'lodash/prefer-immutable-method': 'warn',
'lodash/prefer-includes': 'warn',
@@ -63,67 +53,43 @@ module.exports = {
'lodash/prefer-lodash-typecheck': 'warn',
'lodash/prefer-noop': 'off',
'lodash/prefer-spread': 'off',
'import/extensions': 'off',
'max-len': 'off',
'func-names': 'off',
'vue/no-v-html': 'off',
'vue/singleline-html-element-content-newline': 'warn',
'vue/html-closing-bracket-newline': ['warn', { multiline: 'never', singleline: 'never' }],
'vue/max-attributes-per-line': ['warn', {
singleline: 3,
multiline: {
max: 1,
allowFirstLine: true,
},
}],
'nuxt/no-cjs-in-config': 'off',
'nuxt/no-globals-in-created': 'off',
'linebreak-style': 'error',
'max-len': ['warn', { code: 120 }],
'no-await-in-loop': 'warn',
'no-console': 'warn',
'no-continue': 'off',
'no-debugger': 'error',
'no-lone-blocks': 'error',
'no-param-reassign': 'off',
'no-restricted-globals': 'warn',
'no-restricted-syntax': 'off',
'no-shadow': 'off',
'no-underscore-dangle': [
'error',
{
allowAfterThis: true,
},
],
'no-unreachable': 'warn',
'no-unused-vars': 'warn',
'no-useless-constructor': 'warn',
'nuxt/no-globals-in-created': 'off',
'object-shorthand': [
'error',
'always',
],
'padded-blocks': [
'error',
'never',
],
'no-trailing-spaces': 'warn',
'no-tabs': 'error',
'no-undef': 'warn',
'no-empty-function': 'warn',
'class-methods-use-this': 'off',
'comma-dangle': 'warn',
'func-names': 'off',
'global-require': 'off',
'prefer-arrow-callback': 'off',
'no-underscore-dangle': ['error', { allowAfterThis: true }],
'object-shorthand': ['error', 'always'],
'padded-blocks': ['error', 'never'],
'prefer-spread': 'off',
'quote-props': [
'error',
'as-needed',
],
quotes: [
'error',
'single',
{
allowTemplateLiterals: true,
},
],
semi: [
'error',
'never',
],
'promise/no-callback-in-promise': 'off',
'quote-props': ['error', 'as-needed'],
'spaced-comment': 'warn',
'vue/html-closing-bracket-newline': [
'warn',
{
multiline: 'never',
singleline: 'never',
},
],
'vue/html-indent': [
'warn',
2,
],
'vue/html-self-closing': 'error',
'vue/no-v-html': 'off',
'vue/singleline-html-element-content-newline': 'warn',
'nuxt/no-cjs-in-config': 'off',
quotes: ['error', 'single'],
semi: ['error', 'never'],
},
settings: {
'import/resolver': {

+ 10
- 20
src/assets/css/components/_box.scss View File

@@ -1,17 +1,17 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

.box {
@apply flex flex-col;
@apply pb-3 bg-dark-500 shadow-lg rounded-lg;
@apply bg-menus shadow-lg rounded;

&:not(:last-child) {
@apply mb-6;
@@ -33,14 +33,14 @@
}

.box__header {
@apply px-6;
@apply px-6 pt-6;

&:not(:first-child) {
@apply pt-3;
}

.title {
@apply font-semibold text-generic-300;
@apply font-serif font-semibold text-lg text-common-light;
}

.subtitle {
@@ -49,31 +49,20 @@
}

.box__content {
@apply flex-1 px-6;

&:not(:first-child) {
@apply pt-3;
}

&:not(:last-child) {
@apply pb-3;
}
@apply flex-1 p-6;

p {
@apply text-sm mb-3;
}

.item {
@apply px-0;
}
}

.box__footer {
@apply px-6 pt-3;
@apply border-t border-dark-400;
@apply px-6 py-3;
@apply border-t border-menus-light;
}
}

/*
.box-section {
@apply px-0 py-2;

@@ -116,3 +105,4 @@
}
}
}
*/

+ 37
- 50
src/assets/css/components/_button.scss View File

@@ -1,44 +1,39 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

.button {
@apply inline-flex items-center justify-center;
@apply border border-primary-500;
@apply px-4 rounded;
@apply text-primary-400 font-semibold uppercase;
@apply px-3 rounded bg-button text-white font-semibold;
@apply outline-none #{!important};
height: 40px;
transition: all 0.2s ease-in-out;

&:hover {
@apply bg-primary-500-20;
}
@include transition('background-color, color');
height: 35px;

&:hover,
&:active {
@apply bg-primary-500-30;
@apply bg-button-dark;
}

&.button--xs {
@apply px-2 text-xs;
height: 21px;
@apply text-xs;
height: 25px;
}

&.button--sm {
@apply px-2 text-sm;
height: 31px;
@apply text-sm;
height: 30px;
}

&.button--xl {
@apply px-6 text-xl;
height: 51px;
height: 45px;
}

&.button--active,
@@ -46,39 +41,39 @@
@apply text-white bg-primary-500;
}

&.button--danger {
@apply text-danger-400 border-danger-500-30;
&.button--primary {
@apply bg-primary text-black;

&:hover {
@apply bg-danger-500-20;
&:hover,
&:active {
@apply bg-primary-dark;
}
}

&.button--danger {
@apply bg-danger text-black;

&:hover,
&:active {
@apply bg-danger-500-30;
@apply bg-danger-dark;
}
}

&.button--success {
@apply text-success-400 border-success-500-30;

&:hover {
@apply bg-success-500-20;
}
@apply bg-success text-black;

&:hover,
&:active {
@apply bg-success-500-30;
@apply bg-success-dark;
}
}

&.button--info {
@apply text-blue-400 border-blue-500-30;

&:hover {
@apply bg-blue-500-20;
}
@apply bg-blue text-black;

&:hover,
&:active {
@apply bg-blue-500-30;
@apply bg-blue-dark;
}
}

@@ -88,25 +83,17 @@
}

.buttons {
@apply flex items-center flex-wrap justify-start;
@apply flex flex-wrap;

&.is-center {
@apply justify-center;
}
.button {
@apply flex-1 rounded-none;

&.is-right {
@apply justify-end;
}

&.is-group {
.button {
&:not(:last-child) {
@apply rounded-r-none;
}
&:first-child {
@apply rounded-l;
}

&:not(:first-child) {
@apply rounded-l-none border-l-0;
}
&:last-child {
@apply rounded-r;
}
}
}

+ 5
- 5
src/assets/css/components/_container.scss View File

@@ -1,15 +1,15 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

.container {
@apply p-6 ml-auto mr-auto;
max-width: 1920px;
}
@apply ml-auto mr-auto;
max-width: 800px;
}

+ 19
- 7
src/assets/css/components/_form.scss View File

@@ -1,11 +1,11 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

@@ -21,22 +21,34 @@
@apply block font-bold mb-2;
}

label[for] {
@apply cursor-pointer;
}

input[type="checkbox"] {
@apply bg-primary;
}

.input {
@apply border border-dark-400 bg-dark-500 text-generic-500;
@apply py-2 px-3 rounded w-full shadow-inner;
@apply border border-input-light bg-input text-common;
@apply p-2 rounded w-full;
@include transition('background-color, color');
outline: none !important;

&:hover, &:focus {
@apply text-white bg-dark-400;
@apply text-white bg-input-light;
}

&::placeholder {
@apply text-generic-900;
@apply text-common-dark;
}

&[disabled] {
@apply opacity-75 text-generic-900 cursor-not-allowed;
@apply opacity-75 cursor-not-allowed;
}

&[readonly] {
@apply text-common-light cursor-default #{!important};
}

&.input--sm {

+ 3
- 11
src/assets/css/reset/_base.scss View File

@@ -1,25 +1,17 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

*,
*:before,
*:after {
box-sizing: border-box;
margin: 0;
}

html {
@apply bg-background text-generic-500 font-sans;
@apply bg-background text-common;
font-size: 16px;
text-size-adjust: 100%;
font-smoothing: antialiased;
}


+ 4
- 4
src/assets/css/reset/_libs.scss View File

@@ -1,11 +1,11 @@
/*
* DreamTime.
* Copyright (C) DreamNet. All rights reserved.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
*
*
* Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2019.
*/

@@ -37,8 +37,8 @@
}

.swal2-container.swal2-backdrop-show {
backdrop-filter: blur(6px);
transition: all 0.1s;
//backdrop-filter: blur(6px);
//transition: all 0.1s;
}

.swal2-footer {

src/components/Form/InlineField.vue → src/components/Form/FormInlineField.vue View File


+ 0
- 4
src/components/Form/index.js View File

@@ -1,4 +0,0 @@
import Vue from 'vue'
import InlineField from './InlineField.vue'

Vue.component('form-inline-field', InlineField)

src/components/Help/Lesson.vue → src/components/Help/HelpLesson.vue View File


+ 0
- 4
src/components/Help/index.js View File

@@ -1,4 +0,0 @@
import Vue from 'vue'
import HelpLesson from './Lesson.vue'

Vue.component('HelpLesson', HelpLesson)

+ 33
- 45
src/components/Layout/Menubar.vue View File

@@ -1,33 +1,14 @@
<template>
<div class="menu">
<section>
<!-- Upload Mode -->
<select
v-model="$settings.app.uploadMode"
v-tooltip="{ content: 'Upload mode. The uploaded photos will be added to the selected section.', placement: 'right' }"
class="input input--menu">
<option value="none">
Pending
</option>
<option value="go-preferences">
Pending -> Preferences
</option>
<option value="add-queue">
Queue
</option>
</select>
</section>

<!-- Custom menu -->
<portal-target name="menu"
class="menu__custom" />

<!-- Random Lesson -->
<section v-if="help.randomLesson">
<HelpLesson :lesson="help.randomLesson"
:small="true"
@click="$router.push('/help')" />
</section>
<div class="menu__content">
<!-- Custom menu -->
<portal-target name="menu" class="menu__custom" />
</div>

<!-- Ads/Lesson -->
<div class="menu__bottom">
<AppAds />
</div>
</div>
</template>

@@ -42,30 +23,37 @@ export default {
</script>

<style lang="scss" scoped>
@keyframes logoAnim {
0% {
background-position: 0% 0%;
}

50% {
background-position: 100% 0%;
}

100% {
background-position: 0% 0%;
}
}

.menu {
@apply flex flex-col;
@apply p-3 bg-dark-500;
@apply bg-menus relative border-r border-menus-light;
grid-area: menu;

section {
&:not(:last-child) {
@apply pb-6 border-b border-dark-400;
@apply mb-3;
&::v-deep {
section {
@apply mb-6;
}
}
}

.menu__custom {
@apply flex-1;
.item {
@apply mb-1 p-3 #{!important};
}
}
}

.lesson {
@apply bg-dark-900 cursor-pointer;
@apply shadow;
@include transition('background-color, box-shadow', 0.2s);

&:hover {
@apply bg-dark-800 shadow-lg;
}
.menu__content {
@apply flex-1 p-3 h-full overflow-y-auto;
}
</style>

+ 26
- 104
src/components/Layout/Navbar.vue View File

@@ -1,59 +1,41 @@
<template>
<div class="nav">
<div class="nav__left">
<div v-tooltip="$dream.version"
class="nav__item nav__item--logo">
<span>{{ $dream.name }}</span>
</div>

<div class="nav__item nav__item--greetings">
<span v-if="!isBadTime">{{ greetings }}</span>
<span v-else><img src="~/assets/images/games/sans.png"> i don't like what you are doing.</span>
</div>
<nuxt-link v-if="isBadTimeAvailable"
v-tooltip="'Bad Time Minigame ๐ŸŽฎ'"
to="/games/badtime"
class="nav__item nav__item--button">
<img src="~/assets/images/games/sans.png">
</nuxt-link>
</div>

<div class="nav__center">
<nuxt-link v-tooltip="'Upload'"
to="/"
class="nav__item nav__item--link">
<nuxt-link v-tooltip="'Upload'" to="/" class="nav__item nav__item--link">
<font-awesome-icon icon="upload" />
</nuxt-link>

<div v-tooltip="'My panel'"
class="nav__item nav__item--link">
<img :src="avatar"
alt="Me">
</div>

<div v-tooltip="'Advanced Mode'"
class="nav__item nav__item--link">
<font-awesome-icon icon="mask" />
</div>
<nuxt-link v-tooltip="'Photos'" to="/" class="nav__item nav__item--link">
<font-awesome-icon icon="images" />
</nuxt-link>
</div>

<div class="nav__right">
<nuxt-link v-if="isBadTimeAvailable"
v-tooltip="'Bad Time Game'"
to="/games/badtime"
class="nav__item nav__item--button">
<img src="~/assets/images/games/sans.png">
<nuxt-link v-tooltip="'Settings'" to="/settings" class="nav__item nav__item--button">
<font-awesome-icon icon="cog" />
</nuxt-link>

<nuxt-link v-tooltip="'Settings'"
to="/settings"
class="nav__item nav__item--button">
<font-awesome-icon icon="cog" />
<nuxt-link v-tooltip="'About'" to="/about" class="nav__item nav__item--button">
<font-awesome-icon icon="info-circle" />
</nuxt-link>

<a v-if="isDev" class="nav__item" @click.prevent="createError">
DEV: UI Error
</a>
<nuxt-link v-tooltip="'Help & Tips'" to="/help" class="nav__item nav__item--button">
<font-awesome-icon icon="question-circle" />
</nuxt-link>
</div>
</div>
</template>

<script>
import dayjs from 'dayjs'
import Avatars from '@dicebear/avatars'
import sprites from '@dicebear/avatars-jdenticon-sprites'
import { requirements, settings } from '~/modules/system'
@@ -63,7 +45,6 @@ import { events } from '~/modules'
export default {
data: () => ({
isBadTimeAvailable: settings.achievements.badtime,
isBadTime: false,
}),

computed: {
@@ -72,24 +53,6 @@ export default {
return avatars.create(settings.user)
},

greetings() {
const hours = dayjs().hour()

if (hours >= 6 && hours <= 11) {
return 'โ˜• Good morning'
}

if (hours >= 12 && hours <= 19) {
return '๐ŸŒž Good afternoon'
}

if (hours >= 0 && hours <= 5) {
return '๐Ÿ Sweet dreams'
}

return '๐ŸŒ› Good night'
},

canNudify() {
return requirements.canNudify
},
@@ -115,16 +78,6 @@ export default {
events.on('achievements.badtime', () => {
this.isBadTimeAvailable = true
})

this.$router.afterEach((to) => {
if (to.path === '/games/badtime') {
this.$dream.name = 'BadDreamTime'
this.isBadTime = true
} else {
this.$dream.name = process.env.npm_package_displayName
this.isBadTime = false
}
})
},

methods: {
@@ -136,20 +89,6 @@ export default {
</script>

<style lang="scss" scoped>
@keyframes logoAnim {
0% {
background-position: 0% 0%;
}

50% {
background-position: 100% 0%;
}

100% {
background-position: 0% 0%;
}
}

@keyframes alertAnim {
0% {
@apply text-danger-500;
@@ -166,7 +105,7 @@ export default {

.nav {
@apply flex z-10;
@apply h-full bg-dark-500 border-b-2 border-dark-600 shadow;
@apply h-full bg-menus border-b border-menus-light shadow px-3;
grid-area: nav;

.nav__left,
@@ -176,7 +115,7 @@ export default {
}

.nav__left {
@apply flex-1;
@apply items-center;
}

.nav__center {
@@ -197,18 +136,21 @@ export default {
}

&.nav__item--link {
@apply justify-center;
@apply border-b-2 border-transparent text-lg;
@apply justify-center border-b-2 border-transparent;
width: 100px;

.icon {
@apply text-lg;
}

&:hover {
@apply text-primary-500 border-primary-500;
@apply text-primary border-primary;
}
}

&.nav__item--button {
@apply justify-center;
@apply rounded-full text-lg mr-3;
@apply rounded-full text-lg mx-2;
height: 40px;
width: 40px;

@@ -220,26 +162,6 @@ export default {
height: 20px;
}
}

&.nav__item--logo {
@apply text-white text-sm font-bold px-6 select-none;
animation-duration: 10s;
animation-iteration-count: infinite;

animation-name: logoAnim;
animation-timing-function: ease-in-out;

background: rgb(99, 66, 245);
background: linear-gradient(40deg,
rgba(99, 66, 245, 1) 0%,
rgba(239, 125, 199, 1) 100%);
background-position: 0% 0%;
background-size: 200% 100%;
}

&.nav__item--greetings {
@apply text-white text-sm font-light px-3 select-none;
}
}

.layout__navbar {

+ 110
- 15
src/components/Layout/Titlebar.vue View File

@@ -1,7 +1,22 @@
<template>
<div class="titlebar">
<!-- Logo -->
<div class="titlebar__left">
<div class="logo">
<span>{{ $dream.name }}</span>
<span class="ml-2">{{ $dream.version }}</span>
</div>

<div class="logo__greetings">
<span v-if="!isBadTime">{{ greetings }}</span>
<span v-else><img src="~/assets/images/games/sans.png"> i don't like what you are doing.</span>
</div>
</div>

<!-- Drag -->
<div class="titlebar__drag" />

<!-- Window Buttons -->
<div class="titlebar__buttons">
<button id="minimize"
type="button"
@@ -26,11 +41,49 @@
</template>

<script>
import dayjs from 'dayjs'

const { getCurrentWindow } = require('electron').remote

const { api } = $provider.util

export default {
data: () => ({
isBadTime: false,
}),

computed: {
greetings() {
const hours = dayjs().hour()

if (hours >= 6 && hours <= 11) {
return 'โ˜• Good morning'
}

if (hours >= 12 && hours <= 19) {
return '๐ŸŒž Good afternoon'
}

if (hours >= 0 && hours <= 5) {
return '๐Ÿ Sweet dreams'
}

return '๐ŸŒ› Good night'
},
},

mounted() {
this.$router.afterEach((to) => {
if (to.path === '/games/badtime') {
this.$dream.name = 'BadDreamTime'
this.isBadTime = true
} else {
this.$dream.name = process.env.npm_package_displayName
this.isBadTime = false
}
})
},

methods: {
minimize() {
try {
@@ -56,7 +109,19 @@ export default {
</script>

<style lang="scss" scoped>
@keyframes logoAnim {
0% {
background-position: 0% 0%;
}

50% {
background-position: 100% 0%;
}

100% {
background-position: 0% 0%;
}
}

.titlebar {
@apply flex justify-end;
@@ -75,27 +140,57 @@ export default {
height: 18px;
}
}
}

.titlebar__drag {
@apply flex-1;
-webkit-app-region: drag;
.titlebar__left {
@apply flex;
}

.logo {
@apply flex justify-center items-center;
@apply text-white text-sm font-bold px-6 select-none;
animation-duration: 10s;
animation-iteration-count: infinite;

animation-name: logoAnim;
animation-timing-function: ease-in-out;

background: rgb(99, 66, 245);
background: linear-gradient(40deg,
rgba(99, 66, 245, 1) 0%,
rgba(239, 125, 199, 1) 100%);
background-position: 0% 0%;
background-size: 200% 100%;
}

.logo__greetings {
@apply flex justify-center items-center;
@apply text-white text-sm font-light px-3 select-none;

img {
height: 30px;
}
}

.titlebar__drag {
@apply flex-1;
-webkit-app-region: drag;
}

.titlebar__buttons {
@apply flex;
.titlebar__buttons {
@apply flex;

button {
@apply flex items-center justify-center outline-none;
@apply text-xs;
height: 30px;
width: 50px;
button {
@apply flex items-center justify-center outline-none;
@apply text-xs;
height: 30px;
width: 50px;

&:hover {
@apply bg-dark-800;
&:hover {
@apply bg-dark-800;

&.close {
@apply bg-danger-500;
}
&.close {
@apply bg-danger-500;
}
}
}

+ 0
- 9
src/components/Layout/index.js View File

@@ -1,9 +0,0 @@
import Vue from 'vue'

import Titlebar from './Titlebar.vue'
import Navbar from './Navbar.vue'
import Menubar from './Menubar.vue'

Vue.component('Titlebar', Titlebar)
Vue.component('Navbar', Navbar)
Vue.component('Menubar', Menubar)

+ 70
- 0
src/components/Nudify/NudifyMaskPhoto.vue View File

@@ -0,0 +1,70 @@
<template>
<div class="box mask">
<div class="box__photo mask__photo" />

<div class="box__header">
<span class="title">{{ title }}</span>
</div>

<div class="box__footer buttons">
<button class="button button--sm">
<FontAwesomeIcon icon="undo" />
</button>

<button class="button button--sm">
<FontAwesomeIcon icon="file-download" />
</button>

<button class="button button--primary button--sm">
<FontAwesomeIcon icon="file-upload" />
</button>
</div>
</div>
</template>

<script>
export default {
props: {
photo: {
type: Object,
required: true,
},
step: {
type: String,
required: true,
},
},

computed: {
title() {
switch (this.step) {
case 'correct':
return 'Corrected'

case 'mask':
return 'Mask'

case 'maskref':
return 'Maskref'

case 'maskdet':
return 'Maskdet'

case 'maskfin':
return 'Maskfin'

default:
return this.step
}
},
},
}
</script>

<style lang="scss" scoped>
.mask__photo {
background-image: url('~@/assets/images/curls.png');
will-change: transform;
height: 250px;
}
</style>

src/components/Nudity/PhotoRun.vue → src/components/Nudify/NudifyPhotoRun.vue View File


src/components/Nudity/Upload.vue → src/components/Nudify/NudifyUpload.vue View File


+ 0
- 6
src/components/Nudity/index.js View File

@@ -1,6 +0,0 @@
import Vue from 'vue'
import NudifyUpload from './Upload.vue'
import NudifyPhotoRun from './PhotoRun.vue'

Vue.component('nudify-upload', NudifyUpload)
Vue.component('nudify-photo-run', NudifyPhotoRun)

+ 21
- 22
src/components/Page/PageHeader.vue View File

@@ -1,48 +1,47 @@
<template>
<div class="header">
<section class="header">
<div class="header__left">
<slot />
</div>

<div v-if="this.$slots.center"
class="header__center">
<div v-if="this.$slots.center" class="header__center">
<slot name="center" />
</div>

<div v-if="this.$slots.right"
class="header__right">
<div v-if="this.$slots.right" class="header__right">
<slot name="right" />
</div>
</div>
</section>
</template>

<style lang="scss" scoped>
.header {
@apply flex mb-9;
}

.header__left {
@apply flex-1;
&::v-deep {
.title {
@apply text-lg font-semibold text-white mb-0;

&:not(:last-child) {
@apply mr-3;
}
}
.icon {
@apply mr-2;
}
}

.title {
@apply text-lg font-semibold text-generic-100;
.subtitle {
@apply font-thin;
}

.icon {
@apply mr-2;
.tip {
@apply ml-2;
}
}
}

.subtitle {
@apply font-thin;
.header__left {
@apply flex-1;

.help {
@apply ml-2;
cursor: help;
&:not(:last-child) {
@apply mr-3;
}
}
</style>

+ 0
- 4
src/components/Page/index.js View File

@@ -1,4 +0,0 @@
import Vue from 'vue'
import PageHeader from './PageHeader.vue'

Vue.component('PageHeader', PageHeader)

+ 6
- 11
src/components/Queue/QueueBar.vue View File

@@ -1,7 +1,6 @@
<template>
<div id="queuebar"
class="queue">
<div class="queue__section queue__section--running">
<div id="queuebar" class="queue">
<section class="queue__section queue__section--running">
<div class="queue__header">
<p class="title">
<span class="icon"><font-awesome-icon icon="running" /></span>
@@ -18,7 +17,7 @@
:photo="photo"
data-private />
</div>
</div>
</section>

<div class="queue__section queue__section--pending">
<div class="queue__header">
@@ -69,7 +68,7 @@ export default {
<style lang="scss" scoped>
.queue {
@apply flex flex-col;
@apply bg-dark-500;
@apply bg-menus border-l border-menus-light relative;
grid-area: queue;
}

@@ -103,12 +102,8 @@ export default {
}

.queue__content {
@apply flex-1;
@apply overflow-hidden overflow-x-auto whitespace-no-wrap;

.photo {
@apply inline-block;
}
@apply flex-1 grid grid-cols-2 grid-rows-2;
@apply overflow-y-auto whitespace-no-wrap;
}

/*

+ 39
- 38
src/components/Queue/QueuePhoto.vue View File

@@ -1,32 +1,25 @@
<template>
<div class="photo"
:class="photoClass">
<div class="photo__preview"
:style="previewStyle" />
<div class="photo" :class="photoClass">
<div class="photo__preview" :style="previewStyle" />
<img v-tooltip="photo.avatar.name" :src="photo.avatar.image" class="photo__badge">

<div class="photo__content">
<span v-show="photo.running || photo.finished">{{ photo.timer.duration }}s</span>

<button v-tooltip="'Open'"
@click="open">
<button v-tooltip="'Open'" @click="open">
<font-awesome-icon icon="external-link-square-alt" />
</button>

<button v-show="photo.pending"
v-tooltip="'Add to Queue'"
@click="add">
<button v-show="photo.pending" v-tooltip="'Add to Queue'" @click="add">
<font-awesome-icon icon="play" />
</button>

<button v-show="photo.waiting"
v-tooltip="'Remove from Queue'"
@click="cancel">
<button v-show="photo.waiting" v-tooltip="'Remove from Queue'" @click="cancel">
<font-awesome-icon icon="sign-out-alt" />
</button>

<button v-show="photo.running"
v-tooltip="'Stop'"
@click="stop">
<button v-show="photo.running" v-tooltip="'Stop'" @click="stop">
<font-awesome-icon icon="stop" />
</button>
</div>
@@ -89,7 +82,7 @@ export default {

<style lang="scss" scoped>
.photo {
@apply w-1/2 h-full relative border-2 border-dark-800;
@apply relative border-2 border-transparent;
background-image: url('~@/assets/images/curls.png');
will-change: transform;

@@ -106,34 +99,42 @@ export default {
@apply opacity-100;
}
}
}

.photo__preview {
@apply absolute top-0 bottom-0 left-0 right-0 z-10;
@apply bg-contain bg-no-repeat bg-center;
}
.photo__preview {
@apply absolute top-0 bottom-0 left-0 right-0 z-10;
@apply bg-contain bg-no-repeat bg-center;
}

.photo__content {
@apply absolute top-0 bottom-0 left-0 right-0 z-30;
@apply flex bg-dark-500-60 opacity-0;
backdrop-filter: blur(4px);
transition: opacity 0.1s linear;
.photo__badge {
@apply absolute z-20;
top: 5px;
right: 5px;
width: 30px;
height: 30px;
}

span,
button {
@apply flex-1;
}
.photo__content {
@apply absolute top-0 bottom-0 left-0 right-0 z-30;
@apply flex bg-dark-500-60 opacity-0;
backdrop-filter: blur(4px);
transition: opacity 0.1s linear;

span {
@apply flex items-center justify-center;
@apply text-white font-semibold;
}
span,
button {
@apply flex-1;
}

button {
@apply outline-none;
span {
@apply flex items-center justify-center;
@apply text-white font-semibold;
}

&:hover {
@apply text-primary;
}
button {
@apply outline-none;

&:hover {
@apply text-primary;
}
}
}

+ 0
- 15
src/components/Queue/index.js View File

@@ -1,15 +0,0 @@
// DreamTime.
// Copyright (C) DreamNet. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License 3.0 as published by
// the Free Software Foundation. See <https://www.gnu.org/licenses/gpl-3.0.html>
//
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2020.

import Vue from 'vue'
import QueueBar from './QueueBar.vue'
import QueuePhoto from './QueuePhoto.vue'

Vue.component('Queuebar', QueueBar)
Vue.component('QueuePhoto', QueuePhoto)

+ 42
- 23
src/components/Settings/Preference.vue View File

@@ -1,22 +1,20 @@
<template>
<section class="box box--items">
<section v-if="!readonly" class="box">
<div class="box__content">
<box-item :description="`Value: ${currentValue.size}`"
:label="`${label} size`">
<div :style="{ opacity: body.randomize ? 0.3 : 1.0 }">
<VueSlider v-model="currentValue.size"
<MenuItem :description="`Value: ${value$.size}`" :label="`${label} size`">
<div v-if="!body.randomize">
<VueSlider v-model="value$.size"
:min="min"
:max="max"
:interval="0.05" />
</div>
</box-item>
</MenuItem>

<box-item
v-show="!body.randomize && body.progressive.enabled"
<MenuItem
v-if="!body.randomize && body.progressive.enabled"
label="Progressive?"
description="Increase this body part progressively in each run.">
<select v-model="currentValue.progressive"
class="input">
<select v-model="value$.progressive" class="input">
<option :value="true">
Enabled
</option>
@@ -24,13 +22,13 @@
Disabled
</option>
</select>
</box-item>
</MenuItem>

<div v-show="body.randomize">
<box-item
<div v-if="body.randomize">
<MenuItem
label="Randomize?"
description="Randomize this body part in each run.">
<select v-model="currentValue.randomize.enabled"
<select v-model="value$.randomize.enabled"
class="input">
<option :value="true">
Enabled
@@ -39,29 +37,38 @@
Disabled
</option>
</select>
</box-item>
</MenuItem>

<box-item
<MenuItem
label="Random range"
:description="`Min: ${currentValue.randomize.min} - Max: ${currentValue.randomize.max}`">
:description="`Min: ${value$.randomize.min} - Max: ${value$.randomize.max}`">
<VueSlider
v-model="randomizeRange"
:min-range="0.05"
:min="min"
:max="max"
:interval="0.05" />
</box-item>
</MenuItem>
</div>
</div>
</section>

<MenuItem
v-else
:label="label"
action-class="preference__list">
<span class="font-bold">{{ value$.size }}</span>
<span v-if="value$.randomize.enabled === true">Randomized ({{ value$.randomize.min }} - {{ value$.randomize.max }})</span>
<span v-else-if="value$.progressive === true">Progresive</span>
</MenuItem>
</template>

<script>
import { VModel } from '~/mixins'

export default {

mixins: [VModel],

props: {
label: {
type: String,
@@ -75,24 +82,36 @@ export default {
type: Number,
default: 2,
},
readonly: {
type: Boolean,
default: false,
},
},

computed: {
randomizeRange: {
get() {
return [this.currentValue.randomize.min, this.currentValue.randomize.max]
return [this.value$.randomize.min, this.value$.randomize.max]
},
set(value) {
const [min, max] = value

this.currentValue.randomize.min = min
this.currentValue.randomize.max = max
this.value$.randomize.min = min
this.value$.randomize.max = max
},
},

body() {
return this.$parent.currentValue?.body
return this.$parent.value$?.body
},
},
}
</script>

<style lang="scss" scoped>
.preference__list {
span {
@apply text-sm text-center block;
}
}
</style>

+ 163
- 0
src/components/Settings/SettingsField.vue View File

@@ -0,0 +1,163 @@
<template>
<MenuItem
:label="fieldLabel"
:description="fieldDescription"
:data-id="field.id">
<slot>
<div v-if="!readonly" class="flex-1">
<!-- Select -->
<select v-if="field.input === 'select'"
v-model="localValue"
class="input"
v-bind="inputAttrs">
<option v-for="(option, index) in selectOptions" :key="index" :value="option.value">
{{ option.label }}
</option>
</select>

<!-- Input -->
<input v-if="field.input === 'input'"
v-model="localValue"
class="input"
v-bind="inputAttrs">
</div>

<span v-else>{{ valueLabel }}</span>
</slot>
</MenuItem>
</template>

<script>
import { get, set, find } from 'lodash'
import { VModel } from '~/mixins'

export default {
mixins: [VModel],

props: {
fieldId: {
type: String,
required: true,
},

label: {
type: String,
default: null,
},

description: {
type: String,
default: null,
},

options: {
type: Array,
default: null,
},

attrs: {
type: Object,
default: null,
},

readonly: {
type: Boolean,
default: false,
},
},

data: () => ({
localValue: null,
field: null,
}),

computed: {
selectOptions() {
if (this.options) {
return this.options
}

return this.field.options
},

valueLabel() {
if (this.field.input === 'select') {
const option = find(this.selectOptions, { value: this.localValue })
return option.label
}

return this.localValue
},

localFieldId() {
let fieldId = this.field.id

// FIXME: HARD CODED!
if (fieldId.includes('preferences.')) {
fieldId = fieldId.substring('preferences.'.length)
}

return fieldId
},

fieldLabel() {
if (this.label) {
return this.label
}

return this.field.label
},

fieldDescription() {
if (this.description) {
return this.description
}

return this.field.description
},

inputAttrs() {
if (this.attrs) {
return this.attrs
}

return this.field.attrs || {}
},
},

watch: {
localValue(value) {
if (this.value$) {
this.value$ = set(this.value$, this.localFieldId, value)
} else {
this.$settings.set(this.field.id, value)
}
},
},

created() {
this.field = this.$settings.getField(this.fieldId)

if (!this.field) {
throw new Error(`Invalid field ID: ${this.fieldId}`)
}

if (this.value) {
this.localValue = get(this.value, this.localFieldId)
} else {
this.localValue = this.$settings.get(this.fieldId)
}
},
}
</script>

<style lang="scss" scoped>
.item {
&::v-deep {
.item__action {
@apply flex items-center justify-center;
max-width: 300px;
}
}
}
</style>

+ 51
- 125
src/components/Settings/SettingsPreferences.vue View File

@@ -1,97 +1,68 @@
<template>
<div class="c-preferences">
<section v-show="currentValue.advanced.transformMode !== 'import-maskfin'"
id="preferences-runs"
class="box box--items">
<div class="box__header">
<h2 class="title">
Per run.
</h2>
<h3 class="subtitle">
Customize what will happen when you nudify.
</h3>
</div>

<div class="preferences">
<!-- Basics -->
<section id="preferences-basics" class="box">
<div class="box__content">
<box-item
label="Runs."
description="Number of times the photo will be nudified.">
<input v-model="currentValue.body.executions"
type="number"
min="1"
class="input">
</box-item>

<box-item
label="Randomize."
description="Set random body preferences at each run.">
<select v-model="currentValue.body.randomize"
class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
v-show="!currentValue.body.randomize"
label="Progressive."
:description="`Body preferences will increase ${currentValue.body.progressive.rate} at each run.`">
<select v-model="currentValue.body.progressive.enabled"
class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
v-show="!currentValue.body.randomize && currentValue.body.progressive.enabled"
label="Progressive rate."
:description="`Value: ${currentValue.body.progressive.rate}`">
<VueSlider v-model="currentValue.body.progressive.rate"
:min="0.1"
:max="0.9"
:interval="0.05" />
</box-item>
<SettingsField v-model="value$" field-id="preferences.mode" />

<SettingsField v-if="value$.mode > 0" v-model="value$" field-id="preferences.advanced.scaleMode" />
</div>
</section>

<!-- Boobs -->
<Preference id="preferences-body"
v-model="currentValue.body.boobs"
v-model="value$.body.boobs"
label="Boobs"
:min="0" />

<!-- Areola -->
<Preference v-model="currentValue.body.areola"
<Preference v-model="value$.body.areola"
label="Areola"
:min="0" />

<!-- Nipple -->
<Preference v-model="currentValue.body.nipple"
<Preference v-model="value$.body.nipple"
label="Nipple"
:min="0" />

<!-- Vagina -->
<Preference v-model="currentValue.body.vagina"
<Preference v-model="value$.body.vagina"
label="Vagina"
:max="1.5" />

<!-- Pubic Hair -->
<Preference v-model="currentValue.body.pubicHair"
<Preference v-model="value$.body.pubicHair"
label="Pubic Hair"
:min="0" />

<!-- Runs -->
<section v-if="value$.mode === 2" id="preferences-runs" class="box">
<div class="box__header">
<h2 class="title">
Per run.
</h2>
<h3 class="subtitle">
Customize what will happen each run.
<AppTip tooltip="The runs allow you to nudify the same photo with different preferences." />
</h3>
</div>

<div class="box__content">
<SettingsField v-model="value$" field-id="preferences.body.executions" />

<SettingsField v-model="value$" field-id="preferences.body.randomize" />

<SettingsField v-model="value$" field-id="preferences.body.progressive.enabled" :description="`Body preferences will increase ${value$.body.progressive.rate} at each run.`" />

<SettingsField v-if="!value$.body.randomize && value$.body.progressive.enabled"
v-model="value$"
field-id="preferences.body.progressive.rate"
:description="`Value: ${value$.body.progressive.rate}`" />
</div>
</section>

<!-- Advanced -->
<section id="preferences-advanced"
class="box box--items">
<section v-if="value$.mode > 1" id="preferences-advanced" class="box">
<div class="box__header">
<h2 class="title">
Advanced.
@@ -102,64 +73,9 @@
</div>

<div class="box__content">
<box-item
id="preferences-advanced-scale"
label="Scale method."
description="Indicates how the photo will be scaled, this changes the quality of the result dramatically.">
<select v-model="currentValue.advanced.scaleMode"
class="input">
<option value="none">
None
</option>
<option value="auto-rescale">
Fixed
</option>
<option value="auto-resize">
Scale and pad
</option>
<option value="auto-resize-crop">
Scale and crop
</option>
<option value="overlay">
Overlay
</option>
<option value="cropjs">
Crop
</option>
</select>
</box-item>

<box-item
id="preferences-advanced-color"
label="Color transfer."
description="Use a experimental algorithm to try to recover the original colors of the photo.">
<select v-model="currentValue.advanced.useColorTransfer"
class="input">
<option :value="true">
Enabled
</option>
<option :value="false">
Disabled
</option>
</select>
</box-item>

<box-item
label="Transformation method."
description="Advanced users. Indicates additional options for transformation.">
<select v-model="currentValue.advanced.transformMode"
class="input">
<option value="normal">
Nudify
</option>
<option value="export-maskfin">
Nudify & Maskfin
</option>
<option value="import-maskfin">
Nudify with Maskfin
</option>
</select>
</box-item>
<SettingsField v-model="value$" field-id="preferences.advanced.useColorTransfer" />

<SettingsField v-model="value$" field-id="preferences.advanced.useWaifu" />
</div>
</section>
</div>
@@ -177,3 +93,13 @@ export default {
},
}
</script>

<style lang="scss" scoped>
.preferences {
&::v-deep {
.box .box__header {
@apply pt-6;
}
}
}
</style>

+ 0
- 17
src/components/Settings/index.js View File

@@ -1,17 +0,0 @@
/*
* DreamTime | (C) 2019 by Ivan Bravo Bravo <ivan@dreamnet.tech>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 3.0 as published by
* the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import Vue from 'vue'
import SettingsPreferences from './SettingsPreferences.vue'
import Preference from './Preference.vue'

Vue.component('settings-preferences', SettingsPreferences)
Vue.component('Preference', Preference)

+ 135
- 0
src/components/UI/AppAds.vue View File

@@ -0,0 +1,135 @@
<template>
<div v-if="show" class="ads">
<div v-if="showAd">
<ins data-revive-zoneid="3" data-revive-id="7e048c7f8d85676181a4b65ec87d61fe" />
</div>

<HelpLesson v-if="showLesson"
:lesson="lesson"
:small="true"
@click="$router.push('/help')" />
</div>
</template>

<script>
import { isNil, sample } from 'lodash'
import { settings } from '~/modules/system'
import { Help } from '~/modules'

const CHANGE_INTERVAL = process.env.NODE_ENV === 'development' ? 1 * 60 * 1000 : 15 * 60 * 1000

export default {
data: () => ({
type: null,
ready: false,
interval: null,
lesson: null,
}),

computed: {
show() {
return !isNil(this.type)
},

isAd() {
return this.type === 'ad'
},

showAd() {
return this.isAd && this.ready
},

isLesson() {
return this.type === 'lesson'
},

showLesson() {
return this.isLesson && this.ready
},
},

created() {
this.init()
this.interval = setInterval(this.init.bind(this), CHANGE_INTERVAL)
},

beforeDestroy() {
if (this.interval) {
clearInterval(this.interval)
}
},

methods: {
init() {
const types = []

if (settings.app.showAds) {
types.push('ad')
}

if (settings.app.showTips) {
types.push('lesson')
}

if (types.length === 0) {
this.type = null
} else if (types.length === 1) {
// eslint-disable-next-line prefer-destructuring
this.type = types[0]
} else {
this.type = sample(types)
}

this.ready = false

if (this.isAd) {
this.refreshAd()
} else if (this.isLesson) {
this.refreshLesson()
}
},

refreshAd() {
if (!window.reviveAsync) {
return
}

if (!window.reviveAsync['7e048c7f8d85676181a4b65ec87d61fe']) {
return
}

this.$nextTick(() => {
this.ready = true

this.$nextTick(() => {
window.reviveAsync['7e048c7f8d85676181a4b65ec87d61fe'].refresh()
})
})
},