├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── FUNDING.yml ├── .gitignore ├── .postcssrc.js ├── .stylintrc ├── LICENSE ├── README.md ├── babel.config.js ├── env.dev.example ├── env.example ├── jsconfig.json ├── lib ├── boot │ ├── capacitor │ │ ├── admob.js │ │ ├── iap.js │ │ └── index.js │ ├── electron.js │ ├── index.js │ ├── spa.js │ └── utils.js ├── commons │ ├── OpusBtnDropdownSelect.js │ ├── OpusBtnToggle.js │ ├── OpusDialog.vue │ ├── OpusFab.js │ ├── OpusImgCaption.js │ ├── OpusImgCaptionGroup.js │ ├── OpusMoreActionsMenuBtn.vue │ ├── Pomodoro │ │ ├── PomodoroDesktop.vue │ │ ├── PomodoroMobile.vue │ │ ├── index.js │ │ └── mixin.js │ ├── opus-dialog-functions.js │ └── premium-guard │ │ ├── PremiumGuardDialog.vue │ │ └── premium-guard-mixin.js ├── constants │ └── index.js ├── dialogs │ └── index.js ├── notifications │ ├── capacitor.js │ ├── electron.js │ ├── index.js │ └── spa.js ├── pomodoro │ ├── audio-controller.js │ ├── index.js │ └── notification-controller.js ├── preferences.js └── utils │ └── index.js ├── package.json ├── quasar.conf.js ├── quasar.extensions.json ├── src-capacitor ├── android │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── capacitor.build.gradle │ │ ├── debug │ │ │ └── output.json │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── getcapacitor │ │ │ │ └── myapp │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ │ └── capacitor.config.json │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── nightowl │ │ │ │ │ └── enfocus │ │ │ │ │ └── app │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── drawable-land-hdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-land-mdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-land-xhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-land-xxhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-land-xxxhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-port-hdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-port-mdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-port-xhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-port-xxhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-port-xxxhdpi │ │ │ │ └── splash.png │ │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── drawable │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── splash.png │ │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── values │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ │ └── xml │ │ │ │ ├── config.xml │ │ │ │ └── file_paths.xml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── getcapacitor │ │ │ └── myapp │ │ │ └── ExampleUnitTest.java │ ├── build.gradle │ ├── capacitor.settings.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── variables.gradle ├── capacitor-flag.d.ts ├── capacitor.config.json ├── ios │ ├── App │ │ ├── App │ │ │ ├── Assets.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ │ ├── AppIcon-29x29@1x.png │ │ │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ │ │ ├── AppIcon-29x29@2x.png │ │ │ │ │ ├── AppIcon-29x29@3x.png │ │ │ │ │ ├── AppIcon-40x40@1x.png │ │ │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ │ │ ├── AppIcon-40x40@2x.png │ │ │ │ │ ├── AppIcon-40x40@3x.png │ │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ │ ├── AppIcon-60x60@2x.png │ │ │ │ │ ├── AppIcon-60x60@3x.png │ │ │ │ │ ├── AppIcon-76x76@1x.png │ │ │ │ │ ├── AppIcon-76x76@2x.png │ │ │ │ │ └── AppIcon-83.5x83.5@2x.png │ │ │ │ └── Splash.imageset │ │ │ │ │ ├── splash-2732x2732-1.png │ │ │ │ │ ├── splash-2732x2732-2.png │ │ │ │ │ └── splash-2732x2732.png │ │ │ ├── capacitor.config.json │ │ │ └── config.xml │ │ └── public │ │ │ ├── cordova.js │ │ │ ├── cordova_plugins.js │ │ │ ├── css │ │ │ ├── 5.db20d1f3.css │ │ │ ├── 6.4e2a38a7.css │ │ │ ├── 7.1b22cbe8.css │ │ │ ├── 8.c8bc3c72.css │ │ │ ├── app.59867fff.css │ │ │ ├── app.9a730dc9.css │ │ │ ├── app.d7db14ee.css │ │ │ ├── chunk-common.068be305.css │ │ │ ├── chunk-common.2a6b31f3.css │ │ │ ├── chunk-common.3b3ed363.css │ │ │ ├── chunk-common.517ea842.css │ │ │ ├── chunk-common.564d0bb9.css │ │ │ ├── chunk-common.a2448107.css │ │ │ ├── chunk-common.c9d7f250.css │ │ │ ├── chunk-common.dd3ee329.css │ │ │ ├── chunk-common.f6034d34.css │ │ │ └── chunk-common.fb06f277.css │ │ │ ├── fonts │ │ │ ├── KFOkCnqEu92Fr1MmgVxGIzQ.woff │ │ │ ├── KFOlCnqEu92Fr1MmEU9fChc-.woff │ │ │ ├── KFOlCnqEu92Fr1MmSU5fChc-.woff │ │ │ ├── KFOlCnqEu92Fr1MmWUlfChc-.woff │ │ │ ├── KFOlCnqEu92Fr1MmYUtfChc-.woff │ │ │ ├── KFOmCnqEu92Fr1Mu7GxM.woff │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff │ │ │ └── flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2 │ │ │ ├── img │ │ │ ├── art_museum.svg │ │ │ ├── empty.svg │ │ │ ├── financial_data.svg │ │ │ ├── pie_chart.svg │ │ │ ├── quasar-logo-full.svg │ │ │ ├── taken.svg │ │ │ ├── throw_away.svg │ │ │ └── voting.svg │ │ │ ├── index.html │ │ │ ├── js │ │ │ ├── 10.js │ │ │ ├── 11.js │ │ │ ├── 12.js │ │ │ ├── 13.js │ │ │ ├── 14.js │ │ │ ├── 15.js │ │ │ ├── 16.js │ │ │ ├── 17.js │ │ │ ├── 18.js │ │ │ ├── 19.js │ │ │ ├── 2.js │ │ │ ├── 20.js │ │ │ ├── 3.js │ │ │ ├── 5.js │ │ │ ├── 6.js │ │ │ ├── 7.js │ │ │ ├── 8.js │ │ │ ├── 9.js │ │ │ ├── app.js │ │ │ ├── chunk-common.js │ │ │ └── vendor.js │ │ │ ├── native-bridge.js │ │ │ ├── plugins │ │ │ ├── cordova-plugin-network-information │ │ │ │ └── www │ │ │ │ │ ├── Connection.js │ │ │ │ │ └── network.js │ │ │ ├── cordova-plugin-purchase │ │ │ │ └── www │ │ │ │ │ └── store-ios.js │ │ │ └── cordova-plugin-sqlite-2 │ │ │ │ └── dist │ │ │ │ └── sqlite-plugin.js │ │ │ └── statics │ │ │ ├── desktop-sidenav-icon.png │ │ │ └── media │ │ │ ├── pause.mp3 │ │ │ ├── ping.mp3 │ │ │ ├── restart.mp3 │ │ │ └── start.mp3 │ └── capacitor-cordova-ios-plugins │ │ ├── CordovaPlugins.podspec │ │ ├── CordovaPluginsResources.podspec │ │ ├── CordovaPluginsStatic.podspec │ │ ├── resources │ │ └── .gitkeep │ │ └── sources │ │ ├── .gitkeep │ │ ├── CordovaPluginNetworkInformation │ │ ├── CDVConnection.h │ │ ├── CDVConnection.m │ │ ├── CDVReachability.h │ │ └── CDVReachability.m │ │ ├── CordovaPluginPurchase │ │ ├── FileUtility.h │ │ ├── FileUtility.m │ │ ├── InAppPurchase.h │ │ ├── InAppPurchase.m │ │ ├── SKProduct+LocalizedPrice.h │ │ ├── SKProduct+LocalizedPrice.m │ │ ├── SKProductDiscount+LocalizedPrice.h │ │ └── SKProductDiscount+LocalizedPrice.m │ │ └── CordovaPluginSqlite2 │ │ ├── SQLitePlugin.h │ │ └── SQLitePlugin.m ├── package-lock.json ├── package.json └── yarn.lock ├── src-electron ├── electron-flag.d.ts ├── icon.ico ├── icons │ ├── icon.icns │ ├── icon.ico │ └── icon.png └── main-process │ ├── electron-main.dev.js │ └── electron-main.js ├── src ├── App.vue ├── api │ ├── database │ │ ├── index.js │ │ └── schema │ │ │ ├── project.js │ │ │ ├── report.js │ │ │ └── task.js │ ├── helpers.js │ ├── projects.js │ ├── reports.js │ └── tasks.js ├── assets │ ├── art_museum.svg │ ├── decide.svg │ ├── empty.svg │ ├── financial_data.svg │ ├── icon.png │ ├── pie_chart.svg │ ├── quasar-logo-full.svg │ ├── sad.svg │ ├── solution_mindset.svg │ ├── taken.svg │ ├── throw_away.svg │ ├── void.svg │ └── voting.svg ├── boot │ ├── .gitkeep │ ├── axios.js │ └── opus.js ├── components │ ├── AboutDialog.vue │ ├── EssentialLink.vue │ ├── MenuNav.vue │ ├── SideNav.vue │ ├── eisenhower │ │ ├── EisenhowerBox.vue │ │ ├── EisenhowerTabChooserDialog.vue │ │ ├── EisenhowerTabDescriptions.vue │ │ └── EisenhowerTabLabel.vue │ ├── projects │ │ ├── EditProjectDialog.vue │ │ ├── NewProjectDialog.vue │ │ ├── ProjectDetails.vue │ │ ├── ProjectDetailsDialog.vue │ │ ├── ProjectItem.vue │ │ └── project-details.js │ ├── reports │ │ ├── CustomReports.vue │ │ ├── DonutChart.vue │ │ ├── ProjectByNDaysChart.vue │ │ ├── ProjectDonut.vue │ │ ├── StandardReports.vue │ │ ├── TasksByDayChart.vue │ │ ├── TasksByNDaysChart.vue │ │ ├── mixin-event-handlers.js │ │ └── mixin-stacked-bar-chart.js │ ├── settings │ │ └── SettingsDialog.vue │ └── tasks │ │ ├── ActiveTask.vue │ │ ├── EditTaskDialog.vue │ │ ├── NewTaskDialog.vue │ │ ├── TaskDetailsDialog.vue │ │ ├── TaskItem.vue │ │ └── TaskList.vue ├── css │ ├── app.scss │ └── quasar.variables.scss ├── index.template.html ├── layouts │ ├── DefaultLayout.vue │ ├── TasksLayout.vue │ └── desktop │ │ ├── FullPageLayout.vue │ │ ├── RootLayout.vue │ │ └── SplitLayout.vue ├── pages │ ├── Eisenhower.vue │ ├── Error404.vue │ ├── Projects.vue │ ├── Reports.vue │ ├── Tasks.vue │ ├── desktop │ │ ├── Eisenhower.vue │ │ ├── Projects.vue │ │ ├── Reports.vue │ │ └── Tasks.vue │ ├── mixin-eisenhower.js │ ├── mixin-projects.js │ ├── mixin-reports.js │ ├── mixin-task-actions.js │ ├── mixin-tasks-dialogs.js │ └── mixin-tasks.js ├── router │ ├── capacitor.routes.js │ ├── electron.routes.js │ ├── index.js │ ├── routes.js │ └── spa.routes.js ├── statics │ ├── app-logo-128x128.png │ ├── desktop-sidenav-icon.png │ ├── icons │ │ ├── app-logo-desktop-nav-128x128.png │ │ ├── apple-icon-120x120.png │ │ ├── apple-icon-152x152.png │ │ ├── apple-icon-167x167.png │ │ ├── apple-icon-180x180.png │ │ ├── favicon-128x128.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── icon-128x128.png │ │ ├── icon-192x192.png │ │ ├── icon-256x256.png │ │ ├── icon-384x384.png │ │ ├── icon-512x512.png │ │ ├── icon.png │ │ ├── ms-icon-144x144.png │ │ └── safari-pinned-tab.svg │ └── media │ │ ├── pause.mp3 │ │ ├── ping.mp3 │ │ ├── restart.mp3 │ │ └── start.mp3 └── store │ ├── index.js │ ├── pomodoro │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── mutations.js │ ├── state.js │ └── store-flag.d.ts │ ├── projects │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── mutations.js │ ├── state.js │ └── store-flag.d.ts │ ├── store-flag.d.ts │ └── tasks │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── mutations.js │ ├── state.js │ └── store-flag.d.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 4 | parserOptions: { 5 | parser: 'babel-eslint', 6 | sourceType: 'module' 7 | }, 8 | 9 | env: { 10 | browser: true 11 | }, 12 | 13 | extends: [ 14 | 'standard', 15 | // https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention 16 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 17 | 'plugin:vue/essential' 18 | ], 19 | 20 | // required to lint *.vue files 21 | plugins: [ 22 | 'vue' 23 | ], 24 | 25 | globals: { 26 | 'ga': true, // Google Analytics 27 | 'cordova': true, 28 | '__statics': true, 29 | 'process': true, 30 | 'Capacitor': true, 31 | 'chrome': true 32 | }, 33 | 34 | // add your custom rules here 35 | rules: { 36 | // allow async-await 37 | 'generator-star-spacing': 'off', 38 | // allow paren-less arrow functions 39 | 'arrow-parens': 'off', 40 | 'one-var': 'off', 41 | 42 | 'import/first': 'off', 43 | 'import/named': 'error', 44 | 'import/namespace': 'error', 45 | 'import/default': 'error', 46 | 'import/export': 'error', 47 | 'import/extensions': 'off', 48 | 'import/no-unresolved': 'off', 49 | 'import/no-extraneous-dependencies': 'off', 50 | 'prefer-promise-reject-errors': 'off', 51 | 52 | // allow debugger during development only 53 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: vycoder 4 | custom: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VZ6MAQNE99TT2&source=url" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | node_modules 4 | 5 | # Quasar core related directories 6 | .quasar 7 | /dist 8 | 9 | # Cordova related directories and files 10 | /src-cordova/node_modules 11 | /src-cordova/platforms 12 | /src-cordova/plugins 13 | /src-cordova/www 14 | 15 | # Capacitor related directories and files 16 | /src-capacitor/www 17 | /src-capacitor/node_modules 18 | 19 | # BEX related directories and files 20 | /src-bex/www 21 | /src-bex/js/core 22 | 23 | # Log files 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # Editor directories and files 29 | .idea 30 | .vscode 31 | *.suo 32 | *.ntvs* 33 | *.njsproj 34 | *.sln 35 | 36 | # keystores 37 | *.keystore 38 | *.jks 39 | *.jceks 40 | 41 | # env files 42 | *.env* 43 | 44 | dev.env 45 | .env -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: [ 5 | // to edit target browsers: use "browserslist" field in package.json 6 | require('autoprefixer') 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.stylintrc: -------------------------------------------------------------------------------- 1 | { 2 | "blocks": "never", 3 | "brackets": "never", 4 | "colons": "never", 5 | "colors": "always", 6 | "commaSpace": "always", 7 | "commentSpace": "always", 8 | "cssLiteral": "never", 9 | "depthLimit": false, 10 | "duplicates": true, 11 | "efficient": "always", 12 | "extendPref": false, 13 | "globalDupe": true, 14 | "indentPref": 2, 15 | "leadingZero": "never", 16 | "maxErrors": false, 17 | "maxWarnings": false, 18 | "mixed": false, 19 | "namingConvention": false, 20 | "namingConventionStrict": false, 21 | "none": "never", 22 | "noImportant": false, 23 | "parenSpace": "never", 24 | "placeholder": false, 25 | "prefixVarsWithDollar": "always", 26 | "quotePref": "single", 27 | "semicolons": "never", 28 | "sortOrder": false, 29 | "stackedProperties": "never", 30 | "trailingWhitespace": "never", 31 | "universal": "never", 32 | "valid": true, 33 | "zeroUnits": "never", 34 | "zIndexNormalize": false 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qodo - Quasar Todo 2 | 3 | This project aims to help beginners and newcomers in learning how to use [Quasar Framework](https://quasar.dev) to build multi-platform apps. This is a relatively medium-size project, complete with a local client database (using [RxDB](https://rxdb.info)) that demonstrates how you can build your app for both Mobile and Desktop platform. Treat this project as a reference or a learning resource. 4 | 5 | Check out the live `enFocus` version here: 6 | - Mobile - [Google Play](https://play.google.com/store/apps/details?id=com.nightowl.enfocus.app) 7 | - Desktop - [www.getenfocus.com](https://www.getenfocus.com) 8 | 9 | ## Getting Started 10 | This project requires `yarn` and `@quasar/cli`, check docs for more details on [Quasar CLI Installation](https://quasar.dev/quasar-cli/installation). 11 | 12 | ### Install the dependencies 13 | ```bash 14 | yarn 15 | ``` 16 | 17 | ### Setup environment variables 18 | ```bash 19 | cp env.dev.example .env.dev #.env for production 20 | ``` 21 | 22 | #### Start the app in development mode (hot-code reloading, error reporting, etc.) 23 | ```bash 24 | # run as capacitor mode 25 | quasar dev -m capacitor -T [android|ios] 26 | 27 | # run as electron mode 28 | quasar dev -m electron 29 | ``` 30 | 31 | #### Lint the files 32 | ```bash 33 | yarn run lint 34 | ``` 35 | 36 | ## Monetizing via AdMob and In-app Purchase 37 | > WIP - Tutorial. 38 | 39 | ## Deployment 40 | > WIP - Tutorial. 41 | 42 | ## Donate 43 | You can buy my next beer or coffee if you ever find this project useful. 44 | - [kofi](https://ko-fi.com/vycoder) 45 | - [Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VZ6MAQNE99TT2&source=url) 46 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@quasar/babel-preset-app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /env.dev.example: -------------------------------------------------------------------------------- 1 | DB_NAME= 2 | ELECTRON_PREMIUM_FLAG= 3 | PREMIUM_REDIRECT_LINK= 4 | ADMOB_ANDROID_ID= 5 | ADMOB_ANDROID_BANNER_ID= 6 | -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | DB_NAME= 2 | ELECTRON_PREMIUM_FLAG= 3 | PREMIUM_REDIRECT_LINK= 4 | ADMOB_ANDROID_ID= 5 | ADMOB_ANDROID_BANNER_ID= 6 | ADMOB_IOS_ID= 7 | ADMOB_IOS_BANNER_ID= 8 | IAP_PRODUCT_ID= 9 | IAP_DEBUG= 10 | IAP_VALIDATOR= 11 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "src/*": ["src/*"], 6 | "app/*": ["*"], 7 | "components/*": ["src/components/*"], 8 | "layouts/*": ["src/layouts/*"], 9 | "pages/*": ["src/pages/*"], 10 | "assets/*": ["src/assets/*"], 11 | "boot/*": ["src/boot/*"], 12 | "lib/*": ["lib/*"], 13 | "api/*": ["src/api/*"], 14 | "vue$": ["node_modules/vue/dist/vue.esm.js"] 15 | } 16 | }, 17 | "exclude": [ 18 | "dist", 19 | ".quasar", 20 | "node_modules" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /lib/boot/capacitor/admob.js: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | import { Plugins } from '@capacitor/core' 3 | const { AdMobAdvanced } = Plugins 4 | import { AdSize, AdPosition } from 'capacitor-admob-advanced' 5 | 6 | import { PremiumFlagKey } from 'lib/boot/utils' 7 | 8 | export const paddingClass = document.createElement('style') 9 | paddingClass.id = 'admobPadding' 10 | paddingClass.type = 'text/css' 11 | paddingClass.innerHTML = '.admob-padding { padding-top: 60px !important }' // 60px is the height of AdSize.FULL_BANNER 12 | 13 | export const initializeAdMob = async (cb) => { 14 | AdMobAdvanced.addListener('onBannerAdLoaded', () => { 15 | if (!LocalStorage.getItem(PremiumFlagKey).current) { 16 | document 17 | .getElementsByTagName('head')[0] 18 | .appendChild(paddingClass) 19 | } 20 | }) 21 | 22 | AdMobAdvanced.addListener('onBannerAdFailedToLoad', () => { 23 | document 24 | .getElementsByTagName('head')[0] 25 | .removeChild(document.getElementById(paddingClass.id)) 26 | }) 27 | 28 | return AdMobAdvanced.initialize({ 29 | appIdAndroid: process.env.ADBMOB_ANDROID_ID, 30 | appIdIos: process.env.ADMOB_IOS_ID 31 | }).then( 32 | value => cb(value), 33 | error => console.error(error) 34 | ) 35 | } 36 | 37 | export const showAdBanner = async () => { 38 | return AdMobAdvanced.showBanner({ 39 | adIdAndroid: process.env.ADMOB_ANDROID_BANNER_ID, 40 | adIdIos: process.env.ADMOB_IOS_BANNER_ID, 41 | adSize: AdSize.FULL_BANNER, 42 | adPosition: AdPosition.TOP, 43 | isTesting: process.env.DEV 44 | }) 45 | } 46 | 47 | export const removeAdBanner = () => { 48 | return AdMobAdvanced 49 | .removeBanner() 50 | .then( 51 | value => { 52 | document 53 | .getElementsByTagName('head')[0] 54 | .removeChild(document.getElementById(paddingClass.id)) 55 | }, 56 | error => { console.error(error) }) 57 | } 58 | 59 | export default { 60 | initialize: initializeAdMob, 61 | showBanner: showAdBanner, 62 | removeBanner: removeAdBanner, 63 | admobPaddingClass: paddingClass 64 | } 65 | -------------------------------------------------------------------------------- /lib/boot/capacitor/iap.js: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | import Admob from './admob' 3 | 4 | const initIAPStore = (PremiumFlagKey) => { 5 | if (process.env.DEV) { 6 | return 7 | } 8 | 9 | const productId = process.env.IAP_PRODUCT_ID 10 | const IAPStore = window.store 11 | 12 | if (process.env.IAP_DEBUG) { 13 | IAPStore.verbosity = IAPStore.DEBUG 14 | IAPStore.error((e) => { 15 | console.error(`--> ${e.code} : ${e.message}`) 16 | }) 17 | 18 | IAPStore.when(productId).updated((p) => { 19 | console.log('--> debug updated', JSON.stringify(p)) 20 | }) 21 | } 22 | 23 | IAPStore.register([{ 24 | id: productId, 25 | type: IAPStore.PAID_SUBSCRIPTION 26 | }]) 27 | 28 | IAPStore.validator = process.env.IAP_VALIDATOR 29 | 30 | IAPStore.when(productId).approved(p => (p.verify())) 31 | IAPStore.when(productId).verified(p => { 32 | const cacheStatus = LocalStorage.getItem(PremiumFlagKey) 33 | LocalStorage.set(PremiumFlagKey, { prev: cacheStatus.prev, current: true }) 34 | Admob.removeBanner() 35 | p.finish() 36 | }) 37 | 38 | IAPStore 39 | .when(productId) 40 | .updated(product => { 41 | if (product.state !== IAPStore.VALID) { 42 | return 43 | } 44 | 45 | if (!product.owned) { 46 | const cacheStatus = LocalStorage.getItem(PremiumFlagKey) 47 | LocalStorage.set(PremiumFlagKey, { prev: cacheStatus.current, current: false }) 48 | Admob.initialize(() => (Admob.showBanner())) 49 | } 50 | }) 51 | 52 | IAPStore.when(productId) 53 | .cancelled((p) => { 54 | const cacheStatus = LocalStorage.getItem(PremiumFlagKey) 55 | LocalStorage.set(PremiumFlagKey, { prev: cacheStatus.current, current: false }) 56 | Admob.showBanner() 57 | }) 58 | IAPStore.when(productId) 59 | .refunded((p) => { 60 | const cacheStatus = LocalStorage.getItem(PremiumFlagKey) 61 | LocalStorage.set(PremiumFlagKey, { prev: cacheStatus.current, current: false }) 62 | Admob.showBanner() 63 | }) 64 | IAPStore.when(productId) 65 | .expired((p) => { 66 | const cacheStatus = LocalStorage.getItem(PremiumFlagKey) 67 | LocalStorage.set(PremiumFlagKey, { prev: cacheStatus.current, current: false }) 68 | Admob.showBanner() 69 | }) 70 | 71 | IAPStore.refresh() 72 | } 73 | 74 | export default { 75 | initialize: initIAPStore, 76 | store: window.store 77 | } 78 | -------------------------------------------------------------------------------- /lib/boot/capacitor/index.js: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | import { Plugins, StatusBarStyle } from '@capacitor/core' 3 | import { PremiumFlagKey } from '../utils' 4 | 5 | import InAppPurchase from './iap' 6 | 7 | const { 8 | CapacitorKeepScreenOn, 9 | StatusBar, 10 | Network 11 | } = Plugins 12 | 13 | CapacitorKeepScreenOn.enable() 14 | 15 | StatusBar.setStyle({ style: StatusBarStyle.Light }) 16 | StatusBar.setBackgroundColor({ color: 'white' }) 17 | StatusBar.hide() 18 | 19 | if (!LocalStorage.has(PremiumFlagKey)) { 20 | LocalStorage.set(PremiumFlagKey, { 21 | prev: false, 22 | current: false 23 | }) 24 | } 25 | 26 | Network 27 | .getStatus() 28 | .then(({ connected }) => { 29 | if (connected) { 30 | InAppPurchase.initialize(PremiumFlagKey) 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /lib/boot/electron.js: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | 3 | import { PremiumFlagKey } from './utils' 4 | 5 | if (!LocalStorage.has(PremiumFlagKey)) { 6 | LocalStorage.set(PremiumFlagKey, { 7 | prev: false, 8 | current: false 9 | }) 10 | } 11 | 12 | const { ELECTRON_PREMIUM_FLAG } = process.env 13 | if (ELECTRON_PREMIUM_FLAG === 'true') { 14 | LocalStorage.set(PremiumFlagKey, { 15 | prev: true, current: true 16 | }) 17 | } else { 18 | LocalStorage.set(PremiumFlagKey, { 19 | prev: false, current: false 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /lib/boot/index.js: -------------------------------------------------------------------------------- 1 | require(`./${process.env.MODE}`) 2 | -------------------------------------------------------------------------------- /lib/boot/spa.js: -------------------------------------------------------------------------------- 1 | // no-op 2 | -------------------------------------------------------------------------------- /lib/boot/utils.js: -------------------------------------------------------------------------------- 1 | export const PremiumFlagKey = 'opus.pflag' 2 | -------------------------------------------------------------------------------- /lib/commons/OpusBtnDropdownSelect.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import { 4 | QBtnDropdown, 5 | QList, 6 | QItem, 7 | ClosePopup, 8 | QItemSection, 9 | QItemLabel 10 | } from 'quasar' 11 | 12 | export default Vue.extend({ 13 | name: 'OpusBtnDropdownSelect', 14 | props: { 15 | value: { type: String, required: true }, 16 | size: { type: String, default: 'sm' }, 17 | options: { type: Array, required: true }, 18 | color: { type: String, default: 'accent' } 19 | }, 20 | render (h) { 21 | const children = this.options.map(option => 22 | h(QItem, { 23 | props: { 24 | clickable: true 25 | }, 26 | directives: [ClosePopup], 27 | on: { 28 | click: () => this.$emit('input', option.value) 29 | } 30 | }, [h(QItemSection, [h(QItemLabel, [option.label])])]) 31 | ) 32 | return h(QBtnDropdown, { 33 | props: { 34 | label: this.options.find(o => o.value === this.value).label, 35 | color: this.color, 36 | size: this.size, 37 | rounded: true, 38 | noCaps: true, 39 | unelevated: true 40 | } 41 | }, [h(QList, children)]) 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /lib/commons/OpusBtnToggle.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import { QBtn } from 'quasar' 4 | 5 | export default Vue.extend({ 6 | name: 'OpusBtnToggle', 7 | props: { 8 | value: { type: String, required: true }, 9 | size: { type: String, default: 'sm' }, 10 | options: { type: Array, required: true }, 11 | nullable: { type: Boolean, default: false }, 12 | color: { type: String, default: 'primary' } 13 | }, 14 | methods: { 15 | select (option) { 16 | if (this.nullable && option.value === this.value) { 17 | this.$emit('input', '') 18 | return 19 | } 20 | this.$emit('input', option.value) 21 | }, 22 | isSelected (option) { 23 | return option.value === this.value 24 | } 25 | }, 26 | render (h) { 27 | const btns = this.options.map(option => 28 | h(QBtn, { 29 | props: { 30 | noCaps: true, 31 | rounded: true, 32 | size: this.size, 33 | color: this.color, 34 | label: option.label, 35 | outline: !this.isSelected(option), 36 | unelevated: this.isSelected(option) 37 | }, 38 | on: { 39 | click: () => this.select(option) 40 | } 41 | }) 42 | ) 43 | return h( 44 | 'section', 45 | { class: 'row' + this.class || 'q-gutter-x-xs' }, 46 | btns 47 | ) 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /lib/commons/OpusDialog.vue: -------------------------------------------------------------------------------- 1 | 41 | 96 | -------------------------------------------------------------------------------- /lib/commons/OpusFab.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import { QBtn } from 'quasar' 4 | 5 | export default Vue.extend({ 6 | name: 'OpusFab', 7 | props: { 8 | icon: { type: String, default: 'add' }, 9 | color: { type: String, default: 'accent' }, 10 | show: { type: Boolean, default: true }, 11 | appear: { type: Boolean, default: false }, 12 | size: { type: String } 13 | }, 14 | render (h) { 15 | const children = [] 16 | if (this.show) { 17 | const props = { 18 | icon: this.icon, 19 | color: this.color, 20 | unelevated: true 21 | } 22 | if (this.size) { 23 | props.round = true 24 | props.size = this.size 25 | } else { 26 | props.fab = true 27 | } 28 | children.push(h(QBtn, { 29 | props, 30 | class: 'shadow-10', 31 | on: { 32 | click: () => this.$emit('click') 33 | } 34 | })) 35 | } 36 | return h('transition', { 37 | props: { 38 | appear: this.appear, 39 | enterActiveClass: 'animated bounceIn', 40 | leaveActiveClass: 'animated bounceOut' 41 | } 42 | }, children) 43 | } 44 | 45 | }) 46 | -------------------------------------------------------------------------------- /lib/commons/OpusImgCaption.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { QImg } from 'quasar' 3 | 4 | export default Vue.extend({ 5 | name: 'OpusImgCaption', 6 | props: { 7 | src: { type: String, required: true }, 8 | width: { type: String, default: '250px' }, 9 | contentClasses: { type: String, default: 'q-pa-md fixed-center text-center' }, 10 | contentStyle: { type: String, default: '' }, 11 | caption: { type: String } 12 | }, 13 | render (h) { 14 | const children = [] 15 | children.push(h(QImg, { 16 | props: { 17 | src: require(`assets/${this.src}`), 18 | width: this.width, 19 | basic: true 20 | } 21 | })) 22 | if (this.$slots.default) { 23 | children.push(this.$slots.default) 24 | } else { 25 | children.push(h('div', 26 | { class: 'text-caption text-grey q-mt-md text-italic' }, 27 | this.caption)) 28 | } 29 | return h('section', { 30 | class: this.contentClasses, 31 | style: 'z-index: -1;' + this.contentStyle 32 | }, children) 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /lib/commons/OpusImgCaptionGroup.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import OpusImgCaption from './OpusImgCaption' 3 | 4 | export default Vue.extend({ 5 | functional: true, 6 | name: 'OpusImgCaptionGroup', 7 | props: { 8 | value: { type: String, required: true }, 9 | options: { type: Object, required: true }, 10 | contextClasses: { type: String } 11 | }, 12 | render (h, { props }) { 13 | const { src, caption } = props.options[props.value] 14 | 15 | return h(OpusImgCaption, { 16 | props: { 17 | src, 18 | caption: caption || 'Nothing to see here...' 19 | }, 20 | class: props.contextClasses 21 | }) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /lib/commons/OpusMoreActionsMenuBtn.vue: -------------------------------------------------------------------------------- 1 | 42 | 77 | -------------------------------------------------------------------------------- /lib/commons/Pomodoro/PomodoroDesktop.vue: -------------------------------------------------------------------------------- 1 | 56 | 70 | -------------------------------------------------------------------------------- /lib/commons/Pomodoro/PomodoroMobile.vue: -------------------------------------------------------------------------------- 1 | 44 | 52 | -------------------------------------------------------------------------------- /lib/commons/Pomodoro/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { Platform } from 'quasar' 3 | 4 | const component = Platform.is.electron ? require('./PomodoroDesktop') : require('./PomodoroMobile') 5 | 6 | export default Vue.extend({ 7 | functional: true, 8 | render (h, context) { 9 | return h( 10 | component.default, 11 | context.data, 12 | context.children) 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /lib/commons/Pomodoro/mixin.js: -------------------------------------------------------------------------------- 1 | import { mapGetters } from 'vuex' 2 | import { padZero, inMinutes } from 'lib/utils' 3 | 4 | export default { 5 | computed: { 6 | ...mapGetters('pomodoro', [ 7 | 'isRunning', 8 | 'currentSprintCount', 9 | 'currentSprintMode', 10 | 'isBreakMode', 11 | 'sprintDuration', 12 | 'elapsedSeconds' 13 | ]), 14 | delta () { 15 | return this.sprintDuration - this.elapsedSeconds 16 | }, 17 | ss () { 18 | return padZero(this.delta % 60, 2) 19 | }, 20 | mm () { 21 | return inMinutes(this.delta, 2) 22 | } 23 | }, 24 | methods: { 25 | start () { 26 | this.$o.pomodoro.start() 27 | this.$emit('start') 28 | }, 29 | reset () { 30 | if (this.elapsedSeconds > 0) { 31 | this.$o.pomodoro.reset() 32 | this.$emit('reset') 33 | } 34 | }, 35 | skip () { 36 | this.$o.pomodoro.skip() 37 | this.$emit('skip') 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/commons/opus-dialog-functions.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | show () { 4 | this.$refs.dialog.show() 5 | }, 6 | hide () { 7 | this.$refs.dialog.hide() 8 | }, 9 | onDialogHide () { 10 | this.$emit('hide') 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/commons/premium-guard/premium-guard-mixin.js: -------------------------------------------------------------------------------- 1 | import { openURL } from 'quasar' 2 | 3 | import PremiumGuardDialog from './PremiumGuardDialog' 4 | 5 | export default { 6 | methods: { 7 | premiumGuardUpdate (option, model, key) { 8 | if (typeof (option) !== 'object') { 9 | model[key] = option 10 | return 11 | } 12 | 13 | if (this.$o.app.isPremium() || !option.premium) { 14 | model[key] = option.value 15 | return 16 | } 17 | 18 | if (this.$q.platform.is.electron) { 19 | openURL(process.env.PREMIUM_REDIRECT_LINK) 20 | return 21 | } 22 | // Show 'Upgrade to Premium Dialog' on mobile. 23 | this.$q.dialog({ 24 | component: PremiumGuardDialog, 25 | parent: this 26 | }) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/dialogs/index.js: -------------------------------------------------------------------------------- 1 | import { Dialog } from 'quasar' 2 | 3 | export default { 4 | confirmDeleteTask (task) { 5 | return Dialog.create({ 6 | title: 'Delete Task', 7 | message: `Remove task ${task.name} forever?
This action cannot be undone.`, 8 | color: 'negative', 9 | persistent: true, 10 | cancel: true, 11 | html: true 12 | }) 13 | }, 14 | confirmDeleteProject (project) { 15 | return Dialog.create({ 16 | title: 'Delete Project', 17 | message: ` 18 | Remove project ${project.name} 19 | and all tasks (${project.tasks.length}) along with it?
20 | This action cannot be undone 21 | `, 22 | color: 'negative', 23 | persistent: true, 24 | cancel: true, 25 | html: true 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/notifications/capacitor.js: -------------------------------------------------------------------------------- 1 | import { Notify } from 'quasar' 2 | 3 | export const create = async (title, { message, icon, handler }) => { 4 | return Notify.create({ 5 | icon, 6 | color: 'primary', 7 | message: title, 8 | caption: message, 9 | position: 'top-right', 10 | actions: [{ label: 'Start', color: 'white', handler }] 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/notifications/electron.js: -------------------------------------------------------------------------------- 1 | export const create = (title, { message, icon, handler = () => {} }) => { 2 | if (Notification.permission === 'granted') { 3 | const notif = new Notification(title, { body: message, icon }) 4 | notif.onclick = handler 5 | return notif 6 | } 7 | 8 | if (Notification.permission !== 'denied') { 9 | return new Promise((resolve, reject) => { 10 | Notification.requestPermission((permission) => { 11 | if (permission === 'granted') { 12 | const n = new Notification(title, { body: message, icon }) 13 | n.onclick = handler 14 | return n 15 | } 16 | return reject(permission) 17 | }) 18 | }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/notifications/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | create: (title, { message, icon, handler }) => new Promise((resolve, reject) => { 3 | return import(`./${process.env.MODE}`) 4 | .then(({ create }) => resolve(create(title, { message, icon, handler }))) 5 | }) 6 | } 7 | -------------------------------------------------------------------------------- /lib/notifications/spa.js: -------------------------------------------------------------------------------- 1 | // no-op 2 | -------------------------------------------------------------------------------- /lib/pomodoro/audio-controller.js: -------------------------------------------------------------------------------- 1 | export default class { 2 | constructor (prefs) { 3 | this.prefs = prefs 4 | this.ticktock = new Audio('statics/media/start.mp3') 5 | this.wind = new Audio('statics/media/restart.mp3') 6 | this.ping = new Audio('statics/media/ping.mp3') 7 | this.halt = new Audio('statics/media/pause.mp3') 8 | } 9 | 10 | start () { 11 | this._stop(this.wind) 12 | this._play(this.ticktock) 13 | } 14 | 15 | pause () { 16 | this._stop(this.ticktock) 17 | this._play(this.halt) 18 | } 19 | 20 | stop () { 21 | this._stop(this.ticktock) 22 | this._play(this.wind) 23 | } 24 | 25 | completed () { 26 | this._stop(this.wind) 27 | this._play(this.ping) 28 | } 29 | 30 | _play (track) { 31 | if (this.prefs.isAudioEnabled()) { 32 | track.play() 33 | } 34 | } 35 | 36 | _stop (track) { 37 | track.pause() 38 | track.currentTime = 0 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/pomodoro/notification-controller.js: -------------------------------------------------------------------------------- 1 | import Notification from 'lib/notifications' 2 | 3 | export default class { 4 | constructor (pomodoro) { 5 | this.pomodoro = pomodoro 6 | } 7 | 8 | async workSprintCompleted (sprintCount) { 9 | const options = { 10 | message: 'Proceed with a short break?', 11 | handler: () => (this.pomodoro.start()) 12 | } 13 | if (sprintCount === 4) { 14 | options.message = 'You have completed 4 consecutive work sprints. Take a long break?' 15 | } 16 | return Notification.create('Work Sprint Completed', options) 17 | } 18 | 19 | async breakSprintCompleted () { 20 | return Notification.create('Break Sprint Completed', { 21 | message: 'Continue with a work sprint?', 22 | handler: () => (this.pomodoro.start()) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/preferences.js: -------------------------------------------------------------------------------- 1 | import { LocalStorage } from 'quasar' 2 | import { toSeconds } from './utils' 3 | 4 | const PreferencesKey = 'opus.pref' 5 | 6 | const DefaultPreferences = Object.freeze({ 7 | audio: true, 8 | sprintDuration: { 9 | work: toSeconds(25), 10 | shortBreak: toSeconds(5), 11 | longBreak: toSeconds(15) 12 | } 13 | }) 14 | 15 | export default class { 16 | constructor (store) { 17 | this.store = store 18 | this.preferences = null 19 | this.initialize() 20 | } 21 | 22 | initialize () { 23 | if (!LocalStorage.has(PreferencesKey)) { 24 | LocalStorage.set(PreferencesKey, { ...DefaultPreferences }) 25 | } 26 | this.preferences = LocalStorage.getItem(PreferencesKey) 27 | this.store.commit('pomodoro/setDurations', this.preferences.sprintDuration) 28 | } 29 | 30 | isAudioEnabled () { 31 | return this.preferences.audio 32 | } 33 | 34 | getSprintDuration () { 35 | return this.preferences.sprintDuration 36 | } 37 | 38 | save ({ audio, sprintDuration: { work, shortBreak, longBreak } }) { 39 | this.preferences.audio = audio 40 | this.preferences.sprintDuration = { work, shortBreak, longBreak } 41 | LocalStorage.set(PreferencesKey, { ...this.preferences }) 42 | this.store.commit('pomodoro/setDurations', this.preferences.sprintDuration) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enfocus.app", 3 | "version": "1.8.1", 4 | "description": "Task Management Application", 5 | "productName": "enFocus", 6 | "cordovaId": "com.nightowl.enfocus.app", 7 | "capacitorId": "com.nightowl.enfocus.app", 8 | "author": "yev ", 9 | "private": true, 10 | "scripts": { 11 | "lint": "eslint --ext .js,.vue src lib", 12 | "test": "echo \"No test specified\" && exit 0", 13 | "deploy:linux": "quasar build -m electron -T linux -P always", 14 | "deploy:windows": "quasar build -m electron -T win -P always", 15 | "deploy:desktop": "yarn deploy:linux && yarn deploy:windows" 16 | }, 17 | "dependencies": { 18 | "@capacitor/core": "^2.1.0", 19 | "@quasar/extras": "^1.8.1", 20 | "apexcharts": "^3.24.0", 21 | "axios": "^0.21.1", 22 | "capacitor-admob-advanced": "^1.4.0", 23 | "pouchdb-adapter-cordova-sqlite": "^2.0.7", 24 | "pouchdb-adapter-idb": "^7.2.1", 25 | "quasar": "^1.12.4", 26 | "rxdb": "^8.8.0", 27 | "rxjs": "^6.5.4", 28 | "vue-apexcharts": "^1.5.3" 29 | }, 30 | "devDependencies": { 31 | "@quasar/app": "^1.9.4", 32 | "@quasar/quasar-app-extension-dotenv": "^1.0.1", 33 | "babel-eslint": "^10.0.1", 34 | "devtron": "^1.4.0", 35 | "electron": "^9.4.0", 36 | "electron-builder": "^22.4.0", 37 | "electron-debug": "^3.0.1", 38 | "electron-devtools-installer": "^2.2.4", 39 | "electron-packager": "^14.1.1", 40 | "eslint": "^6.8.0", 41 | "eslint-config-standard": "^14.1.0", 42 | "eslint-loader": "^3.0.3", 43 | "eslint-plugin-import": "^2.14.0", 44 | "eslint-plugin-node": "^11.0.0", 45 | "eslint-plugin-promise": "^4.0.1", 46 | "eslint-plugin-standard": "^4.0.0", 47 | "eslint-plugin-vue": "^6.1.2" 48 | }, 49 | "engines": { 50 | "node": ">= 10.18.1", 51 | "npm": ">= 6.13.4", 52 | "yarn": ">= 1.21.1" 53 | }, 54 | "browserslist": [ 55 | "last 1 version, not dead, ie >= 11" 56 | ], 57 | "resolutions": { 58 | "@babel/parser": "7.7.5" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /quasar.extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "@quasar/dotenv": { 3 | "env_development": ".env.dev", 4 | "env_production": ".env", 5 | "common_root_object": "none", 6 | "create_env_files": true, 7 | "add_env_to_gitignore": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src-capacitor/android/.gitignore: -------------------------------------------------------------------------------- 1 | # NPM renames .gitignore to .npmignore 2 | # In order to prevent that, we remove the initial "." 3 | # And the CLI then renames it 4 | 5 | # Using Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore 6 | 7 | # Built application files 8 | *.apk 9 | *.ap_ 10 | *.aab 11 | 12 | # Files for the ART/Dalvik VM 13 | *.dex 14 | 15 | # Java class files 16 | *.class 17 | 18 | # Generated files 19 | bin/ 20 | gen/ 21 | out/ 22 | release/ 23 | 24 | # Gradle files 25 | .gradle/ 26 | build/ 27 | 28 | # Local configuration file (sdk path, etc) 29 | local.properties 30 | 31 | # Proguard folder generated by Eclipse 32 | proguard/ 33 | 34 | # Log Files 35 | *.log 36 | 37 | # Android Studio Navigation editor temp files 38 | .navigation/ 39 | 40 | # Android Studio captures folder 41 | captures/ 42 | 43 | # IntelliJ 44 | *.iml 45 | .idea/workspace.xml 46 | .idea/tasks.xml 47 | .idea/gradle.xml 48 | .idea/assetWizardSettings.xml 49 | .idea/dictionaries 50 | .idea/libraries 51 | # Android Studio 3 in .gitignore file. 52 | .idea/caches 53 | .idea/modules.xml 54 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 55 | .idea/navEditor.xml 56 | 57 | # Keystore files 58 | # Uncomment the following lines if you do not want to check your keystore files in. 59 | #*.jks 60 | #*.keystore 61 | 62 | # External native build folder generated in Android Studio 2.2 and later 63 | .externalNativeBuild 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | 87 | # Cordova plugins for Capacitor 88 | capacitor-cordova-android-plugins 89 | 90 | # Copied web assets 91 | app/src/main/assets/public 92 | -------------------------------------------------------------------------------- /src-capacitor/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | !/build/.npmkeep 3 | -------------------------------------------------------------------------------- /src-capacitor/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | applicationId "com.nightowl.enfocus.app" 7 | minSdkVersion rootProject.ext.minSdkVersion 8 | targetSdkVersion rootProject.ext.targetSdkVersion 9 | versionCode 8 10 | versionName "1.7.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | repositories { 22 | flatDir{ 23 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(include: ['*.jar'], dir: 'libs') 29 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 30 | implementation project(':capacitor-android') 31 | testImplementation "junit:junit:$junitVersion" 32 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 33 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 34 | implementation project(':capacitor-cordova-android-plugins') 35 | } 36 | 37 | apply from: 'capacitor.build.gradle' 38 | 39 | try { 40 | def servicesJSON = file('google-services.json') 41 | if (servicesJSON.text) { 42 | apply plugin: 'com.google.gms.google-services' 43 | } 44 | } catch(Exception e) { 45 | logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work") 46 | } 47 | -------------------------------------------------------------------------------- /src-capacitor/android/app/capacitor.build.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | 3 | android { 4 | compileOptions { 5 | sourceCompatibility JavaVersion.VERSION_1_8 6 | targetCompatibility JavaVersion.VERSION_1_8 7 | } 8 | } 9 | 10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" 11 | dependencies { 12 | implementation project(':capacitor-admob-advanced') 13 | implementation project(':capacitor-keep-screen-on') 14 | implementation "com.android.billingclient:billing:2.2.0" 15 | } 16 | 17 | 18 | if (hasProperty('postBuildExtras')) { 19 | postBuildExtras() 20 | } 21 | -------------------------------------------------------------------------------- /src-capacitor/android/app/debug/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":7,"versionName":"1.6.0","enabled":true,"outputFile":"app-debug.apk","fullName":"debug","baseName":"debug","dirName":""},"path":"app-debug.apk","properties":{}}] -------------------------------------------------------------------------------- /src-capacitor/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() throws Exception { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.getcapacitor.app", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/assets/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "com.nightowl.enfocus.app", 3 | "appName": "enFocus", 4 | "bundledWebRuntime": false, 5 | "npmClient": "yarn", 6 | "webDir": "www", 7 | "plugins": { 8 | "SplashScreen": { 9 | "launchShowDuration": 4000 10 | }, 11 | "cordova-plugin-purchase": { 12 | "BILLING_KEY": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbYnf9Vdf//ad4befFPsopdnfrugO3e7R2miJijpel1hxFlNexlOn5oWfbYcMgWmcKJkkLzZ71EysOyWKQ6XN71VkXFonCZEqNxq2djfWNoatGI2c6hNSJ09PoPT0s8kQ/FR7VfN8IGxp7v93MJHX60f+kmt4Aav+7kaDZGmVoYi6ZdU+yqye1pigngHacb/gYVI/54Fuhf8JGnt4mF9ptoskDAJ4Xx6gVY1Ug5/e6jXRepVazQAvPbN7EZSfFkaHjSTW+/YzhopMbkO1wque/sO1/80axKN+1SP8prsA8V8yVAHoj2KYfd/AO/+VoGXIX3QQGAKz5v7tb1fqWtXvwIDAQAB" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/java/com/nightowl/enfocus/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.nightowl.enfocus.app; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.devutex.admobadvanced.AdMobAdvanced; 6 | import com.getcapacitor.BridgeActivity; 7 | import com.getcapacitor.Plugin; 8 | import com.go.capacitor.keepscreenon.CapacitorKeepScreenOn; 9 | 10 | import java.util.ArrayList; 11 | 12 | public class MainActivity extends BridgeActivity { 13 | @Override 14 | public void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | 17 | // Initializes the Bridge 18 | this.init(savedInstanceState, new ArrayList>() {{ 19 | // Additional plugins you've installed go here 20 | // Ex: add(TotallyAwesomePlugin.class); 21 | add(CapacitorKeepScreenOn.class); 22 | add(AdMobAdvanced.class); 23 | }}); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | enFocus 4 | enFocus 5 | com.nightowl.enfocus.app 6 | com.nightowl.enfocus.app 7 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbYnf9Vdf//ad4befFPsopdnfrugO3e7R2miJijpel1hxFlNexlOn5oWfbYcMgWmcKJkkLzZ71EysOyWKQ6XN71VkXFonCZEqNxq2djfWNoatGI2c6hNSJ09PoPT0s8kQ/FR7VfN8IGxp7v93MJHX60f+kmt4Aav+7kaDZGmVoYi6ZdU+yqye1pigngHacb/gYVI/54Fuhf8JGnt4mF9ptoskDAJ4Xx6gVY1Ug5/e6jXRepVazQAvPbN7EZSfFkaHjSTW+/YzhopMbkO1wque/sO1/80axKN+1SP8prsA8V8yVAHoj2KYfd/AO/+VoGXIX3QQGAKz5v7tb1fqWtXvwIDAQAB 8 | 9 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 17 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src-capacitor/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src-capacitor/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.6.1' 11 | classpath 'com.google.gms:google-services:4.3.3' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | apply from: "variables.gradle" 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | jcenter() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /src-capacitor/android/capacitor.settings.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | include ':capacitor-android' 3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') 4 | 5 | include ':capacitor-admob-advanced' 6 | project(':capacitor-admob-advanced').projectDir = new File('../node_modules/capacitor-admob-advanced/android') 7 | 8 | include ':capacitor-keep-screen-on' 9 | project(':capacitor-keep-screen-on').projectDir = new File('../node_modules/capacitor-keep-screen-on/android') 10 | -------------------------------------------------------------------------------- /src-capacitor/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # Supports AndroidX 20 | android.useAndroidX=true 21 | android.enableJetifier=true -------------------------------------------------------------------------------- /src-capacitor/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src-capacitor/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 30 13:14:22 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /src-capacitor/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src-capacitor/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':capacitor-cordova-android-plugins' 3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') 4 | 5 | apply from: 'capacitor.settings.gradle' -------------------------------------------------------------------------------- /src-capacitor/android/variables.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | minSdkVersion = 21 3 | compileSdkVersion = 29 4 | targetSdkVersion = 29 5 | androidxAppCompatVersion = '1.1.0' 6 | androidxCoreVersion = '1.2.0' 7 | androidxMaterialVersion = '1.1.0-rc02' 8 | androidxBrowserVersion = '1.2.0' 9 | androidxLocalbroadcastmanagerVersion = '1.0.0' 10 | firebaseMessagingVersion = '20.1.2' 11 | playServicesLocationVersion = '17.0.0' 12 | junitVersion = '4.12' 13 | androidxJunitVersion = '1.1.1' 14 | androidxEspressoCoreVersion = '3.2.0' 15 | cordovaAndroidVersion = '7.0.0' 16 | } -------------------------------------------------------------------------------- /src-capacitor/capacitor-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | capacitor: true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src-capacitor/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "com.nightowl.enfocus.app", 3 | "appName": "enFocus", 4 | "bundledWebRuntime": false, 5 | "npmClient": "yarn", 6 | "webDir": "www", 7 | "plugins": { 8 | "SplashScreen": { 9 | "launchShowDuration": 4000 10 | }, 11 | "cordova-plugin-purchase": { 12 | "BILLING_KEY": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbYnf9Vdf//ad4befFPsopdnfrugO3e7R2miJijpel1hxFlNexlOn5oWfbYcMgWmcKJkkLzZ71EysOyWKQ6XN71VkXFonCZEqNxq2djfWNoatGI2c6hNSJ09PoPT0s8kQ/FR7VfN8IGxp7v93MJHX60f+kmt4Aav+7kaDZGmVoYi6ZdU+yqye1pigngHacb/gYVI/54Fuhf8JGnt4mF9ptoskDAJ4Xx6gVY1Ug5/e6jXRepVazQAvPbN7EZSfFkaHjSTW+/YzhopMbkO1wque/sO1/80axKN+1SP8prsA8V8yVAHoj2KYfd/AO/+VoGXIX3QQGAKz5v7tb1fqWtXvwIDAQAB" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "com.nightowl.enfocus.app", 3 | "appName": "enFocus", 4 | "bundledWebRuntime": false, 5 | "npmClient": "yarn", 6 | "webDir": "www", 7 | "plugins": { 8 | "SplashScreen": { 9 | "launchShowDuration": 4000 10 | }, 11 | "cordova-plugin-purchase": { 12 | "BILLING_KEY": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbYnf9Vdf//ad4befFPsopdnfrugO3e7R2miJijpel1hxFlNexlOn5oWfbYcMgWmcKJkkLzZ71EysOyWKQ6XN71VkXFonCZEqNxq2djfWNoatGI2c6hNSJ09PoPT0s8kQ/FR7VfN8IGxp7v93MJHX60f+kmt4Aav+7kaDZGmVoYi6ZdU+yqye1pigngHacb/gYVI/54Fuhf8JGnt4mF9ptoskDAJ4Xx6gVY1Ug5/e6jXRepVazQAvPbN7EZSfFkaHjSTW+/YzhopMbkO1wque/sO1/80axKN+1SP8prsA8V8yVAHoj2KYfd/AO/+VoGXIX3QQGAKz5v7tb1fqWtXvwIDAQAB" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src-capacitor/ios/App/App/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/cordova_plugins.js: -------------------------------------------------------------------------------- 1 | 2 | cordova.define('cordova/plugin_list', function(require, exports, module) { 3 | module.exports = [ 4 | { 5 | "id": "cordova-plugin-network-information.Connection", 6 | "file": "plugins/cordova-plugin-network-information/www/Connection.js", 7 | "pluginId": "cordova-plugin-network-information", 8 | "clobbers": [ 9 | "Connection" 10 | ] 11 | }, 12 | { 13 | "id": "cordova-plugin-network-information.network", 14 | "file": "plugins/cordova-plugin-network-information/www/network.js", 15 | "pluginId": "cordova-plugin-network-information", 16 | "clobbers": [ 17 | "navigator.connection", 18 | "navigator.network.connection" 19 | ] 20 | }, 21 | { 22 | "id": "cordova-plugin-sqlite-2.sqlitePlugin", 23 | "file": "plugins/cordova-plugin-sqlite-2/dist/sqlite-plugin.js", 24 | "pluginId": "cordova-plugin-sqlite-2", 25 | "clobbers": [ 26 | "sqlitePlugin" 27 | ] 28 | }, 29 | { 30 | "id": "cordova-plugin-purchase.InAppPurchase", 31 | "file": "plugins/cordova-plugin-purchase/www/store-ios.js", 32 | "pluginId": "cordova-plugin-purchase", 33 | "clobbers": [ 34 | "store" 35 | ] 36 | } 37 | ]; 38 | module.exports.metadata = 39 | // TOP OF METADATA 40 | { 41 | "cordova-plugin-network-information": "2.0.2", 42 | "cordova-plugin-purchase": "10.2.0", 43 | "cordova-plugin-sqlite-2": "1.0.6" 44 | }; 45 | // BOTTOM OF METADATA 46 | }); 47 | -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/5.db20d1f3.css: -------------------------------------------------------------------------------- 1 | .q-item[data-v-ea57afb0]{border-top-left-radius:1rem;border-bottom-left-radius:1rem}.active[data-v-ea57afb0]{color:#3299ad!important} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/6.4e2a38a7.css: -------------------------------------------------------------------------------- 1 | .sleeve[data-v-6597b37c]:after,.sleeve[data-v-6597b37c]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-6597b37c] .q-layout-container div.absolute-full{right:0px!important}[data-v-6597b37c] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-6597b37c] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-6597b37c] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-6597b37c] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/7.1b22cbe8.css: -------------------------------------------------------------------------------- 1 | .pill{padding:10px 4px;border-radius:.2rem;border-color:currentColor;cursor:pointer} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/8.c8bc3c72.css: -------------------------------------------------------------------------------- 1 | .top-left[data-v-1c25dbc2]{border-top-left-radius:16px}.top-right[data-v-1c25dbc2]{border-top-right-radius:16px}.bottom-left[data-v-1c25dbc2]{border-bottom-left-radius:16px}.bottom-right[data-v-1c25dbc2]{border-bottom-right-radius:16px}.active[data-v-1c25dbc2]{outline-color:currentColor;outline-width:2px;outline-style:dashed;background-color:#eee} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.068be305.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-78724254]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-78724254]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-78724254]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-78724254]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-78724254]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.2a6b31f3.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-5029828a]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-5029828a]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-5029828a]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-5029828a]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-5029828a]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.3b3ed363.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-1361a359]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-1361a359]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-1361a359]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-1361a359]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-1361a359]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.517ea842.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-3afbbf51]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-3afbbf51]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-3afbbf51]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-3afbbf51]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-3afbbf51]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.564d0bb9.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-2fd9e8cc]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-2fd9e8cc]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-2fd9e8cc]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-2fd9e8cc]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-2fd9e8cc]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.a2448107.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-496252d6]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-496252d6]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-496252d6]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-496252d6]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-496252d6]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.c9d7f250.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-10a093bc]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-10a093bc]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-10a093bc]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-10a093bc]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-10a093bc]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.dd3ee329.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-291c5140]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-291c5140]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-291c5140]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-291c5140]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-291c5140]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.f6034d34.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-97c03560]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-97c03560]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-97c03560]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-97c03560]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-97c03560]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/css/chunk-common.fb06f277.css: -------------------------------------------------------------------------------- 1 | .night-fade[data-v-136d229d]{background-image:linear-gradient(0deg,#a18cd1 0%,#fbc2eb)}.true-sunset[data-v-136d229d]{background-image:linear-gradient(90deg,#fa709a 0%,#fee140)}.morpheus-den[data-v-136d229d]{background-image:linear-gradient(0deg,#30cfd0 0%,#330867)}.passionate-bed[data-v-136d229d]{background-image:linear-gradient(90deg,#ff758c 0%,#ff7eb3)}.night-party[data-v-136d229d]{background-image:linear-gradient(0deg,#0250c5 0%,#d43f8d)}.description[data-v-2821c4b3]{border-bottom:1px dashed #bdbdbd;padding-bottom:5px;min-height:3rem}.sleeve[data-v-c899b3dc]:after,.sleeve[data-v-c899b3dc]:before{box-shadow:0 -25px 0 0 #fafafa}[data-v-c899b3dc] .q-layout-container div.absolute-full{right:0px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll{left:0px;right:0px!important;scrollbar-width:thin!important;width:100%!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar{background-color:#fff;width:5px!important}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-thumb{border-radius:10px;background:linear-gradient(270deg,#80deea,#1ccad8)}[data-v-c899b3dc] .q-layout-container div.absolute-full .scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1);border:1px solid #ccc}.item-label[data-v-3cdc3b32]{max-width:200px}@media (min-width:1023px){.item-label[data-v-3cdc3b32]{max-width:140px}} -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOkCnqEu92Fr1MmgVxGIzQ.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOkCnqEu92Fr1MmgVxGIzQ.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmEU9fChc-.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmEU9fChc-.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmSU5fChc-.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmSU5fChc-.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmWUlfChc-.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmWUlfChc-.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmYUtfChc-.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOlCnqEu92Fr1MmYUtfChc-.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/KFOmCnqEu92Fr1Mu7GxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/KFOmCnqEu92Fr1Mu7GxM.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/index.html: -------------------------------------------------------------------------------- 1 | enFocus
-------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/11.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[11],{"04dd":function(e,a,t){"use strict";t.r(a);var n=function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("q-layout",{attrs:{view:"lHh Lpr lFf"}},[t("q-header",{staticClass:"q-pl-md q-py-xs bg-white text-primary shadow-light admob-padding"},[t("q-toolbar",[t("q-toolbar-title",{staticClass:"underline"},[e._v("\n "+e._s(e.$route.name)+"\n ")]),t("q-btn",{attrs:{color:"accent",flat:"",round:"",dense:"",icon:"menu_open"},on:{click:function(a){e.leftDrawerOpen=!0}}})],1),t("div",{staticClass:"sleeve q-pb-sm"})],1),t("q-drawer",{attrs:{"show-if-above":"",side:"right",bordered:"","content-class":"bg-grey-1 admob-padding"},model:{value:e.leftDrawerOpen,callback:function(a){e.leftDrawerOpen=a},expression:"leftDrawerOpen"}},[t("side-nav")],1),t("q-page-container",[t("keep-alive",[t("router-view")],1)],1),t("q-footer",{staticClass:"bg-white shadow-1"},[t("menu-nav")],1)],1)},r=[],o=t("ef1c"),l=t("99b8"),s={name:"DefaultLayout",components:{MenuNav:o["a"],SideNav:l["a"]},data:function(){return{leftDrawerOpen:!1}}},i=s,c=t("2877"),d=t("4d5a"),u=t("e359"),p=t("65c6"),f=t("6ac5"),w=t("9c40"),b=t("9404"),v=t("09e3"),m=t("7ff0"),h=t("eebe"),q=t.n(h),g=Object(c["a"])(i,n,r,!1,null,null,null);a["default"]=g.exports;q()(g,"components",{QLayout:d["a"],QHeader:u["a"],QToolbar:p["a"],QToolbarTitle:f["a"],QBtn:w["a"],QDrawer:b["a"],QPageContainer:v["a"],QFooter:m["a"]})}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/13.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[13],{e51e:function(t,e,n){"use strict";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"fixed-center text-center"},[t._m(0),t._m(1),n("q-btn",{staticStyle:{width:"200px"},attrs:{color:"secondary",to:"/",label:"Go back"}})],1)},c=[function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("p",[r("img",{staticStyle:{width:"30vw","max-width":"150px"},attrs:{src:n("c4e4")}})])},function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("p",{staticClass:"text-faded"},[t._v("Sorry, nothing here..."),n("strong",[t._v("(404)")])])}],a={name:"Error404"},s=a,i=n("2877"),l=n("9c40"),o=n("eebe"),u=n.n(o),d=Object(i["a"])(s,r,c,!1,null,null,null);e["default"]=d.exports;u()(d,"components",{QBtn:l["a"]})}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/14.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[14],{"7f1d":function(t,e,o){"use strict";o.r(e);var s=function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("q-page",{attrs:{padding:""}},[t.projects.length?o("q-list",{staticClass:"column q-gutter-y-md q-pt-xs"},t._l(t.projects,(function(e){return o("project-item",{key:e.id,attrs:{project:e,flat:""},on:{click:t.showProjectDetails},scopedSlots:t._u([{key:"actions",fn:function(){return[o("opus-more-actions-btn",{attrs:{target:e,actions:t.actions}})]},proxy:!0}],null,!0)})})),1):o("opus-img-caption",{attrs:{caption:"You currently have 0 Projects",src:"solution_mindset.svg"}}),o("q-page-sticky",{staticStyle:{"z-index":"2001"},attrs:{offset:[18,-26],position:"bottom-right"}},[o("opus-fab",{attrs:{show:!t.hasOpenDialog},on:{click:t.showNewProjectDialog}})],1)],1)},n=[],a=o("45de"),c=o("b1cd"),i=o("8d3d"),r=o("777c"),p=o("ba2d"),l={name:"Projects",mixins:[a["a"]],components:{OpusFab:c["a"],OpusImgCaption:i["a"],ProjectItem:p["a"],OpusMoreActionsBtn:r["a"]}},u=l,d=o("2877"),g=o("9989"),m=o("1c1c"),f=o("de5e"),b=o("eebe"),j=o.n(b),w=Object(d["a"])(u,s,n,!1,null,null,null);e["default"]=w.exports;j()(w,"components",{QPage:g["a"],QList:m["a"],QPageSticky:f["a"]})}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/15.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[15],{b439:function(e,t,n){"use strict";n.r(t);var o=function(){var e=this,t=this,n=t.$createElement,o=t._self._c||n;return o("q-page",{attrs:{padding:""}},[o("q-list",[o("q-item-label",{staticClass:"q-py-none",attrs:{header:""}},[o("q-select",{staticClass:"text-h6",attrs:{value:t.model,options:t.options,"map-options":"",behavior:!0===t.$q.platform.is.ios?"dialog":"menu"},on:{input:function(n){return t.premiumGuardUpdate(n,e,"model")}},scopedSlots:t._u([{key:"option",fn:function(e){return[o("q-item",t._g(t._b({},"q-item",e.itemProps,!1),e.itemEvents),[o("q-item-section",[o("q-item-label",{domProps:{innerHTML:t._s(e.opt.label)}})],1),e.opt.premium&&!t.$o.app.isPremium()?o("q-item-section",{attrs:{side:""}},[o("q-badge",{attrs:{color:"amber",label:"Premium"}})],1):t._e()],1)]}}])})],1)],1),o(t.chartComponent,{tag:"component",attrs:{value:t.model}})],1)},a=[],i=n("50ea"),s={name:"ReportsPage",mixins:[i["a"]],computed:{chartComponent:function(){return"custom"===this.model?function(){return Promise.all([n.e(0),n.e(1)]).then(n.bind(null,"77b3"))}:function(){return Promise.all([n.e(0),n.e(1),n.e(2)]).then(n.bind(null,"c147"))}}}},r=s,l=n("2877"),m=n("9989"),u=n("1c1c"),p=n("0170"),c=n("ddd8"),d=n("66e5"),b=n("4074"),q=n("58a8"),f=n("eebe"),h=n.n(f),g=Object(l["a"])(r,o,a,!1,null,null,null);t["default"]=g.exports;h()(g,"components",{QPage:m["a"],QList:u["a"],QItemLabel:p["a"],QSelect:c["a"],QItem:d["a"],QItemSection:b["a"],QBadge:q["a"]})}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/18.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[18],{f02f:function(t,e,a){"use strict";a.r(e);var n=function(){var t=this,e=this,a=e.$createElement,n=e._self._c||a;return n("full-page-layout",{attrs:{title:e.$route.name}},[n("q-page",{staticClass:"bg-grey-1 overflow-hidden",attrs:{padding:""}},[n("div",{staticClass:"row items-end text-secondary q-gutter-x-md q-px-xl q-pt-lg"},[n("q-select",{staticClass:"text-h2 col text-primary",attrs:{value:e.model,options:e.options,"map-options":"",color:"secondary",behavior:!0===e.$q.platform.is.ios?"dialog":"menu"},on:{input:function(a){return e.premiumGuardUpdate(a,t,"model")}},scopedSlots:e._u([{key:"option",fn:function(t){return[n("q-item",e._g(e._b({},"q-item",t.itemProps,!1),t.itemEvents),[n("q-item-section",[n("q-item-label",{domProps:{innerHTML:e._s(t.opt.label)}})],1),t.opt.premium&&!e.$o.app.isPremium()?n("q-item-section",{attrs:{side:""}},[n("q-badge",{attrs:{color:"amber",label:"Premium"}})],1):e._e()],1)]}}])}),n("q-space"),n("div",{staticClass:"text-h1 text-weight-light"},[e._v(e._s(e._f("formatDate")(e.currentDate,"D")))]),n("div",{staticClass:"column"},[n("div",{staticClass:"text-h2 text-weight-bold text-uppercase"},[e._v(e._s(e._f("formatDate")(e.currentDate,"MMMM")))]),n("div",{staticClass:"text-h4"},[e._v(e._s(e._f("formatDate")(e.currentDate,"dddd")))])])],1),n("div",{staticClass:"q-pa-lg q-px-xl q-mt-lg"},[n(e.chartComponent,{tag:"component",attrs:{value:e.model}})],1)])],1)},o=[],s=a("50ea"),i=a("a201"),r={name:"Reports",components:{FullPageLayout:i["a"]},mixins:[s["a"]],computed:{currentDate:function(){return Date.now()},chartComponent:function(){return"custom"===this.model?function(){return Promise.all([a.e(0),a.e(1)]).then(a.bind(null,"77b3"))}:function(){return Promise.all([a.e(0),a.e(1),a.e(2)]).then(a.bind(null,"c147"))}}}},l=r,c=a("2877"),m=a("9989"),u=a("ddd8"),p=a("66e5"),d=a("4074"),f=a("0170"),g=a("58a8"),b=a("2c91"),h=a("eebe"),q=a.n(h),v=Object(c["a"])(l,n,o,!1,null,null,null);e["default"]=v.exports;q()(v,"components",{QPage:m["a"],QSelect:u["a"],QItem:p["a"],QItemSection:d["a"],QItemLabel:f["a"],QBadge:g["a"],QSpace:b["a"]})}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/2.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[2],{c147:function(t,e,r){"use strict";r.r(e);var n=function(){var t=this,e=t.$createElement,r=t._self._c||e;return t.loading?t._e():r("section",{staticClass:"q-mt-lg"},[t.reports.length?[r(t.chartComponent,{key:t.value,ref:"chart",tag:"component",attrs:{data:t.reports}}),r("div",{staticClass:"q-mt-xl q-pt-xl desktop-only"}),r("project-donut",{attrs:{data:t.reports}})]:r("opus-img-caption",{staticClass:"absolute-center",staticStyle:{"z-index":"2001","margin-top":"4rem"},attrs:{caption:"No Data",src:"financial_data.svg",width:t.emptyImgPlaceholderWidth}})],2)},a=[],s=r("967e"),o=r.n(s),i=(r("96cf"),r("fa84")),u=r.n(i),c=r("0e3e"),d=r("44ba"),l=r("bd4c"),p=r("8d3d"),f=r("d342"),m=l["b"].subtractFromDate,h={name:"StandardReports",components:{OpusImgCaption:p["a"],ProjectDonut:f["a"]},mixins:[c["a"]],props:{value:{type:String,required:!0}},data:function(){return{reports:[],loading:!1}},watch:{value:{immediate:!0,handler:function(t,e){t!==e&&this.render(t)}}},computed:{isLinear:function(){return"today"===this.value||"yesterday"===this.value},emptyImgPlaceholderWidth:function(){return this.$q.platform.is.mobile?"250px":"50vw"},chartComponent:function(){return this.isLinear?function(){return Promise.all([r.e(0),r.e(10)]).then(r.bind(null,"2366"))}:function(){return Promise.all([r.e(0),r.e(3)]).then(r.bind(null,"ec8f"))}}},methods:{render:function(t){var e=this;return u()(o.a.mark((function r(){var n,a,s;return o.a.wrap((function(r){while(1)switch(r.prev=r.next){case 0:r.prev=0,e.loading=!0,r.t0=t,r.next="today"===r.t0?5:"yesterday"===r.t0?9:"seven"===r.t0?14:"fourteen"===r.t0?19:24;break;case 5:return r.next=7,d["a"].findDates({from:Date.now()});case 7:return e.reports=r.sent,r.abrupt("break",26);case 9:return n=m(Date.now(),{days:1}),r.next=12,d["a"].findDates({from:n,to:n});case 12:return e.reports=r.sent,r.abrupt("break",26);case 14:return a=m(Date.now(),{days:7}),r.next=17,d["a"].findDates({from:a});case 17:return e.reports=r.sent,r.abrupt("break",26);case 19:return s=m(Date.now(),{days:14}),r.next=22,d["a"].findDates({from:s});case 22:return e.reports=r.sent,r.abrupt("break",26);case 24:return e.reports=[],r.abrupt("break",26);case 26:return r.prev=26,e.loading=!1,r.finish(26);case 29:case"end":return r.stop()}}),r,null,[[0,,26,29]])})))()},updateRecords:function(){this.render(this.value)}}},b=h,v=r("2877"),w=Object(v["a"])(b,n,a,!1,null,null,null);e["default"]=w.exports}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/20.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[20],{"0591":function(n,r,e){"use strict";e.r(r),e.d(r,"create",(function(){return s}));var t=e("967e"),a=e.n(t),c=(e("96cf"),e("fa84")),o=e.n(c),i=e("2a19"),s=function(){var n=o()(a.a.mark((function n(r,e){var t,c,o;return a.a.wrap((function(n){while(1)switch(n.prev=n.next){case 0:return t=e.message,c=e.icon,o=e.handler,n.abrupt("return",i["a"].create({icon:c,color:"primary",message:r,caption:t,position:"top-right",actions:[{label:"Start",color:"white",handler:o}]}));case 2:case"end":return n.stop()}}),n)})));return function(r,e){return n.apply(this,arguments)}}()}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/5.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[5],{"0820":function(t,e,a){"use strict";a.r(e);var s=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("q-layout",{attrs:{view:"lHh Lpr lFf"}},[a("q-drawer",{attrs:{mini:"","show-if-above":"",value:!0,width:200,breakpoint:500,bordered:"","no-swipe-open":"","no-swipe-close":"","no-swipe-backdrop":"","content-class":"bg-grey-3 column"}},[a("q-scroll-area",{staticClass:"fit bg-secondary col"},[a("q-list",{attrs:{padding:""}},[a("q-item",{staticClass:"q-mb-md",attrs:{clickable:""}},[a("q-item-section",{attrs:{avatar:""}},[a("q-avatar",{attrs:{rounded:""}},[a("img",{attrs:{src:"statics/desktop-sidenav-icon.png"}})])],1)],1),t._l(t.menus,(function(e){return a("q-item",{directives:[{name:"ripple",rawName:"v-ripple"}],key:e.name,staticClass:"q-mb-xs text-white",attrs:{to:e.path,exact:e.exact,clickable:"","active-class":"bg-grey-1 shadow-light active"}},[a("q-item-section",{attrs:{avatar:""}},[a("q-icon",{attrs:{name:e.icon,size:"xs"}})],1),a("q-item-section",[t._v("\n "+t._s(e.name)+"\n ")])],1)}))],2)],1),a("q-list",{staticClass:"q-mt-auto col-auto bg-secondary"},[a("q-separator"),a("q-item",{directives:[{name:"ripple",rawName:"v-ripple"}],staticClass:"text-white",attrs:{dense:"",clickable:""},on:{click:t.showSettingsDialog}},[a("q-item-section",{attrs:{avatar:""}},[a("q-icon",{attrs:{name:"settings",size:"xs"}})],1),a("q-item-section",[t._v("Settings")])],1)],1)],1),a("q-page-container",[a("keep-alive",[a("router-view")],1)],1)],1)},i=[],n=a("c289"),r={name:"DefaultDesktopLayout",data:function(){return{menus:[{name:"tasks",path:"/",icon:"fas fa-tasks",exact:!0},{name:"projects",path:"/projects",icon:"fa fa-laptop-code"},{name:"eisenhower",path:"/eisenhower",icon:"fas fa-th-large"},{name:"reports",path:"/reports",icon:"fas fa-chart-pie"}]}},methods:{showSettingsDialog:function(){return this.$q.dialog({component:n["a"],parent:this})}}},o=r,c=(a("de48"),a("2877")),l=a("4d5a"),p=a("9404"),m=a("4983"),d=a("1c1c"),u=a("66e5"),b=a("4074"),w=a("cb32"),f=a("0016"),h=a("eb85"),v=a("09e3"),q=a("714f"),g=a("eebe"),k=a.n(g),Q=Object(c["a"])(o,s,i,!1,null,"ea57afb0",null);e["default"]=Q.exports;k()(Q,"components",{QLayout:l["a"],QDrawer:p["a"],QScrollArea:m["a"],QList:d["a"],QItem:u["a"],QItemSection:b["a"],QAvatar:w["a"],QIcon:f["a"],QSeparator:h["a"],QPageContainer:v["a"]}),k()(Q,"directives",{Ripple:q["a"]})},b0b3:function(t,e,a){},de48:function(t,e,a){"use strict";var s=a("b0b3"),i=a.n(s);i.a}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/js/6.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[6],{8919:function(t,a,e){},c3ac:function(t,a,e){"use strict";var s=e("8919"),o=e.n(s);o.a},ce04:function(t,a,e){"use strict";e.r(a);var s=function(t,a){var e=a._c;return e("q-page",[e("q-layout",{staticStyle:{height:"100vh"},attrs:{container:"",view:"lHh Lpr lFf"}},[e("q-drawer",{attrs:{value:!0,"show-if-above":"",bordered:"","no-swipe-open":"","no-swipe-close":"","no-swipe-backdrop":"",behavior:"desktop","content-class":"bg-grey-2"}},[e("q-layout",{attrs:{container:""}},[e("q-header",{staticClass:"bg-grey-1 q-px-sm q-pl-md q-py-xs text-primary shadow-light"},[e("q-toolbar",[e("q-toolbar-title",{staticClass:"text-bold"},[a._v("\n "+a._s(a.props.title)+"\n ")])],1),e("div",{staticClass:"sleeve"})],1),e("q-page-container",[e("q-page",{staticClass:"q-pb-md"},[a._t("side")],2)],1),e("q-footer",{staticClass:"bg-grey-3",attrs:{bordered:""}},[a._t("side-bottom-actions",[e("div",{staticClass:"q-pa-md"})])],2)],1)],1),e("q-page-container",[a._t("default")],2)],1)],1)},o=[],r=(e("c3ac"),e("2877")),i={},n=Object(r["a"])(i,s,o,!0,null,"6597b37c",null);a["default"]=n.exports}}]); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/plugins/cordova-plugin-network-information/www/Connection.js: -------------------------------------------------------------------------------- 1 | cordova.define("cordova-plugin-network-information.Connection", function(require, exports, module) { 2 | /* 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | /** 24 | * Network status 25 | */ 26 | module.exports = { 27 | UNKNOWN: 'unknown', 28 | ETHERNET: 'ethernet', 29 | WIFI: 'wifi', 30 | CELL_2G: '2g', 31 | CELL_3G: '3g', 32 | CELL_4G: '4g', 33 | CELL: 'cellular', 34 | NONE: 'none' 35 | }; 36 | }); -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/statics/desktop-sidenav-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/statics/desktop-sidenav-icon.png -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/statics/media/pause.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/statics/media/pause.mp3 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/statics/media/ping.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/statics/media/ping.mp3 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/statics/media/restart.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/statics/media/restart.mp3 -------------------------------------------------------------------------------- /src-capacitor/ios/App/public/statics/media/start.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/App/public/statics/media/start.mp3 -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/CordovaPlugins.podspec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/capacitor-cordova-ios-plugins/CordovaPlugins.podspec -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/CordovaPluginsResources.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'CordovaPluginsResources' 3 | s.version = '0.0.105' 4 | s.summary = 'Resources for Cordova plugins' 5 | s.social_media_url = 'http://twitter.com/getcapacitor' 6 | s.license = 'MIT' 7 | s.homepage = 'https://capacitor.ionicframework.com/' 8 | s.authors = { 'Ionic Team' => 'hi@ionicframework.com' } 9 | s.source = { :git => 'https://github.com/ionic-team/capacitor.git', :tag => s.version.to_s } 10 | s.resources = ['resources/*'] 11 | end -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/CordovaPluginsStatic.podspec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-capacitor/ios/capacitor-cordova-ios-plugins/CordovaPluginsStatic.podspec -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/resources/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginNetworkInformation/CDVConnection.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import 21 | #import 22 | #import "CDVReachability.h" 23 | 24 | @interface CDVConnection : CDVPlugin { 25 | NSString* type; 26 | NSString* _callbackId; 27 | 28 | CDVReachability* internetReach; 29 | } 30 | 31 | @property (copy) NSString* connectionType; 32 | @property (strong) CDVReachability* internetReach; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginPurchase/FileUtility.h: -------------------------------------------------------------------------------- 1 | @interface FileUtility : NSObject 2 | { 3 | // Static Class 4 | } 5 | 6 | 7 | 8 | #pragma mark Files & Paths 9 | 10 | +(BOOL) copyToDocuments:(NSString *)file; 11 | 12 | +(NSArray *) listDocs:(NSString *)extension; 13 | +(NSArray *) listFiles:(NSString *)path extension:(NSString *)extension; 14 | 15 | +(NSString *) getDocumentPath; 16 | +(BOOL) isDocumentExist:(NSString *)file; 17 | +(BOOL) isFileExist:(NSString *)path; 18 | +(BOOL) isFolderExist:(NSString *)path; 19 | +(NSString *) getAppendDocPath:(NSString *)file; 20 | +(BOOL) createFolder:(NSString *)folder; 21 | +(BOOL) copyFile:(NSString *)src dst:(NSString *)dst; 22 | 23 | #pragma end 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginPurchase/SKProduct+LocalizedPrice.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // arc / no-arc portability code 5 | #ifndef __has_feature 6 | # define __has_feature(x) 0 7 | #endif 8 | 9 | #if __has_feature(objc_arc) 10 | # define ARC_ENABLED 1 11 | #else 12 | # define ARC_DISABLED 1 13 | #endif 14 | 15 | /* 16 | #if !defined(__clang__) || __clang_major__ < 3 17 | # ifndef __bridge 18 | # define __bridge 19 | # endif 20 | # ifndef __bridge_retained 21 | # define __bridge_retained 22 | # endif 23 | # ifndef __bridge_transfer 24 | # define __bridge_transfer 25 | # endif 26 | # ifndef __autoreleasing 27 | # define __autoreleasing 28 | # endif 29 | # ifndef __strong 30 | # define __strong 31 | # endif 32 | # ifndef __weak 33 | # define __weak 34 | # endif 35 | # ifndef __unsafe_unretained 36 | # define __unsafe_unretained 37 | # endif 38 | #endif // __clang_major__ < 3 39 | */ 40 | 41 | 42 | @interface SKProduct (LocalizedPrice) 43 | 44 | @property (nonatomic, readonly) NSString *localizedPrice; 45 | @property (nonatomic, readonly) NSString *localizedIntroPrice; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginPurchase/SKProduct+LocalizedPrice.m: -------------------------------------------------------------------------------- 1 | #import "SKProduct+LocalizedPrice.h" 2 | #import "SKProductDiscount+LocalizedPrice.h" 3 | 4 | @implementation SKProduct (LocalizedPrice) 5 | 6 | - (NSString *)localizedPrice 7 | { 8 | NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 9 | [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 10 | [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 11 | [numberFormatter setLocale:self.priceLocale]; 12 | NSString *formattedString = [numberFormatter stringFromNumber:self.price]; 13 | #if ARC_DISABLED 14 | [numberFormatter release]; 15 | #endif 16 | return formattedString; 17 | } 18 | 19 | - (NSString *)localizedIntroPrice 20 | { 21 | // Introductory price are supported from iOS 11.2 and macOS 10.13.2 22 | if (@available(iOS 11.2, macOS 10.13.2, *)) { 23 | if (self.introductoryPrice != nil) { 24 | return self.introductoryPrice.localizedPrice; 25 | } 26 | } 27 | return nil; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginPurchase/SKProductDiscount+LocalizedPrice.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // arc / no-arc portability code 5 | #ifndef __has_feature 6 | # define __has_feature(x) 0 7 | #endif 8 | 9 | #if __has_feature(objc_arc) 10 | # define ARC_ENABLED 1 11 | #else 12 | # define ARC_DISABLED 1 13 | #endif 14 | 15 | /* 16 | #if !defined(__clang__) || __clang_major__ < 3 17 | # ifndef __bridge 18 | # define __bridge 19 | # endif 20 | # ifndef __bridge_retained 21 | # define __bridge_retained 22 | # endif 23 | # ifndef __bridge_transfer 24 | # define __bridge_transfer 25 | # endif 26 | # ifndef __autoreleasing 27 | # define __autoreleasing 28 | # endif 29 | # ifndef __strong 30 | # define __strong 31 | # endif 32 | # ifndef __weak 33 | # define __weak 34 | # endif 35 | # ifndef __unsafe_unretained 36 | # define __unsafe_unretained 37 | # endif 38 | #endif // __clang_major__ < 3 39 | */ 40 | 41 | 42 | @interface SKProductDiscount (LocalizedPrice) 43 | 44 | @property (nonatomic, readonly) NSString *localizedPrice; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginPurchase/SKProductDiscount+LocalizedPrice.m: -------------------------------------------------------------------------------- 1 | #import "SKProductDiscount+LocalizedPrice.h" 2 | 3 | @implementation SKProductDiscount (LocalizedPrice) 4 | 5 | - (NSString *)localizedPrice 6 | { 7 | // Introductory price are supported from iOS 11.2 and macOS 10.13.2 8 | if (@available(iOS 11.2, macOS 10.13.2, *)) { 9 | NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 10 | [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 11 | [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 12 | [numberFormatter setLocale:self.priceLocale]; 13 | NSString *formattedString = [numberFormatter stringFromNumber:self.price]; 14 | #if ARC_DISABLED 15 | [numberFormatter release]; 16 | #endif 17 | return formattedString; 18 | } 19 | return nil; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /src-capacitor/ios/capacitor-cordova-ios-plugins/sources/CordovaPluginSqlite2/SQLitePlugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nolan Lawson 3 | * License: Apache 2 4 | */ 5 | 6 | #import 7 | 8 | struct sqlite3; // remove dep on sqlite3.h in this .h file 9 | 10 | @interface SQLitePlugin : CDVPlugin { 11 | } 12 | 13 | @property (nonatomic, copy) NSMutableDictionary *cachedDatabases; 14 | 15 | -(void) exec: (CDVInvokedUrlCommand *)command; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /src-capacitor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enfocus.app", 3 | "version": "1.7.0", 4 | "description": "Task Management Application", 5 | "author": "yev ", 6 | "private": true, 7 | "dependencies": { 8 | "@capacitor/android": "^2.1.1", 9 | "@capacitor/cli": "^2.1.1", 10 | "@capacitor/core": "^2.1.1", 11 | "capacitor-admob-advanced": "^1.4.1", 12 | "capacitor-keep-screen-on": "^1.0.0-alpha.6", 13 | "cordova-plugin-network-information": "^2.0.2", 14 | "cordova-plugin-purchase": "^10.2.0", 15 | "cordova-plugin-sqlite-2": "^1.0.6" 16 | } 17 | } -------------------------------------------------------------------------------- /src-electron/electron-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | electron: true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src-electron/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-electron/icon.ico -------------------------------------------------------------------------------- /src-electron/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-electron/icons/icon.icns -------------------------------------------------------------------------------- /src-electron/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-electron/icons/icon.ico -------------------------------------------------------------------------------- /src-electron/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src-electron/icons/icon.png -------------------------------------------------------------------------------- /src-electron/main-process/electron-main.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | // Install `electron-debug` with `devtron` 9 | require('electron-debug')({ showDevTools: true }) 10 | 11 | // Install `vue-devtools` 12 | require('electron').app.on('ready', () => { 13 | let installExtension = require('electron-devtools-installer') 14 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 15 | .then(() => {}) 16 | .catch(err => { 17 | console.log('Unable to install `vue-devtools`: \n', err) 18 | }) 19 | }) 20 | 21 | // Require `main` process to boot app 22 | require('./electron-main') 23 | -------------------------------------------------------------------------------- /src-electron/main-process/electron-main.js: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow, nativeTheme } from 'electron' 2 | 3 | try { 4 | if (process.platform === 'win32' && nativeTheme.shouldUseDarkColors === true) { 5 | require('fs').unlinkSync(require('path').join(app.getPath('userData'), 'DevTools Extensions')) 6 | } 7 | } catch (_) { } 8 | 9 | /** 10 | * Set `__statics` path to static files in production; 11 | * The reason we are setting it here is that the path needs to be evaluated at runtime 12 | */ 13 | if (process.env.PROD) { 14 | global.__statics = require('path').join(__dirname, 'statics').replace(/\\/g, '\\\\') 15 | } 16 | 17 | let mainWindow 18 | 19 | function createWindow () { 20 | /** 21 | * Initial window options 22 | */ 23 | mainWindow = new BrowserWindow({ 24 | width: 1440, 25 | height: 877, 26 | minWidth: 1000, 27 | minHeight: 600, 28 | useContentSize: true, 29 | webPreferences: { 30 | // Change from /quasar.conf.js > electron > nodeIntegration; 31 | // More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration 32 | nodeIntegration: QUASAR_NODE_INTEGRATION, 33 | nodeIntegrationInWorker: QUASAR_NODE_INTEGRATION, 34 | 35 | // More info: /quasar-cli/developing-electron-apps/electron-preload-script 36 | // preload: path.resolve(__dirname, 'electron-preload.js') 37 | } 38 | }) 39 | 40 | mainWindow.loadURL(process.env.APP_URL) 41 | mainWindow.setMenuBarVisibility(false) 42 | 43 | mainWindow.on('closed', () => { 44 | mainWindow = null 45 | }) 46 | } 47 | 48 | app.on('ready', createWindow) 49 | app.allowRendererProcessReuse = false 50 | 51 | app.on('window-all-closed', () => { 52 | if (process.platform !== 'darwin') { 53 | app.quit() 54 | } 55 | }) 56 | 57 | app.on('activate', () => { 58 | if (mainWindow === null) { 59 | createWindow() 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | -------------------------------------------------------------------------------- /src/api/database/index.js: -------------------------------------------------------------------------------- 1 | import { Platform } from 'quasar' 2 | import RxDB from 'rxdb' 3 | import ProjectSchema from './schema/project' 4 | import TaskSchema from './schema/task' 5 | import ReportSchema from './schema/report' 6 | 7 | const dbName = process.env.DB_NAME || 'opus_db' 8 | 9 | export const createDB = async () => { 10 | if (Platform.is.capacitor) { 11 | // Pre-req: Install sqlite cordova plugin first: https://github.com/nolanlawson/cordova-plugin-sqlite-2 12 | RxDB.plugin(require('pouchdb-adapter-cordova-sqlite')) 13 | return RxDB.create({ name: dbName, adapter: 'cordova-sqlite' }) 14 | } 15 | RxDB.plugin(require('pouchdb-adapter-idb')) 16 | // RxDB.removeDatabase(dbName, 'idb') 17 | return RxDB.create({ name: dbName, adapter: 'idb' }) 18 | } 19 | 20 | const initializeCollection = async (db, name, schema) => { 21 | return db.collection({ name, schema }) 22 | } 23 | 24 | export let db = null 25 | export const initializeDb = async () => { 26 | db = await createDB() 27 | await initializeCollection(db, 'projects', ProjectSchema) 28 | await initializeCollection(db, 'tasks', TaskSchema) 29 | await initializeCollection(db, 'reports', ReportSchema) 30 | } 31 | 32 | export default { 33 | db, 34 | initializeDb 35 | } 36 | -------------------------------------------------------------------------------- /src/api/database/schema/project.js: -------------------------------------------------------------------------------- 1 | export default { 2 | version: 0, 3 | keyCompression: true, 4 | name: 'project', 5 | title: 'Projects', 6 | type: 'object', 7 | properties: { 8 | id: { type: 'string', primary: true }, 9 | name: { type: 'string' }, 10 | description: { type: 'string' }, 11 | created: { type: 'number' }, 12 | updated: { type: 'number' } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/api/database/schema/report.js: -------------------------------------------------------------------------------- 1 | export default { 2 | version: 0, 3 | keyCompression: true, 4 | name: 'report', 5 | title: 'Reports', 6 | type: 'object', 7 | properties: { 8 | id: { type: 'string', primary: true }, 9 | datekey: { type: 'number', index: true }, 10 | progress: { type: 'number', default: 0 }, 11 | timestamp: { type: 'number' }, 12 | task: { 13 | type: 'string', 14 | ref: 'tasks', 15 | index: true 16 | }, 17 | project: { 18 | type: 'string', 19 | ref: 'projects', 20 | index: true 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/api/database/schema/task.js: -------------------------------------------------------------------------------- 1 | export default { 2 | version: 0, 3 | keyCompression: true, 4 | name: 'task', 5 | title: 'Tasks', 6 | type: 'object', 7 | properties: { 8 | id: { type: 'string', primary: true }, 9 | name: { type: 'string' }, 10 | description: { type: 'string' }, 11 | urgent: { type: 'boolean', default: false }, 12 | important: { type: 'boolean', default: false }, 13 | completed: { type: 'boolean', default: false }, 14 | progress: { type: 'number' }, 15 | project: { 16 | type: 'string', 17 | ref: 'projects' 18 | }, 19 | created: { type: 'number' }, 20 | updated: { type: 'number' } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/api/helpers.js: -------------------------------------------------------------------------------- 1 | import { DateKeyFormat } from 'lib/constants' 2 | import { date } from 'quasar' 3 | const { formatDate } = date 4 | 5 | export const toJSON = doc => doc.toJSON() 6 | export const asDateKey = timestamp => parseInt(formatDate(timestamp, DateKeyFormat), 10) 7 | -------------------------------------------------------------------------------- /src/api/projects.js: -------------------------------------------------------------------------------- 1 | import { uid } from 'quasar' 2 | import { db } from './database' 3 | 4 | import { toJSON } from './helpers' 5 | 6 | export const getAllProjects = async () => (await db.projects.find().exec()).map(toJSON) 7 | 8 | export const createProject = async ({ 9 | name, 10 | description, 11 | timestamp = Date.now() 12 | }) => db.projects 13 | .insert({ 14 | id: uid(), 15 | name, 16 | description, 17 | created: timestamp, 18 | updated: timestamp 19 | }).then(toJSON) 20 | 21 | export const updateProject = async (projectId, update) => 22 | db.projects 23 | .findOne({ id: projectId }) 24 | .update({ $set: { ...update, updated: Date.now() } }) 25 | .then(toJSON) 26 | 27 | export const removeProject = async projectQuery => 28 | db.projects 29 | .findOne(projectQuery) 30 | .remove() 31 | 32 | export default { 33 | create: createProject, 34 | getAll: getAllProjects, 35 | update: updateProject, 36 | remove: removeProject 37 | } 38 | -------------------------------------------------------------------------------- /src/api/reports.js: -------------------------------------------------------------------------------- 1 | import { uid } from 'quasar' 2 | import { db } from './database' 3 | 4 | import { toJSON, asDateKey } from './helpers' 5 | 6 | export const createReport = async ({ 7 | timestamp = Date.now(), 8 | progress, 9 | taskId, 10 | projectId 11 | }) => db.reports 12 | .insert({ 13 | id: uid(), 14 | progress, 15 | timestamp, 16 | task: taskId, 17 | project: projectId, 18 | datekey: asDateKey(timestamp) 19 | }) 20 | .then(toJSON) 21 | 22 | export const removeReportsOnTask = async taskId => 23 | db.reports 24 | .find({ task: taskId }) 25 | .remove() 26 | 27 | export const removeReportsOnProject = async projectId => 28 | db.reports 29 | .find({ project: projectId }) 30 | .remove() 31 | 32 | export const removeReportsOn = async query => 33 | db.reports 34 | .find({ ...query }) 35 | .remove() 36 | 37 | export const findReportsOnDates = async ({ 38 | from = new Date(), 39 | to = new Date() 40 | }) => 41 | (await db 42 | .reports 43 | .find({ 44 | datekey: { $gte: asDateKey(from), $lte: asDateKey(to) } 45 | }) 46 | .exec()) 47 | .map(toJSON) 48 | 49 | export const findReportsOnTask = async taskId => 50 | (await db 51 | .reports 52 | .find({ task: taskId }) 53 | .exec()) 54 | .map(toJSON) 55 | 56 | export const findReportsOnProject = async projectId => 57 | (await db 58 | .reports 59 | .find({ project: projectId }) 60 | .exec()) 61 | .map(toJSON) 62 | 63 | export const bindTaskProject = async (taskId, projectId) => 64 | db.reports 65 | .find({ task: taskId }) 66 | .update({ 67 | $set: { project: projectId } 68 | }) 69 | 70 | export const unBindTaskProject = async taskId => 71 | db.reports 72 | .find({ task: taskId }) 73 | .update({ 74 | $unset: { project: '' } 75 | }) 76 | 77 | export default { 78 | create: createReport, 79 | findTask: findReportsOnTask, 80 | findDates: findReportsOnDates, 81 | findProject: findReportsOnProject, 82 | removeOnTask: removeReportsOnTask, 83 | removeOnProject: removeReportsOnProject, 84 | removeOn: removeReportsOn, 85 | bindProject: bindTaskProject, 86 | unBindProject: unBindTaskProject 87 | } 88 | -------------------------------------------------------------------------------- /src/api/tasks.js: -------------------------------------------------------------------------------- 1 | import { uid } from 'quasar' 2 | import { db } from './database' 3 | 4 | import { toJSON } from './helpers' 5 | 6 | export const createTask = async ({ 7 | name, 8 | description, 9 | project, 10 | urgent = false, 11 | important = false, 12 | timestamp = Date.now() 13 | }) => db.tasks 14 | .insert({ 15 | id: uid(), 16 | name, 17 | description, 18 | project, 19 | urgent, 20 | important, 21 | progress: 0, 22 | completed: false, 23 | created: timestamp, 24 | updated: timestamp 25 | }).then(toJSON) 26 | 27 | export const getAllTasks = async () => (await db.tasks.find().exec()).map(toJSON) 28 | 29 | export const getAllOrphanTasks = async () => 30 | (await db.tasks 31 | .find() 32 | .where('project') 33 | .exists(false) 34 | .exec()) 35 | .map(toJSON) 36 | 37 | export const updateTask = async (taskId, update) => 38 | db.tasks 39 | .findOne({ id: taskId }) 40 | .update({ $set: { ...update, updated: Date.now() } }) 41 | .then(toJSON) 42 | 43 | export const removeTask = async taskQuery => 44 | db.tasks 45 | .findOne(taskQuery) 46 | .remove() 47 | 48 | export const setTaskProject = async ({ taskId, projectId }) => 49 | db.tasks 50 | .findOne({ id: taskId }) 51 | .update({ $set: { project: projectId, updated: Date.now() } }) 52 | .then(toJSON) 53 | 54 | export const removeTaskProject = async taskId => 55 | db.tasks 56 | .findOne({ id: taskId }) 57 | .update({ 58 | $set: { updated: Date.now() }, 59 | $unset: { project: '' } 60 | }) 61 | .then(toJSON) 62 | 63 | export default { 64 | create: createTask, 65 | getAll: getAllTasks, 66 | getOrphans: getAllOrphanTasks, 67 | update: updateTask, 68 | remove: removeTask, 69 | setProject: setTaskProject, 70 | removeProject: removeTaskProject 71 | } 72 | -------------------------------------------------------------------------------- /src/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/assets/icon.png -------------------------------------------------------------------------------- /src/boot/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/boot/.gitkeep -------------------------------------------------------------------------------- /src/boot/axios.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | 4 | Vue.prototype.$axios = axios 5 | -------------------------------------------------------------------------------- /src/boot/opus.js: -------------------------------------------------------------------------------- 1 | import { Platform, LocalStorage } from 'quasar' 2 | import { initializeDb } from 'api/database' 3 | import Pomodoro from 'lib/pomodoro' 4 | import Preferences from 'lib/preferences' 5 | 6 | import { PremiumFlagKey } from 'lib/boot/utils' 7 | 8 | import { productName, version } from 'app/package.json' 9 | 10 | require('lib/boot') 11 | 12 | import CommonDialogs from 'lib/dialogs' 13 | 14 | import { 15 | inMinutes, 16 | inHours, 17 | padZero, 18 | elapsedTime, 19 | formatDate, 20 | shortenNum 21 | } from 'lib/utils' 22 | 23 | const initializeFilters = (Vue) => { 24 | Vue.filter('inMinutes', inMinutes) 25 | Vue.filter('inHours', inHours) 26 | Vue.filter('elapsedTime', elapsedTime) 27 | Vue.filter('padZero', padZero) 28 | Vue.filter('formatDate', formatDate) 29 | Vue.filter('shortenNum', shortenNum) 30 | } 31 | 32 | const iap = { 33 | store: window.store, 34 | productId: process.env.IAP_PRODUCT_ID, 35 | product: {} 36 | } 37 | 38 | if (Platform.is.capacitor) { 39 | iap.store.when(iap.productId).updated(p => (iap.product = p)) 40 | } 41 | 42 | export default async ({ Vue, store }) => { 43 | initializeFilters(Vue) 44 | await initializeDb() 45 | 46 | const preferences = new Preferences(store) 47 | const pomodoro = new Pomodoro(store, preferences) 48 | 49 | if (Platform.is.electron) { 50 | Vue.component('QSplitLayout', () => import('layouts/desktop/SplitLayout')) 51 | } 52 | 53 | Vue.prototype.$o = { 54 | pomodoro, 55 | preferences, 56 | tearDown () { 57 | pomodoro.tearDown() 58 | }, 59 | dialog: CommonDialogs, 60 | app: { 61 | name: productName, 62 | version, 63 | isPremium: () => { 64 | return process.env.DEV || 65 | LocalStorage.getItem(PremiumFlagKey).current === true 66 | } 67 | }, 68 | iap 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/components/EssentialLink.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 40 | -------------------------------------------------------------------------------- /src/components/MenuNav.vue: -------------------------------------------------------------------------------- 1 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/eisenhower/EisenhowerTabChooserDialog.vue: -------------------------------------------------------------------------------- 1 | 39 | 67 | -------------------------------------------------------------------------------- /src/components/eisenhower/EisenhowerTabDescriptions.vue: -------------------------------------------------------------------------------- 1 | 15 | 26 | -------------------------------------------------------------------------------- /src/components/eisenhower/EisenhowerTabLabel.vue: -------------------------------------------------------------------------------- 1 | 59 | 69 | 77 | -------------------------------------------------------------------------------- /src/components/projects/ProjectItem.vue: -------------------------------------------------------------------------------- 1 | 39 | 83 | -------------------------------------------------------------------------------- /src/components/projects/project-details.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | selectedFilter: 'all', 5 | filters: [ 6 | { label: 'Ongoing', value: 'ongoing' }, 7 | { label: 'To do', value: 'todo' }, 8 | { label: 'Completed', value: 'completed' }, 9 | { label: 'All', value: 'all' } 10 | ] 11 | } 12 | }, 13 | computed: { 14 | tasks () { 15 | return (filter) => { 16 | const tasks = this.$store.getters['tasks/projectTasks'](this.project) 17 | if (filter === 'completed') { 18 | return tasks.filter(task => task.completed) 19 | } else if (filter === 'ongoing') { 20 | return tasks 21 | .filter(task => !task.completed) 22 | .filter(task => task.progress > 0) 23 | } else if (filter === 'todo') { 24 | return tasks.filter(task => task.progress === 0) 25 | } else { 26 | return tasks 27 | } 28 | } 29 | }, 30 | selectedTasks () { 31 | return this.tasks(this.selectedFilter) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/reports/DonutChart.vue: -------------------------------------------------------------------------------- 1 | 9 | 74 | -------------------------------------------------------------------------------- /src/components/reports/ProjectDonut.vue: -------------------------------------------------------------------------------- 1 | 15 | 62 | -------------------------------------------------------------------------------- /src/components/reports/mixin-event-handlers.js: -------------------------------------------------------------------------------- 1 | import { RootEvents } from 'lib/constants' 2 | import { PomodoroEvents } from 'lib/pomodoro' 3 | 4 | export default { 5 | mounted () { 6 | this.$o.pomodoro.registerOn(PomodoroEvents.Update, this.updateRecords) 7 | this.$root.$on(RootEvents.TaskDeleted, this.updateRecords) 8 | this.$root.$on(RootEvents.TaskProgressUpdated, this.updateRecords) 9 | this.$root.$on(RootEvents.ProjectDeleted, this.updateRecords) 10 | }, 11 | methods: { 12 | updateRecords () { 13 | // This should be overridden 14 | } 15 | }, 16 | beforeDestroy () { 17 | this.$o.pomodoro.unRegister(PomodoroEvents.Update, this.updateRecords) 18 | this.$root.$on(RootEvents.TaskDeleted, this.updateRecords) 19 | this.$root.$on(RootEvents.TaskProgressUpdated, this.updateRecords) 20 | this.$root.$on(RootEvents.ProjectDeleted, this.updateRecords) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/reports/mixin-stacked-bar-chart.js: -------------------------------------------------------------------------------- 1 | const UNIT_HEIGHT = 20 2 | const OFFSET_HEIGHT = 120 3 | const DEFAULT_HEIGHT = 500 4 | 5 | export default { 6 | mounted () { 7 | this.setHeight() 8 | }, 9 | data () { 10 | return { 11 | chartHeight: 100 // non-zero seed 12 | } 13 | }, 14 | watch: { 15 | series (a, b) { 16 | this.setHeight() 17 | } 18 | }, 19 | methods: { 20 | /** 21 | * Sets chart height dynamically proportional to the number of categories. 22 | * Takes into account the legends area that also grows in height. 23 | */ 24 | setHeight () { 25 | const baseHeight = this.chartOptions.xaxis.categories.length * UNIT_HEIGHT 26 | if (!baseHeight || !this.$refs.chart) { 27 | this.chartHeight = DEFAULT_HEIGHT 28 | return 29 | } 30 | const legendHeight = this.$refs.chart.$el.getElementsByClassName('apexcharts-legend')[0].clientHeight 31 | if (this.$q.platform.is.desktop) { 32 | this.chartHeight = DEFAULT_HEIGHT + legendHeight 33 | return 34 | } 35 | this.chartHeight = baseHeight + legendHeight + OFFSET_HEIGHT 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/tasks/ActiveTask.vue: -------------------------------------------------------------------------------- 1 | 32 | 43 | -------------------------------------------------------------------------------- /src/components/tasks/TaskList.vue: -------------------------------------------------------------------------------- 1 | 21 | 35 | -------------------------------------------------------------------------------- /src/css/app.scss: -------------------------------------------------------------------------------- 1 | // app global css in SCSS form 2 | .underline { 3 | &::before { 4 | position: absolute; 5 | content: ''; 6 | background-color: $secondary; 7 | width: 32px; 8 | height: 6px; 9 | bottom: 0px; 10 | border-radius: 5px; 11 | } 12 | &--accent::before { 13 | background-color: $accent; 14 | } 15 | } 16 | 17 | .shadow-light { 18 | box-shadow: 0 6px 6px -3px rgba(0,0,0,0.02), 0 10px 14px 1px rgba(0,0,0,0.02), 0 4px 18px 3px rgba(0,0,0,0.02); 19 | } 20 | 21 | .sleeve { 22 | border-top-left-radius: 0%; 23 | border-top-right-radius: 0%; 24 | &::before { 25 | content: ""; 26 | position: absolute; 27 | background-color: transparent; 28 | bottom: -50px; 29 | height: 50px; 30 | width: 25px; 31 | left: 0; 32 | border-top-left-radius: 25px; 33 | box-shadow: 0 -25px 0 0 white; 34 | z-index: -1; 35 | } 36 | &::after { 37 | content: ""; 38 | position: absolute; 39 | background-color: transparent; 40 | bottom: -50px; 41 | height: 50px; 42 | width: 25px; 43 | right: 0; 44 | border-top-right-radius: 25px; 45 | box-shadow: 0 -25px 0 0 white; 46 | z-index: -1; 47 | } 48 | } 49 | 50 | .bg-none { 51 | background-color: transparent; 52 | } 53 | -------------------------------------------------------------------------------- /src/css/quasar.variables.scss: -------------------------------------------------------------------------------- 1 | // Quasar SCSS (& Sass) Variables 2 | // -------------------------------------------------- 3 | // To customize the look and feel of this app, you can override 4 | // the Sass/SCSS variables found in Quasar's source Sass/SCSS files. 5 | 6 | // Check documentation for full list of Quasar variables 7 | 8 | // Your own variables (that are declared here) and Quasar's own 9 | // ones will be available out of the box in your .vue/.scss/.sass files 10 | 11 | // It's highly recommended to change the default colors 12 | // to match your app's branding. 13 | // Tip: Use the "Theme Builder" on Quasar's documentation website. 14 | 15 | $primary : #2F97C1; 16 | $secondary: #3299AD; 17 | $accent : #1CCAD8; 18 | 19 | $dark : #1D1D1D; 20 | 21 | $positive : #0CF574; 22 | $negative : #C10015; 23 | $info : #15E6CD; 24 | $warning : #F2C037; 25 | 26 | $generic-border-radius: 16px; 27 | -------------------------------------------------------------------------------- /src/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= htmlWebpackPlugin.options.productName %> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /src/layouts/DefaultLayout.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 57 | -------------------------------------------------------------------------------- /src/layouts/desktop/FullPageLayout.vue: -------------------------------------------------------------------------------- 1 | 23 | 54 | -------------------------------------------------------------------------------- /src/layouts/desktop/SplitLayout.vue: -------------------------------------------------------------------------------- 1 | 46 | 79 | -------------------------------------------------------------------------------- /src/pages/Error404.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | -------------------------------------------------------------------------------- /src/pages/Projects.vue: -------------------------------------------------------------------------------- 1 | 32 | 52 | -------------------------------------------------------------------------------- /src/pages/Reports.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 47 | -------------------------------------------------------------------------------- /src/pages/desktop/Reports.vue: -------------------------------------------------------------------------------- 1 | 37 | 61 | -------------------------------------------------------------------------------- /src/pages/mixin-eisenhower.js: -------------------------------------------------------------------------------- 1 | import { 2 | EisenhowerQuadrants, 3 | EinserhowerEmptyQuadrantImages, 4 | EisenhowerQuadrantDescriptions 5 | } from 'lib/constants' 6 | 7 | import TaskDetailsDialog from 'components/tasks/TaskDetailsDialog' 8 | 9 | export default { 10 | data () { 11 | return { 12 | hasOpenDialog: false, 13 | currentQuadrant: '', 14 | quadrants: EisenhowerQuadrants, 15 | quadrantOptions: Object.keys(EisenhowerQuadrants) 16 | .map(key => ({ 17 | id: key, 18 | ...EisenhowerQuadrants[key] 19 | })), 20 | selectedTaskId: null, 21 | quadrantDescriptions: EisenhowerQuadrantDescriptions, 22 | emptyQuadrantImg: EinserhowerEmptyQuadrantImages 23 | } 24 | }, 25 | computed: { 26 | tasks () { 27 | return id => { 28 | const allTasks = this.$store.getters['tasks/allTasks'].filter(task => !task.completed) 29 | switch (id) { 30 | case 'do': 31 | return allTasks.filter(({ important, urgent }) => important && urgent) 32 | case 'decide': 33 | return allTasks.filter(({ important, urgent }) => important && !urgent) 34 | case 'delegate': 35 | return allTasks.filter(({ important, urgent }) => !important && urgent) 36 | case 'delete': 37 | return allTasks.filter(({ important, urgent }) => !important && !urgent) 38 | default: 39 | return allTasks 40 | } 41 | } 42 | } 43 | }, 44 | methods: { 45 | async transferToQuadrant (taskId, to) { 46 | let update = null 47 | switch (to) { 48 | case 'do': 49 | update = { important: true, urgent: true } 50 | break 51 | case 'decide': 52 | update = { important: true, urgent: false } 53 | break 54 | case 'delegate': 55 | update = { important: false, urgent: true } 56 | break 57 | case 'delete': 58 | update = { important: false, urgent: false } 59 | break 60 | } 61 | if (update && taskId) { 62 | return this.$store.dispatch('tasks/updateTask', { id: taskId, update }) 63 | } 64 | }, 65 | showTaskDetailsDialog (task) { 66 | this.hasOpenDialog = true 67 | this.$q.dialog({ 68 | component: TaskDetailsDialog, 69 | parent: this, 70 | task 71 | }).onDismiss(() => (this.hasOpenDialog = false)) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pages/mixin-projects.js: -------------------------------------------------------------------------------- 1 | import { RootEvents } from 'lib/constants' 2 | 3 | import NewProjectDialog from 'components/projects/NewProjectDialog' 4 | import EditProjectDialog from 'components/projects/EditProjectDialog' 5 | import ProjectDetailsDialog from 'components/projects/ProjectDetailsDialog' 6 | 7 | export default { 8 | data () { 9 | return { 10 | hasOpenDialog: false, 11 | editModalOpened: false, 12 | actions: [ 13 | { label: 'Open', icon: { name: 'fullscreen', color: 'grey' }, handler: this.showProjectDetails }, 14 | { label: 'Edit', icon: { name: 'edit', color: 'blue' }, handler: this.showEditProjectDialog }, 15 | {}, 16 | { label: 'Delete', icon: { name: 'delete', color: 'negative' }, handler: this.confirmDelete } 17 | ] 18 | } 19 | }, 20 | computed: { 21 | projects () { 22 | return this.$store 23 | .getters['projects/allProjects'] 24 | .slice() 25 | .sort((a, b) => b.updated - a.updated) 26 | }, 27 | tasks () { 28 | return this.$store.getters['tasks/projectTasks'] 29 | } 30 | }, 31 | methods: { 32 | showEditProjectDialog (project) { 33 | if (project) { 34 | this.hasOpenDialog = true 35 | this.$q.dialog({ 36 | component: EditProjectDialog, 37 | parent: this, 38 | project 39 | }).onDismiss(() => (this.hasOpenDialog = false)) 40 | } 41 | }, 42 | showNewProjectDialog () { 43 | this.hasOpenDialog = true 44 | this.$q.dialog({ 45 | component: NewProjectDialog, 46 | parent: this 47 | }).onDismiss(() => (this.hasOpenDialog = false)) 48 | }, 49 | showProjectDetails (project) { 50 | this.hasOpenDialog = true 51 | this.$q.dialog({ 52 | component: ProjectDetailsDialog, 53 | parent: this, 54 | project 55 | }).onDismiss(() => (this.hasOpenDialog = false)) 56 | }, 57 | confirmDelete (project) { 58 | this.hasOpenDialog = true 59 | this.$o 60 | .dialog 61 | .confirmDeleteProject({ 62 | ...project, 63 | tasks: this.tasks(project) 64 | }) 65 | .onOk(async () => { 66 | await this.$store.dispatch('projects/removeProject', { id: project.id }) 67 | await Promise.all([ 68 | ...this.tasks(project) 69 | .map(task => task.id) 70 | .map(id => this.$store.dispatch('tasks/removeTask', { id })) 71 | ]) 72 | this.$root.$emit(RootEvents.ProjectDeleted, { ...project }) 73 | }) 74 | .onDismiss(() => (this.hasOpenDialog = false)) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/pages/mixin-reports.js: -------------------------------------------------------------------------------- 1 | import { ReportOptions } from 'lib/constants' 2 | import UsePremiumGuard from 'lib/commons/premium-guard/premium-guard-mixin' 3 | 4 | export default { 5 | mixins: [UsePremiumGuard], 6 | data () { 7 | return { 8 | model: 'today', 9 | options: ReportOptions.map((option) => ({ value: option.name, ...option })) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/mixin-task-actions.js: -------------------------------------------------------------------------------- 1 | import Utils from 'lib/utils' 2 | import { RootEvents } from 'lib/constants' 3 | 4 | import { mapGetters } from 'vuex' 5 | 6 | export default { 7 | computed: { ...mapGetters('tasks', ['activeTask']) }, 8 | methods: { 9 | async startTask (task, reset = () => {}) { 10 | if (this.activeTask) { 11 | await this.$o.pomodoro.updateActiveTask() 12 | this.$root.$emit(RootEvents.TaskProgressUpdated, { ...this.activeTask }) 13 | } 14 | this.$store.commit('tasks/setActiveTask', task) 15 | this.$store.commit('pomodoro/clear') 16 | this.$o.pomodoro.start() 17 | reset() 18 | await this.$nextTick() 19 | Utils.scrollTo('active-task') 20 | }, 21 | async clearActiveTask (reset = () => {}) { 22 | await this.$o.pomodoro.updateActiveTask() 23 | this.$root.$emit(RootEvents.TaskProgressUpdated, { ...this.activeTask }) 24 | this.$store.commit('tasks/clearActiveTask') 25 | this.$store.commit('pomodoro/clear') 26 | reset() 27 | }, 28 | async markComplete (task, reset = () => {}) { 29 | reset() 30 | if (this.activeTask && this.activeTask.id === task.id) { 31 | await this.clearActiveTask() 32 | } 33 | return this.$store.dispatch('tasks/updateTask', { 34 | id: task.id, 35 | update: { completed: true } 36 | }) 37 | }, 38 | markUnComplete (task) { 39 | return this.$store.dispatch('tasks/updateTask', { 40 | id: task.id, 41 | update: { completed: false } 42 | }) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/pages/mixin-tasks-dialogs.js: -------------------------------------------------------------------------------- 1 | import { RootEvents } from 'lib/constants' 2 | 3 | import TaskDetailsDialog from 'components/tasks/TaskDetailsDialog' 4 | import NewTaskDialog from 'components/tasks/NewTaskDialog' 5 | import EditTaskDialog from 'components/tasks/EditTaskDialog' 6 | 7 | export default { 8 | data () { 9 | return { 10 | hasOpenDialog: false 11 | } 12 | }, 13 | methods: { 14 | showTaskDetailsDialog (task) { 15 | this.hasOpenDialog = true 16 | this.$q.dialog({ 17 | component: TaskDetailsDialog, 18 | parent: this, 19 | task 20 | }).onDismiss(() => (this.hasOpenDialog = false)) 21 | }, 22 | showNewTaskDialog () { 23 | this.hasOpenDialog = true 24 | this.$q.dialog({ 25 | component: NewTaskDialog, 26 | parent: this 27 | }).onDismiss(() => (this.hasOpenDialog = false)) 28 | }, 29 | showEditTaskDialog (task) { 30 | this.hasOpenDialog = true 31 | this.$q.dialog({ 32 | component: EditTaskDialog, 33 | parent: this, 34 | task 35 | }).onDismiss(() => (this.hasOpenDialog = false)) 36 | }, 37 | deleteTask (task) { 38 | this.$o 39 | .dialog 40 | .confirmDeleteTask(task) 41 | .onOk(async () => { 42 | await this.$store.dispatch('tasks/removeTask', task) 43 | this.$root.$emit(RootEvents.TaskDeleted, { ...task }) 44 | }) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pages/mixin-tasks.js: -------------------------------------------------------------------------------- 1 | import UseTasksDialogs from './mixin-tasks-dialogs' 2 | import UseTaskActions from './mixin-task-actions' 3 | 4 | import { mapGetters } from 'vuex' 5 | 6 | export default { 7 | mixins: [ 8 | UseTasksDialogs, 9 | UseTaskActions 10 | ], 11 | data () { 12 | return { 13 | selectedFilter: '', 14 | filters: [ 15 | { label: 'Ongoing', value: 'ongoing' }, 16 | { label: 'To do', value: 'todo' }, 17 | { label: 'Completed', value: 'completed' } 18 | ], 19 | hasOpenDialog: false 20 | } 21 | }, 22 | computed: { 23 | ...mapGetters('tasks', ['activeTask']), 24 | tasks () { 25 | let tasks = this.$store 26 | .getters['tasks/allTasks'] 27 | .slice() 28 | .sort((a, b) => b.updated - a.updated) 29 | 30 | if (this.activeTask) { 31 | tasks = tasks.filter(task => task.id !== this.activeTask.id) 32 | } 33 | 34 | if (this.selectedFilter === 'completed') { 35 | return tasks.filter(task => task.completed) 36 | } else if (this.selectedFilter === 'ongoing') { 37 | return tasks 38 | .filter(task => !task.completed) 39 | .filter(task => task.progress > 0) 40 | } else if (this.selectedFilter === 'todo') { 41 | return tasks.filter(task => task.progress === 0) 42 | } else { 43 | return tasks.filter(task => !task.completed) 44 | } 45 | }, 46 | actions () { 47 | const generics = [ 48 | {}, 49 | { 50 | label: 'Edit', 51 | icon: { name: 'edit', color: 'blue' }, 52 | handler: this.showEditTaskDialog 53 | }, 54 | {}, 55 | { 56 | label: 'Delete', 57 | icon: { name: 'delete', color: 'negative' }, 58 | handler: this.deleteTask 59 | } 60 | ] 61 | const primary = this.selectedFilter === 'completed' 62 | ? [{ 63 | label: 'Ongoing', 64 | icon: { name: 'restore', color: 'secondary' }, 65 | handler: this.markUnComplete 66 | }] : [{ 67 | label: 'Start', 68 | icon: { name: 'play_arrow', color: 'primary' }, 69 | handler: this.startTask 70 | }, 71 | { 72 | label: 'Mark as Complete', 73 | icon: { name: 'done', color: 'positive' }, 74 | handler: this.markComplete 75 | }] 76 | 77 | return [ 78 | ...primary, 79 | ...generics 80 | ] 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/router/capacitor.routes.js: -------------------------------------------------------------------------------- 1 | export const routes = [ 2 | { 3 | path: '/', 4 | component: () => import('layouts/TasksLayout'), 5 | children: [ 6 | { name: 'Your Tasks', path: '', component: () => import('pages/Tasks') } 7 | ] 8 | }, 9 | { 10 | path: '/o', // parent container, to create simple way to separate parent layout 11 | component: () => import('layouts/DefaultLayout.vue'), 12 | children: [ 13 | { name: 'Projects', path: 'projects', component: () => import('pages/Projects') }, 14 | { name: 'Prioritize', path: 'eisenhower', component: () => import('pages/Eisenhower') }, 15 | { name: 'Reports', path: 'reports', component: () => import('pages/Reports') } 16 | ] 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /src/router/electron.routes.js: -------------------------------------------------------------------------------- 1 | export const routes = [ 2 | { 3 | path: '/', 4 | component: () => import('layouts/desktop/RootLayout.vue'), 5 | children: [ 6 | { name: 'Your Tasks', path: '', component: () => import('pages/desktop/Tasks') }, 7 | { name: 'Projects', path: '/projects', component: () => import('pages/desktop/Projects') }, 8 | { name: 'Eisenhower Matrix', path: '/eisenhower', component: () => import('pages/desktop/Eisenhower') }, 9 | { name: 'Reports', path: '/reports', component: () => import('pages/desktop/Reports') } 10 | ] 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | import routes from './routes' 5 | 6 | Vue.use(VueRouter) 7 | 8 | /* 9 | * If not building with SSR mode, you can 10 | * directly export the Router instantiation; 11 | * 12 | * The function below can be async too; either use 13 | * async/await or return a Promise which resolves 14 | * with the Router instance. 15 | */ 16 | 17 | export default function (/* { store, ssrContext } */) { 18 | const Router = new VueRouter({ 19 | scrollBehavior: () => ({ x: 0, y: 0 }), 20 | routes, 21 | 22 | // Leave these as they are and change in quasar.conf.js instead! 23 | // quasar.conf.js -> build -> vueRouterMode 24 | // quasar.conf.js -> build -> publicPath 25 | mode: process.env.VUE_ROUTER_MODE, 26 | base: process.env.VUE_ROUTER_BASE 27 | }) 28 | 29 | return Router 30 | } 31 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | const { routes } = require(`./${process.env.MODE}.routes`) 2 | 3 | // Always leave this as last one 4 | if (process.env.MODE !== 'ssr') { 5 | routes.push({ 6 | path: '*', 7 | component: () => import('pages/Error404.vue') 8 | }) 9 | } 10 | 11 | export default routes 12 | -------------------------------------------------------------------------------- /src/router/spa.routes.js: -------------------------------------------------------------------------------- 1 | // Duplicate of capacitor.routes.js. Used for browser testing 2 | import { routes as capacitorRoutes } from './capacitor.routes' 3 | export const routes = capacitorRoutes 4 | -------------------------------------------------------------------------------- /src/statics/app-logo-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/app-logo-128x128.png -------------------------------------------------------------------------------- /src/statics/desktop-sidenav-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/desktop-sidenav-icon.png -------------------------------------------------------------------------------- /src/statics/icons/app-logo-desktop-nav-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/app-logo-desktop-nav-128x128.png -------------------------------------------------------------------------------- /src/statics/icons/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/apple-icon-120x120.png -------------------------------------------------------------------------------- /src/statics/icons/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/apple-icon-152x152.png -------------------------------------------------------------------------------- /src/statics/icons/apple-icon-167x167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/apple-icon-167x167.png -------------------------------------------------------------------------------- /src/statics/icons/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/apple-icon-180x180.png -------------------------------------------------------------------------------- /src/statics/icons/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/favicon-128x128.png -------------------------------------------------------------------------------- /src/statics/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/favicon-16x16.png -------------------------------------------------------------------------------- /src/statics/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/favicon-32x32.png -------------------------------------------------------------------------------- /src/statics/icons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/favicon-96x96.png -------------------------------------------------------------------------------- /src/statics/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/favicon.ico -------------------------------------------------------------------------------- /src/statics/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon-128x128.png -------------------------------------------------------------------------------- /src/statics/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon-192x192.png -------------------------------------------------------------------------------- /src/statics/icons/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon-256x256.png -------------------------------------------------------------------------------- /src/statics/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon-384x384.png -------------------------------------------------------------------------------- /src/statics/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon-512x512.png -------------------------------------------------------------------------------- /src/statics/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/icon.png -------------------------------------------------------------------------------- /src/statics/icons/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/icons/ms-icon-144x144.png -------------------------------------------------------------------------------- /src/statics/media/pause.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/media/pause.mp3 -------------------------------------------------------------------------------- /src/statics/media/ping.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/media/ping.mp3 -------------------------------------------------------------------------------- /src/statics/media/restart.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/media/restart.mp3 -------------------------------------------------------------------------------- /src/statics/media/start.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vycoder/qodo/35851a98de15c9d60707ec685891b791b98b06a4/src/statics/media/start.mp3 -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import projects from './projects' 5 | import tasks from './tasks' 6 | import pomodoro from './pomodoro' 7 | 8 | Vue.use(Vuex) 9 | 10 | /* 11 | * If not building with SSR mode, you can 12 | * directly export the Store instantiation; 13 | * 14 | * The function below can be async too; either use 15 | * async/await or return a Promise which resolves 16 | * with the Store instance. 17 | */ 18 | 19 | export default function (/* { ssrContext } */) { 20 | const Store = new Vuex.Store({ 21 | modules: { 22 | projects, 23 | tasks, 24 | pomodoro 25 | }, 26 | 27 | // enable strict mode (adds overhead!) 28 | // for dev mode only 29 | strict: process.env.DEV 30 | }) 31 | 32 | return Store 33 | } 34 | -------------------------------------------------------------------------------- /src/store/pomodoro/actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | export function someAction (context) { 3 | } 4 | */ 5 | -------------------------------------------------------------------------------- /src/store/pomodoro/getters.js: -------------------------------------------------------------------------------- 1 | 2 | export function isRunning (state) { 3 | return state.running 4 | } 5 | 6 | export function isWorkMode (state) { 7 | return state.sprintMode === 'work' 8 | } 9 | 10 | export function isBreakMode (state) { 11 | return state.sprintMode === 'break' 12 | } 13 | 14 | export function elapsedSeconds (state) { 15 | return state.elapsedSeconds 16 | } 17 | 18 | export function currentSprintMode (state) { 19 | return state.sprintMode 20 | } 21 | 22 | export function currentSprintCount (state) { 23 | return state.sprintCounts[state.sprintMode] 24 | } 25 | 26 | export function sprintDuration (state) { 27 | if (state.sprintMode === 'work') { 28 | return state.sprintDuration.work 29 | } 30 | if (currentSprintCount(state) === 4) { 31 | return state.sprintDuration.longBreak 32 | } 33 | return state.sprintDuration.shortBreak 34 | } 35 | -------------------------------------------------------------------------------- /src/store/pomodoro/index.js: -------------------------------------------------------------------------------- 1 | import state from './state' 2 | import * as getters from './getters' 3 | import * as mutations from './mutations' 4 | import * as actions from './actions' 5 | 6 | export default { 7 | namespaced: true, 8 | state, 9 | getters, 10 | mutations, 11 | actions 12 | } 13 | -------------------------------------------------------------------------------- /src/store/pomodoro/mutations.js: -------------------------------------------------------------------------------- 1 | export function setDurations (state, { work, shortBreak, longBreak }) { 2 | state.sprintDuration.work = work 3 | state.sprintDuration.shortBreak = shortBreak 4 | state.sprintDuration.longBreak = longBreak 5 | } 6 | 7 | export function start (state) { 8 | state.running = true 9 | } 10 | 11 | export function stop (state) { 12 | state.running = false 13 | } 14 | 15 | export function incrementElapsedSeconds (state) { 16 | state.elapsedSeconds++ 17 | } 18 | 19 | export function clearElapsedSeconds (state) { 20 | state.elapsedSeconds = 0 21 | } 22 | 23 | export function updateSprint (state) { 24 | const currentSprintCount = state.sprintCounts[state.sprintMode] 25 | state.sprintCounts[state.sprintMode] = currentSprintCount === 4 ? 1 : currentSprintCount + 1 26 | state.sprintMode = state.sprintMode === 'work' ? 'break' : 'work' 27 | } 28 | 29 | export function clear (state) { 30 | state.running = false 31 | state.elapsedSeconds = 0 32 | state.sprintMode = 'work' 33 | state.sprintCounts.work = 1 34 | state.sprintCounts.break = 1 35 | } 36 | -------------------------------------------------------------------------------- /src/store/pomodoro/state.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return { 3 | running: false, 4 | elapsedSeconds: 0, // in seconds 5 | sprintMode: 'work', 6 | sprintCounts: { 7 | work: 1, break: 1 8 | }, 9 | sprintDuration: { // in seconds 10 | work: 60, 11 | shortBreak: 60, 12 | longBreak: 120 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/store/pomodoro/store-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | store: true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/store/projects/actions.js: -------------------------------------------------------------------------------- 1 | import ProjectsAPI from 'api/projects' 2 | import ReportsAPI from 'api/reports' 3 | 4 | export async function fetchProjects ({ commit }) { 5 | commit('setProjects', await ProjectsAPI.getAll()) 6 | } 7 | 8 | export async function createProject ({ commit }, project) { 9 | const newProject = await ProjectsAPI.create(project) 10 | commit('addProject', newProject) 11 | return newProject 12 | } 13 | 14 | export async function updateProject ({ commit }, { id, update }) { 15 | const project = await ProjectsAPI.update(id, update) 16 | commit('updateProject', project) 17 | return project 18 | } 19 | 20 | export async function removeProject ({ commit }, query) { 21 | const project = await ProjectsAPI.remove(query) 22 | await ReportsAPI.removeOnProject(project.id) 23 | commit('removeProject', project) 24 | } 25 | -------------------------------------------------------------------------------- /src/store/projects/getters.js: -------------------------------------------------------------------------------- 1 | 2 | export function allProjects (state) { 3 | return state.projects 4 | } 5 | 6 | export function projectById (state) { 7 | return id => state.projects.find(project => project.id === id) 8 | } 9 | -------------------------------------------------------------------------------- /src/store/projects/index.js: -------------------------------------------------------------------------------- 1 | import state from './state' 2 | import * as getters from './getters' 3 | import * as mutations from './mutations' 4 | import * as actions from './actions' 5 | 6 | export default { 7 | namespaced: true, 8 | state, 9 | getters, 10 | mutations, 11 | actions 12 | } 13 | -------------------------------------------------------------------------------- /src/store/projects/mutations.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue' 3 | 4 | export function setProjects (state, projects) { 5 | state.projects = [...projects] 6 | } 7 | 8 | export function addProject (state, project) { 9 | const found = state.projects.findIndex(({ id }) => id === project.id) 10 | if (found >= 0) { 11 | Vue.set(state.projects, found, { 12 | ...state.projects[found], 13 | ...project 14 | }) 15 | return 16 | } 17 | state.projects.push(project) 18 | } 19 | 20 | const findProject = (list, { id }, callback = () => {}) => { 21 | const found = list.findIndex(task => task.id === id) 22 | if (found >= 0) { 23 | callback(found) 24 | return true 25 | } 26 | return false 27 | } 28 | 29 | export function updateProject (state, update) { 30 | findProject( 31 | state.projects, 32 | update, 33 | (index) => { 34 | Vue.set(state.projects, index, { 35 | ...state.projects[index], ...update 36 | }) 37 | } 38 | ) 39 | } 40 | 41 | export function removeProject (state, project) { 42 | findProject(state.projects, project, index => state.projects.splice(index, 1)) 43 | } 44 | -------------------------------------------------------------------------------- /src/store/projects/state.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return { 3 | projects: [] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/store/projects/store-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | store: true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/store/store-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | store: true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/store/tasks/actions.js: -------------------------------------------------------------------------------- 1 | import TasksAPI from 'api/tasks' 2 | import ReportsAPI from 'api/reports' 3 | 4 | export async function fetchTasks ({ commit }) { 5 | commit('setTasks', await TasksAPI.getAll()) 6 | } 7 | 8 | export async function createTask ({ commit }, task) { 9 | const newTask = await TasksAPI.create(task) 10 | commit('addTask', newTask) 11 | return newTask 12 | } 13 | 14 | export async function updateTask ({ commit }, { id, update }) { 15 | const task = await TasksAPI.update(id, update) 16 | commit('updateTask', task) 17 | return task 18 | } 19 | 20 | export async function removeTask ({ commit }, query) { 21 | const task = await TasksAPI.remove(query) 22 | await ReportsAPI.removeOnTask(task.id) 23 | commit('removeTask', task) 24 | } 25 | 26 | export async function updateActiveTaskProgress ({ getters, dispatch }, progress) { 27 | const { activeTask } = getters 28 | if (!activeTask) { 29 | return Promise.resolve() 30 | } 31 | return Promise.all([ 32 | dispatch('updateTask', { 33 | id: activeTask.id, 34 | update: { 35 | progress: activeTask.progress + progress 36 | } 37 | }), 38 | ReportsAPI.create({ 39 | progress, 40 | taskId: activeTask.id, 41 | projectId: activeTask.project 42 | }) 43 | ]) 44 | } 45 | 46 | export async function setTaskProject ({ commit }, { taskId, projectId }) { 47 | await TasksAPI.setProject({ taskId, projectId }) 48 | await Promise.all([ 49 | TasksAPI.setProject({ taskId, projectId }), 50 | ReportsAPI.bindProject(taskId, projectId) 51 | ]) 52 | commit('setTaskProject', { taskId, projectId }) 53 | } 54 | 55 | export async function removeTaskProject ({ commit }, id) { 56 | await Promise.all([ 57 | TasksAPI.removeProject(id), 58 | ReportsAPI.unBindProject(id) 59 | ]) 60 | commit('removeTaskProject', id) 61 | } 62 | -------------------------------------------------------------------------------- /src/store/tasks/getters.js: -------------------------------------------------------------------------------- 1 | 2 | export function allTasks (state) { 3 | return state.tasks 4 | } 5 | 6 | export function orphanTasks (state) { 7 | return state.tasks.filter(task => !task.project) 8 | } 9 | 10 | export function taskById (state) { 11 | return id => state.tasks.find(task => task.id === id) 12 | } 13 | 14 | export function projectTasks (state) { 15 | return ({ id }) => state.tasks.filter(task => task.project === id) 16 | } 17 | 18 | export function activeTask (state) { 19 | return state.tasks.find(task => task.id === state.activeTaskId) 20 | } 21 | -------------------------------------------------------------------------------- /src/store/tasks/index.js: -------------------------------------------------------------------------------- 1 | import state from './state' 2 | import * as getters from './getters' 3 | import * as mutations from './mutations' 4 | import * as actions from './actions' 5 | 6 | export default { 7 | namespaced: true, 8 | state, 9 | getters, 10 | mutations, 11 | actions 12 | } 13 | -------------------------------------------------------------------------------- /src/store/tasks/mutations.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export function setTasks (state, tasks) { 4 | state.tasks = [...tasks] 5 | } 6 | 7 | export function addTask (state, task) { 8 | const found = state.tasks.findIndex(({ id }) => id === task.id) 9 | if (found >= 0) { 10 | Vue.set(state.tasks, found, { 11 | ...state.tasks[found], ...task 12 | }) 13 | return 14 | } 15 | state.tasks.push(task) 16 | } 17 | 18 | const findTask = (list, { id }, callback = () => {}) => { 19 | const found = list.findIndex(task => task.id === id) 20 | if (found >= 0) { 21 | callback(found) 22 | } 23 | } 24 | 25 | export function removeTask (state, task) { 26 | findTask(state.tasks, task, index => (state.tasks.splice(index, 1))) 27 | } 28 | 29 | export function updateTask (state, update) { 30 | findTask( 31 | state.tasks, 32 | update, 33 | (index) => { 34 | Vue.set(state.tasks, index, { 35 | ...state.tasks[index], ...update 36 | }) 37 | } 38 | ) 39 | } 40 | 41 | export function setTaskProject (state, { taskId, projectId }) { 42 | findTask( 43 | state.tasks, 44 | { id: taskId }, 45 | (index) => { 46 | Vue.set(state.tasks[index], 'project', projectId) 47 | } 48 | ) 49 | } 50 | 51 | export function removeTaskProject (state, id) { 52 | findTask(state.tasks, { id }, (index) => Vue.set(state.tasks[index], 'project', null)) 53 | } 54 | 55 | export function setActiveTask (state, { id }) { 56 | state.activeTaskId = id 57 | } 58 | 59 | export function clearActiveTask (state) { 60 | state.activeTaskId = '' 61 | } 62 | -------------------------------------------------------------------------------- /src/store/tasks/state.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return { 3 | tasks: [], 4 | activeTaskId: '' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/store/tasks/store-flag.d.ts: -------------------------------------------------------------------------------- 1 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 2 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 3 | import "quasar/dist/types/feature-flag"; 4 | 5 | declare module "quasar/dist/types/feature-flag" { 6 | interface QuasarFeatureFlags { 7 | store: true; 8 | } 9 | } 10 | --------------------------------------------------------------------------------