cleanup
8595
.update_backup/package-lock.json
generated
Normal file
46
.update_backup/package.json
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"name": "enrecipes",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A native application built with NativeScript-Vue",
|
||||||
|
"author": "Vishnu Raghav <design@vishnuraghav.com>",
|
||||||
|
"license": "GPL",
|
||||||
|
"scripts": {
|
||||||
|
"run": "ns run android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nativescript-community/perms": "^2.1.1",
|
||||||
|
"@nativescript-community/ui-material-activityindicator": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-button": "^5.1.0",
|
||||||
|
"@nativescript-community/ui-material-floatingactionbutton": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-progress": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-ripple": "^5.0.30",
|
||||||
|
"@nativescript/core": "~7.0.0",
|
||||||
|
"@nativescript/imagepicker": "^1.0.0",
|
||||||
|
"@nativescript/social-share": "^2.0.1",
|
||||||
|
"@nativescript/theme": "^3.0.0",
|
||||||
|
"@nativescript/webpack": "3.0.0",
|
||||||
|
"@nativescript/zip": "^5.0.0",
|
||||||
|
"@nstudio/nativescript-checkbox": "^2.0.4",
|
||||||
|
"nativescript-clipboard": "^2.0.0",
|
||||||
|
"nativescript-couchbase-plugin": "^0.9.6",
|
||||||
|
"nativescript-feedback": "^2.0.0",
|
||||||
|
"nativescript-imagecropper": "^4.0.1",
|
||||||
|
"nativescript-plugin-filepicker": "^1.0.0",
|
||||||
|
"nativescript-toast": "^2.0.0",
|
||||||
|
"nativescript-ui-listview": "^9.0.4",
|
||||||
|
"nativescript-ui-sidedrawer": "^9.0.3",
|
||||||
|
"nativescript-vue": "^2.6.1",
|
||||||
|
"vuex": "^3.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.0.0",
|
||||||
|
"@babel/preset-env": "^7.0.0",
|
||||||
|
"@nativescript/android": "7.0.1",
|
||||||
|
"@types/node": "^14.0.27",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"nativescript-vue-template-compiler": "^2.6.0",
|
||||||
|
"node-sass": "^4.13.1",
|
||||||
|
"vue-loader": "^15.9.1"
|
||||||
|
},
|
||||||
|
"main": "main"
|
||||||
|
}
|
369
.update_backup/webpack.config.js
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
const { join, relative, resolve, sep } = require("path");
|
||||||
|
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
|
||||||
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
const NsVueTemplateCompiler = require("nativescript-vue-template-compiler");
|
||||||
|
|
||||||
|
const nsWebpack = require("@nativescript/webpack");
|
||||||
|
const nativescriptTarget = require("@nativescript/webpack/nativescript-target");
|
||||||
|
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
|
||||||
|
const hashSalt = Date.now().toString();
|
||||||
|
|
||||||
|
module.exports = env => {
|
||||||
|
// Add your custom Activities, Services and other android app components here.
|
||||||
|
const appComponents = env.appComponents || [];
|
||||||
|
appComponents.push(...[
|
||||||
|
"@nativescript/core/ui/frame",
|
||||||
|
"@nativescript/core/ui/frame/activity",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const platform = env && (env.android && "android" || env.ios && "ios" || env.platform);
|
||||||
|
if (!platform) {
|
||||||
|
throw new Error("You need to provide a target platform!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const platforms = ["ios", "android"];
|
||||||
|
const projectRoot = __dirname;
|
||||||
|
|
||||||
|
if (env.platform) {
|
||||||
|
platforms.push(env.platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destination inside platforms/<platform>/...
|
||||||
|
const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
|
||||||
|
|
||||||
|
const {
|
||||||
|
// The 'appPath' and 'appResourcesPath' values are fetched from
|
||||||
|
// the nsconfig.json configuration file.
|
||||||
|
appPath = "app",
|
||||||
|
appResourcesPath = "app/App_Resources",
|
||||||
|
|
||||||
|
// You can provide the following flags when running 'tns run android|ios'
|
||||||
|
snapshot, // --env.snapshot
|
||||||
|
production, // --env.production
|
||||||
|
report, // --env.report
|
||||||
|
hmr, // --env.hmr
|
||||||
|
sourceMap, // --env.sourceMap
|
||||||
|
hiddenSourceMap, // --env.hiddenSourceMap
|
||||||
|
unitTesting, // --env.unitTesting
|
||||||
|
testing, // --env.testing
|
||||||
|
verbose, // --env.verbose
|
||||||
|
snapshotInDocker, // --env.snapshotInDocker
|
||||||
|
skipSnapshotTools, // --env.skipSnapshotTools
|
||||||
|
compileSnapshot // --env.compileSnapshot
|
||||||
|
} = env;
|
||||||
|
|
||||||
|
const useLibs = compileSnapshot;
|
||||||
|
const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap;
|
||||||
|
const externals = nsWebpack.getConvertedExternals(env.externals);
|
||||||
|
|
||||||
|
const mode = production ? "production" : "development"
|
||||||
|
|
||||||
|
const appFullPath = resolve(projectRoot, appPath);
|
||||||
|
const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot });
|
||||||
|
let coreModulesPackageName = "tns-core-modules";
|
||||||
|
const alias = env.alias || {};
|
||||||
|
alias['~/package.json'] = resolve(projectRoot, 'package.json');
|
||||||
|
alias['~'] = appFullPath;
|
||||||
|
alias['@'] = appFullPath;
|
||||||
|
alias['vue'] = 'nativescript-vue';
|
||||||
|
|
||||||
|
if (hasRootLevelScopedModules) {
|
||||||
|
coreModulesPackageName = "@nativescript/core";
|
||||||
|
alias["tns-core-modules"] = coreModulesPackageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
|
||||||
|
|
||||||
|
const copyIgnore = { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] };
|
||||||
|
|
||||||
|
const entryModule = nsWebpack.getEntryModule(appFullPath, platform);
|
||||||
|
const entryPath = `.${sep}${entryModule}`;
|
||||||
|
const entries = env.entries || {};
|
||||||
|
entries.bundle = entryPath;
|
||||||
|
|
||||||
|
const areCoreModulesExternal = Array.isArray(env.externals) && env.externals.some(e => e.indexOf("@nativescript") > -1);
|
||||||
|
if (platform === "ios" && !areCoreModulesExternal && !testing) {
|
||||||
|
entries["tns_modules/@nativescript/core/inspector_modules"] = "inspector_modules";
|
||||||
|
};
|
||||||
|
console.log(`Bundling application for entryPath ${entryPath}...`);
|
||||||
|
|
||||||
|
let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist);
|
||||||
|
|
||||||
|
const itemsToClean = [`${dist}/**/*`];
|
||||||
|
if (platform === "android") {
|
||||||
|
itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "src", "main", "assets", "snapshots")}`);
|
||||||
|
itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "build", "configurations", "nativescript-android-snapshot")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsWebpack.processAppComponents(appComponents, platform);
|
||||||
|
const config = {
|
||||||
|
mode: mode,
|
||||||
|
context: appFullPath,
|
||||||
|
externals,
|
||||||
|
watchOptions: {
|
||||||
|
ignored: [
|
||||||
|
appResourcesFullPath,
|
||||||
|
// Don't watch hidden files
|
||||||
|
"**/.*",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
target: nativescriptTarget,
|
||||||
|
// target: nativeScriptVueTarget,
|
||||||
|
entry: entries,
|
||||||
|
output: {
|
||||||
|
pathinfo: false,
|
||||||
|
path: dist,
|
||||||
|
sourceMapFilename,
|
||||||
|
libraryTarget: "commonjs2",
|
||||||
|
filename: "[name].js",
|
||||||
|
globalObject: "global",
|
||||||
|
hashSalt
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".vue", ".ts", ".js", ".scss", ".css"],
|
||||||
|
// Resolve {N} system modules from @nativescript/core
|
||||||
|
modules: [
|
||||||
|
resolve(__dirname, `node_modules/${coreModulesPackageName}`),
|
||||||
|
resolve(__dirname, "node_modules"),
|
||||||
|
`node_modules/${coreModulesPackageName}`,
|
||||||
|
"node_modules",
|
||||||
|
],
|
||||||
|
alias,
|
||||||
|
// resolve symlinks to symlinked modules
|
||||||
|
symlinks: true,
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
|
// don't resolve symlinks to symlinked loaders
|
||||||
|
symlinks: false,
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
// Disable node shims that conflict with NativeScript
|
||||||
|
"http": false,
|
||||||
|
"timers": false,
|
||||||
|
"setImmediate": false,
|
||||||
|
"fs": "empty",
|
||||||
|
"__dirname": false,
|
||||||
|
},
|
||||||
|
devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"),
|
||||||
|
optimization: {
|
||||||
|
runtimeChunk: "single",
|
||||||
|
noEmitOnErrors: true,
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
name: "vendor",
|
||||||
|
chunks: "all",
|
||||||
|
test: (module) => {
|
||||||
|
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
|
||||||
|
return /[\\/]node_modules[\\/]/.test(moduleName) ||
|
||||||
|
appComponents.some(comp => comp === moduleName);
|
||||||
|
|
||||||
|
},
|
||||||
|
enforce: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minimize: Boolean(production),
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
parallel: true,
|
||||||
|
cache: true,
|
||||||
|
sourceMap: isAnySourceMapEnabled,
|
||||||
|
terserOptions: {
|
||||||
|
output: {
|
||||||
|
comments: false,
|
||||||
|
semicolons: !isAnySourceMapEnabled
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
// The Android SBG has problems parsing the output
|
||||||
|
// when these options are enabled
|
||||||
|
'collapse_vars': platform !== "android",
|
||||||
|
sequences: platform !== "android",
|
||||||
|
},
|
||||||
|
keep_fnames: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
include: [join(appFullPath, entryPath + ".js"), join(appFullPath, entryPath + ".ts")],
|
||||||
|
use: [
|
||||||
|
// Require all Android app components
|
||||||
|
platform === "android" && {
|
||||||
|
loader: "@nativescript/webpack/helpers/android-app-components-loader",
|
||||||
|
options: { modules: appComponents },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
loader: "@nativescript/webpack/bundle-config-loader",
|
||||||
|
options: {
|
||||||
|
registerPages: true, // applicable only for non-angular apps
|
||||||
|
loadCss: !snapshot, // load the application css if in debug mode
|
||||||
|
unitTesting,
|
||||||
|
appFullPath,
|
||||||
|
projectRoot,
|
||||||
|
ignoredFiles: nsWebpack.getUserDefinedEntries(entries, platform)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
].filter(loader => Boolean(loader)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /[\/|\\]app\.css$/,
|
||||||
|
use: [
|
||||||
|
'@nativescript/webpack/helpers/style-hot-loader',
|
||||||
|
{
|
||||||
|
loader: "@nativescript/webpack/helpers/css2json-loader",
|
||||||
|
options: { useForImports: true }
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /[\/|\\]app\.scss$/,
|
||||||
|
use: [
|
||||||
|
'@nativescript/webpack/helpers/style-hot-loader',
|
||||||
|
{
|
||||||
|
loader: "@nativescript/webpack/helpers/css2json-loader",
|
||||||
|
options: { useForImports: true }
|
||||||
|
},
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: /[\/|\\]app\.css$/,
|
||||||
|
use: [
|
||||||
|
'@nativescript/webpack/helpers/style-hot-loader',
|
||||||
|
'@nativescript/webpack/helpers/apply-css-loader.js',
|
||||||
|
{ loader: "css-loader", options: { url: false } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
exclude: /[\/|\\]app\.scss$/,
|
||||||
|
use: [
|
||||||
|
'@nativescript/webpack/helpers/style-hot-loader',
|
||||||
|
'@nativescript/webpack/helpers/apply-css-loader.js',
|
||||||
|
{ loader: "css-loader", options: { url: false } },
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
appendTsSuffixTo: [/\.vue$/],
|
||||||
|
allowTsInNodeModules: true,
|
||||||
|
compilerOptions: {
|
||||||
|
declaration: false
|
||||||
|
},
|
||||||
|
getCustomTransformers: (program) => ({
|
||||||
|
before: [
|
||||||
|
require("@nativescript/webpack/transformers/ns-transform-native-classes").default
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: "vue-loader",
|
||||||
|
options: {
|
||||||
|
compiler: NsVueTemplateCompiler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// ... Vue Loader plugin omitted
|
||||||
|
// make sure to include the plugin!
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
// Define useful constants like TNS_WEBPACK
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
"global.TNS_WEBPACK": "true",
|
||||||
|
"global.isAndroid": platform === 'android',
|
||||||
|
"global.isIOS": platform === 'ios',
|
||||||
|
"TNS_ENV": JSON.stringify(mode),
|
||||||
|
"process": "global.process"
|
||||||
|
}),
|
||||||
|
// Remove all files from the out dir.
|
||||||
|
new CleanWebpackPlugin({
|
||||||
|
cleanOnceBeforeBuildPatterns: itemsToClean,
|
||||||
|
verbose: !!verbose
|
||||||
|
}),
|
||||||
|
// Copy assets
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
|
{ from: 'assets/**', noErrorOnMissing: true, globOptions: { dot: false, ...copyIgnore } },
|
||||||
|
{ from: 'fonts/**', noErrorOnMissing: true, globOptions: { dot: false, ...copyIgnore } },
|
||||||
|
{ from: '**/*.+(jpg|png)', noErrorOnMissing: true, globOptions: { dot: false, ...copyIgnore } }
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new nsWebpack.GenerateNativeScriptEntryPointsPlugin("bundle"),
|
||||||
|
// For instructions on how to set up workers with webpack
|
||||||
|
// check out https://github.com/nativescript/worker-loader
|
||||||
|
new NativeScriptWorkerPlugin(),
|
||||||
|
new nsWebpack.PlatformFSPlugin({
|
||||||
|
platform,
|
||||||
|
platforms,
|
||||||
|
}),
|
||||||
|
// Does IPC communication with the {N} CLI to notify events when running in watch mode.
|
||||||
|
new nsWebpack.WatchStateLoggerPlugin()
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (unitTesting) {
|
||||||
|
config.module.rules.push(
|
||||||
|
{
|
||||||
|
test: /-page\.js$/,
|
||||||
|
use: "@nativescript/webpack/helpers/script-hot-loader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(html|xml)$/,
|
||||||
|
use: "@nativescript/webpack/helpers/markup-hot-loader"
|
||||||
|
},
|
||||||
|
|
||||||
|
{ test: /\.(html|xml)$/, use: "@nativescript/webpack/helpers/xml-namespace-loader" }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report) {
|
||||||
|
// Generate report files for bundles content
|
||||||
|
config.plugins.push(new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: "static",
|
||||||
|
openAnalyzer: false,
|
||||||
|
generateStatsFile: true,
|
||||||
|
reportFilename: resolve(projectRoot, "report", `report.html`),
|
||||||
|
statsFilename: resolve(projectRoot, "report", `stats.json`),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot) {
|
||||||
|
config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
|
||||||
|
chunk: "vendor",
|
||||||
|
requireModules: [
|
||||||
|
"@nativescript/core/bundle-entry-points",
|
||||||
|
],
|
||||||
|
projectRoot,
|
||||||
|
webpackConfig: config,
|
||||||
|
snapshotInDocker,
|
||||||
|
skipSnapshotTools,
|
||||||
|
useLibs
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hmr) {
|
||||||
|
config.plugins.push(new webpack.HotModuleReplacementPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
# NativeScript-Vue Application
|
# EnRecipes
|
||||||
|
|
||||||
> A native application built with NativeScript-Vue
|
> A native application built with NativeScript-Vue
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
versionCode 2
|
versionCode 1
|
||||||
versionName '1.0.0'
|
versionName '1.0.0'
|
||||||
applicationId 'com.vishnuraghav.enrecipes'
|
applicationId 'com.vishnuraghav.enrecipes'
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
generatedDensities = []
|
generatedDensities = []
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters.clear()
|
abiFilters.clear()
|
||||||
abiFilters.addAll(['arm64-v8a','x86'])
|
abiFilters.addAll(['arm64-v8a'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="__PACKAGE__" android:versionCode="10000" android:versionName="1.0">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="__PACKAGE__" android:versionCode="10000" android:versionName="1.0">
|
||||||
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" />
|
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" tools:node="remove" />
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<!-- <uses-feature android:name="android.hardware.camera" /> -->
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
|
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
|
||||||
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:hardwareAccelerated="true" android:largeHeap="true" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
|
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:hardwareAccelerated="true" android:largeHeap="true" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
|
||||||
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:screenOrientation="portrait" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme" android:windowSoftInputMode="adjustPan">
|
<activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:screenOrientation="portrait" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme" android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
|
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/camera.png
Normal file
After Width: | Height: | Size: 687 B |
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/check.png
Normal file
After Width: | Height: | Size: 587 B |
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/detail.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/photo.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/plus.png
Normal file
After Width: | Height: | Size: 229 B |
BIN
app/App_Resources/Android/src/main/res/drawable-hdpi/share.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/camera.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/check.png
Normal file
After Width: | Height: | Size: 341 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/detail.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/photo.png
Normal file
After Width: | Height: | Size: 310 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/plus.png
Normal file
After Width: | Height: | Size: 173 B |
BIN
app/App_Resources/Android/src/main/res/drawable-ldpi/share.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/camera.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/check.png
Normal file
After Width: | Height: | Size: 324 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/detail.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/photo.png
Normal file
After Width: | Height: | Size: 300 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/plus.png
Normal file
After Width: | Height: | Size: 165 B |
BIN
app/App_Resources/Android/src/main/res/drawable-mdpi/share.png
Normal file
After Width: | Height: | Size: 341 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/camera.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/check.png
Normal file
After Width: | Height: | Size: 573 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/detail.png
Normal file
After Width: | Height: | Size: 328 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/photo.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/plus.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xhdpi/share.png
Normal file
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 1.2 KiB |
BIN
app/App_Resources/Android/src/main/res/drawable-xxhdpi/check.png
Normal file
After Width: | Height: | Size: 969 B |
After Width: | Height: | Size: 515 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xxhdpi/photo.png
Normal file
After Width: | Height: | Size: 824 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xxhdpi/plus.png
Normal file
After Width: | Height: | Size: 250 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xxhdpi/share.png
Normal file
After Width: | Height: | Size: 930 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1 KiB |
After Width: | Height: | Size: 604 B |
After Width: | Height: | Size: 882 B |
BIN
app/App_Resources/Android/src/main/res/drawable-xxxhdpi/plus.png
Normal file
After Width: | Height: | Size: 295 B |
After Width: | Height: | Size: 928 B |
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ns_primary">
|
<color name="ns_primary">
|
||||||
#fafafa
|
#f1f3f5
|
||||||
</color>
|
</color>
|
||||||
<color name="ns_primaryDark">
|
<color name="ns_primaryDark">
|
||||||
#ff5200
|
#ff5200
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<!-- theme to use FOR launch screen -->
|
<!-- theme to use FOR launch screen -->
|
||||||
<style name="LaunchScreenThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="LaunchScreenThemeBase" parent="Theme.MaterialComponents.NoActionBar">
|
||||||
<item name="toolbarStyle">
|
<item name="toolbarStyle">
|
||||||
@style/NativeScriptToolbarStyle
|
@style/NativeScriptToolbarStyle
|
||||||
</item>
|
</item>
|
||||||
|
@ -27,7 +27,10 @@
|
||||||
<style name="LaunchScreenTheme" parent="LaunchScreenThemeBase">
|
<style name="LaunchScreenTheme" parent="LaunchScreenThemeBase">
|
||||||
</style>
|
</style>
|
||||||
<!-- theme to use AFTER launch screen is loaded -->
|
<!-- theme to use AFTER launch screen is loaded -->
|
||||||
<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="AppThemeBase" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||||
|
<item name="searchViewStyle">
|
||||||
|
@style/SearchViewMy
|
||||||
|
</item>
|
||||||
<item name="toolbarStyle">
|
<item name="toolbarStyle">
|
||||||
@style/NativeScriptToolbarStyle
|
@style/NativeScriptToolbarStyle
|
||||||
</item>
|
</item>
|
||||||
|
@ -40,21 +43,42 @@
|
||||||
<item name="colorAccent">
|
<item name="colorAccent">
|
||||||
@color/ns_accent
|
@color/ns_accent
|
||||||
</item>
|
</item>
|
||||||
|
<item name="colorControlNormal">
|
||||||
|
#868e96
|
||||||
|
</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="AppTheme" parent="AppThemeBase">
|
<style name="AppTheme" parent="AppThemeBase">
|
||||||
</style>
|
</style>
|
||||||
<!-- theme for action-bar -->
|
<!-- theme for action-bar -->
|
||||||
<style name="NativeScriptToolbarStyleBase" parent="Widget.AppCompat.Toolbar">
|
<style name="NativeScriptToolbarStyleBase" parent="Widget.MaterialComponents.Toolbar">
|
||||||
|
<item name="contentInsetStart">
|
||||||
|
0dp
|
||||||
|
</item>
|
||||||
|
<item name="contentInsetEnd">
|
||||||
|
0dp
|
||||||
|
</item>
|
||||||
|
<item name="android:divider">
|
||||||
|
#ff0000
|
||||||
|
</item>
|
||||||
<item name="android:background">
|
<item name="android:background">
|
||||||
@color/ns_primary
|
@color/ns_primary
|
||||||
</item>
|
</item>
|
||||||
<item name="theme">
|
<item name="theme">
|
||||||
@style/ThemeOverlay.AppCompat.ActionBar
|
@style/ThemeOverlay.MaterialComponents.ActionBar
|
||||||
</item>
|
</item>
|
||||||
<item name="popupTheme">
|
<item name="popupTheme">
|
||||||
@style/ThemeOverlay.AppCompat
|
@style/ThemeOverlay.MaterialComponents
|
||||||
</item>
|
</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase">
|
<style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase">
|
||||||
</style>
|
</style>
|
||||||
|
<!-- theme for searchview -->
|
||||||
|
<style name="SearchViewMy" parent="Widget.AppCompat.Light.SearchView">
|
||||||
|
<item name="searchHintIcon">
|
||||||
|
@null
|
||||||
|
</item>
|
||||||
|
<!-- <item name="closeIcon">
|
||||||
|
@null
|
||||||
|
</item> -->
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
290
app/app.scss
|
@ -1,27 +1,24 @@
|
||||||
// NativeScript core theme
|
// NativeScript core theme
|
||||||
// @see https://docs.nativescript.org/ui/theme
|
// @see https://docs.nativescript.org/ui/theme
|
||||||
@import "~@nativescript/theme/core";
|
@import "~@nativescript/theme/core";
|
||||||
|
|
||||||
// Override variables here
|
// Override variables here
|
||||||
|
$gray1: #f1f3f5;
|
||||||
$grayD4: #212121;
|
$gray2: #e9ecef;
|
||||||
$grayD3: #424242;
|
$gray3: #dee2e6;
|
||||||
$grayD2: #616161;
|
$gray4: #ced4da;
|
||||||
$grayD1: #757575;
|
$gray5: #adb5bd; // rgb(173,181,189)
|
||||||
$gray: #9e9e9e;
|
$gray6: #868e96;
|
||||||
$grayL1: #e0e0e0;
|
$gray7: #495057;
|
||||||
$grayL2: #eeeeee;
|
$gray8: #343a40;
|
||||||
$grayL3: #f5f5f5;
|
$gray9: #212529;
|
||||||
$grayL4: #fafafa;
|
|
||||||
$orange: #ff5200;
|
$orange: #ff5200;
|
||||||
|
$fabRipple: #ff864d;
|
||||||
|
$red: #c92a2a;
|
||||||
// Global SCSS styling
|
// Global SCSS styling
|
||||||
// @see https://docs.nativescript.org/ui/styling
|
// @see https://docs.nativescript.org/ui/styling
|
||||||
|
|
||||||
// * {
|
Page,
|
||||||
// font-size: 16;
|
.ns-modal {
|
||||||
// }
|
|
||||||
Page {
|
|
||||||
font-family: "Orkney-Regular";
|
font-family: "Orkney-Regular";
|
||||||
}
|
}
|
||||||
.orkm {
|
.orkm {
|
||||||
|
@ -36,26 +33,30 @@ Page {
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ns-light {
|
.ns-light {
|
||||||
Page,
|
Page,
|
||||||
ActionBar,
|
ActionBar,
|
||||||
SearchBar,
|
SearchBar,
|
||||||
TabView,
|
TabView,
|
||||||
ListPicker {
|
ListPicker {
|
||||||
color: $grayD4;
|
color: $gray9;
|
||||||
background: $grayL4;
|
background: $gray1;
|
||||||
}
|
}
|
||||||
|
MDRipple,
|
||||||
|
MDButton {
|
||||||
|
ripple-color: rgba($gray6, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
TabView {
|
TabView {
|
||||||
tab-background-color: $grayL4;
|
tab-background-color: $gray1;
|
||||||
selected-tab-text-color: $grayD4;
|
selected-tab-text-color: $gray9;
|
||||||
}
|
}
|
||||||
.hr {
|
.hr {
|
||||||
border-color: $grayL2;
|
border-color: $gray3;
|
||||||
}
|
}
|
||||||
.sd,
|
.sd,
|
||||||
.fieldLabel {
|
.fieldLabel {
|
||||||
background: $grayL4;
|
background: $gray1;
|
||||||
}
|
}
|
||||||
.referenceItem,
|
.referenceItem,
|
||||||
.recipeText,
|
.recipeText,
|
||||||
|
@ -63,36 +64,32 @@ Page {
|
||||||
.recipeItem {
|
.recipeItem {
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
.option-highlight,
|
|
||||||
.selected-sd-item {
|
|
||||||
background: $grayL2;
|
|
||||||
}
|
|
||||||
.sd-item,
|
.sd-item,
|
||||||
.sd-group-header,
|
.sd-group-header,
|
||||||
.time .bx {
|
.time .bx {
|
||||||
color: $grayD2;
|
color: $gray8;
|
||||||
}
|
|
||||||
.fab-button {
|
|
||||||
color: white;
|
|
||||||
background-color: $orange;
|
|
||||||
}
|
|
||||||
.option,
|
|
||||||
.icon-option {
|
|
||||||
.bx,
|
|
||||||
.option-info {
|
|
||||||
color: $grayD2;
|
|
||||||
}
|
}
|
||||||
|
.option .bx,
|
||||||
|
.option .info {
|
||||||
|
color: $gray7;
|
||||||
}
|
}
|
||||||
.imageHolder {
|
.imageHolder {
|
||||||
color: $gray;
|
color: $gray4;
|
||||||
background: $grayL2;
|
background: $gray3;
|
||||||
}
|
}
|
||||||
.count {
|
.count {
|
||||||
color: $grayL4;
|
color: $gray1;
|
||||||
background: $grayD4;
|
background: $gray9;
|
||||||
}
|
}
|
||||||
.instruction {
|
.instruction {
|
||||||
border-color: $grayD4;
|
border-color: $gray9;
|
||||||
|
}
|
||||||
|
MDProgress {
|
||||||
|
progress-background-color: $gray4;
|
||||||
|
}
|
||||||
|
MDFloatingActionButton {
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,56 +99,56 @@ Page {
|
||||||
SearchBar,
|
SearchBar,
|
||||||
TabView,
|
TabView,
|
||||||
ListPicker {
|
ListPicker {
|
||||||
color: $grayL4;
|
color: $gray1;
|
||||||
background: $grayD4;
|
background: $gray9;
|
||||||
}
|
}
|
||||||
TabView {
|
TabView {
|
||||||
tab-background-color: $grayD4;
|
tab-background-color: $gray9;
|
||||||
selected-tab-text-color: $grayL4;
|
selected-tab-text-color: $gray1;
|
||||||
}
|
}
|
||||||
|
MDRipple,
|
||||||
|
MDButton {
|
||||||
|
ripple-color: rgba($gray4, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.hr {
|
.hr {
|
||||||
border-color: #111;
|
border-color: #111;
|
||||||
}
|
}
|
||||||
.sd,
|
.sd,
|
||||||
.fieldLabel {
|
.fieldLabel {
|
||||||
background: $grayD4;
|
background: $gray9;
|
||||||
}
|
}
|
||||||
.referenceItem,
|
.referenceItem,
|
||||||
.recipeText,
|
.recipeText,
|
||||||
.overviewItem,
|
.overviewItem,
|
||||||
.recipeItem,
|
.recipeItem {
|
||||||
.option-highlight {
|
background: $gray8;
|
||||||
background: $grayD3;
|
|
||||||
}
|
}
|
||||||
.sd-item,
|
.sd-item,
|
||||||
.sd-group-header,
|
.sd-group-header,
|
||||||
.time .bx {
|
.time .bx {
|
||||||
color: $grayL2;
|
color: $gray3;
|
||||||
}
|
|
||||||
.selected-sd-item {
|
|
||||||
background: #111;
|
|
||||||
}
|
|
||||||
.fab-button {
|
|
||||||
color: #111;
|
|
||||||
background: $orange;
|
|
||||||
}
|
|
||||||
.option,
|
|
||||||
.icon-option {
|
|
||||||
.bx,
|
|
||||||
.option-info {
|
|
||||||
color: $gray;
|
|
||||||
}
|
}
|
||||||
|
.option .bx,
|
||||||
|
.option .info {
|
||||||
|
color: $gray5;
|
||||||
}
|
}
|
||||||
.imageHolder {
|
.imageHolder {
|
||||||
color: $gray;
|
color: $gray8;
|
||||||
background: #111;
|
background: #111;
|
||||||
}
|
}
|
||||||
.count {
|
.count {
|
||||||
color: $grayD4;
|
color: $gray9;
|
||||||
background: $grayL4;
|
background: $gray1;
|
||||||
}
|
}
|
||||||
.instruction {
|
.instruction {
|
||||||
border-color: $grayL4;
|
border-color: $gray1;
|
||||||
|
}
|
||||||
|
MDProgress {
|
||||||
|
progress-background-color: $gray6;
|
||||||
|
}
|
||||||
|
MDFloatingActionButton {
|
||||||
|
color: $gray9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
@ -165,48 +162,56 @@ TimePickerField {
|
||||||
padding: 14 14 13;
|
padding: 14 14 13;
|
||||||
margin: 8 0 0 0;
|
margin: 8 0 0 0;
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
border-color: $gray;
|
border-color: $gray6;
|
||||||
placeholder-color: $gray;
|
placeholder-color: $gray6;
|
||||||
}
|
}
|
||||||
TextView {
|
TextView {
|
||||||
line-height: 12;
|
line-height: 12;
|
||||||
}
|
}
|
||||||
|
SearchBar {
|
||||||
|
font-family: "Orkney-Regular";
|
||||||
|
font-size: 16;
|
||||||
|
text-field-hint-color: $gray6;
|
||||||
|
}
|
||||||
TabView {
|
TabView {
|
||||||
tab-text-color: $gray;
|
tab-text-color: $gray6;
|
||||||
}
|
}
|
||||||
.inputField {
|
.inputField {
|
||||||
margin-top: 16;
|
margin-bottom: 14;
|
||||||
}
|
}
|
||||||
.fieldLabel {
|
.fieldLabel {
|
||||||
font-size: 12;
|
font-size: 12;
|
||||||
margin-left: 8;
|
margin-left: 12;
|
||||||
padding: 0 8;
|
padding: 0 4;
|
||||||
}
|
}
|
||||||
// prettier-ignore
|
|
||||||
.progressContainer {
|
.progressContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
// prettier-ignore
|
|
||||||
.text-btn,
|
.text-btn,
|
||||||
.group-header,
|
.group-header,
|
||||||
.category,
|
.category,
|
||||||
ActivityIndicator,
|
MDActivityIndicator {
|
||||||
Progress {
|
|
||||||
color: $orange;
|
color: $orange;
|
||||||
}
|
}
|
||||||
|
MDProgress {
|
||||||
|
progress-color: $orange;
|
||||||
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// ActionBar
|
// ActionBar
|
||||||
ActionBar {
|
ActionBar {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0 8;
|
||||||
height: 64;
|
height: 64;
|
||||||
.bx {
|
GridLayout {
|
||||||
padding: 16 16 16 4;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
MDButton.bx {
|
||||||
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
vertical-alignment: center;
|
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
padding-left: 8;
|
padding-left: 12;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 18;
|
font-size: 18;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +223,6 @@ ActionBar {
|
||||||
}
|
}
|
||||||
.sd-item {
|
.sd-item {
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
padding: 0 16;
|
|
||||||
height: 48;
|
height: 48;
|
||||||
vertical-alignment: center;
|
vertical-alignment: center;
|
||||||
.bx {
|
.bx {
|
||||||
|
@ -226,25 +230,50 @@ ActionBar {
|
||||||
}
|
}
|
||||||
&.selected-sd-item {
|
&.selected-sd-item {
|
||||||
color: $orange;
|
color: $orange;
|
||||||
|
background: rgba($orange, 0.1);
|
||||||
|
MDRipple {
|
||||||
|
ripple-color: transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
Label {
|
Label {
|
||||||
|
padding: 0 16 0 0;
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
vertical-alignment: center;
|
vertical-alignment: center;
|
||||||
|
&.bx{
|
||||||
|
padding: 0 0 0 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MDRipple {
|
||||||
|
padding: 0 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sd-group-header {
|
.sd-group-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8 8 16;
|
padding: 8 0 8 8;
|
||||||
|
}
|
||||||
|
MDRipple {
|
||||||
|
border-radius: 4;
|
||||||
|
}
|
||||||
|
MDButton {
|
||||||
|
padding: 8;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
&.bx {
|
||||||
|
padding: 0;
|
||||||
|
width: 48;
|
||||||
|
height: 48;
|
||||||
|
margin: 0 8 0 0;
|
||||||
|
border-radius: 99;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// HOME
|
// HOME
|
||||||
|
.emptyStateContainer {
|
||||||
.emptyState {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.noResult {
|
.emptyState {
|
||||||
line-height: 8;
|
line-height: 8;
|
||||||
padding: 0 32;
|
padding: 0 32;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -253,7 +282,7 @@ ActionBar {
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 64;
|
font-size: 64;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $gray;
|
color: $gray5;
|
||||||
margin-bottom: 16;
|
margin-bottom: 16;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
|
@ -271,6 +300,9 @@ ActionBar {
|
||||||
vertical-alignment: center;
|
vertical-alignment: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.noResult {
|
||||||
|
margin-top: 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Recipe Items
|
// Recipe Items
|
||||||
|
@ -313,7 +345,7 @@ RadListView {
|
||||||
}
|
}
|
||||||
.swipe-item {
|
.swipe-item {
|
||||||
margin: 0 8;
|
margin: 0 8;
|
||||||
background: #c62828;
|
background: $red;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
height: 128;
|
height: 128;
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
|
@ -324,17 +356,19 @@ RadListView {
|
||||||
padding: 8;
|
padding: 8;
|
||||||
}
|
}
|
||||||
.main-container {
|
.main-container {
|
||||||
padding: 16 8 128;
|
padding: 8 8 128;
|
||||||
.option {
|
.option {
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
padding: 16;
|
|
||||||
.bx {
|
.bx {
|
||||||
margin: 0 24 0 0;
|
margin: 16 24 16 16;
|
||||||
}
|
}
|
||||||
.option-info {
|
.info {
|
||||||
font-size: 12;
|
font-size: 12;
|
||||||
line-height: 4;
|
line-height: 4;
|
||||||
}
|
}
|
||||||
|
StackLayout {
|
||||||
|
margin: 16 24 16 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
@ -374,17 +408,16 @@ RadListView {
|
||||||
margin-top: 12;
|
margin-top: 12;
|
||||||
.overviewItem {
|
.overviewItem {
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
padding: 8;
|
|
||||||
margin: 8;
|
margin: 8;
|
||||||
android-elevation: 1;
|
android-elevation: 1;
|
||||||
.bx {
|
.bx {
|
||||||
color: $gray;
|
padding: 12 0 0 12;
|
||||||
width: 24;
|
color: $gray6;
|
||||||
horizontal-alignment: left;
|
horizontal-alignment: left;
|
||||||
}
|
}
|
||||||
.itemCount {
|
.itemCount {
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
padding: 8 4 4;
|
padding: 8 12 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +427,7 @@ RadListView {
|
||||||
padding-bottom: 12;
|
padding-bottom: 12;
|
||||||
}
|
}
|
||||||
.ingredient-check {
|
.ingredient-check {
|
||||||
margin-bottom: 12;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
.count {
|
.count {
|
||||||
width: 24;
|
width: 24;
|
||||||
|
@ -432,15 +465,14 @@ RadListView {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
.referenceItem {
|
.referenceItem {
|
||||||
padding: 14 16;
|
margin: 8 16;
|
||||||
margin: 8 16 8;
|
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
.bx {
|
.bx {
|
||||||
font-size: 24;
|
font-size: 24;
|
||||||
}
|
}
|
||||||
.recipeLink {
|
.recipeLink {
|
||||||
padding: 0 16 0 0;
|
padding: 16;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +480,7 @@ RadListView {
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
line-height: 6;
|
line-height: 6;
|
||||||
padding: 16;
|
padding: 16;
|
||||||
margin: 8 16 8;
|
margin: 8 16;
|
||||||
border-radius: 4;
|
border-radius: 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,14 +490,10 @@ RadListView {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.fab-button {
|
MDFloatingActionButton {
|
||||||
height: 56;
|
|
||||||
width: 56;
|
|
||||||
border-radius: 28;
|
|
||||||
padding: 16;
|
|
||||||
margin: 16;
|
margin: 16;
|
||||||
vertical-alignment: center;
|
background: $orange;
|
||||||
android-elevation: 6;
|
ripple-color: $fabRipple;
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// EDIT RECIPE
|
// EDIT RECIPE
|
||||||
|
@ -475,51 +503,67 @@ RadListView {
|
||||||
.text-btn {
|
.text-btn {
|
||||||
font-size: 14;
|
font-size: 14;
|
||||||
horizontal-alignment: left;
|
horizontal-alignment: left;
|
||||||
padding: 16;
|
padding: 12;
|
||||||
margin: 8 0 0 0;
|
margin: 8 0 0 0;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.closeBtn {
|
MDButton.closeBtn {
|
||||||
padding: 4;
|
padding: 4;
|
||||||
margin-top: 16;
|
margin-top: 16;
|
||||||
|
min-width: 0;
|
||||||
vertical-alignment: top;
|
vertical-alignment: top;
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// DIALOGS
|
// DIALOGS
|
||||||
.dialogContainer {
|
.dialogContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: $grayD4;
|
color: $gray9;
|
||||||
background: $grayL4;
|
background: $gray1;
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
&.dark {
|
&.dark {
|
||||||
color: $grayL4;
|
color: $gray1;
|
||||||
background: $grayD4;
|
background: $gray9;
|
||||||
}
|
}
|
||||||
.dialogTitle {
|
.dialogTitle {
|
||||||
padding: 24 24 12;
|
padding: 24 24 16;
|
||||||
font-size: 20;
|
font-size: 20;
|
||||||
}
|
}
|
||||||
.dialogInput {
|
.dialogInput {
|
||||||
padding: 0 24 16;
|
padding: 0 24 16;
|
||||||
}
|
}
|
||||||
.dialogDescription {
|
.dialogDescription {
|
||||||
line-height: 4;
|
line-height: 6;
|
||||||
padding: 0 24 16;
|
padding: 0 24 8;
|
||||||
}
|
}
|
||||||
.actionItem {
|
.actionItem {
|
||||||
padding: 8 24;
|
letter-spacing: 0;
|
||||||
|
text-transform: none;
|
||||||
|
padding: 16 24;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.actionsContainer {
|
.actionsContainer {
|
||||||
padding: 24;
|
padding: 8;
|
||||||
}
|
}
|
||||||
.action {
|
.action {
|
||||||
font-size: 12;
|
font-size: 12;
|
||||||
|
padding: 12;
|
||||||
|
min-width: 0;
|
||||||
color: #ff7043;
|
color: #ff7043;
|
||||||
}
|
}
|
||||||
|
MDButton.actionIcon {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 16 24;
|
||||||
|
border-radius: 4;
|
||||||
|
letter-spacing: 0;
|
||||||
|
text-transform: none;
|
||||||
|
margin: 0 16 16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
ActivityIndicator {
|
MDActivityIndicator {
|
||||||
width: 24;
|
width: 24;
|
||||||
height: 24;
|
height: 24;
|
||||||
margin: 16;
|
margin: 16;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<Page @loaded="initializePage">
|
<Page @loaded="onPageLoad">
|
||||||
<ActionBar :flat="viewIsScrolled ? false : true">
|
<ActionBar :flat="viewIsScrolled ? false : true">
|
||||||
<GridLayout rows="*" columns="auto, *">
|
<GridLayout rows="*" columns="auto, *">
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.menu"
|
:text="icon.menu"
|
||||||
automationText="Back"
|
automationText="Back"
|
||||||
|
@ -21,67 +22,73 @@
|
||||||
>
|
>
|
||||||
<Image src="res://logo_light" class="appIcon" stretch="aspectFit" />
|
<Image src="res://logo_light" class="appIcon" stretch="aspectFit" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout orientation="horizontal" class="option">
|
<StackLayout class="m-8"></StackLayout>
|
||||||
<Label class="bx" :text="icon.info" />
|
<GridLayout columns="auto, *" class="option">
|
||||||
<StackLayout>
|
<Label col="0" class="bx" :text="icon.info" />
|
||||||
|
<StackLayout col="1">
|
||||||
<Label text="Version" />
|
<Label text="Version" />
|
||||||
<Label :text="getVersion" class="option-info" textWrap="true" />
|
<Label :text="getVersion" class="info" textWrap="true" />
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
orientation="horizontal"
|
|
||||||
class="option"
|
|
||||||
@tap="openURL($event, 'https://github.com/vishnuraghavb/enrecipes')"
|
|
||||||
>
|
|
||||||
<Label class="bx" :text="icon.link" />
|
|
||||||
<Label text="View project on GitHub" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
orientation="horizontal"
|
|
||||||
class="option"
|
|
||||||
@tap="openURL($event, 'https://t.me/enrecipes')"
|
|
||||||
>
|
|
||||||
<Label class="bx" :text="icon.telegram" />
|
|
||||||
<Label text="Join the Telegram group" />
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
</GridLayout>
|
||||||
|
<GridLayout columns="auto, *" class="option">
|
||||||
|
<MDRipple
|
||||||
|
colSpan="2"
|
||||||
|
@tap="openURL('https://github.com/vishnuraghavb/enrecipes')"
|
||||||
|
/>
|
||||||
|
<Label col="0" class="bx" :text="icon.link" />
|
||||||
|
<Label
|
||||||
|
verticalAlignment="center"
|
||||||
|
col="1"
|
||||||
|
text="View project on GitHub"
|
||||||
|
/>
|
||||||
|
</GridLayout>
|
||||||
|
<GridLayout columns="auto, *" class="option">
|
||||||
|
<MDRipple colSpan="2" @tap="openURL('https://t.me/enrecipes')" />
|
||||||
|
<Label col="0" class="bx" :text="icon.telegram" />
|
||||||
|
<Label
|
||||||
|
verticalAlignment="center"
|
||||||
|
col="1"
|
||||||
|
text="Join the Telegram group"
|
||||||
|
/>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
<StackLayout class="hr m-10"></StackLayout>
|
<StackLayout class="hr m-10"></StackLayout>
|
||||||
|
|
||||||
<Label text="Author" class="group-header" />
|
<Label text="Author" class="group-header orkm" />
|
||||||
<StackLayout
|
<GridLayout columns="auto, *" class="option">
|
||||||
orientation="horizontal"
|
<MDRipple
|
||||||
class="option"
|
colSpan="2"
|
||||||
@tap="openURL($event, 'https://www.vishnuraghav.com')"
|
@tap="openURL('https://www.vishnuraghav.com')"
|
||||||
>
|
/>
|
||||||
<Label class="bx" :text="icon.user" />
|
<Label col="0" class="bx" :text="icon.user" />
|
||||||
<Label text="Vishnu Raghav" />
|
<Label verticalAlignment="center" col="1" text="Vishnu Raghav" />
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout columns="auto, *" class="option">
|
||||||
orientation="horizontal"
|
<MDRipple
|
||||||
class="option"
|
colSpan="2"
|
||||||
@tap="openURL($event, 'https://github.com/vishnuraghavb')"
|
@tap="openURL('https://github.com/vishnuraghavb')"
|
||||||
>
|
/>
|
||||||
<Label class="bx" :text="icon.link" />
|
<Label col="0" class="bx" :text="icon.link" />
|
||||||
<Label text="Follow on GitHub" />
|
<Label verticalAlignment="center" col="1" text="Follow on GitHub" />
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout columns="auto, *" class="option">
|
||||||
orientation="horizontal"
|
<MDRipple
|
||||||
class="option"
|
colSpan="2"
|
||||||
@tap="openURL($event, 'https://mastodon.social/@vishnuraghavb')"
|
@tap="openURL('https://mastodon.social/@vishnuraghavb')"
|
||||||
>
|
/>
|
||||||
<Label class="bx" :text="icon.link" />
|
<Label col="0" class="bx" :text="icon.link" />
|
||||||
<Label text="Follow on Mastodon" />
|
<Label verticalAlignment="center" col="1" text="Follow on Mastodon" />
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Utils, Application } from "@nativescript/core"
|
import { Application, Utils } from "@nativescript/core"
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapActions, mapState } from "vuex"
|
||||||
export default {
|
export default {
|
||||||
props: ["highlight", "showDrawer", "title"],
|
props: ["showDrawer", "title"],
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["icon", "currentComponent"]),
|
...mapState(["icon", "currentComponent"]),
|
||||||
getVersion() {
|
getVersion() {
|
||||||
|
@ -98,16 +105,16 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["setCurrentComponentAction"]),
|
...mapActions(["setCurrentComponentAction"]),
|
||||||
initializePage() {
|
onPageLoad() {
|
||||||
this.setCurrentComponentAction("About")
|
this.setCurrentComponentAction("About")
|
||||||
},
|
},
|
||||||
|
// HELPERS
|
||||||
onScroll(args) {
|
onScroll(args) {
|
||||||
args.scrollY
|
args.scrollY
|
||||||
? (this.viewIsScrolled = true)
|
? (this.viewIsScrolled = true)
|
||||||
: (this.viewIsScrolled = false)
|
: (this.viewIsScrolled = false)
|
||||||
},
|
},
|
||||||
openURL(args, url) {
|
openURL(url) {
|
||||||
this.highlight(args)
|
|
||||||
Utils.openUrl(url)
|
Utils.openUrl(url)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<Page
|
<Page
|
||||||
@loaded="initialize"
|
@loaded="onPageLoad"
|
||||||
actionBarHidden="true"
|
actionBarHidden="true"
|
||||||
:androidStatusBarBackground="themeName == 'Light' ? '#fafafa' : '#212121'"
|
:androidStatusBarBackground="appTheme == 'Light' ? '#f1f3f5' : '#212529'"
|
||||||
>
|
>
|
||||||
<RadSideDrawer
|
<RadSideDrawer
|
||||||
ref="drawer"
|
ref="drawer"
|
||||||
|
@ -19,12 +19,16 @@
|
||||||
columns="auto, 24, *"
|
columns="auto, 24, *"
|
||||||
v-for="(item, index) in topmenu"
|
v-for="(item, index) in topmenu"
|
||||||
:key="index"
|
:key="index"
|
||||||
@tap="navigateTo(item.component, false, false)"
|
|
||||||
class="sd-item orkm"
|
class="sd-item orkm"
|
||||||
:class="{
|
:class="{
|
||||||
'selected-sd-item': currentComponent === item.component,
|
'selected-sd-item': currentComponent === item.component,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
<MDRipple
|
||||||
|
row="0"
|
||||||
|
colSpan="3"
|
||||||
|
@tap="navigateTo(item.component, false, false)"
|
||||||
|
/>
|
||||||
<Label col="0" row="0" class="bx" :text="icon[item.icon]" />
|
<Label col="0" row="0" class="bx" :text="icon[item.icon]" />
|
||||||
<Label col="2" row="0" :text="item.title" />
|
<Label col="2" row="0" :text="item.title" />
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
|
@ -35,17 +39,17 @@
|
||||||
columns="*, auto"
|
columns="*, auto"
|
||||||
v-if="categoriesWithRecipes.length"
|
v-if="categoriesWithRecipes.length"
|
||||||
>
|
>
|
||||||
<Label col="0" text="Categories" />
|
<Label verticalAlignment="center" col="0" text="Categories" />
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
@tap="toggleCatEdit"
|
@tap="toggleCatEdit"
|
||||||
col="2"
|
col="2"
|
||||||
:text="catEditMode ? 'DONE' : 'RENAME'"
|
:text="editCategory ? 'DONE' : 'RENAME'"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<ScrollView height="100%">
|
<ScrollView height="100%">
|
||||||
<StackLayout>
|
<StackLayout>
|
||||||
<GridLayout
|
<GridLayout
|
||||||
@tap="navigateTo(item, false, true)"
|
|
||||||
v-for="(item, index) in categoriesWithRecipes"
|
v-for="(item, index) in categoriesWithRecipes"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="sd-item orkm"
|
class="sd-item orkm"
|
||||||
|
@ -54,6 +58,11 @@
|
||||||
}"
|
}"
|
||||||
columns="auto, *, auto"
|
columns="auto, *, auto"
|
||||||
>
|
>
|
||||||
|
<MDRipple
|
||||||
|
row="0"
|
||||||
|
colSpan="3"
|
||||||
|
@tap="navigateTo(item, false, true)"
|
||||||
|
/>
|
||||||
<Label
|
<Label
|
||||||
col="0"
|
col="0"
|
||||||
class="bx"
|
class="bx"
|
||||||
|
@ -61,8 +70,9 @@
|
||||||
margin="0 24 0 0"
|
margin="0 24 0 0"
|
||||||
/>
|
/>
|
||||||
<Label col="1" :text="item" />
|
<Label col="1" :text="item" />
|
||||||
<Label
|
<MDButton
|
||||||
v-if="catEditMode"
|
variant="text"
|
||||||
|
v-if="editCategory"
|
||||||
@tap="renameCategory(item)"
|
@tap="renameCategory(item)"
|
||||||
col="2"
|
col="2"
|
||||||
class="bx"
|
class="bx"
|
||||||
|
@ -74,30 +84,25 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout row="1">
|
<StackLayout row="1">
|
||||||
<StackLayout class="hr m-10"></StackLayout>
|
<StackLayout class="hr m-10"></StackLayout>
|
||||||
<!-- <StackLayout
|
<GridLayout
|
||||||
orientation="horizontal"
|
|
||||||
class="sd-item orkm"
|
|
||||||
@tap="donate"
|
|
||||||
>
|
|
||||||
<Label class="bx" :text="icon.donate" margin="0 24 0 0" />
|
|
||||||
<Label text="Donate" />
|
|
||||||
</StackLayout> -->
|
|
||||||
<StackLayout
|
|
||||||
@tap="navigateTo(item.component, true, false)"
|
|
||||||
v-for="(item, index) in bottommenu"
|
|
||||||
:key="index"
|
|
||||||
orientation="horizontal"
|
|
||||||
class="sd-item orkm"
|
class="sd-item orkm"
|
||||||
:class="{
|
:class="{
|
||||||
'selected-sd-item': currentComponent == item.title,
|
'selected-sd-item': currentComponent == item.title,
|
||||||
}"
|
}"
|
||||||
|
v-for="(item, index) in bottommenu"
|
||||||
|
:key="index"
|
||||||
|
rows="48"
|
||||||
|
columns="auto, 24, *"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon[item.icon]" margin="0 24 0 0" />
|
<MDRipple
|
||||||
<Label :text="item.title" />
|
colSpan="3"
|
||||||
</StackLayout>
|
@tap="navigateTo(item.component, true, false)"
|
||||||
|
/>
|
||||||
|
<Label class="bx" col="0" :text="icon[item.icon]" />
|
||||||
|
<Label col="2" :text="item.title" />
|
||||||
|
</GridLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
|
|
||||||
<GridLayout ~mainContent rows="*" columns="*">
|
<GridLayout ~mainContent rows="*" columns="*">
|
||||||
<Frame row="0" col="0" ref="mainFrame" id="main-frame">
|
<Frame row="0" col="0" ref="mainFrame" id="main-frame">
|
||||||
<!-- Home -->
|
<!-- Home -->
|
||||||
|
@ -119,29 +124,28 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
Utils,
|
|
||||||
ApplicationSettings,
|
ApplicationSettings,
|
||||||
AndroidApplication,
|
AndroidApplication,
|
||||||
|
ApplicationEventData,
|
||||||
Application,
|
Application,
|
||||||
|
Color,
|
||||||
|
Utils,
|
||||||
} from "@nativescript/core"
|
} from "@nativescript/core"
|
||||||
|
|
||||||
import Theme from "@nativescript/theme"
|
import Theme from "@nativescript/theme"
|
||||||
import * as Toast from "nativescript-toast"
|
import * as Toast from "nativescript-toast"
|
||||||
import * as application from "tns-core-modules/application"
|
import * as application from "tns-core-modules/application"
|
||||||
|
import { mapActions, mapState } from "vuex"
|
||||||
|
|
||||||
import EnRecipes from "./EnRecipes.vue"
|
import EnRecipes from "./EnRecipes.vue"
|
||||||
import Settings from "./Settings.vue"
|
import Settings from "./Settings.vue"
|
||||||
import About from "./About.vue"
|
import About from "./About.vue"
|
||||||
import PromptDialog from "./modal/PromptDialog.vue"
|
|
||||||
import { mapState, mapActions } from "vuex"
|
|
||||||
|
|
||||||
let page
|
import PromptDialog from "./modal/PromptDialog.vue"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
EnRecipes,
|
EnRecipes,
|
||||||
Settings,
|
|
||||||
About,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedCategory: null,
|
selectedCategory: null,
|
||||||
|
@ -176,8 +180,8 @@ export default {
|
||||||
icon: "info",
|
icon: "info",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
catEditMode: false,
|
editCategory: false,
|
||||||
themeName: "Light",
|
appTheme: "Light",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -203,16 +207,19 @@ export default {
|
||||||
"initializeYieldUnits",
|
"initializeYieldUnits",
|
||||||
"renameCategoryAction",
|
"renameCategoryAction",
|
||||||
]),
|
]),
|
||||||
initialize() {
|
onPageLoad() {
|
||||||
if (this.themeName === "Light") {
|
if (this.appTheme === "Light") {
|
||||||
const View = android.view.View
|
const View = android.view.View
|
||||||
const window = Application.android.startActivity.getWindow()
|
const window = Application.android.startActivity.getWindow()
|
||||||
const decorView = window.getDecorView()
|
const decorView = window.getDecorView()
|
||||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
|
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
|
||||||
|
// window.setNavigationBarColor(new Color("#e0e0e0").android)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HELPERS
|
||||||
toggleCatEdit() {
|
toggleCatEdit() {
|
||||||
this.catEditMode = !this.catEditMode
|
this.editCategory = !this.editCategory
|
||||||
if (this.selectedCategory) this.setComponent("EnRecipes")
|
if (this.selectedCategory) this.setComponent("EnRecipes")
|
||||||
this.filterFavorites = this.filterTrylater = false
|
this.filterFavorites = this.filterTrylater = false
|
||||||
this.selectedCategory = null
|
this.selectedCategory = null
|
||||||
|
@ -226,99 +233,22 @@ export default {
|
||||||
this.$showModal(PromptDialog, {
|
this.$showModal(PromptDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: `Rename category`,
|
title: `Rename category`,
|
||||||
hint: category,
|
text: category,
|
||||||
action: "RENAME",
|
action: "RENAME",
|
||||||
},
|
},
|
||||||
}).then((newCategory) => {
|
}).then((newCategory) => {
|
||||||
this.hijackGlobalBackEvent()
|
this.hijackGlobalBackEvent()
|
||||||
if (newCategory.length) {
|
if (newCategory.length) {
|
||||||
this.renameCategoryAction({ current: category, updated: newCategory })
|
this.renameCategoryAction({ current: category, updated: newCategory })
|
||||||
this.catEditMode = false
|
this.editCategory = false
|
||||||
this.navigateTo(newCategory, false, true)
|
this.navigateTo(newCategory, false, true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
highlight(args) {
|
|
||||||
let temp = args.object.className
|
|
||||||
args.object.className = `${temp} option-highlight`
|
|
||||||
setTimeout(() => (args.object.className = temp), 100)
|
|
||||||
},
|
|
||||||
// Navigation
|
|
||||||
setSelectedCategory(e) {
|
setSelectedCategory(e) {
|
||||||
this.selectedCategory = e.item
|
this.selectedCategory = e.item
|
||||||
this.closeDrawer()
|
this.closeDrawer()
|
||||||
},
|
},
|
||||||
hijackGlobalBackEvent() {
|
|
||||||
AndroidApplication.on(
|
|
||||||
AndroidApplication.activityBackPressedEvent,
|
|
||||||
this.globalBackEvent
|
|
||||||
)
|
|
||||||
},
|
|
||||||
releaseGlobalBackEvent() {
|
|
||||||
AndroidApplication.off(
|
|
||||||
AndroidApplication.activityBackPressedEvent,
|
|
||||||
this.globalBackEvent
|
|
||||||
)
|
|
||||||
},
|
|
||||||
globalBackEvent(args) {
|
|
||||||
function preventDefault() {
|
|
||||||
args.cancel = true
|
|
||||||
}
|
|
||||||
let vm = this
|
|
||||||
function isFiltered() {
|
|
||||||
vm.filterFavorites
|
|
||||||
? vm.setComponent("Favorites")
|
|
||||||
: vm.filterTrylater
|
|
||||||
? vm.setComponent("Try later")
|
|
||||||
: vm.selectedCategory
|
|
||||||
? vm.setComponent(vm.selectedCategory)
|
|
||||||
: vm.setComponent("EnRecipes")
|
|
||||||
}
|
|
||||||
if (this.$refs.drawer && this.$refs.drawer.nativeView.getIsOpen()) {
|
|
||||||
preventDefault()
|
|
||||||
this.closeDrawer()
|
|
||||||
this.catEditMode = false
|
|
||||||
} else if (
|
|
||||||
["Favorites", "Try later", this.selectedCategory].includes(
|
|
||||||
this.currentComponent
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
preventDefault()
|
|
||||||
this.setComponent("EnRecipes")
|
|
||||||
this.filterFavorites = this.filterTrylater = false
|
|
||||||
this.selectedCategory = null
|
|
||||||
this.$refs.enrecipes.updateFilter()
|
|
||||||
this.releaseGlobalBackEvent()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
navigateTo(to, isTrueComponent, isCategory) {
|
|
||||||
if (isTrueComponent) {
|
|
||||||
this.$navigateTo(to, {
|
|
||||||
frame: "main-frame",
|
|
||||||
props: {
|
|
||||||
highlight: this.highlight,
|
|
||||||
showDrawer: this.showDrawer,
|
|
||||||
restartApp: this.restartApp,
|
|
||||||
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
|
||||||
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
|
||||||
openAppSettingsPage: this.openAppSettingsPage,
|
|
||||||
},
|
|
||||||
backstackVisible: false,
|
|
||||||
})
|
|
||||||
this.closeDrawer()
|
|
||||||
} else if (!this.catEditMode || !isCategory) {
|
|
||||||
this.releaseGlobalBackEvent()
|
|
||||||
this.hijackGlobalBackEvent()
|
|
||||||
this.setComponent(to)
|
|
||||||
this.$navigateBack({ frame: "main-frame", backstackVisible: false })
|
|
||||||
this.filterFavorites = to === "Favorites" ? true : false
|
|
||||||
this.filterTrylater = to === "Try later" ? true : false
|
|
||||||
this.selectedCategory = isCategory ? to : null
|
|
||||||
this.$refs.enrecipes.updateFilter()
|
|
||||||
this.closeDrawer()
|
|
||||||
}
|
|
||||||
this.catEditMode = false
|
|
||||||
},
|
|
||||||
restartApp() {
|
restartApp() {
|
||||||
// Code from nativescript-master-technology
|
// Code from nativescript-master-technology
|
||||||
const mStartActivity = new android.content.Intent(
|
const mStartActivity = new android.content.Intent(
|
||||||
|
@ -360,19 +290,91 @@ export default {
|
||||||
closeDrawer() {
|
closeDrawer() {
|
||||||
this.$refs.drawer.nativeView.closeDrawer()
|
this.$refs.drawer.nativeView.closeDrawer()
|
||||||
},
|
},
|
||||||
donate(args) {
|
|
||||||
this.highlight(args)
|
// NAVIGATION HANDLERS
|
||||||
|
hijackGlobalBackEvent() {
|
||||||
|
AndroidApplication.on(
|
||||||
|
AndroidApplication.activityBackPressedEvent,
|
||||||
|
this.globalBackEvent
|
||||||
|
)
|
||||||
|
},
|
||||||
|
releaseGlobalBackEvent() {
|
||||||
|
AndroidApplication.off(
|
||||||
|
AndroidApplication.activityBackPressedEvent,
|
||||||
|
this.globalBackEvent
|
||||||
|
)
|
||||||
|
},
|
||||||
|
globalBackEvent(args) {
|
||||||
|
function preventDefault() {
|
||||||
|
args.cancel = true
|
||||||
|
}
|
||||||
|
let vm = this
|
||||||
|
function isFiltered() {
|
||||||
|
vm.filterFavorites
|
||||||
|
? vm.setComponent("Favorites")
|
||||||
|
: vm.filterTrylater
|
||||||
|
? vm.setComponent("Try later")
|
||||||
|
: vm.selectedCategory
|
||||||
|
? vm.setComponent(vm.selectedCategory)
|
||||||
|
: vm.setComponent("EnRecipes")
|
||||||
|
}
|
||||||
|
if (this.$refs.drawer && this.$refs.drawer.nativeView.getIsOpen()) {
|
||||||
|
preventDefault()
|
||||||
|
this.closeDrawer()
|
||||||
|
this.editCategory = false
|
||||||
|
} else if (
|
||||||
|
["Favorites", "Try later", this.selectedCategory].includes(
|
||||||
|
this.currentComponent
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
preventDefault()
|
||||||
|
this.setComponent("EnRecipes")
|
||||||
|
this.filterFavorites = this.filterTrylater = false
|
||||||
|
this.selectedCategory = null
|
||||||
|
this.$refs.enrecipes.updateFilter()
|
||||||
|
this.releaseGlobalBackEvent()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigateTo(to, isTrueComponent, isCategory) {
|
||||||
|
if (isTrueComponent) {
|
||||||
|
this.$navigateTo(to, {
|
||||||
|
frame: "main-frame",
|
||||||
|
props: {
|
||||||
|
showDrawer: this.showDrawer,
|
||||||
|
restartApp: this.restartApp,
|
||||||
|
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
||||||
|
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
||||||
|
openAppSettingsPage: this.openAppSettingsPage,
|
||||||
|
},
|
||||||
|
backstackVisible: false,
|
||||||
|
})
|
||||||
|
this.closeDrawer()
|
||||||
|
} else if (!this.editCategory || !isCategory) {
|
||||||
|
this.releaseGlobalBackEvent()
|
||||||
|
this.hijackGlobalBackEvent()
|
||||||
|
this.setComponent(to)
|
||||||
|
this.$navigateBack({ frame: "main-frame", backstackVisible: false })
|
||||||
|
this.filterFavorites = to === "Favorites" ? true : false
|
||||||
|
this.filterTrylater = to === "Try later" ? true : false
|
||||||
|
this.selectedCategory = isCategory ? to : null
|
||||||
|
this.$refs.enrecipes.updateFilter()
|
||||||
|
this.closeDrawer()
|
||||||
|
}
|
||||||
|
this.editCategory = false
|
||||||
|
},
|
||||||
|
|
||||||
|
donate() {
|
||||||
Utils.openUrl("https://www.vishnuraghav.com/donate/")
|
Utils.openUrl("https://www.vishnuraghav.com/donate/")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.themeName = ApplicationSettings.getString("appTheme", "Light")
|
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
|
||||||
setTimeout((e) => {
|
setTimeout((e) => {
|
||||||
Theme.setMode(Theme[this.themeName])
|
Theme.setMode(Theme[this.appTheme])
|
||||||
}, 50)
|
}, 50)
|
||||||
if (!this.recipes.length) this.initializeRecipes()
|
this.initializeRecipes()
|
||||||
if (!this.categories.length) this.initializeCategories()
|
this.initializeCategories()
|
||||||
if (!this.yieldUnits.length) this.initializeYieldUnits()
|
this.initializeYieldUnits()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<Page @loaded="initialize" @unloaded="releaseBackEvent">
|
<Page @loaded="onPageLoad" @unloaded="releaseBackEvent">
|
||||||
<ActionBar :flat="viewIsScrolled ? false : true">
|
<ActionBar :flat="viewIsScrolled ? false : true">
|
||||||
<GridLayout rows="*" columns="auto, *, auto">
|
<GridLayout rows="*" columns="auto, *, auto">
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.back"
|
:text="icon.back"
|
||||||
automationText="Back"
|
automationText="Back"
|
||||||
|
@ -10,14 +11,15 @@
|
||||||
@tap="navigateBack"
|
@tap="navigateBack"
|
||||||
/>
|
/>
|
||||||
<Label class="title orkm" :text="title" col="1" />
|
<Label class="title orkm" :text="title" col="1" />
|
||||||
<Label
|
<MDButton
|
||||||
v-if="hasEnoughDetails && !imageLoading"
|
variant="text"
|
||||||
|
v-if="hasChanges && !imageLoading"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.save"
|
:text="icon.save"
|
||||||
col="2"
|
col="2"
|
||||||
@tap="saveOperation"
|
@tap="saveOperation"
|
||||||
/>
|
/>
|
||||||
<ActivityIndicator col="2" v-if="imageLoading" :busy="imageLoading" />
|
<MDActivityIndicator col="2" v-if="imageLoading" :busy="imageLoading" />
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
<GridLayout rows="*" columns="*">
|
<GridLayout rows="*" columns="*">
|
||||||
|
@ -51,18 +53,16 @@
|
||||||
:text="icon.image"
|
:text="icon.image"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout width="100%" :top="screenWidth - 42">
|
|
||||||
<transition :name="recipeContent.imageSrc ? 'null' : 'bounce'">
|
<transition :name="recipeContent.imageSrc ? 'null' : 'bounce'">
|
||||||
<Label
|
<MDFloatingActionButton
|
||||||
v-if="showFab"
|
v-if="showFab"
|
||||||
horizontalAlignment="right"
|
:top="screenWidth - 44"
|
||||||
|
:left="screenWidth - 88"
|
||||||
|
class="bx"
|
||||||
|
src="res://camera"
|
||||||
@tap="imageHandler"
|
@tap="imageHandler"
|
||||||
class="bx fab-button"
|
|
||||||
:text="icon.camera"
|
|
||||||
androidElevation="6"
|
|
||||||
/>
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
</StackLayout>
|
|
||||||
</AbsoluteLayout>
|
</AbsoluteLayout>
|
||||||
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
|
@ -71,6 +71,7 @@
|
||||||
hint="My Healthy Recipe"
|
hint="My Healthy Recipe"
|
||||||
v-model="recipeContent.title"
|
v-model="recipeContent.title"
|
||||||
autocapitalizationType="words"
|
autocapitalizationType="words"
|
||||||
|
autocorrect="true"
|
||||||
/>
|
/>
|
||||||
<Label top="0" class="fieldLabel" text="Title" />
|
<Label top="0" class="fieldLabel" text="Title" />
|
||||||
</AbsoluteLayout>
|
</AbsoluteLayout>
|
||||||
|
@ -103,7 +104,7 @@
|
||||||
<GridLayout columns="*, 8, *">
|
<GridLayout columns="*, 8, *">
|
||||||
<AbsoluteLayout class="inputField" col="0">
|
<AbsoluteLayout class="inputField" col="0">
|
||||||
<TextField
|
<TextField
|
||||||
:text="formattedTimeRequired"
|
:text="timeRequired"
|
||||||
editable="false"
|
editable="false"
|
||||||
@tap="setTimeRequired"
|
@tap="setTimeRequired"
|
||||||
/>
|
/>
|
||||||
|
@ -127,30 +128,33 @@
|
||||||
v-model="recipeContent.ingredients[index].item"
|
v-model="recipeContent.ingredients[index].item"
|
||||||
:hint="`Item ${index + 1}`"
|
:hint="`Item ${index + 1}`"
|
||||||
autocapitalizationType="words"
|
autocapitalizationType="words"
|
||||||
|
autocorrect="true"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
width="72"
|
width="68"
|
||||||
col="2"
|
col="2"
|
||||||
v-model="recipeContent.ingredients[index].quantity"
|
v-model="recipeContent.ingredients[index].quantity"
|
||||||
hint="1.000"
|
hint="1.00"
|
||||||
keyboardType="number"
|
keyboardType="number"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
width="64"
|
width="68"
|
||||||
col="4"
|
col="4"
|
||||||
v-model="recipeContent.ingredients[index].unit"
|
v-model="recipeContent.ingredients[index].unit"
|
||||||
hint="Unit"
|
hint="Unit"
|
||||||
editable="false"
|
editable="false"
|
||||||
@tap="showUnits($event)"
|
@tap="showUnits($event)"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
col="6"
|
col="6"
|
||||||
class="bx closeBtn"
|
class="bx closeBtn"
|
||||||
:text="icon.close"
|
:text="icon.close"
|
||||||
@tap="removeIngredient(index)"
|
@tap="removeIngredient(index)"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
class="text-btn orkm"
|
class="text-btn orkm"
|
||||||
text="+ ADD INGREDIENT"
|
text="+ ADD INGREDIENT"
|
||||||
@tap="addIngredient()"
|
@tap="addIngredient()"
|
||||||
|
@ -172,15 +176,18 @@
|
||||||
:hint="`Step ${index + 1}`"
|
:hint="`Step ${index + 1}`"
|
||||||
v-model="recipeContent.instructions[index]"
|
v-model="recipeContent.instructions[index]"
|
||||||
editable="true"
|
editable="true"
|
||||||
|
autocorrect="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
col="2"
|
col="2"
|
||||||
class="bx closeBtn"
|
class="bx closeBtn"
|
||||||
:text="icon.close"
|
:text="icon.close"
|
||||||
@tap="removeInstruction(index)"
|
@tap="removeInstruction(index)"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
class="text-btn orkm"
|
class="text-btn orkm"
|
||||||
text="+ ADD STEP"
|
text="+ ADD STEP"
|
||||||
@tap="addInstruction()"
|
@tap="addInstruction()"
|
||||||
|
@ -201,15 +208,22 @@
|
||||||
v-model="recipeContent.notes[index]"
|
v-model="recipeContent.notes[index]"
|
||||||
:hint="`Note ${index + 1}`"
|
:hint="`Note ${index + 1}`"
|
||||||
editable="true"
|
editable="true"
|
||||||
|
autocorrect="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
col="2"
|
col="2"
|
||||||
class="bx closeBtn"
|
class="bx closeBtn"
|
||||||
:text="icon.close"
|
:text="icon.close"
|
||||||
@tap="removeNote(index)"
|
@tap="removeNote(index)"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label class="text-btn orkm" text="+ ADD NOTE" @tap="addNote()" />
|
<MDButton
|
||||||
|
variant="text"
|
||||||
|
class="text-btn orkm"
|
||||||
|
text="+ ADD NOTE"
|
||||||
|
@tap="addNote()"
|
||||||
|
/>
|
||||||
<StackLayout class="hr" margin="24 16"></StackLayout>
|
<StackLayout class="hr" margin="24 16"></StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
|
@ -226,15 +240,18 @@
|
||||||
v-model="recipeContent.references[index]"
|
v-model="recipeContent.references[index]"
|
||||||
hint="Text or Website/Video URL"
|
hint="Text or Website/Video URL"
|
||||||
editable="true"
|
editable="true"
|
||||||
|
autocorrect="true"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
col="2"
|
col="2"
|
||||||
class="bx closeBtn"
|
class="bx closeBtn"
|
||||||
:text="icon.close"
|
:text="icon.close"
|
||||||
@tap="removeReference(index)"
|
@tap="removeReference(index)"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
class="text-btn orkm"
|
class="text-btn orkm"
|
||||||
text="+ ADD REFERENCE"
|
text="+ ADD REFERENCE"
|
||||||
@tap="addReference()"
|
@tap="addReference()"
|
||||||
|
@ -248,31 +265,30 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { WorkerService } from "../worker.service"
|
// import { WorkerService } from "../worker.service"
|
||||||
const workerService = new WorkerService()
|
// const workerService = new WorkerService()
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Screen,
|
|
||||||
AndroidApplication,
|
AndroidApplication,
|
||||||
ImageSource,
|
Application,
|
||||||
path,
|
|
||||||
getFileAccess,
|
|
||||||
knownFolders,
|
|
||||||
Utils,
|
|
||||||
File,
|
|
||||||
ApplicationSettings,
|
ApplicationSettings,
|
||||||
|
File,
|
||||||
|
getFileAccess,
|
||||||
|
ImageSource,
|
||||||
|
knownFolders,
|
||||||
|
path,
|
||||||
|
Screen,
|
||||||
|
Utils,
|
||||||
} from "@nativescript/core"
|
} from "@nativescript/core"
|
||||||
|
import * as Permissions from "@nativescript-community/perms"
|
||||||
import { Mediafilepicker } from "nativescript-mediafilepicker"
|
import * as Toast from "nativescript-toast"
|
||||||
|
import * as ImagePicker from "@nativescript/imagepicker"
|
||||||
|
import { ImageCropper } from "nativescript-imagecropper"
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapState, mapActions } from "vuex"
|
||||||
|
|
||||||
import ActionDialog from "./modal/ActionDialog.vue"
|
import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
||||||
import PromptDialog from "./modal/PromptDialog.vue"
|
import PromptDialog from "./modal/PromptDialog.vue"
|
||||||
import ListPicker from "./modal/ListPicker.vue"
|
import ListPicker from "./modal/ListPicker.vue"
|
||||||
import * as Permissions from "@nativescript-community/perms"
|
|
||||||
import * as Toast from "nativescript-toast"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
@ -310,6 +326,7 @@ export default {
|
||||||
newRecipeID: null,
|
newRecipeID: null,
|
||||||
showFab: false,
|
showFab: false,
|
||||||
imageLoading: false,
|
imageLoading: false,
|
||||||
|
cacheImagePath: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -324,13 +341,16 @@ export default {
|
||||||
screenWidth() {
|
screenWidth() {
|
||||||
return Screen.mainScreen.widthDIPs
|
return Screen.mainScreen.widthDIPs
|
||||||
},
|
},
|
||||||
hasEnoughDetails() {
|
appTheme() {
|
||||||
|
return Application.systemAppearance()
|
||||||
|
},
|
||||||
|
hasChanges() {
|
||||||
return (
|
return (
|
||||||
JSON.stringify(this.recipeContent) !==
|
JSON.stringify(this.recipeContent) !==
|
||||||
JSON.stringify(this.tempRecipeContent)
|
JSON.stringify(this.tempRecipeContent)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
formattedTimeRequired() {
|
timeRequired() {
|
||||||
let t = this.recipeContent.timeRequired.split(":")
|
let t = this.recipeContent.timeRequired.split(":")
|
||||||
let h = parseInt(t[0])
|
let h = parseInt(t[0])
|
||||||
let m = parseInt(t[1])
|
let m = parseInt(t[1])
|
||||||
|
@ -345,7 +365,7 @@ export default {
|
||||||
"addCategoryAction",
|
"addCategoryAction",
|
||||||
"addYieldUnitAction",
|
"addYieldUnitAction",
|
||||||
]),
|
]),
|
||||||
initialize() {
|
onPageLoad() {
|
||||||
this.showFab = true
|
this.showFab = true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -394,11 +414,11 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
title: "Category",
|
title: "Category",
|
||||||
list: [...this.categories],
|
list: [...this.categories],
|
||||||
height: "408",
|
// height: "420",
|
||||||
action: "CREATE NEW",
|
action: "ADD NEW",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
if (action == "CREATE NEW") {
|
if (action == "ADD NEW") {
|
||||||
this.$showModal(PromptDialog, {
|
this.$showModal(PromptDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "New category",
|
title: "New category",
|
||||||
|
@ -425,11 +445,11 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
title: "Yield measured in",
|
title: "Yield measured in",
|
||||||
list: [...this.yieldUnits],
|
list: [...this.yieldUnits],
|
||||||
height: "408",
|
// height: "420",
|
||||||
action: "CREATE NEW",
|
action: "ADD NEW",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
if (action == "CREATE NEW") {
|
if (action == "ADD NEW") {
|
||||||
this.$showModal(PromptDialog, {
|
this.$showModal(PromptDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "New yield unit",
|
title: "New yield unit",
|
||||||
|
@ -456,7 +476,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
title: "Unit",
|
title: "Unit",
|
||||||
list: [...this.units],
|
list: [...this.units],
|
||||||
height: "408",
|
// height: "420",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
this.hijackBackEvent()
|
this.hijackBackEvent()
|
||||||
|
@ -466,21 +486,19 @@ export default {
|
||||||
|
|
||||||
// NAVIGATION HANDLERS
|
// NAVIGATION HANDLERS
|
||||||
navigateBack() {
|
navigateBack() {
|
||||||
if (this.hasEnoughDetails) {
|
if (this.hasChanges) {
|
||||||
this.blockModal = true
|
this.blockModal = true
|
||||||
this.$showModal(ConfirmDialog, {
|
this.$showModal(ConfirmDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "Unsaved changes",
|
title: "Unsaved changes",
|
||||||
description:
|
description:
|
||||||
"Do you want to save the changes you made in this recipe?",
|
"Are you sure you want to discard unsaved changes to this recipe?",
|
||||||
cancelButtonText: "DISCARD",
|
cancelButtonText: "DISCARD",
|
||||||
okButtonText: "SAVE",
|
okButtonText: "KEEP EDITING",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
this.blockModal = false
|
this.blockModal = false
|
||||||
if (action) {
|
if (action != null && !action) {
|
||||||
this.saveOperation()
|
|
||||||
} else if (action != null) {
|
|
||||||
this.$navigateBack()
|
this.$navigateBack()
|
||||||
this.releaseBackEvent()
|
this.releaseBackEvent()
|
||||||
}
|
}
|
||||||
|
@ -503,7 +521,7 @@ export default {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
backEvent(args) {
|
backEvent(args) {
|
||||||
if (this.hasEnoughDetails && !this.blockModal) {
|
if (this.hasChanges && !this.blockModal) {
|
||||||
args.cancel = true
|
args.cancel = true
|
||||||
this.navigateBack()
|
this.navigateBack()
|
||||||
}
|
}
|
||||||
|
@ -522,28 +540,22 @@ export default {
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
this.blockModal = false
|
this.blockModal = false
|
||||||
if (action) {
|
if (action) {
|
||||||
this.permissionCheck(
|
this.permissionCheck(this.permissionConfirmation, this.imagePicker)
|
||||||
this.imagePickerPermissionConfirmation,
|
|
||||||
this.imagePicker
|
|
||||||
)
|
|
||||||
} else if (action != null) {
|
} else if (action != null) {
|
||||||
this.recipeContent.imageSrc = null
|
this.recipeContent.imageSrc = null
|
||||||
this.releaseBackEvent()
|
this.releaseBackEvent()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.permissionCheck(
|
this.permissionCheck(this.permissionConfirmation, this.imagePicker)
|
||||||
this.imagePickerPermissionConfirmation,
|
|
||||||
this.imagePicker
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imagePickerPermissionConfirmation() {
|
permissionConfirmation() {
|
||||||
return this.$showModal(ConfirmDialog, {
|
return this.$showModal(ConfirmDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "Grant permission",
|
title: "Grant permission",
|
||||||
description:
|
description:
|
||||||
"EnRecipes requires storage and camera permission in order to set recipe photo.",
|
"EnRecipes requires storage permission in order to set recipe photo.",
|
||||||
cancelButtonText: "NOT NOW",
|
cancelButtonText: "NOT NOW",
|
||||||
okButtonText: "CONTINUE",
|
okButtonText: "CONTINUE",
|
||||||
},
|
},
|
||||||
|
@ -553,52 +565,82 @@ export default {
|
||||||
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
||||||
confirmation().then((e) => {
|
confirmation().then((e) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
Permissions.request("camera").then((res) => {
|
Permissions.request("photo").then((status) => {
|
||||||
let status = res[Object.keys(res)[0]]
|
switch (status[0]) {
|
||||||
if (status === "authorized") action()
|
case "authorized":
|
||||||
if (status === "never_ask_again")
|
action()
|
||||||
|
break
|
||||||
|
case "never_ask_again":
|
||||||
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
||||||
if (status === "denied")
|
break
|
||||||
|
case "denied":
|
||||||
Toast.makeText("Permission denied").show()
|
Toast.makeText("Permission denied").show()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Permissions.check("camera").then((res) => {
|
Permissions.check("photo").then((res) => {
|
||||||
if (res[0] !== "authorized") {
|
res[0] !== "authorized"
|
||||||
confirmation().then((e) => {
|
? confirmation().then((e) => e && this.openAppSettingsPage())
|
||||||
e && this.openAppSettingsPage()
|
: action()
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Permissions.request("storage").then((res) => {
|
|
||||||
let status = res[Object.keys(res)[0]]
|
|
||||||
if (status !== "authorized") {
|
|
||||||
confirmation().then((e) => {
|
|
||||||
e && this.openAppSettingsPage()
|
|
||||||
})
|
|
||||||
} else action()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imagePicker() {
|
imagePicker() {
|
||||||
const vm = this
|
|
||||||
const mediafilepicker = new Mediafilepicker()
|
|
||||||
mediafilepicker.openImagePicker({
|
|
||||||
android: {
|
|
||||||
isCaptureMood: false, // if true then camera will open directly.
|
|
||||||
isNeedCamera: true,
|
|
||||||
maxNumberFiles: 1,
|
|
||||||
isNeedFolderList: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
mediafilepicker.on("getFiles", (image) => {
|
|
||||||
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
||||||
vm.recipeContent.imageSrc = image.object.get("results")[0].file
|
this.cacheImagePath = path.join(
|
||||||
|
knownFolders.temp().path,
|
||||||
|
`${this.getRandomID()}.jpg`
|
||||||
|
)
|
||||||
|
let screenWidth = Math.round(this.screenWidth * 2)
|
||||||
|
ImagePicker.create({
|
||||||
|
mode: "single",
|
||||||
|
mediaType: ImagePicker.ImagePickerMediaType.Image,
|
||||||
|
})
|
||||||
|
.present()
|
||||||
|
.then((selection) => {
|
||||||
|
let imgPath = selection[0]._android
|
||||||
|
ImageSource.fromFile(imgPath).then((image) => {
|
||||||
|
ImageCropper.prototype
|
||||||
|
.show(
|
||||||
|
image,
|
||||||
|
{
|
||||||
|
width: screenWidth,
|
||||||
|
height: screenWidth,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hideBottomControls: true,
|
||||||
|
toolbarTitle: "Crop photo",
|
||||||
|
statusBarColor: "#ff5200",
|
||||||
|
toolbarTextColor:
|
||||||
|
this.appTheme == "light" ? "#212529" : "#f1f3f5",
|
||||||
|
toolbarColor:
|
||||||
|
this.appTheme == "light" ? "#f1f3f5" : "#212529",
|
||||||
|
cropFrameColor: "#ff5200",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then((cropped) => {
|
||||||
|
cropped.image.saveToFile(this.cacheImagePath, "jpg", 75)
|
||||||
|
this.recipeContent.imageSrc = this.cacheImagePath
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// INPUT FIELD HANDLERS
|
||||||
|
fieldDeletionConfirm(item) {
|
||||||
|
return this.$showModal(ConfirmDialog, {
|
||||||
|
props: {
|
||||||
|
title: `Delete ${item}?`,
|
||||||
|
cancelButtonText: "CANCEL",
|
||||||
|
okButtonText: "DELETE",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
addIngredient() {
|
addIngredient() {
|
||||||
this.recipeContent.ingredients.push({
|
this.recipeContent.ingredients.push({
|
||||||
item: "",
|
item: "",
|
||||||
|
@ -607,30 +649,55 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeIngredient(index) {
|
removeIngredient(index) {
|
||||||
|
if (this.recipeContent.ingredients[index].item.length) {
|
||||||
|
this.fieldDeletionConfirm("ingredient").then((res) => {
|
||||||
|
if (res) {
|
||||||
this.recipeContent.ingredients.splice(index, 1)
|
this.recipeContent.ingredients.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else this.recipeContent.ingredients.splice(index, 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
addInstruction() {
|
addInstruction() {
|
||||||
this.recipeContent.instructions.push("")
|
this.recipeContent.instructions.push("")
|
||||||
},
|
},
|
||||||
removeInstruction(index) {
|
removeInstruction(index) {
|
||||||
|
if (this.recipeContent.instructions[index].length) {
|
||||||
|
this.fieldDeletionConfirm("instruction").then((res) => {
|
||||||
|
if (res) {
|
||||||
this.recipeContent.instructions.splice(index, 1)
|
this.recipeContent.instructions.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else this.recipeContent.instructions.splice(index, 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
addNote() {
|
addNote() {
|
||||||
this.recipeContent.notes.push("")
|
this.recipeContent.notes.push("")
|
||||||
},
|
},
|
||||||
removeNote(index) {
|
removeNote(index) {
|
||||||
|
if (this.recipeContent.notes[index].length) {
|
||||||
|
this.fieldDeletionConfirm("note").then((res) => {
|
||||||
|
if (res) {
|
||||||
this.recipeContent.notes.splice(index, 1)
|
this.recipeContent.notes.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else this.recipeContent.notes.splice(index, 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
addReference() {
|
addReference() {
|
||||||
this.recipeContent.references.push("")
|
this.recipeContent.references.push("")
|
||||||
},
|
},
|
||||||
removeReference(index) {
|
removeReference(index) {
|
||||||
|
if (this.recipeContent.references[index].length) {
|
||||||
|
this.fieldDeletionConfirm("reference").then((res) => {
|
||||||
|
if (res) {
|
||||||
this.recipeContent.references.splice(index, 1)
|
this.recipeContent.references.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else this.recipeContent.references.splice(index, 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// SAVE OPERATION
|
||||||
clearEmptyFields() {
|
clearEmptyFields() {
|
||||||
if (!this.recipeContent.title)
|
if (!this.recipeContent.title)
|
||||||
this.recipeContent.title = "Untitled Recipe"
|
this.recipeContent.title = "Untitled Recipe"
|
||||||
|
@ -651,37 +718,50 @@ export default {
|
||||||
this.imageLoading = true
|
this.imageLoading = true
|
||||||
this.clearEmptyFields()
|
this.clearEmptyFields()
|
||||||
this.recipeContent.lastModified = new Date()
|
this.recipeContent.lastModified = new Date()
|
||||||
if (this.recipeContent.imageSrc) {
|
if (this.cacheImagePath) {
|
||||||
if (this.tempRecipeContent.imageSrc) {
|
let recipeImage = path.join(
|
||||||
if (this.tempRecipeContent.imageSrc !== this.recipeContent.imageSrc) {
|
|
||||||
getFileAccess().deleteFile(this.tempRecipeContent.imageSrc)
|
|
||||||
this.imageSaveOperation()
|
|
||||||
} else this.saveRecipe()
|
|
||||||
} else this.imageSaveOperation()
|
|
||||||
} else if (this.tempRecipeContent.imageSrc) {
|
|
||||||
getFileAccess().deleteFile(this.tempRecipeContent.imageSrc)
|
|
||||||
this.saveRecipe()
|
|
||||||
} else this.saveRecipe()
|
|
||||||
},
|
|
||||||
imageSaveOperation() {
|
|
||||||
let imgSavedToPath = path.join(
|
|
||||||
knownFolders
|
knownFolders
|
||||||
.documents()
|
.documents()
|
||||||
.getFolder("EnRecipes")
|
.getFolder("EnRecipes")
|
||||||
.getFolder("Images").path,
|
.getFolder("Images").path,
|
||||||
`${this.getRandomID()}.jpg`
|
`${this.getRandomID()}.jpg`
|
||||||
)
|
)
|
||||||
let workerService = new WorkerService()
|
let binarySource = File.fromPath(this.cacheImagePath).readSync()
|
||||||
let ImageProcessor = workerService.initImageProcessor()
|
File.fromPath(recipeImage).writeSync(binarySource)
|
||||||
ImageProcessor.postMessage({
|
this.recipeContent.imageSrc = recipeImage
|
||||||
imgFile: this.recipeContent.imageSrc,
|
knownFolders.temp().clear()
|
||||||
imgSavedToPath,
|
|
||||||
})
|
|
||||||
ImageProcessor.onmessage = ({ data }) => {
|
|
||||||
this.recipeContent.imageSrc = imgSavedToPath
|
|
||||||
this.saveRecipe()
|
|
||||||
}
|
}
|
||||||
|
if (this.recipeContent.imageSrc) {
|
||||||
|
if (
|
||||||
|
this.tempRecipeContent.imageSrc &&
|
||||||
|
this.tempRecipeContent.imageSrc !== this.recipeContent.imageSrc
|
||||||
|
) {
|
||||||
|
getFileAccess().deleteFile(this.tempRecipeContent.imageSrc)
|
||||||
|
}
|
||||||
|
} else if (this.tempRecipeContent.imageSrc) {
|
||||||
|
getFileAccess().deleteFile(this.tempRecipeContent.imageSrc)
|
||||||
|
}
|
||||||
|
this.saveRecipe()
|
||||||
},
|
},
|
||||||
|
// imageSaveOperation() {
|
||||||
|
// let imgSavedToPath = path.join(
|
||||||
|
// knownFolders
|
||||||
|
// .documents()
|
||||||
|
// .getFolder("EnRecipes")
|
||||||
|
// .getFolder("Images").path,
|
||||||
|
// `${this.getRandomID()}.jpg`
|
||||||
|
// )
|
||||||
|
// let workerService = new WorkerService()
|
||||||
|
// let ImageProcessor = workerService.initImageProcessor()
|
||||||
|
// ImageProcessor.postMessage({
|
||||||
|
// imgFile: this.recipeContent.imageSrc,
|
||||||
|
// imgSavedToPath,
|
||||||
|
// })
|
||||||
|
// ImageProcessor.onmessage = ({ data }) => {
|
||||||
|
// this.recipeContent.imageSrc = imgSavedToPath
|
||||||
|
// this.saveRecipe()
|
||||||
|
// }
|
||||||
|
// },
|
||||||
saveRecipe() {
|
saveRecipe() {
|
||||||
if (this.recipeID) {
|
if (this.recipeID) {
|
||||||
this.overwriteRecipeAction({
|
this.overwriteRecipeAction({
|
||||||
|
@ -705,6 +785,7 @@ export default {
|
||||||
this.setCurrentComponentAction("EditRecipe")
|
this.setCurrentComponentAction("EditRecipe")
|
||||||
}, 500)
|
}, 500)
|
||||||
this.title = this.recipeID ? "Edit recipe" : "New recipe"
|
this.title = this.recipeID ? "Edit recipe" : "New recipe"
|
||||||
|
|
||||||
if (this.recipeID) {
|
if (this.recipeID) {
|
||||||
let recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
|
let recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
|
||||||
Object.assign(this.recipeContent, JSON.parse(JSON.stringify(recipe)))
|
Object.assign(this.recipeContent, JSON.parse(JSON.stringify(recipe)))
|
||||||
|
@ -713,13 +794,14 @@ export default {
|
||||||
JSON.parse(JSON.stringify(this.recipeContent))
|
JSON.parse(JSON.stringify(this.recipeContent))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
if (this.selectedCategory)
|
||||||
|
this.recipeContent.category = this.selectedCategory
|
||||||
|
if (this.filterFavorites) this.recipeContent.isFavorite = true
|
||||||
Object.assign(
|
Object.assign(
|
||||||
this.tempRecipeContent,
|
this.tempRecipeContent,
|
||||||
JSON.parse(JSON.stringify(this.recipeContent))
|
JSON.parse(JSON.stringify(this.recipeContent))
|
||||||
)
|
)
|
||||||
if (this.selectedCategory)
|
|
||||||
this.recipeContent.category = this.selectedCategory
|
|
||||||
if (this.filterFavorites) this.recipeContent.isFavorite = true
|
|
||||||
this.newRecipeID = this.getRandomID()
|
this.newRecipeID = this.getRandomID()
|
||||||
}
|
}
|
||||||
this.hijackBackEvent()
|
this.hijackBackEvent()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<Page @loaded="initializePage">
|
<Page @loaded="onPageLoad">
|
||||||
<ActionBar :flat="viewIsScrolled ? false : true">
|
<ActionBar :flat="viewIsScrolled ? false : true">
|
||||||
<!-- Search Actionbar -->
|
<!-- Search Actionbar -->
|
||||||
<GridLayout
|
<GridLayout
|
||||||
|
@ -7,9 +7,10 @@
|
||||||
columns="auto, *"
|
columns="auto, *"
|
||||||
verticalAlignment="center"
|
verticalAlignment="center"
|
||||||
>
|
>
|
||||||
<Label
|
<MDButton
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.back"
|
:text="icon.back"
|
||||||
|
variant="text"
|
||||||
automationText="Back"
|
automationText="Back"
|
||||||
col="0"
|
col="0"
|
||||||
@tap="closeSearch"
|
@tap="closeSearch"
|
||||||
|
@ -17,33 +18,35 @@
|
||||||
<SearchBar
|
<SearchBar
|
||||||
col="1"
|
col="1"
|
||||||
hint="Search"
|
hint="Search"
|
||||||
textFieldHintColor="#bdbdbd"
|
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
@textChange="updateFilter"
|
@textChange="updateFilter"
|
||||||
@clear="updateFilter"
|
@clear="clearSearch"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<!-- Home Actionbar -->
|
<!-- Home Actionbar -->
|
||||||
<GridLayout v-else columns="auto, *, auto, auto">
|
<GridLayout v-else columns="auto, *, auto, auto">
|
||||||
<Label
|
<MDButton
|
||||||
class="bx"
|
class="bx"
|
||||||
|
col="0"
|
||||||
|
variant="text"
|
||||||
|
@tap="showDrawer"
|
||||||
:text="icon.menu"
|
:text="icon.menu"
|
||||||
automationText="Back"
|
automationText="Back"
|
||||||
@tap="showDrawer"
|
|
||||||
col="0"
|
|
||||||
/>
|
/>
|
||||||
<Label class="title orkm" :text="currentComponent" col="1" />
|
<Label class="title orkm" :text="currentComponent" col="1" />
|
||||||
<Label
|
<MDButton
|
||||||
v-if="recipes.length"
|
v-if="recipes.length"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.search"
|
:text="icon.search"
|
||||||
|
variant="text"
|
||||||
col="2"
|
col="2"
|
||||||
@tap="openSearch"
|
@tap="openSearch"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
v-if="recipes.length"
|
v-if="recipes.length"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.sort"
|
:text="icon.sort"
|
||||||
|
variant="text"
|
||||||
col="3"
|
col="3"
|
||||||
@tap="sortDialog"
|
@tap="sortDialog"
|
||||||
/>
|
/>
|
||||||
|
@ -58,10 +61,10 @@
|
||||||
@itemSwipeProgressChanged="onSwiping"
|
@itemSwipeProgressChanged="onSwiping"
|
||||||
@itemSwipeProgressEnded="onSwipeEnded"
|
@itemSwipeProgressEnded="onSwipeEnded"
|
||||||
@scrolled="onScroll"
|
@scrolled="onScroll"
|
||||||
@itemTap="viewRecipe"
|
|
||||||
:filteringFunction="filterFunction"
|
:filteringFunction="filterFunction"
|
||||||
:sortingFunction="sortFunction"
|
:sortingFunction="sortFunction"
|
||||||
>
|
>
|
||||||
|
<!-- @itemTap="viewRecipe" -->
|
||||||
<v-template>
|
<v-template>
|
||||||
<GridLayout
|
<GridLayout
|
||||||
class="recipeItem"
|
class="recipeItem"
|
||||||
|
@ -69,6 +72,7 @@
|
||||||
columns="112, *"
|
columns="112, *"
|
||||||
androidElevation="1"
|
androidElevation="1"
|
||||||
>
|
>
|
||||||
|
<MDRipple colSpan="2" @tap="viewRecipe(recipe)" />
|
||||||
<GridLayout class="imageHolder card" rows="112" columns="112">
|
<GridLayout class="imageHolder card" rows="112" columns="112">
|
||||||
<Image
|
<Image
|
||||||
row="0"
|
row="0"
|
||||||
|
@ -114,31 +118,85 @@
|
||||||
<StackLayout height="128"></StackLayout>
|
<StackLayout height="128"></StackLayout>
|
||||||
</v-template>
|
</v-template>
|
||||||
</RadListView>
|
</RadListView>
|
||||||
<GridLayout rows="96, auto, *" columns="*" class="emptyState">
|
<GridLayout rows="*, auto, *, 88" columns="*" class="emptyStateContainer">
|
||||||
<StackLayout
|
<StackLayout
|
||||||
col="0"
|
col="0"
|
||||||
row="1"
|
row="1"
|
||||||
class="noResult"
|
class="emptyState"
|
||||||
v-if="!recipes.length && !filterFavorites && !filterTrylater"
|
v-if="
|
||||||
|
!recipes.length &&
|
||||||
|
!filterFavorites &&
|
||||||
|
!filterTrylater &&
|
||||||
|
!selectedCategory
|
||||||
|
"
|
||||||
|
@tap="addRecipe"
|
||||||
>
|
>
|
||||||
<Image class="logo" src="res://icon_gray" stretch="aspectFit" />
|
<Label class="bx icon" :text="icon.plusCircle" />
|
||||||
<Label
|
<Label
|
||||||
class="title orkm"
|
class="title orkm"
|
||||||
text="Start adding your recipes!"
|
text="Start adding your recipes!"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<StackLayout orientation="horizontal" horizontalAlignment="center">
|
<StackLayout orientation="horizontal" horizontalAlignment="center">
|
||||||
<Label text="Use the " textWrap="true" />
|
<Label text="Use the " />
|
||||||
<Label class="bx" :text="icon.plus" />
|
<Label class="bx" :text="icon.plus" />
|
||||||
<Label text=" button to add a new recipe" textWrap="true" />
|
<Label text=" button to add one" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout
|
<StackLayout
|
||||||
col="0"
|
col="0"
|
||||||
row="1"
|
row="1"
|
||||||
class="noResult"
|
class="emptyState"
|
||||||
|
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
|
||||||
|
>
|
||||||
|
<Label class="bx icon" :text="icon.heartOutline" textWrap="true" />
|
||||||
|
<Label class="title orkm" text="No favorites yet" textWrap="true" />
|
||||||
|
<Label
|
||||||
|
text="Recipes you mark as favorite will be listed here"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout
|
||||||
|
col="0"
|
||||||
|
row="1"
|
||||||
|
class="emptyState"
|
||||||
|
v-if="!filteredRecipes.length && filterTrylater && !searchQuery"
|
||||||
|
>
|
||||||
|
<Label class="bx icon" :text="icon.trylaterOutline" textWrap="true" />
|
||||||
|
<Label class="title orkm" text="All done!" textWrap="true" />
|
||||||
|
<Label
|
||||||
|
text="Recipes you mark as try later will be listed here"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout
|
||||||
|
col="0"
|
||||||
|
row="1"
|
||||||
|
class="emptyState"
|
||||||
|
v-if="
|
||||||
|
!filteredRecipes.length &&
|
||||||
|
!filterFavorites &&
|
||||||
|
!filterTrylater &&
|
||||||
|
selectedCategory
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<Label class="bx icon" :text="icon.labelOutline" textWrap="true" />
|
||||||
|
<Label
|
||||||
|
class="title orkm"
|
||||||
|
text="Category looks empty"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
<StackLayout orientation="horizontal" horizontalAlignment="center">
|
||||||
|
<Label text="Use the " textWrap="true" />
|
||||||
|
<Label class="bx" :text="icon.plus" />
|
||||||
|
<Label text=" button to add a recipe" textWrap="true" />
|
||||||
|
</StackLayout>
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout
|
||||||
|
col="0"
|
||||||
|
row="0"
|
||||||
|
class="emptyState noResult"
|
||||||
v-if="!filteredRecipes.length && searchQuery"
|
v-if="!filteredRecipes.length && searchQuery"
|
||||||
verticalAlignment="top"
|
|
||||||
>
|
>
|
||||||
<Label class="bx icon" :text="icon.search" textWrap="true" />
|
<Label class="bx icon" :text="icon.search" textWrap="true" />
|
||||||
<Label class="title orkm" text="No recipes found" textWrap="true" />
|
<Label class="title orkm" text="No recipes found" textWrap="true" />
|
||||||
|
@ -153,45 +211,15 @@
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout
|
|
||||||
col="0"
|
|
||||||
row="1"
|
|
||||||
class="noResult"
|
|
||||||
v-if="!filteredRecipes.length && filterFavorites && !searchQuery"
|
|
||||||
>
|
|
||||||
<Label class="bx icon" :text="icon.heartOutline" textWrap="true" />
|
|
||||||
<Label class="title orkm" text="No favorites yet!" textWrap="true" />
|
|
||||||
<Label
|
|
||||||
text="Your favorited recipes will be listed here"
|
|
||||||
textWrap="true"
|
|
||||||
/>
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
col="0"
|
|
||||||
row="1"
|
|
||||||
class="noResult"
|
|
||||||
v-if="!filteredRecipes.length && filterTrylater && !searchQuery"
|
|
||||||
>
|
|
||||||
<Label class="bx icon" :text="icon.trylaterOutline" textWrap="true" />
|
|
||||||
<Label
|
|
||||||
class="title orkm"
|
|
||||||
text="Nothing to try next!"
|
|
||||||
textWrap="true"
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
text="Recipes you wanted to try later will be listed here"
|
|
||||||
textWrap="true"
|
|
||||||
/>
|
|
||||||
</StackLayout>
|
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<GridLayout id="btnFabContainer" rows="*, auto" columns="*, auto">
|
<GridLayout id="btnFabContainer" rows="*, auto" columns="*, auto">
|
||||||
<transition name="bounce">
|
<transition name="bounce">
|
||||||
<Label
|
<MDFloatingActionButton
|
||||||
v-if="showFAB"
|
v-if="showFAB"
|
||||||
row="1"
|
row="1"
|
||||||
col="1"
|
col="1"
|
||||||
class="bx fab-button"
|
class="bx fab-button"
|
||||||
:text="icon.plus"
|
src="res://plus"
|
||||||
@tap="addRecipe"
|
@tap="addRecipe"
|
||||||
/>
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -201,13 +229,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Utils, AndroidApplication } from "@nativescript/core"
|
import { AndroidApplication, Utils } from "@nativescript/core"
|
||||||
|
import { mapActions, mapState } from "vuex"
|
||||||
|
|
||||||
import EditRecipe from "./EditRecipe.vue"
|
import EditRecipe from "./EditRecipe.vue"
|
||||||
import ViewRecipe from "./ViewRecipe.vue"
|
import ViewRecipe from "./ViewRecipe.vue"
|
||||||
|
|
||||||
import ActionDialog from "./modal/ActionDialog.vue"
|
import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
||||||
import { mapState, mapActions } from "vuex"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
@ -261,7 +290,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["setCurrentComponentAction", "deleteRecipeAction"]),
|
...mapActions(["setCurrentComponentAction", "deleteRecipeAction"]),
|
||||||
initializePage() {
|
onPageLoad() {
|
||||||
this.filterFavorites
|
this.filterFavorites
|
||||||
? this.setComponent("Favorites")
|
? this.setComponent("Favorites")
|
||||||
: this.filterTrylater
|
: this.filterTrylater
|
||||||
|
@ -271,10 +300,46 @@ export default {
|
||||||
: this.setComponent("EnRecipes")
|
: this.setComponent("EnRecipes")
|
||||||
this.showFAB = true
|
this.showFAB = true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HELPERS
|
||||||
openSearch() {
|
openSearch() {
|
||||||
this.showSearch = true
|
this.showSearch = true
|
||||||
|
this.showFAB = false
|
||||||
this.hijackLocalBackEvent()
|
this.hijackLocalBackEvent()
|
||||||
},
|
},
|
||||||
|
closeSearch() {
|
||||||
|
if (this.searchQuery) this.updateFilter()
|
||||||
|
this.searchQuery = ""
|
||||||
|
Utils.ad.dismissSoftInput()
|
||||||
|
this.showSearch = false
|
||||||
|
this.showFAB = true
|
||||||
|
this.releaseLocalBackEvent()
|
||||||
|
},
|
||||||
|
setComponent(comp) {
|
||||||
|
this.setCurrentComponentAction(comp)
|
||||||
|
this.hijackGlobalBackEvent()
|
||||||
|
},
|
||||||
|
clearSearch() {
|
||||||
|
if (this.searchQuery !== "") {
|
||||||
|
this.updateFilter()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formattedTime(time) {
|
||||||
|
let t = time.split(":")
|
||||||
|
let h = parseInt(t[0])
|
||||||
|
let m = parseInt(t[1])
|
||||||
|
return {
|
||||||
|
time: h ? (m ? `${h}h ${m}m` : `${h}h`) : `${m}m`,
|
||||||
|
duration: `${h}${m}`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onScroll(args) {
|
||||||
|
args.scrollOffset
|
||||||
|
? (this.viewIsScrolled = true)
|
||||||
|
: (this.viewIsScrolled = false)
|
||||||
|
},
|
||||||
|
|
||||||
|
// NAVIGATION HANDLERS
|
||||||
hijackLocalBackEvent() {
|
hijackLocalBackEvent() {
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
AndroidApplication.on(
|
AndroidApplication.on(
|
||||||
|
@ -293,20 +358,49 @@ export default {
|
||||||
args.cancel = true
|
args.cancel = true
|
||||||
this.closeSearch()
|
this.closeSearch()
|
||||||
},
|
},
|
||||||
closeSearch() {
|
addRecipe() {
|
||||||
if (this.searchQuery) this.updateFilter()
|
this.showFAB = false
|
||||||
this.searchQuery = ""
|
this.releaseGlobalBackEvent()
|
||||||
Utils.ad.dismissSoftInput()
|
this.$navigateTo(EditRecipe, {
|
||||||
this.showSearch = false
|
// transition: {
|
||||||
this.releaseLocalBackEvent()
|
// name: "fade",
|
||||||
|
// duration: 200,
|
||||||
|
// curve: "easeOut",
|
||||||
|
// },
|
||||||
|
props: {
|
||||||
|
selectedCategory: this.selectedCategory,
|
||||||
|
openAppSettingsPage: this.openAppSettingsPage,
|
||||||
|
filterFavorites: this.filterFavorites,
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
viewRecipe(item) {
|
||||||
|
let index = this.recipes.indexOf(item)
|
||||||
|
this.showFAB = false
|
||||||
|
this.$navigateTo(ViewRecipe, {
|
||||||
|
// transition: {
|
||||||
|
// name: "fade",
|
||||||
|
// duration: 200,
|
||||||
|
// curve: "easeOut",
|
||||||
|
// },
|
||||||
|
props: {
|
||||||
|
filterTrylater: this.filterTrylater,
|
||||||
|
recipeIndex: index,
|
||||||
|
recipeID: item.id,
|
||||||
|
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
||||||
|
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// LIST HANDLERS
|
||||||
sortDialog() {
|
sortDialog() {
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
this.$showModal(ActionDialog, {
|
this.$showModal(ActionDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "Sort by",
|
title: "Sort by",
|
||||||
list: ["Natural order", "Title", "Duration", "Last modified"],
|
list: ["Natural order", "Title", "Duration", "Last modified"],
|
||||||
height: "216", // 54*4
|
height: "225",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
if (action && action !== "Cancel" && this.sortType !== action) {
|
if (action && action !== "Cancel" && this.sortType !== action) {
|
||||||
|
@ -346,10 +440,6 @@ export default {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setComponent(comp) {
|
|
||||||
this.setCurrentComponentAction(comp)
|
|
||||||
this.hijackGlobalBackEvent()
|
|
||||||
},
|
|
||||||
updateFilter() {
|
updateFilter() {
|
||||||
let listView = this.$refs.listView.nativeView
|
let listView = this.$refs.listView.nativeView
|
||||||
setTimeout((e) => {
|
setTimeout((e) => {
|
||||||
|
@ -392,6 +482,8 @@ export default {
|
||||||
this.deleteRecipe(index, recipeID)
|
this.deleteRecipe(index, recipeID)
|
||||||
this.rightAction = false
|
this.rightAction = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// DATA HANDLERS
|
||||||
deleteRecipe(index, recipeID) {
|
deleteRecipe(index, recipeID) {
|
||||||
this.deletionDialogActive = true
|
this.deletionDialogActive = true
|
||||||
this.$showModal(ConfirmDialog, {
|
this.$showModal(ConfirmDialog, {
|
||||||
|
@ -408,54 +500,6 @@ export default {
|
||||||
this.deletionDialogActive = false
|
this.deletionDialogActive = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
formattedTime(time) {
|
|
||||||
let t = time.split(":")
|
|
||||||
let h = parseInt(t[0])
|
|
||||||
let m = parseInt(t[1])
|
|
||||||
return {
|
|
||||||
time: h ? (m ? `${h}h ${m}m` : `${h}h`) : `${m}m`,
|
|
||||||
duration: `${h}${m}`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onScroll(args) {
|
|
||||||
args.scrollOffset
|
|
||||||
? (this.viewIsScrolled = true)
|
|
||||||
: (this.viewIsScrolled = false)
|
|
||||||
},
|
|
||||||
addRecipe() {
|
|
||||||
this.showFAB = false
|
|
||||||
this.releaseGlobalBackEvent()
|
|
||||||
this.$navigateTo(EditRecipe, {
|
|
||||||
// transition: {
|
|
||||||
// name: "fade",
|
|
||||||
// duration: 200,
|
|
||||||
// curve: "easeOut",
|
|
||||||
// },
|
|
||||||
props: {
|
|
||||||
selectedCategory: this.selectedCategory,
|
|
||||||
openAppSettingsPage: this.openAppSettingsPage,
|
|
||||||
filterFavorites: this.filterFavorites,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
viewRecipe({ item, index }) {
|
|
||||||
this.showFAB = false
|
|
||||||
this.$navigateTo(ViewRecipe, {
|
|
||||||
// transition: {
|
|
||||||
// name: "fade",
|
|
||||||
// duration: 200,
|
|
||||||
// curve: "easeOut",
|
|
||||||
// },
|
|
||||||
props: {
|
|
||||||
filterTrylater: this.filterTrylater,
|
|
||||||
recipeIndex: index,
|
|
||||||
recipeID: item.id,
|
|
||||||
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
|
||||||
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.showFAB = true
|
this.showFAB = true
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<Page @loaded="initializePage">
|
<Page @loaded="onPageLoad">
|
||||||
<ActionBar :flat="viewIsScrolled ? false : true">
|
<ActionBar :flat="viewIsScrolled ? false : true">
|
||||||
<GridLayout rows="*" columns="auto, *">
|
<GridLayout rows="*" columns="auto, *">
|
||||||
<Label
|
<MDButton
|
||||||
class="bx"
|
class="bx left"
|
||||||
|
variant="text"
|
||||||
:text="icon.menu"
|
:text="icon.menu"
|
||||||
automationText="Back"
|
automationText="Back"
|
||||||
@tap="showDrawer"
|
@tap="showDrawer"
|
||||||
|
@ -14,55 +15,59 @@
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
<ScrollView scrollBarIndicatorVisible="false" @scroll="onScroll">
|
<ScrollView scrollBarIndicatorVisible="false" @scroll="onScroll">
|
||||||
<StackLayout class="main-container">
|
<StackLayout class="main-container">
|
||||||
<Label text="Interface" class="group-header" />
|
<Label text="Interface" class="group-header orkm" />
|
||||||
<StackLayout
|
<GridLayout columns="auto, *" class="option">
|
||||||
orientation="horizontal"
|
<MDRipple colSpan="2" @tap="selectThemes" />
|
||||||
class="option"
|
<Label
|
||||||
@tap="selectThemes"
|
col="0"
|
||||||
>
|
verticalAlignment="center"
|
||||||
<Label verticalAlignment="center" class="bx" :text="icon.theme" />
|
class="bx"
|
||||||
<StackLayout>
|
:text="icon.theme"
|
||||||
|
/>
|
||||||
|
<StackLayout col="1">
|
||||||
<Label text="Theme" />
|
<Label text="Theme" />
|
||||||
<Label :text="appTheme" class="option-info" textWrap="true" />
|
<Label :text="appTheme" class="info" textWrap="true" />
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
</GridLayout>
|
||||||
<StackLayout class="hr m-10"></StackLayout>
|
<StackLayout class="hr m-10"></StackLayout>
|
||||||
<Label text="Database" class="group-header" />
|
<Label text="Database" class="group-header orkm" />
|
||||||
<StackLayout orientation="horizontal" class="option" @tap="backupCheck">
|
<GridLayout columns="auto, *" class="option">
|
||||||
<Label class="bx" :text="icon.export" />
|
<MDRipple colSpan="2" @tap="exportCheck" />
|
||||||
<StackLayout>
|
<Label col="0" class="bx" :text="icon.export" />
|
||||||
|
<StackLayout col="1">
|
||||||
<Label text="Export a full backup" />
|
<Label text="Export a full backup" />
|
||||||
<GridLayout
|
<GridLayout
|
||||||
class="progressContainer"
|
class="progressContainer"
|
||||||
v-if="backupInProgress"
|
v-if="backupInProgress"
|
||||||
columns="*, 64"
|
columns="*, 64"
|
||||||
>
|
>
|
||||||
<Progress col="0" :value="backupProgress" />
|
<MDProgress
|
||||||
|
col="0"
|
||||||
|
:value="backupProgress"
|
||||||
|
maxValue="100"
|
||||||
|
></MDProgress>
|
||||||
<Label col="1" :text="` ${backupProgress}%`" />
|
<Label col="1" :text="` ${backupProgress}%`" />
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label
|
<Label
|
||||||
v-else
|
v-else
|
||||||
text="Generates a zip file that contains all your data. This file can be imported back."
|
text="Generates a zip file that contains all your data. This file can be imported back."
|
||||||
class="option-info"
|
class="info"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout columns="auto, *" class="option"
|
||||||
orientation="horizontal"
|
><MDRipple colSpan="2" @tap="importCheck" />
|
||||||
class="option"
|
<Label col="0" class="bx" :text="icon.import" />
|
||||||
@tap="restoreCheck"
|
<StackLayout col="1">
|
||||||
>
|
|
||||||
<Label class="bx" :text="icon.import" />
|
|
||||||
<StackLayout>
|
|
||||||
<Label text="Import from backup" />
|
<Label text="Import from backup" />
|
||||||
<Label
|
<Label
|
||||||
text="Supports full backups exported by this app."
|
text="Supports full backups exported by this app."
|
||||||
class="option-info"
|
class="info"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -83,14 +88,13 @@ import { Zip } from "@nativescript/zip"
|
||||||
import * as Toast from "nativescript-toast"
|
import * as Toast from "nativescript-toast"
|
||||||
import * as Filepicker from "nativescript-plugin-filepicker"
|
import * as Filepicker from "nativescript-plugin-filepicker"
|
||||||
import Theme from "@nativescript/theme"
|
import Theme from "@nativescript/theme"
|
||||||
|
import { mapState, mapActions } from "vuex"
|
||||||
|
|
||||||
import ActionDialog from "./modal/ActionDialog.vue"
|
import ActionDialog from "./modal/ActionDialog.vue"
|
||||||
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
import ConfirmDialog from "./modal/ConfirmDialog.vue"
|
||||||
|
|
||||||
import { Couchbase } from "nativescript-couchbase-plugin"
|
|
||||||
import { mapState, mapActions } from "vuex"
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
"highlight",
|
|
||||||
"showDrawer",
|
"showDrawer",
|
||||||
"restartApp",
|
"restartApp",
|
||||||
"hijackGlobalBackEvent",
|
"hijackGlobalBackEvent",
|
||||||
|
@ -121,22 +125,25 @@ export default {
|
||||||
"importYieldUnitsAction",
|
"importYieldUnitsAction",
|
||||||
"importRecipesAction",
|
"importRecipesAction",
|
||||||
]),
|
]),
|
||||||
initializePage() {
|
onPageLoad() {
|
||||||
this.setCurrentComponentAction("Settings")
|
this.setCurrentComponentAction("Settings")
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HELPERS
|
||||||
onScroll(args) {
|
onScroll(args) {
|
||||||
args.scrollY
|
args.scrollY
|
||||||
? (this.viewIsScrolled = true)
|
? (this.viewIsScrolled = true)
|
||||||
: (this.viewIsScrolled = false)
|
: (this.viewIsScrolled = false)
|
||||||
},
|
},
|
||||||
selectThemes(args) {
|
|
||||||
this.highlight(args)
|
// THEME SELECTION
|
||||||
|
selectThemes() {
|
||||||
this.$showModal(ActionDialog, {
|
this.$showModal(ActionDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "Theme",
|
title: "Theme",
|
||||||
list: ["Light", "Dark"],
|
list: ["Light", "Dark"],
|
||||||
height: "108",
|
height: "113",
|
||||||
},
|
},
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
if (action && action !== "Cancel" && this.appTheme !== action) {
|
if (action && action !== "Cancel" && this.appTheme !== action) {
|
||||||
|
@ -159,53 +166,23 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
writeFile(file, data) {
|
// EXPORT HANDLERS
|
||||||
file.writeText(JSON.stringify(data))
|
exportCheck() {
|
||||||
},
|
if (!this.recipes.length) {
|
||||||
BackupDataFiles(option) {
|
Toast.makeText(
|
||||||
const folder = path.join(knownFolders.documents().path, "EnRecipes")
|
"Add at least one recipe to perform a backup",
|
||||||
const EnRecipesFile = File.fromPath(path.join(folder, "EnRecipes.json"))
|
"long"
|
||||||
let userCategoriesFile, userYieldUnitsFile
|
).show()
|
||||||
if (this.userCategories.length) {
|
} else {
|
||||||
userCategoriesFile = File.fromPath(
|
this.permissionCheck(
|
||||||
path.join(folder, "userCategories.json")
|
this.permissionConfirmation,
|
||||||
|
"EnRecipes requires storage permission in order to backup your data to this device.",
|
||||||
|
this.exportBackup
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (this.userYieldUnits.length) {
|
|
||||||
userYieldUnitsFile = File.fromPath(
|
|
||||||
path.join(folder, "userYieldUnits.json")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
switch (option) {
|
|
||||||
case "create":
|
|
||||||
this.writeFile(EnRecipesFile, this.recipes)
|
|
||||||
this.userCategories.length &&
|
|
||||||
this.writeFile(userCategoriesFile, this.userCategories)
|
|
||||||
this.userYieldUnits.length &&
|
|
||||||
this.writeFile(userYieldUnitsFile, this.userYieldUnits)
|
|
||||||
break
|
|
||||||
case "delete":
|
|
||||||
EnRecipesFile.remove()
|
|
||||||
this.userCategories.length && userCategoriesFile.remove()
|
|
||||||
this.userYieldUnits.length && userYieldUnitsFile.remove()
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
backupPermissionConfirmation() {
|
exportBackup() {
|
||||||
return this.$showModal(ConfirmDialog, {
|
this.exportFiles("create")
|
||||||
props: {
|
|
||||||
title: "Grant permission",
|
|
||||||
description:
|
|
||||||
"EnRecipes requires storage permission in order to backup your data to this device",
|
|
||||||
cancelButtonText: "NOT NOW",
|
|
||||||
okButtonText: "CONTINUE",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
backupData() {
|
|
||||||
this.BackupDataFiles("create")
|
|
||||||
let date = new Date()
|
let date = new Date()
|
||||||
let formattedDate =
|
let formattedDate =
|
||||||
date.getFullYear() +
|
date.getFullYear() +
|
||||||
|
@ -242,48 +219,59 @@ export default {
|
||||||
"Backup file successfully saved to Downloads",
|
"Backup file successfully saved to Downloads",
|
||||||
"long"
|
"long"
|
||||||
).show()
|
).show()
|
||||||
this.BackupDataFiles("delete")
|
this.exportFiles("delete")
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
backupCheck(args) {
|
exportFiles(option) {
|
||||||
let btn = args.object
|
const folder = path.join(knownFolders.documents().path, "EnRecipes")
|
||||||
this.highlight(args)
|
const EnRecipesFile = File.fromPath(path.join(folder, "EnRecipes.json"))
|
||||||
if (!this.recipes.length) {
|
let userCategoriesFile, userYieldUnitsFile
|
||||||
Toast.makeText(
|
if (this.userCategories.length) {
|
||||||
"Add at least one recipe to perform a backup",
|
userCategoriesFile = File.fromPath(
|
||||||
"long"
|
path.join(folder, "userCategories.json")
|
||||||
).show()
|
)
|
||||||
} else {
|
}
|
||||||
this.permissionCheck(this.backupPermissionConfirmation, this.backupData)
|
if (this.userYieldUnits.length) {
|
||||||
|
userYieldUnitsFile = File.fromPath(
|
||||||
|
path.join(folder, "userYieldUnits.json")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch (option) {
|
||||||
|
case "create":
|
||||||
|
this.writeDataToFile(EnRecipesFile, this.recipes)
|
||||||
|
this.userCategories.length &&
|
||||||
|
this.writeDataToFile(userCategoriesFile, this.userCategories)
|
||||||
|
this.userYieldUnits.length &&
|
||||||
|
this.writeDataToFile(userYieldUnitsFile, this.userYieldUnits)
|
||||||
|
break
|
||||||
|
case "delete":
|
||||||
|
EnRecipesFile.remove()
|
||||||
|
this.userCategories.length && userCategoriesFile.remove()
|
||||||
|
this.userYieldUnits.length && userYieldUnitsFile.remove()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
writeDataToFile(file, data) {
|
||||||
restorePermissionConfirmation() {
|
file.writeText(JSON.stringify(data))
|
||||||
return this.$showModal(ConfirmDialog, {
|
|
||||||
props: {
|
|
||||||
title: "Grant permission",
|
|
||||||
description:
|
|
||||||
"EnRecipes requires storage permission in order to restore your data from a previous backup.",
|
|
||||||
cancelButtonText: "NOT NOW",
|
|
||||||
okButtonText: "CONTINUE",
|
|
||||||
},
|
},
|
||||||
})
|
|
||||||
},
|
|
||||||
restoreCheck(args) {
|
|
||||||
let btn = args.object
|
|
||||||
this.highlight(args)
|
|
||||||
|
|
||||||
|
// IMPORT HANDLERS
|
||||||
|
importCheck() {
|
||||||
this.permissionCheck(
|
this.permissionCheck(
|
||||||
this.restorePermissionConfirmation,
|
this.permissionConfirmation,
|
||||||
|
"EnRecipes requires storage permission in order to restore your data from a previous backup.",
|
||||||
this.openFilePicker
|
this.openFilePicker
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
openFilePicker() {
|
openFilePicker() {
|
||||||
let context = Filepicker.create({
|
Filepicker.create({
|
||||||
mode: "single", // use "multiple" for multiple selection
|
mode: "single",
|
||||||
extensions: ["zip"],
|
extensions: ["zip"],
|
||||||
})
|
})
|
||||||
context.present().then((selection) => {
|
.present()
|
||||||
|
.then((selection) => {
|
||||||
Toast.makeText("Processing...").show()
|
Toast.makeText("Processing...").show()
|
||||||
let result = selection[0]
|
let result = selection[0]
|
||||||
let zipPath = result
|
let zipPath = result
|
||||||
|
@ -294,7 +282,7 @@ export default {
|
||||||
importDataToDB(data, db, zipPath) {
|
importDataToDB(data, db, zipPath) {
|
||||||
switch (db) {
|
switch (db) {
|
||||||
case "EnRecipesDB":
|
case "EnRecipesDB":
|
||||||
this.copyImages(zipPath)
|
this.importImages(zipPath)
|
||||||
this.importRecipesAction(data)
|
this.importRecipesAction(data)
|
||||||
break
|
break
|
||||||
case "userCategoriesDB":
|
case "userCategoriesDB":
|
||||||
|
@ -307,7 +295,7 @@ export default {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isImportedDataValid(file) {
|
isFileDataValid(file) {
|
||||||
file.forEach((file, i) => {
|
file.forEach((file, i) => {
|
||||||
if (File.exists(file.path)) {
|
if (File.exists(file.path)) {
|
||||||
File.fromPath(file.path)
|
File.fromPath(file.path)
|
||||||
|
@ -329,7 +317,7 @@ export default {
|
||||||
const userCategoriesFilePath = cacheFolderPath + "/userCategories.json"
|
const userCategoriesFilePath = cacheFolderPath + "/userCategories.json"
|
||||||
const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json"
|
const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json"
|
||||||
if (Folder.exists(cacheFolderPath)) {
|
if (Folder.exists(cacheFolderPath)) {
|
||||||
this.isImportedDataValid([
|
this.isFileDataValid([
|
||||||
{
|
{
|
||||||
zipPath,
|
zipPath,
|
||||||
path: EnRecipesFilePath,
|
path: EnRecipesFilePath,
|
||||||
|
@ -341,30 +329,33 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
Folder.fromPath(extractedFolderPath).remove()
|
Folder.fromPath(extractedFolderPath).remove()
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
"Zip modified externally or incorrect file",
|
"Import failed. Backup file is incorrect or corrupt",
|
||||||
"long"
|
"long"
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
if (Folder.exists(cacheFolderPath + "/Images")) {
|
if (Folder.exists(cacheFolderPath + "/Images")) {
|
||||||
this.copyImages(cacheFolderPath + "/Images")
|
this.importImages(cacheFolderPath + "/Images")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
copyImages(sourcePath) {
|
importImages(sourcePath) {
|
||||||
let dest = knownFolders.documents().path
|
let dest = knownFolders.documents().path
|
||||||
Zip.unzip({
|
Zip.unzip({
|
||||||
archive: sourcePath,
|
archive: sourcePath,
|
||||||
directory: dest,
|
directory: dest,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
Toast.makeText("Import successful!", "long").show()
|
Toast.makeText("Import successful", "long").show()
|
||||||
|
this.$navigateBack()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
permissionCheck(confirmation, action) {
|
|
||||||
|
// PERMISSIONS HANDLER
|
||||||
|
permissionCheck(confirmation, description, action) {
|
||||||
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
||||||
confirmation().then((e) => {
|
confirmation(description).then((e) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
Permissions.request("storage").then((res) => {
|
Permissions.request("photo").then((res) => {
|
||||||
let status = res[Object.keys(res)[0]]
|
let status = res[Object.keys(res)[0]]
|
||||||
if (status === "authorized") action()
|
if (status === "authorized") action()
|
||||||
if (status !== "denied")
|
if (status !== "denied")
|
||||||
|
@ -374,16 +365,26 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Permissions.request("storage").then((res) => {
|
Permissions.check("photo").then((res) => {
|
||||||
let status = res[Object.keys(res)[0]]
|
let status = res[Object.keys(res)[0]]
|
||||||
if (status !== "authorized") {
|
if (status !== "authorized") {
|
||||||
confirmation().then((e) => {
|
confirmation(description).then((e) => {
|
||||||
e && this.openAppSettingsPage()
|
e && this.openAppSettingsPage()
|
||||||
})
|
})
|
||||||
} else action()
|
} else action()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
permissionConfirmation(description) {
|
||||||
|
return this.$showModal(ConfirmDialog, {
|
||||||
|
props: {
|
||||||
|
title: "Grant permission",
|
||||||
|
description,
|
||||||
|
cancelButtonText: "NOT NOW",
|
||||||
|
okButtonText: "CONTINUE",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
|
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<Page @loaded="initializePage" @unloaded="unLoad">
|
<Page @loaded="onPageLoad" @unloaded="onPageUnload">
|
||||||
<ActionBar height="112" margin="0" flat="true">
|
<ActionBar height="112" margin="0" flat="true">
|
||||||
<GridLayout rows="64, 48" columns="auto, *, auto,auto, auto">
|
<GridLayout rows="64, 48" columns="auto, *, auto,auto, auto">
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
row="0"
|
row="0"
|
||||||
col="0"
|
col="0"
|
||||||
class="bx"
|
class="bx"
|
||||||
|
@ -23,30 +24,36 @@
|
||||||
verticalAlignment="bottom"
|
verticalAlignment="bottom"
|
||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<Label
|
<FlexboxLayout row="0" col="2" alignItems="center">
|
||||||
row="0"
|
<MDButton
|
||||||
col="3"
|
variant="text"
|
||||||
class="bx"
|
|
||||||
:text="recipe.isFavorite ? icon.heart : icon.heartOutline"
|
|
||||||
@tap="toggleFavorite"
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
v-if="!filterTrylater"
|
|
||||||
row="0"
|
|
||||||
col="4"
|
|
||||||
class="bx"
|
|
||||||
:text="recipe.tried ? icon.trylaterOutline : icon.trylater"
|
|
||||||
@tap="toggleTrylater"
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
v-if="!busy"
|
v-if="!busy"
|
||||||
row="0"
|
|
||||||
col="2"
|
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.edit"
|
:text="icon.edit"
|
||||||
@tap="editRecipe"
|
@tap="editRecipe"
|
||||||
/>
|
/>
|
||||||
<ActivityIndicator v-else row="0" col="2" :busy="busy" />
|
<MDActivityIndicator v-else :busy="busy" />
|
||||||
|
<MDButton
|
||||||
|
variant="text"
|
||||||
|
class="bx"
|
||||||
|
:text="recipe.isFavorite ? icon.heart : icon.heartOutline"
|
||||||
|
@tap="toggleFavorite"
|
||||||
|
/>
|
||||||
|
<MDButton
|
||||||
|
variant="text"
|
||||||
|
v-if="!filterTrylater"
|
||||||
|
class="bx"
|
||||||
|
:text="recipe.tried ? icon.trylaterOutline : icon.trylater"
|
||||||
|
@tap="toggleTrylater"
|
||||||
|
/>
|
||||||
|
<MDButton
|
||||||
|
variant="text"
|
||||||
|
v-else
|
||||||
|
class="bx"
|
||||||
|
:text="icon.share"
|
||||||
|
@tap="shareHandler"
|
||||||
|
/>
|
||||||
|
</FlexboxLayout>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</ActionBar>
|
</ActionBar>
|
||||||
<AbsoluteLayout>
|
<AbsoluteLayout>
|
||||||
|
@ -91,27 +98,26 @@
|
||||||
:text="recipe.title"
|
:text="recipe.title"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<Label class="time">
|
<StackLayout orientation="horizontal" class="time">
|
||||||
<FormattedString>
|
<Label text="Time required:" />
|
||||||
<Span text="Time required:"></Span>
|
<Label :text="` ${formattedTime(recipe.timeRequired)}`" />
|
||||||
<Span
|
</StackLayout>
|
||||||
:text="` ${formattedTime(recipe.timeRequired)}`"
|
|
||||||
></Span>
|
|
||||||
</FormattedString>
|
|
||||||
</Label>
|
|
||||||
<GridLayout
|
<GridLayout
|
||||||
rows="auto, auto"
|
rows="auto, auto"
|
||||||
columns="*, *"
|
columns="*, *"
|
||||||
class="overviewContainer"
|
class="overviewContainer"
|
||||||
>
|
>
|
||||||
<StackLayout
|
<GridLayout
|
||||||
class="overviewItem"
|
class="overviewItem"
|
||||||
row="0"
|
row="0"
|
||||||
col="0"
|
col="0"
|
||||||
@tap="selectedTabIndex = 1"
|
rows="auto, auto"
|
||||||
|
columns="*"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon.item" />
|
<MDRipple rowSpan="2" @tap="selectedTabIndex = 1" />
|
||||||
|
<Label row="0" class="bx" :text="icon.item" />
|
||||||
<Label
|
<Label
|
||||||
|
row="1"
|
||||||
class="itemCount"
|
class="itemCount"
|
||||||
:text="
|
:text="
|
||||||
`${recipe.ingredients.length} ${
|
`${recipe.ingredients.length} ${
|
||||||
|
@ -122,15 +128,18 @@
|
||||||
"
|
"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout
|
||||||
class="overviewItem"
|
class="overviewItem"
|
||||||
row="0"
|
row="0"
|
||||||
col="1"
|
col="1"
|
||||||
@tap="selectedTabIndex = 2"
|
rows="auto, auto"
|
||||||
|
columns="*"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon.step" />
|
<MDRipple rowSpan="2" @tap="selectedTabIndex = 2" />
|
||||||
|
<Label row="0" class="bx" :text="icon.step" />
|
||||||
<Label
|
<Label
|
||||||
|
row="1"
|
||||||
class="itemCount"
|
class="itemCount"
|
||||||
:text="
|
:text="
|
||||||
`${recipe.instructions.length} ${
|
`${recipe.instructions.length} ${
|
||||||
|
@ -139,15 +148,18 @@
|
||||||
"
|
"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout
|
||||||
class="overviewItem"
|
class="overviewItem"
|
||||||
row="1"
|
row="1"
|
||||||
col="0"
|
col="0"
|
||||||
@tap="selectedTabIndex = 3"
|
rows="auto, auto"
|
||||||
|
columns="*"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon.note" />
|
<MDRipple rowSpan="2" @tap="selectedTabIndex = 3" />
|
||||||
|
<Label row="0" class="bx" :text="icon.note" />
|
||||||
<Label
|
<Label
|
||||||
|
row="1"
|
||||||
class="itemCount"
|
class="itemCount"
|
||||||
:text="
|
:text="
|
||||||
`${recipe.notes.length} ${
|
`${recipe.notes.length} ${
|
||||||
|
@ -156,15 +168,18 @@
|
||||||
"
|
"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
<StackLayout
|
<GridLayout
|
||||||
class="overviewItem"
|
class="overviewItem"
|
||||||
row="1"
|
row="1"
|
||||||
col="1"
|
col="1"
|
||||||
@tap="selectedTabIndex = 4"
|
rows="auto, auto"
|
||||||
|
columns="*"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon.source" />
|
<MDRipple rowSpan="2" @tap="selectedTabIndex = 4" />
|
||||||
|
<Label row="0" class="bx" :text="icon.source" />
|
||||||
<Label
|
<Label
|
||||||
|
row="1"
|
||||||
class="itemCount"
|
class="itemCount"
|
||||||
:text="
|
:text="
|
||||||
`${recipe.references.length} ${
|
`${recipe.references.length} ${
|
||||||
|
@ -175,7 +190,7 @@
|
||||||
"
|
"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</GridLayout>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
@ -185,11 +200,11 @@
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
v-if="!recipe.ingredients.length"
|
v-if="!recipe.ingredients.length"
|
||||||
rows="96, auto, *"
|
rows="*, auto, *, 88"
|
||||||
columns="*"
|
columns="*"
|
||||||
class="emptyState"
|
class="emptyStateContainer"
|
||||||
>
|
>
|
||||||
<StackLayout col="0" row="1" class="noResult">
|
<StackLayout col="0" row="1" class="emptyState">
|
||||||
<Label class="bx icon" :text="icon.item" textWrap="true" />
|
<Label class="bx icon" :text="icon.item" textWrap="true" />
|
||||||
<StackLayout orientation="horizontal" class="title orkm">
|
<StackLayout orientation="horizontal" class="title orkm">
|
||||||
<Label text="Use the " />
|
<Label text="Use the " />
|
||||||
|
@ -199,7 +214,7 @@
|
||||||
<Label text="to add some ingredients" textWrap="true" />
|
<Label text="to add some ingredients" textWrap="true" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<StackLayout v-else padding="16 16 134">
|
<StackLayout v-else padding="32 16 134">
|
||||||
<AbsoluteLayout class="inputField">
|
<AbsoluteLayout class="inputField">
|
||||||
<TextField
|
<TextField
|
||||||
width="50%"
|
width="50%"
|
||||||
|
@ -212,7 +227,7 @@
|
||||||
:text="`Required ${recipe.yield.unit.toLowerCase()}`"
|
:text="`Required ${recipe.yield.unit.toLowerCase()}`"
|
||||||
/>
|
/>
|
||||||
</AbsoluteLayout>
|
</AbsoluteLayout>
|
||||||
<StackLayout margin="24 0 16 0">
|
<StackLayout margin="16 0">
|
||||||
<Label
|
<Label
|
||||||
class="title orkm"
|
class="title orkm"
|
||||||
:text="
|
:text="
|
||||||
|
@ -231,7 +246,7 @@
|
||||||
v-if="filterTrylater"
|
v-if="filterTrylater"
|
||||||
class="ingredient-check"
|
class="ingredient-check"
|
||||||
checkPadding="16"
|
checkPadding="16"
|
||||||
:fillColor="`${isLightMode ? '#ff5200' : '#ff7043'}`"
|
fillColor="#ff5200"
|
||||||
:text="
|
:text="
|
||||||
`${
|
`${
|
||||||
roundedQuantity(item.quantity)
|
roundedQuantity(item.quantity)
|
||||||
|
@ -264,11 +279,11 @@
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
v-if="!recipe.instructions.length"
|
v-if="!recipe.instructions.length"
|
||||||
rows="96, auto, *"
|
rows="*, auto, *, 88"
|
||||||
columns="*"
|
columns="*"
|
||||||
class="emptyState"
|
class="emptyStateContainer"
|
||||||
>
|
>
|
||||||
<StackLayout col="0" row="1" class="noResult">
|
<StackLayout col="0" row="1" class="emptyState">
|
||||||
<Label class="bx icon" :text="icon.step" textWrap="true" />
|
<Label class="bx icon" :text="icon.step" textWrap="true" />
|
||||||
<StackLayout orientation="horizontal" class="title orkm">
|
<StackLayout orientation="horizontal" class="title orkm">
|
||||||
<Label text="Use the " />
|
<Label text="Use the " />
|
||||||
|
@ -309,11 +324,11 @@
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
v-if="!recipe.notes.length"
|
v-if="!recipe.notes.length"
|
||||||
rows="96, auto, *"
|
rows="*, auto, *, 88"
|
||||||
columns="*"
|
columns="*"
|
||||||
class="emptyState"
|
class="emptyStateContainer"
|
||||||
>
|
>
|
||||||
<StackLayout col="0" row="1" class="noResult">
|
<StackLayout col="0" row="1" class="emptyState">
|
||||||
<Label class="bx icon" :text="icon.note" textWrap="true" />
|
<Label class="bx icon" :text="icon.note" textWrap="true" />
|
||||||
<StackLayout orientation="horizontal" class="title orkm">
|
<StackLayout orientation="horizontal" class="title orkm">
|
||||||
<Label text="Use the " />
|
<Label text="Use the " />
|
||||||
|
@ -351,11 +366,11 @@
|
||||||
<ScrollView scrollBarIndicatorVisible="false">
|
<ScrollView scrollBarIndicatorVisible="false">
|
||||||
<GridLayout
|
<GridLayout
|
||||||
v-if="!recipe.references.length"
|
v-if="!recipe.references.length"
|
||||||
rows="96, auto, *"
|
rows="*, auto, *, 88"
|
||||||
columns="*"
|
columns="*"
|
||||||
class="emptyState"
|
class="emptyStateContainer"
|
||||||
>
|
>
|
||||||
<StackLayout col="0" row="1" class="noResult">
|
<StackLayout col="0" row="1" class="emptyState">
|
||||||
<Label class="bx icon" :text="icon.source" textWrap="true" />
|
<Label class="bx icon" :text="icon.source" textWrap="true" />
|
||||||
<StackLayout orientation="horizontal" class="title orkm">
|
<StackLayout orientation="horizontal" class="title orkm">
|
||||||
<Label text="Use the " />
|
<Label text="Use the " />
|
||||||
|
@ -375,8 +390,8 @@
|
||||||
columns="*, auto"
|
columns="*, auto"
|
||||||
class="referenceItem"
|
class="referenceItem"
|
||||||
androidElevation="1"
|
androidElevation="1"
|
||||||
@longPress="copyURL($event, reference)"
|
|
||||||
>
|
>
|
||||||
|
<MDRipple colSpan="3" @tap="copyURL(reference)" />
|
||||||
<Label
|
<Label
|
||||||
col="0"
|
col="0"
|
||||||
verticalAlignment="center"
|
verticalAlignment="center"
|
||||||
|
@ -384,11 +399,13 @@
|
||||||
:text="reference"
|
:text="reference"
|
||||||
textWrap="false"
|
textWrap="false"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
variant="text"
|
||||||
|
automationText="openURL"
|
||||||
col="1"
|
col="1"
|
||||||
class="bx"
|
class="bx"
|
||||||
:text="icon.source"
|
:text="icon.source"
|
||||||
@tap="openURL($event, reference)"
|
@tap="openURL(reference)"
|
||||||
/>
|
/>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Label
|
<Label
|
||||||
|
@ -403,21 +420,19 @@
|
||||||
</TabViewItem>
|
</TabViewItem>
|
||||||
</TabView>
|
</TabView>
|
||||||
<GridLayout id="btnFabContainer" rows="*, auto" columns="*, auto">
|
<GridLayout id="btnFabContainer" rows="*, auto" columns="*, auto">
|
||||||
<Label
|
<MDFloatingActionButton
|
||||||
row="1"
|
row="1"
|
||||||
col="1"
|
col="1"
|
||||||
class="bx fab-button"
|
src="res://check"
|
||||||
:text="icon.check"
|
|
||||||
@tap="recipeTried"
|
@tap="recipeTried"
|
||||||
v-if="filterTrylater"
|
v-if="filterTrylater"
|
||||||
/>
|
/>
|
||||||
<transition name="dolly" appear>
|
<transition name="dolly" appear>
|
||||||
<Label
|
<MDFloatingActionButton
|
||||||
row="1"
|
row="1"
|
||||||
col="1"
|
col="1"
|
||||||
class="bx fab-button"
|
src="res://share"
|
||||||
:text="icon.share"
|
@tap="shareHandler"
|
||||||
@tap="shareRecipe"
|
|
||||||
v-if="!filterTrylater && showFab"
|
v-if="!filterTrylater && showFab"
|
||||||
/>
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -428,22 +443,24 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
Screen,
|
Color,
|
||||||
Utils,
|
|
||||||
ImageSource,
|
|
||||||
Device,
|
Device,
|
||||||
File,
|
File,
|
||||||
Color,
|
knownFolders,
|
||||||
|
path,
|
||||||
|
ImageSource,
|
||||||
|
Screen,
|
||||||
|
Utils,
|
||||||
} from "@nativescript/core"
|
} from "@nativescript/core"
|
||||||
import { Feedback, FeedbackType, FeedbackPosition } from "nativescript-feedback"
|
import { Feedback, FeedbackType, FeedbackPosition } from "nativescript-feedback"
|
||||||
import * as Toast from "nativescript-toast"
|
import * as Toast from "nativescript-toast"
|
||||||
import * as SocialShare from "nativescript-social-share-ns-7"
|
import * as SocialShare from "@nativescript/social-share"
|
||||||
import { setText } from "nativescript-clipboard"
|
import { setText } from "nativescript-clipboard"
|
||||||
import { Application } from "@nativescript/core"
|
import { Application } from "@nativescript/core"
|
||||||
|
import { mapActions, mapState } from "vuex"
|
||||||
import { mapState, mapActions } from "vuex"
|
|
||||||
|
|
||||||
import EditRecipe from "./EditRecipe.vue"
|
import EditRecipe from "./EditRecipe.vue"
|
||||||
|
import ShareChooser from "./modal/ShareChooser.vue"
|
||||||
|
|
||||||
let feedback = new Feedback()
|
let feedback = new Feedback()
|
||||||
|
|
||||||
|
@ -480,7 +497,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["toggleStateAction", "setCurrentComponentAction"]),
|
...mapActions(["toggleStateAction", "setCurrentComponentAction"]),
|
||||||
initializePage() {
|
onPageLoad() {
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
this.busy = false
|
this.busy = false
|
||||||
setTimeout((e) => {
|
setTimeout((e) => {
|
||||||
|
@ -488,8 +505,14 @@ export default {
|
||||||
}, 500)
|
}, 500)
|
||||||
this.yieldMultiplier = this.recipe.yield.quantity
|
this.yieldMultiplier = this.recipe.yield.quantity
|
||||||
this.showFab = true
|
this.showFab = true
|
||||||
this.toggleScreenOn(true)
|
this.keepScreenOn(true)
|
||||||
},
|
},
|
||||||
|
onPageUnload() {
|
||||||
|
feedback.hide()
|
||||||
|
this.keepScreenOn(false)
|
||||||
|
},
|
||||||
|
|
||||||
|
// HELPERS
|
||||||
niceDates(time) {
|
niceDates(time) {
|
||||||
let lastTried = new Date(time).getTime()
|
let lastTried = new Date(time).getTime()
|
||||||
let now = new Date().getTime()
|
let now = new Date().getTime()
|
||||||
|
@ -509,26 +532,15 @@ export default {
|
||||||
selectedIndexChange(args) {
|
selectedIndexChange(args) {
|
||||||
this.selectedTabIndex = args.object.selectedIndex
|
this.selectedTabIndex = args.object.selectedIndex
|
||||||
},
|
},
|
||||||
showInfo() {
|
showLastTried() {
|
||||||
feedback.show({
|
feedback.show({
|
||||||
title: `You tried this recipe ${this.niceDates(
|
title: `You tried this recipe ${this.niceDates(
|
||||||
this.recipe.lastTried
|
this.recipe.lastTried
|
||||||
)}!`,
|
)}!`,
|
||||||
titleColor: new Color(`${this.isLightMode ? "#fff" : "#111"}`),
|
titleColor: new Color(`${this.isLightMode ? "#f1f3f5" : "#212529"}`),
|
||||||
backgroundColor: new Color(
|
backgroundColor: new Color("#ff5200"),
|
||||||
`${this.isLightMode ? "#ff5200" : "#ff7043"}`
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
unLoad() {
|
|
||||||
feedback.hide()
|
|
||||||
this.toggleScreenOn(false)
|
|
||||||
},
|
|
||||||
highlight(args) {
|
|
||||||
let temp = args.object.className
|
|
||||||
args.object.className = `${temp} option-highlight`
|
|
||||||
setTimeout(() => (args.object.className = temp), 100)
|
|
||||||
},
|
|
||||||
roundedQuantity(quantity) {
|
roundedQuantity(quantity) {
|
||||||
return (
|
return (
|
||||||
Math.round(
|
Math.round(
|
||||||
|
@ -538,6 +550,32 @@ export default {
|
||||||
) / 100
|
) / 100
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
keepScreenOn(boolean) {
|
||||||
|
let activity =
|
||||||
|
Application.android.foregroundActivity ||
|
||||||
|
Application.android.startActivity
|
||||||
|
let window = activity.getWindow()
|
||||||
|
if (boolean)
|
||||||
|
window.addFlags(
|
||||||
|
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||||
|
)
|
||||||
|
else
|
||||||
|
window.clearFlags(
|
||||||
|
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||||
|
)
|
||||||
|
},
|
||||||
|
formattedTime(time) {
|
||||||
|
let t = time.split(":")
|
||||||
|
let h = parseInt(t[0])
|
||||||
|
let m = parseInt(t[1])
|
||||||
|
return h ? (m ? `${h}h ${m}m` : `${h}h`) : `${m}m`
|
||||||
|
},
|
||||||
|
isValidURL(string) {
|
||||||
|
let pattern = new RegExp("^https?|www", "ig")
|
||||||
|
return pattern.test(string)
|
||||||
|
},
|
||||||
|
|
||||||
|
// NAVIGATION HANDLERS
|
||||||
editRecipe() {
|
editRecipe() {
|
||||||
this.showFab = false
|
this.showFab = false
|
||||||
this.busy = true
|
this.busy = true
|
||||||
|
@ -554,6 +592,47 @@ export default {
|
||||||
// backstackVisible: false,
|
// backstackVisible: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// SHARE ACTION
|
||||||
|
shareHandler() {
|
||||||
|
if (this.recipe.imageSrc) {
|
||||||
|
this.$showModal(ShareChooser, {
|
||||||
|
props: {
|
||||||
|
title: "Share",
|
||||||
|
},
|
||||||
|
}).then((result) => {
|
||||||
|
switch (result) {
|
||||||
|
case "photo":
|
||||||
|
// let cacheFilePath = path.join(
|
||||||
|
// knownFolders.temp().path,
|
||||||
|
// `${this.recipe.title}.jpg`
|
||||||
|
// )
|
||||||
|
// if (!File.exists(cacheFilePath)) {
|
||||||
|
// File.fromPath(cacheFilePath).writeSync(
|
||||||
|
// File.fromPath(this.recipe.imageSrc).readSync()
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// let shareFile = new ShareFile()
|
||||||
|
// shareFile.open({
|
||||||
|
// path: cacheFilePath,
|
||||||
|
// title: "Share recipe photo using",
|
||||||
|
// })
|
||||||
|
ImageSource.fromFile(this.recipe.imageSrc).then((res) => {
|
||||||
|
SocialShare.shareImage(res, "Share recipe photo using")
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case "recipe":
|
||||||
|
this.shareRecipe()
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.shareRecipe()
|
||||||
|
}
|
||||||
|
},
|
||||||
shareRecipe() {
|
shareRecipe() {
|
||||||
let overview = `${
|
let overview = `${
|
||||||
this.recipe.title
|
this.recipe.title
|
||||||
|
@ -564,9 +643,11 @@ export default {
|
||||||
this.yieldMultiplier
|
this.yieldMultiplier
|
||||||
} ${this.recipe.yield.unit.toLowerCase()}\n\n`
|
} ${this.recipe.yield.unit.toLowerCase()}\n\n`
|
||||||
this.recipe.ingredients.forEach((e) => {
|
this.recipe.ingredients.forEach((e) => {
|
||||||
ingredients += `- ${this.roundedQuantity(e.quantity)} ${e.unit} ${
|
ingredients += `- ${
|
||||||
e.item
|
e.quantity
|
||||||
}\n`
|
? this.roundedQuantity(e.quantity) + " " + e.unit + " "
|
||||||
|
: ""
|
||||||
|
}${e.item}\n`
|
||||||
})
|
})
|
||||||
shareContent += ingredients
|
shareContent += ingredients
|
||||||
}
|
}
|
||||||
|
@ -592,15 +673,14 @@ export default {
|
||||||
shareContent += references
|
shareContent += references
|
||||||
}
|
}
|
||||||
let sharenote =
|
let sharenote =
|
||||||
"\nCreated and shared via EnRecipes.\nDownload the app on f-droid: https://www.vishnuraghav.com/"
|
"\nCreated and shared via EnRecipes.\nGet it on F-Droid."
|
||||||
|
|
||||||
shareContent += sharenote
|
shareContent += sharenote
|
||||||
|
|
||||||
SocialShare.shareText(
|
SocialShare.shareText(shareContent, "Share recipe using")
|
||||||
shareContent,
|
|
||||||
"How would you like to share this recipe?"
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// DATA HANDLERS
|
||||||
toggle(key, setDate) {
|
toggle(key, setDate) {
|
||||||
this.toggleStateAction({
|
this.toggleStateAction({
|
||||||
index: this.recipeIndex,
|
index: this.recipeIndex,
|
||||||
|
@ -624,53 +704,32 @@ export default {
|
||||||
: this.filterTrylater
|
: this.filterTrylater
|
||||||
? Toast.makeText("You tried this recipe").show()
|
? Toast.makeText("You tried this recipe").show()
|
||||||
: Toast.makeText("Removed from Try later").show()
|
: Toast.makeText("Removed from Try later").show()
|
||||||
// : Toast.makeText("You tried this recipe").show()
|
|
||||||
this.toggle("tried")
|
this.toggle("tried")
|
||||||
},
|
},
|
||||||
recipeTried() {
|
recipeTried() {
|
||||||
this.toggle("tried", true)
|
this.toggle("tried", true)
|
||||||
this.$navigateBack()
|
this.$navigateBack()
|
||||||
},
|
},
|
||||||
formattedTime(time) {
|
|
||||||
let t = time.split(":")
|
// URL ACTION
|
||||||
let h = parseInt(t[0])
|
openURL(url) {
|
||||||
let m = parseInt(t[1])
|
|
||||||
return h ? (m ? `${h}h ${m}m` : `${h}h`) : `${m}m`
|
|
||||||
},
|
|
||||||
isValidURL(string) {
|
|
||||||
let pattern = new RegExp("^https?|www", "ig")
|
|
||||||
return pattern.test(string)
|
|
||||||
},
|
|
||||||
openURL(args, url) {
|
|
||||||
// this.highlight(args)
|
|
||||||
Utils.openUrl(url)
|
Utils.openUrl(url)
|
||||||
},
|
},
|
||||||
copyURL(args, url) {
|
copyURL(url) {
|
||||||
setText(url).then((e) => {
|
setText(url).then((e) => {
|
||||||
Toast.makeText("URL Copied").show()
|
Toast.makeText("URL Copied").show()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
toggleScreenOn(boolean) {
|
|
||||||
let activity =
|
|
||||||
Application.android.foregroundActivity ||
|
|
||||||
Application.android.startActivity
|
|
||||||
let window = activity.getWindow()
|
|
||||||
if (boolean)
|
|
||||||
window.addFlags(
|
|
||||||
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
||||||
)
|
|
||||||
else
|
|
||||||
window.clearFlags(
|
|
||||||
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
|
this.recipe = this.recipes.filter((e) => e.id === this.recipeID)[0]
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.showFab = true
|
this.showFab = true
|
||||||
setTimeout((e) => this.recipe.tried && this.showInfo(), 500)
|
setTimeout(
|
||||||
|
(e) => this.recipe.tried && this.recipe.lastTried && this.showLastTried(),
|
||||||
|
500
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,26 +2,33 @@
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout class="dialogContainer" :class="appTheme">
|
<StackLayout class="dialogContainer" :class="appTheme">
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<ListView
|
<ScrollView width="100%" :height="height ? height : screenHeight - 320">
|
||||||
width="100%"
|
<StackLayout>
|
||||||
:height="height"
|
<MDButton
|
||||||
for="item in list"
|
v-for="(item, index) in list"
|
||||||
@itemTap="tapAction"
|
:key="index"
|
||||||
separatorColor="transparent"
|
class="actionItem"
|
||||||
>
|
variant="text"
|
||||||
<v-template>
|
:rippleColor="rippleColor"
|
||||||
<Label class="actionItem" :text="item" />
|
:text="item"
|
||||||
</v-template>
|
@loaded="onLabelLoaded"
|
||||||
</ListView>
|
@tap="tapAction(item)"
|
||||||
|
/>
|
||||||
|
</StackLayout>
|
||||||
|
</ScrollView>
|
||||||
<GridLayout rows="auto" columns="auto, *, auto" class="actionsContainer">
|
<GridLayout rows="auto" columns="auto, *, auto" class="actionsContainer">
|
||||||
<Label
|
<MDButton
|
||||||
|
:rippleColor="rippleColor"
|
||||||
|
variant="text"
|
||||||
v-if="action"
|
v-if="action"
|
||||||
col="0"
|
col="0"
|
||||||
class="action orkm pull-left"
|
class="action orkm pull-left"
|
||||||
:text="action"
|
:text="action"
|
||||||
@tap="$modal.close(action)"
|
@tap="$modal.close(action)"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
|
:rippleColor="rippleColor"
|
||||||
|
variant="text"
|
||||||
col="2"
|
col="2"
|
||||||
class="action orkm pull-right"
|
class="action orkm pull-right"
|
||||||
text="CANCEL"
|
text="CANCEL"
|
||||||
|
@ -33,18 +40,29 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Application } from "@nativescript/core"
|
import { Application, Screen } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "list", "height", "action"],
|
props: ["title", "list", "height", "action"],
|
||||||
computed: {
|
computed: {
|
||||||
appTheme() {
|
appTheme() {
|
||||||
return Application.systemAppearance()
|
return Application.systemAppearance()
|
||||||
},
|
},
|
||||||
|
rippleColor() {
|
||||||
|
return this.appTheme == "light"
|
||||||
|
? "rgba(134,142,150,0.2)"
|
||||||
|
: "rgba(206,212,218,0.1)"
|
||||||
|
},
|
||||||
|
screenHeight() {
|
||||||
|
return Math.round(Screen.mainScreen.heightDIPs)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tapAction({ item }) {
|
tapAction(item) {
|
||||||
this.$modal.close(item)
|
this.$modal.close(item)
|
||||||
},
|
},
|
||||||
|
onLabelLoaded(args) {
|
||||||
|
args.object.android.setGravity(16)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout class="dialogContainer" :class="isLightMode">
|
<StackLayout class="dialogContainer" :class="appTheme">
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<Label
|
<Label
|
||||||
v-if="description"
|
v-if="description"
|
||||||
|
@ -8,19 +8,19 @@
|
||||||
:text="description"
|
:text="description"
|
||||||
textWrap="true"
|
textWrap="true"
|
||||||
/>
|
/>
|
||||||
<GridLayout
|
<GridLayout rows="auto" columns="*, auto, auto" class="actionsContainer">
|
||||||
rows="auto"
|
<MDButton
|
||||||
columns="*, auto, 32, auto"
|
:rippleColor="rippleColor"
|
||||||
class="actionsContainer"
|
variant="text"
|
||||||
>
|
|
||||||
<Label
|
|
||||||
col="1"
|
col="1"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
:text="cancelButtonText"
|
:text="cancelButtonText"
|
||||||
@tap="$modal.close(false)"
|
@tap="$modal.close(false)"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
col="3"
|
:rippleColor="rippleColor"
|
||||||
|
variant="text"
|
||||||
|
col="2"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
:text="okButtonText"
|
:text="okButtonText"
|
||||||
@tap="$modal.close(true)"
|
@tap="$modal.close(true)"
|
||||||
|
@ -35,9 +35,14 @@ import { Application } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "description", "cancelButtonText", "okButtonText"],
|
props: ["title", "description", "cancelButtonText", "okButtonText"],
|
||||||
computed: {
|
computed: {
|
||||||
isLightMode() {
|
appTheme() {
|
||||||
return Application.systemAppearance()
|
return Application.systemAppearance()
|
||||||
},
|
},
|
||||||
|
rippleColor() {
|
||||||
|
return this.appTheme == "light"
|
||||||
|
? "rgba(134,142,150,0.2)"
|
||||||
|
: "rgba(206,212,218,0.1)"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout class="dialogContainer" :class="isLightMode">
|
<StackLayout class="dialogContainer" :class="appTheme">
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<StackLayout
|
<StackLayout
|
||||||
class="dialogListPicker"
|
class="dialogListPicker"
|
||||||
|
@ -13,12 +13,6 @@
|
||||||
:selectedIndex="hrIndex"
|
:selectedIndex="hrIndex"
|
||||||
@selectedIndexChange="setHrs"
|
@selectedIndexChange="setHrs"
|
||||||
></ListPicker>
|
></ListPicker>
|
||||||
<Label
|
|
||||||
verticalAlignment="center"
|
|
||||||
class="okrb"
|
|
||||||
text=":"
|
|
||||||
textWrap="false"
|
|
||||||
/>
|
|
||||||
<ListPicker
|
<ListPicker
|
||||||
ref="minPicker"
|
ref="minPicker"
|
||||||
:items="mins"
|
:items="mins"
|
||||||
|
@ -26,19 +20,19 @@
|
||||||
@selectedIndexChange="setMins"
|
@selectedIndexChange="setMins"
|
||||||
></ListPicker>
|
></ListPicker>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<GridLayout
|
<GridLayout rows="auto" columns="*, auto, auto" class="actionsContainer">
|
||||||
rows="auto"
|
<MDButton
|
||||||
columns="*, auto, 32, auto"
|
:rippleColor="rippleColor"
|
||||||
class="actionsContainer"
|
variant="text"
|
||||||
>
|
|
||||||
<Label
|
|
||||||
col="1"
|
col="1"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
text="CANCEL"
|
text="CANCEL"
|
||||||
@tap="$modal.close(false)"
|
@tap="$modal.close(false)"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
col="3"
|
:rippleColor="rippleColor"
|
||||||
|
variant="text"
|
||||||
|
col="2"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
:text="action"
|
:text="action"
|
||||||
@tap="$modal.close(selectedTime)"
|
@tap="$modal.close(selectedTime)"
|
||||||
|
@ -55,52 +49,52 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hrs: [
|
hrs: [
|
||||||
"00",
|
"0h",
|
||||||
"01",
|
"1h",
|
||||||
"02",
|
"2h",
|
||||||
"03",
|
"3h",
|
||||||
"04",
|
"4h",
|
||||||
"05",
|
"5h",
|
||||||
"06",
|
"6h",
|
||||||
"07",
|
"7h",
|
||||||
"08",
|
"8h",
|
||||||
"09",
|
"9h",
|
||||||
"10",
|
"10h",
|
||||||
"11",
|
"11h",
|
||||||
"12",
|
"12h",
|
||||||
"13",
|
"13h",
|
||||||
"14",
|
"14h",
|
||||||
"15",
|
"15h",
|
||||||
"16",
|
"16h",
|
||||||
"17",
|
"17h",
|
||||||
"18",
|
"18h",
|
||||||
"19",
|
"19h",
|
||||||
"20",
|
"20h",
|
||||||
"21",
|
"21h",
|
||||||
"22",
|
"22h",
|
||||||
"23",
|
"23h",
|
||||||
],
|
],
|
||||||
mins: [
|
mins: [
|
||||||
"00",
|
"0m",
|
||||||
"01",
|
"1m",
|
||||||
"02",
|
"2m",
|
||||||
"03",
|
"3m",
|
||||||
"04",
|
"4m",
|
||||||
"05",
|
"5m",
|
||||||
"06",
|
"6m",
|
||||||
"07",
|
"7m",
|
||||||
"08",
|
"8m",
|
||||||
"09",
|
"9m",
|
||||||
"10",
|
"10m",
|
||||||
"15",
|
"15m",
|
||||||
"20",
|
"20m",
|
||||||
"25",
|
"25m",
|
||||||
"30",
|
"30m",
|
||||||
"35",
|
"35m",
|
||||||
"40",
|
"40m",
|
||||||
"45",
|
"45m",
|
||||||
"50",
|
"50m",
|
||||||
"55",
|
"55m",
|
||||||
],
|
],
|
||||||
selectedHrs: "00",
|
selectedHrs: "00",
|
||||||
selectedMins: "00",
|
selectedMins: "00",
|
||||||
|
@ -108,24 +102,37 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hrIndex() {
|
hrIndex() {
|
||||||
return this.hrs.indexOf(this.selectedHr)
|
let hr = this.selectedHr
|
||||||
|
if (hr.charAt(0) == "0") hr = hr.slice(-1) + "h"
|
||||||
|
else hr = hr + "h"
|
||||||
|
return this.hrs.indexOf(hr)
|
||||||
},
|
},
|
||||||
minIndex() {
|
minIndex() {
|
||||||
return this.mins.indexOf(this.selectedMin)
|
let min = this.selectedMin
|
||||||
|
if (min.charAt(0) == "0") min = min.slice(-1) + "m"
|
||||||
|
else min = min + "m"
|
||||||
|
return this.mins.indexOf(min)
|
||||||
},
|
},
|
||||||
isLightMode() {
|
appTheme() {
|
||||||
return Application.systemAppearance()
|
return Application.systemAppearance()
|
||||||
},
|
},
|
||||||
|
rippleColor() {
|
||||||
|
return this.appTheme == "light"
|
||||||
|
? "rgba(134,142,150,0.2)"
|
||||||
|
: "rgba(206,212,218,0.1)"
|
||||||
|
},
|
||||||
selectedTime() {
|
selectedTime() {
|
||||||
return this.selectedHrs + ":" + this.selectedMins
|
return this.selectedHrs + ":" + this.selectedMins
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setHrs(args) {
|
setHrs(args) {
|
||||||
this.selectedHrs = this.hrs[args.object.selectedIndex]
|
let hr = "0" + this.hrs[args.object.selectedIndex]
|
||||||
|
this.selectedHrs = hr.slice(-3).slice(0, -1)
|
||||||
},
|
},
|
||||||
setMins(args) {
|
setMins(args) {
|
||||||
this.selectedMins = this.mins[args.object.selectedIndex]
|
let min = "0" + this.mins[args.object.selectedIndex]
|
||||||
|
this.selectedMins = min.slice(-3).slice(0, -1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page>
|
||||||
<StackLayout class="dialogContainer" :class="isLightMode">
|
<StackLayout class="dialogContainer" :class="appTheme">
|
||||||
<Label class="dialogTitle orkm" :text="title" />
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
<StackLayout class="dialogInput">
|
<StackLayout class="dialogInput">
|
||||||
<TextField
|
<TextField
|
||||||
@loaded="focusField"
|
@loaded="focusField"
|
||||||
:hint="hint"
|
:hint="hint ? hint : ''"
|
||||||
v-model="category"
|
v-model="category"
|
||||||
autocapitalizationType="words"
|
autocapitalizationType="words"
|
||||||
/>
|
/>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<GridLayout
|
<GridLayout rows="auto" columns="*, auto, auto" class="actionsContainer">
|
||||||
rows="auto"
|
<MDButton
|
||||||
columns="*, auto, 32, auto"
|
:rippleColor="rippleColor"
|
||||||
class="actionsContainer"
|
variant="text"
|
||||||
>
|
|
||||||
<Label
|
|
||||||
col="1"
|
col="1"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
text="CANCEL"
|
text="CANCEL"
|
||||||
@tap="$modal.close(false)"
|
@tap="$modal.close(false)"
|
||||||
/>
|
/>
|
||||||
<Label
|
<MDButton
|
||||||
col="3"
|
:rippleColor="rippleColor"
|
||||||
|
variant="text"
|
||||||
|
col="2"
|
||||||
class="action orkm"
|
class="action orkm"
|
||||||
:text="action"
|
:text="action"
|
||||||
@tap="$modal.close(category)"
|
@tap="$modal.close(category)"
|
||||||
|
@ -35,16 +35,21 @@
|
||||||
<script>
|
<script>
|
||||||
import { Application, Utils } from "@nativescript/core"
|
import { Application, Utils } from "@nativescript/core"
|
||||||
export default {
|
export default {
|
||||||
props: ["title", "hint", "action"],
|
props: ["title", "hint", "text", "action"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
category: null,
|
category: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isLightMode() {
|
appTheme() {
|
||||||
return Application.systemAppearance()
|
return Application.systemAppearance()
|
||||||
},
|
},
|
||||||
|
rippleColor() {
|
||||||
|
return this.appTheme == "light"
|
||||||
|
? "rgba(134,142,150,0.2)"
|
||||||
|
: "rgba(206,212,218,0.1)"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
focusField(args) {
|
focusField(args) {
|
||||||
|
@ -52,5 +57,10 @@ export default {
|
||||||
setTimeout((e) => Utils.ad.showSoftInput(args.object.android), 1)
|
setTimeout((e) => Utils.ad.showSoftInput(args.object.android), 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.text) {
|
||||||
|
this.category = this.text
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
49
app/components/modal/ShareChooser.vue
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<Page>
|
||||||
|
<StackLayout class="dialogContainer" :class="appTheme">
|
||||||
|
<Label class="dialogTitle orkm" :text="title" />
|
||||||
|
<GridLayout rows="auto, auto" columns="*" class="actionsContainer">
|
||||||
|
<MDButton
|
||||||
|
:rippleColor="rippleColor"
|
||||||
|
:backgroundColor="backgroundColor"
|
||||||
|
row="0"
|
||||||
|
class="actionIcon"
|
||||||
|
src="res://photo"
|
||||||
|
text="Photo"
|
||||||
|
@tap="$modal.close('photo')"
|
||||||
|
/>
|
||||||
|
<MDButton
|
||||||
|
:rippleColor="rippleColor"
|
||||||
|
:backgroundColor="backgroundColor"
|
||||||
|
row="1"
|
||||||
|
class="actionIcon"
|
||||||
|
src="res://detail"
|
||||||
|
text="Recipe"
|
||||||
|
@tap="$modal.close('recipe')"
|
||||||
|
/>
|
||||||
|
</GridLayout>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Application } from "@nativescript/core"
|
||||||
|
import { mapState } from "vuex"
|
||||||
|
export default {
|
||||||
|
props: ["title"],
|
||||||
|
computed: {
|
||||||
|
...mapState(["icon"]),
|
||||||
|
appTheme() {
|
||||||
|
return Application.systemAppearance()
|
||||||
|
},
|
||||||
|
rippleColor() {
|
||||||
|
return this.appTheme == "light"
|
||||||
|
? "rgba(134,142,150,0.2)"
|
||||||
|
: "rgba(206,212,218,0.1)"
|
||||||
|
},
|
||||||
|
backgroundColor() {
|
||||||
|
return this.appTheme == "light" ? "#fff" : "#343a40"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
18
app/main.js
|
@ -5,6 +5,24 @@ import store from "./store"
|
||||||
import RadListView from "nativescript-ui-listview/vue"
|
import RadListView from "nativescript-ui-listview/vue"
|
||||||
Vue.use(RadListView)
|
Vue.use(RadListView)
|
||||||
|
|
||||||
|
import ButtonPlugin from "@nativescript-community/ui-material-button/vue"
|
||||||
|
Vue.use(ButtonPlugin)
|
||||||
|
|
||||||
|
import ActivityIndicatorPlugin from "@nativescript-community/ui-material-activityindicator/vue"
|
||||||
|
Vue.use(ActivityIndicatorPlugin)
|
||||||
|
|
||||||
|
import RipplePlugin from "@nativescript-community/ui-material-ripple/vue"
|
||||||
|
Vue.use(RipplePlugin)
|
||||||
|
|
||||||
|
import FloatingActionButtonPlugin from "@nativescript-community/ui-material-floatingactionbutton/vue"
|
||||||
|
Vue.use(FloatingActionButtonPlugin)
|
||||||
|
|
||||||
|
import ProgressPlugin from "@nativescript-community/ui-material-progress/vue"
|
||||||
|
Vue.use(ProgressPlugin)
|
||||||
|
|
||||||
|
// import SpeedDialPlugin from "@nativescript-community/ui-material-speeddial/vue"
|
||||||
|
// Vue.use(SpeedDialPlugin)
|
||||||
|
|
||||||
Vue.registerElement(
|
Vue.registerElement(
|
||||||
"RadSideDrawer",
|
"RadSideDrawer",
|
||||||
() => require("nativescript-ui-sidedrawer").RadSideDrawer
|
() => require("nativescript-ui-sidedrawer").RadSideDrawer
|
||||||
|
|
|
@ -147,6 +147,7 @@ export default new Vuex.Store({
|
||||||
heart: "\ued36",
|
heart: "\ued36",
|
||||||
heartOutline: "\uea6c",
|
heartOutline: "\uea6c",
|
||||||
label: "\ued51",
|
label: "\ued51",
|
||||||
|
labelOutline: "\uea8b",
|
||||||
cog: "\ueca6",
|
cog: "\ueca6",
|
||||||
info: "\ued49",
|
info: "\ued49",
|
||||||
menu: "\ueac1",
|
menu: "\ueac1",
|
||||||
|
@ -165,6 +166,7 @@ export default new Vuex.Store({
|
||||||
theme: "\uecaa",
|
theme: "\uecaa",
|
||||||
link: "\ueaa0",
|
link: "\ueaa0",
|
||||||
file: "\ued02",
|
file: "\ued02",
|
||||||
|
detail: "\ue9f9",
|
||||||
user: "\uee33",
|
user: "\uee33",
|
||||||
trash: "\uee26",
|
trash: "\uee26",
|
||||||
donate: "\ueb4f",
|
donate: "\ueb4f",
|
||||||
|
@ -185,9 +187,8 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
initializeRecipes(state) {
|
initializeRecipes(state) {
|
||||||
let a = EnRecipesDB.query({ select: [] })
|
EnRecipesDB.query({ select: [] }).forEach((recipe) => {
|
||||||
a.forEach((e) => {
|
state.recipes.push(recipe)
|
||||||
state.recipes.push(e)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
initializeCategories(state) {
|
initializeCategories(state) {
|
||||||
|
|
|
@ -1,17 +1,51 @@
|
||||||
require("tns-core-modules/globals")
|
require("tns-core-modules/globals")
|
||||||
import { ImageSource, ImageAsset } from "@nativescript/core"
|
import { ImageSource } from "@nativescript/core"
|
||||||
|
var ImageCropper = require("nativescript-imagecropper").ImageCropper
|
||||||
|
|
||||||
global.onmessage = function({ data }) {
|
global.onmessage = function({ data }) {
|
||||||
|
console.log(data)
|
||||||
let imgSavedToPath = data.imgSavedToPath
|
let imgSavedToPath = data.imgSavedToPath
|
||||||
let imgAsset = new ImageAsset(data.imgFile)
|
let imgPath = data.imgPath
|
||||||
imgAsset.options = {
|
let screenWidth = data.screenWidth
|
||||||
width: 1200,
|
let toolbarTextColor = data.toolbarTextColor
|
||||||
height: 1200,
|
let toolbarColor = data.toolbarColor
|
||||||
keepAspectRatio: true,
|
|
||||||
|
ImageSource.fromFile(imgPath).then((image) => {
|
||||||
|
ImageCropper.prototype
|
||||||
|
.show(
|
||||||
|
image,
|
||||||
|
{
|
||||||
|
width: screenWidth,
|
||||||
|
height: screenWidth,
|
||||||
|
// compressionQuality: 75,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hideBottomControls: true,
|
||||||
|
toolbarTitle: "Crop photo",
|
||||||
|
statusBarColor: "#ff5200",
|
||||||
|
toolbarTextColor,
|
||||||
|
toolbarColor,
|
||||||
|
cropFrameColor: "#ff5200",
|
||||||
}
|
}
|
||||||
ImageSource.fromAsset(imgAsset).then((imgData) => {
|
)
|
||||||
if (imgData.saveToFile(imgSavedToPath, "jpg", 75)) {
|
.then((cropped) => {
|
||||||
|
if (cropped.image.saveToFile(imgSavedToPath, "jpg", 75))
|
||||||
global.postMessage("savedToFile")
|
global.postMessage("savedToFile")
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// global.onmessage = function({ data }) {
|
||||||
|
// let imgSavedToPath = data.imgSavedToPath
|
||||||
|
// let imgAsset = new ImageAsset(data.imgFile)
|
||||||
|
// imgAsset.options = {
|
||||||
|
// width: 1200,
|
||||||
|
// height: 1200,
|
||||||
|
// keepAspectRatio: true,
|
||||||
|
// }
|
||||||
|
// ImageSource.fromAsset(imgAsset).then((imgData) => {
|
||||||
|
// if (imgData.saveToFile(imgSavedToPath, "jpg", 75)) {
|
||||||
|
// global.postMessage("savedToFile")
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
2490
package-lock.json
generated
14
package.json
|
@ -9,17 +9,22 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nativescript-community/perms": "^2.1.1",
|
"@nativescript-community/perms": "^2.1.1",
|
||||||
|
"@nativescript-community/ui-material-activityindicator": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-button": "^5.1.0",
|
||||||
|
"@nativescript-community/ui-material-floatingactionbutton": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-progress": "^5.0.30",
|
||||||
|
"@nativescript-community/ui-material-ripple": "^5.0.30",
|
||||||
"@nativescript/core": "~7.0.0",
|
"@nativescript/core": "~7.0.0",
|
||||||
|
"@nativescript/imagepicker": "^1.0.0",
|
||||||
|
"@nativescript/social-share": "^2.0.1",
|
||||||
"@nativescript/theme": "^3.0.0",
|
"@nativescript/theme": "^3.0.0",
|
||||||
"@nativescript/webpack": "3.0.0",
|
|
||||||
"@nativescript/zip": "^5.0.0",
|
"@nativescript/zip": "^5.0.0",
|
||||||
"@nstudio/nativescript-checkbox": "^2.0.4",
|
"@nstudio/nativescript-checkbox": "^2.0.4",
|
||||||
"nativescript-clipboard": "^2.0.0",
|
"nativescript-clipboard": "^2.0.0",
|
||||||
"nativescript-couchbase-plugin": "^0.9.6",
|
"nativescript-couchbase-plugin": "^0.9.6",
|
||||||
"nativescript-feedback": "^2.0.0",
|
"nativescript-feedback": "^2.0.0",
|
||||||
"nativescript-mediafilepicker": "^4.0.1",
|
"nativescript-imagecropper": "^4.0.1",
|
||||||
"nativescript-plugin-filepicker": "^1.0.0",
|
"nativescript-plugin-filepicker": "^1.0.0",
|
||||||
"nativescript-social-share-ns-7": "^11.6.0",
|
|
||||||
"nativescript-toast": "^2.0.0",
|
"nativescript-toast": "^2.0.0",
|
||||||
"nativescript-ui-listview": "^9.0.4",
|
"nativescript-ui-listview": "^9.0.4",
|
||||||
"nativescript-ui-sidedrawer": "^9.0.3",
|
"nativescript-ui-sidedrawer": "^9.0.3",
|
||||||
|
@ -34,7 +39,8 @@
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"nativescript-vue-template-compiler": "^2.6.0",
|
"nativescript-vue-template-compiler": "^2.6.0",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
"vue-loader": "^15.9.1"
|
"vue-loader": "^15.9.1",
|
||||||
|
"@nativescript/webpack": "~3.0.0"
|
||||||
},
|
},
|
||||||
"main": "main"
|
"main": "main"
|
||||||
}
|
}
|
||||||
|
|