restores images, data. updated logo
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
versionCode 1
|
versionCode 2
|
||||||
versionName '1.0.0'
|
versionName '1.0.0'
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
generatedDensities = []
|
generatedDensities = []
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
<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" />
|
||||||
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
|
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:roundIcon="@drawable/ic_launcher_round" 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="adjustPan">
|
||||||
<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>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
Before Width: | Height: | Size: 550 B |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 3.6 KiB |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/ic_launcher_background.png
Executable file
After Width: | Height: | Size: 875 B |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/ic_launcher_foreground.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.1 KiB |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/icon_gray.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 9.8 KiB |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/logo_dark.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
App_Resources/Android/src/main/res/drawable-hdpi/logo_white.png
Normal file
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 461 B |
BIN
App_Resources/Android/src/main/res/drawable-ldpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 664 B |
BIN
App_Resources/Android/src/main/res/drawable-ldpi/icon_gray.png
Normal file
After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
BIN
App_Resources/Android/src/main/res/drawable-ldpi/logo_dark.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
App_Resources/Android/src/main/res/drawable-ldpi/logo_white.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 472 B |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 2.4 KiB |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/ic_launcher_background.png
Executable file
After Width: | Height: | Size: 740 B |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/ic_launcher_foreground.png
Executable file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 780 B |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/icon_gray.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.6 KiB |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/logo_dark.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
App_Resources/Android/src/main/res/drawable-mdpi/logo_white.png
Normal file
After Width: | Height: | Size: 11 KiB |
|
@ -2,10 +2,10 @@
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<!-- <solid android:color="@android:color/white" /> -->
|
<!-- <solid android:color="@android:color/white" /> -->
|
||||||
<solid android:color="#ff7043" />
|
<solid android:color="#ff5722" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<bitmap android:gravity="center" android:src="@drawable/logo" />
|
<bitmap android:gravity="center" android:src="@drawable/logo_white" />
|
||||||
</item>
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|
Before Width: | Height: | Size: 680 B |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/ic_launcher_background.png
Executable file
After Width: | Height: | Size: 1.1 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
Executable file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/icon_gray.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/logo_dark.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xhdpi/logo_white.png
Normal file
After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 861 B |
BIN
App_Resources/Android/src/main/res/drawable-xxhdpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 7.1 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxhdpi/ic_launcher_background.png
Executable file
After Width: | Height: | Size: 1.4 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
Executable file
After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxhdpi/icon_gray.png
Normal file
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 24 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxhdpi/logo_dark.png
Normal file
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 1.1 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxxhdpi/ic_launcher.png
Executable file
After Width: | Height: | Size: 9.3 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxxhdpi/ic_launcher_background.png
Executable file
After Width: | Height: | Size: 1.7 KiB |
BIN
App_Resources/Android/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 48 KiB |
61
app/app.scss
|
@ -13,8 +13,7 @@ $grayL1: #e0e0e0;
|
||||||
$grayL2: #eeeeee;
|
$grayL2: #eeeeee;
|
||||||
$grayL3: #f5f5f5;
|
$grayL3: #f5f5f5;
|
||||||
$grayL4: #fafafa;
|
$grayL4: #fafafa;
|
||||||
$orange400: #ff7043;
|
$orange: #ff5722;
|
||||||
$orange500: #ff5722;
|
|
||||||
|
|
||||||
// Global SCSS styling
|
// Global SCSS styling
|
||||||
// @see https://docs.nativescript.org/ui/styling
|
// @see https://docs.nativescript.org/ui/styling
|
||||||
|
@ -78,7 +77,7 @@ Page {
|
||||||
}
|
}
|
||||||
.fab-button {
|
.fab-button {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: $orange500;
|
background-color: $orange;
|
||||||
}
|
}
|
||||||
.option,
|
.option,
|
||||||
.icon-option {
|
.icon-option {
|
||||||
|
@ -97,13 +96,14 @@ Page {
|
||||||
}
|
}
|
||||||
.instruction {
|
.instruction {
|
||||||
border-color: $grayD4;
|
border-color: $grayD4;
|
||||||
}
|
} // prettier-ignore
|
||||||
.text-btn,
|
.text-btn,
|
||||||
.group-header,
|
.group-header,
|
||||||
.category,
|
.category,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
.selected-sd-item {
|
.selected-sd-item,
|
||||||
color: $orange500;
|
Progress {
|
||||||
|
color: $orange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ns-dark {
|
.ns-dark {
|
||||||
|
@ -130,8 +130,7 @@ Page {
|
||||||
.recipeText,
|
.recipeText,
|
||||||
.overviewItem,
|
.overviewItem,
|
||||||
.recipeItem,
|
.recipeItem,
|
||||||
.option-highlight,
|
.option-highlight {
|
||||||
.appIconContainer {
|
|
||||||
background: $grayD3;
|
background: $grayD3;
|
||||||
}
|
}
|
||||||
.sd-item,
|
.sd-item,
|
||||||
|
@ -144,13 +143,13 @@ Page {
|
||||||
}
|
}
|
||||||
.fab-button {
|
.fab-button {
|
||||||
color: #111;
|
color: #111;
|
||||||
background: $orange400;
|
background: $orange;
|
||||||
}
|
}
|
||||||
.option,
|
.option,
|
||||||
.icon-option {
|
.icon-option {
|
||||||
.bx,
|
.bx,
|
||||||
.option-info {
|
.option-info {
|
||||||
color: $grayL2;
|
color: $gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.imageHolder {
|
.imageHolder {
|
||||||
|
@ -164,12 +163,14 @@ Page {
|
||||||
.instruction {
|
.instruction {
|
||||||
border-color: $grayL4;
|
border-color: $grayL4;
|
||||||
}
|
}
|
||||||
|
// prettier-ignore
|
||||||
.text-btn,
|
.text-btn,
|
||||||
.group-header,
|
.group-header,
|
||||||
.category,
|
.category,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
.selected-sd-item {
|
.selected-sd-item,
|
||||||
color: $orange400;
|
Progress {
|
||||||
|
color: $orange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
@ -200,6 +201,10 @@ TabView {
|
||||||
margin-left: 8;
|
margin-left: 8;
|
||||||
padding: 0 8;
|
padding: 0 8;
|
||||||
}
|
}
|
||||||
|
// prettier-ignore
|
||||||
|
.progressContainer{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// ActionBar
|
// ActionBar
|
||||||
ActionBar {
|
ActionBar {
|
||||||
|
@ -260,6 +265,10 @@ ActionBar {
|
||||||
color: $gray;
|
color: $gray;
|
||||||
margin-bottom: 16;
|
margin-bottom: 16;
|
||||||
}
|
}
|
||||||
|
.logo {
|
||||||
|
width: 64;
|
||||||
|
margin-bottom: 16;
|
||||||
|
}
|
||||||
.title {
|
.title {
|
||||||
font-size: 20;
|
font-size: 20;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -280,7 +289,7 @@ RadListView {
|
||||||
}
|
}
|
||||||
.recipeItem {
|
.recipeItem {
|
||||||
margin: 8 16;
|
margin: 8 16;
|
||||||
border-radius: 6;
|
border-radius: 4;
|
||||||
.recipeInfo {
|
.recipeInfo {
|
||||||
margin: 4;
|
margin: 4;
|
||||||
.category,
|
.category,
|
||||||
|
@ -304,10 +313,10 @@ RadListView {
|
||||||
.imageHolder {
|
.imageHolder {
|
||||||
vertical-alignment: center;
|
vertical-alignment: center;
|
||||||
&.card {
|
&.card {
|
||||||
border-radius: 6 0 0 6;
|
border-radius: 4 0 0 4;
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
Image {
|
Image {
|
||||||
border-radius: 6 0 0 6;
|
border-radius: 4 0 0 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +325,7 @@ RadListView {
|
||||||
background: #c62828;
|
background: #c62828;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
height: 128;
|
height: 128;
|
||||||
border-radius: 6;
|
border-radius: 4;
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// SETTINGS
|
// SETTINGS
|
||||||
|
@ -333,22 +342,18 @@ RadListView {
|
||||||
}
|
}
|
||||||
.option-info {
|
.option-info {
|
||||||
font-size: 12;
|
font-size: 12;
|
||||||
|
line-height: 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// ABOUT
|
// ABOUT
|
||||||
.appIconContainer {
|
.appIconContainer {
|
||||||
padding: 32 0;
|
background: $orange;
|
||||||
|
padding: 16 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.appIcon {
|
.appIcon {
|
||||||
width: 56;
|
height: 128;
|
||||||
height: 56;
|
|
||||||
margin: 0 6 0 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.appName {
|
|
||||||
font-size: 24;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
@ -376,7 +381,7 @@ RadListView {
|
||||||
.overviewContainer {
|
.overviewContainer {
|
||||||
margin-top: 12;
|
margin-top: 12;
|
||||||
.overviewItem {
|
.overviewItem {
|
||||||
border-radius: 6;
|
border-radius: 4;
|
||||||
padding: 8;
|
padding: 8;
|
||||||
margin: 8;
|
margin: 8;
|
||||||
android-elevation: 1;
|
android-elevation: 1;
|
||||||
|
@ -405,7 +410,7 @@ RadListView {
|
||||||
padding-top: 4%;
|
padding-top: 4%;
|
||||||
margin: 0 0 0 8;
|
margin: 0 0 0 8;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 100;
|
border-radius: 99;
|
||||||
&.square {
|
&.square {
|
||||||
clip-path: polygon(
|
clip-path: polygon(
|
||||||
5% 0,
|
5% 0,
|
||||||
|
@ -437,7 +442,7 @@ RadListView {
|
||||||
.referenceItem {
|
.referenceItem {
|
||||||
padding: 14 16;
|
padding: 14 16;
|
||||||
margin: 8 16 8;
|
margin: 8 16 8;
|
||||||
border-radius: 6;
|
border-radius: 4;
|
||||||
font-size: 16;
|
font-size: 16;
|
||||||
.bx {
|
.bx {
|
||||||
font-size: 24;
|
font-size: 24;
|
||||||
|
@ -452,7 +457,7 @@ RadListView {
|
||||||
line-height: 6;
|
line-height: 6;
|
||||||
padding: 16;
|
padding: 16;
|
||||||
margin: 8 16 8;
|
margin: 8 16 8;
|
||||||
border-radius: 6;
|
border-radius: 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
|
@ -19,12 +19,7 @@
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
class="appIconContainer"
|
class="appIconContainer"
|
||||||
>
|
>
|
||||||
<Image src="res://icon" class="appIcon" stretch="fill" />
|
<Image src="res://logo_white" class="appIcon" stretch="aspectFit" />
|
||||||
<Label
|
|
||||||
text="EnRecipes"
|
|
||||||
verticalAlignment="center"
|
|
||||||
class="appName orkb"
|
|
||||||
/>
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout orientation="horizontal" class="option">
|
<StackLayout orientation="horizontal" class="option">
|
||||||
<Label class="bx" :text="icon.info" />
|
<Label class="bx" :text="icon.info" />
|
||||||
|
@ -98,6 +93,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
viewIsScrolled: false,
|
viewIsScrolled: false,
|
||||||
|
appTheme: "Light",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
:showDrawer="showDrawer"
|
:showDrawer="showDrawer"
|
||||||
:hijackGlobalBackEvent="hijackGlobalBackEvent"
|
:hijackGlobalBackEvent="hijackGlobalBackEvent"
|
||||||
:releaseGlobalBackEvent="releaseGlobalBackEvent"
|
:releaseGlobalBackEvent="releaseGlobalBackEvent"
|
||||||
|
:openAppSettingsPage="openAppSettingsPage"
|
||||||
/>
|
/>
|
||||||
</Frame>
|
</Frame>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
|
@ -117,6 +118,7 @@ import {
|
||||||
Utils,
|
Utils,
|
||||||
ApplicationSettings,
|
ApplicationSettings,
|
||||||
AndroidApplication,
|
AndroidApplication,
|
||||||
|
Application,
|
||||||
} from "@nativescript/core"
|
} from "@nativescript/core"
|
||||||
|
|
||||||
import Theme from "@nativescript/theme"
|
import Theme from "@nativescript/theme"
|
||||||
|
@ -286,6 +288,7 @@ export default {
|
||||||
restartApp: this.restartApp,
|
restartApp: this.restartApp,
|
||||||
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
hijackGlobalBackEvent: this.hijackGlobalBackEvent,
|
||||||
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
releaseGlobalBackEvent: this.releaseGlobalBackEvent,
|
||||||
|
openAppSettingsPage: this.openAppSettingsPage,
|
||||||
},
|
},
|
||||||
backstackVisible: false,
|
backstackVisible: false,
|
||||||
})
|
})
|
||||||
|
@ -326,6 +329,18 @@ export default {
|
||||||
)
|
)
|
||||||
android.os.Process.killProcess(android.os.Process.myPid())
|
android.os.Process.killProcess(android.os.Process.myPid())
|
||||||
},
|
},
|
||||||
|
openAppSettingsPage() {
|
||||||
|
const intent = new android.content.Intent(
|
||||||
|
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||||
|
)
|
||||||
|
intent.addCategory(android.content.Intent.CATEGORY_DEFAULT)
|
||||||
|
intent.setData(
|
||||||
|
android.net.Uri.parse(
|
||||||
|
"package:" + Application.android.context.getPackageName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Application.android.foregroundActivity.startActivity(intent)
|
||||||
|
},
|
||||||
showDrawer() {
|
showDrawer() {
|
||||||
this.$refs.drawer.nativeView.showDrawer()
|
this.$refs.drawer.nativeView.showDrawer()
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
scrollBarIndicatorVisible="false"
|
scrollBarIndicatorVisible="false"
|
||||||
>
|
>
|
||||||
<StackLayout width="100%" padding="0 0 128">
|
<StackLayout width="100%" padding="0 0 128">
|
||||||
<!-- Image and camera btn -->
|
|
||||||
<AbsoluteLayout>
|
<AbsoluteLayout>
|
||||||
<StackLayout
|
<StackLayout
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -65,7 +64,6 @@
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</AbsoluteLayout>
|
</AbsoluteLayout>
|
||||||
|
|
||||||
<!-- Primary information -->
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
<AbsoluteLayout class="inputField">
|
<AbsoluteLayout class="inputField">
|
||||||
<TextField
|
<TextField
|
||||||
|
@ -115,7 +113,6 @@
|
||||||
<StackLayout class="hr" margin="24 16"></StackLayout>
|
<StackLayout class="hr" margin="24 16"></StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
<!-- Ingredients section -->
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
<Label text="Ingredients" class="sectionTitle" />
|
<Label text="Ingredients" class="sectionTitle" />
|
||||||
<GridLayout
|
<GridLayout
|
||||||
|
@ -161,7 +158,6 @@
|
||||||
<StackLayout class="hr" margin="24 16"></StackLayout>
|
<StackLayout class="hr" margin="24 16"></StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
<!-- Instructions section -->
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
<Label text="Instructions" class="sectionTitle" />
|
<Label text="Instructions" class="sectionTitle" />
|
||||||
<GridLayout
|
<GridLayout
|
||||||
|
@ -191,7 +187,6 @@
|
||||||
<StackLayout class="hr" margin="24 16"></StackLayout>
|
<StackLayout class="hr" margin="24 16"></StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
<!-- Notes section -->
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
<Label text="Notes" class="sectionTitle" />
|
<Label text="Notes" class="sectionTitle" />
|
||||||
<GridLayout
|
<GridLayout
|
||||||
|
@ -217,7 +212,6 @@
|
||||||
<StackLayout class="hr" margin="24 16"></StackLayout>
|
<StackLayout class="hr" margin="24 16"></StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
<!-- References section -->
|
|
||||||
<StackLayout margin="0 16">
|
<StackLayout margin="0 16">
|
||||||
<Label text="References" class="sectionTitle" />
|
<Label text="References" class="sectionTitle" />
|
||||||
<GridLayout
|
<GridLayout
|
||||||
|
@ -265,6 +259,7 @@ import {
|
||||||
knownFolders,
|
knownFolders,
|
||||||
Utils,
|
Utils,
|
||||||
File,
|
File,
|
||||||
|
ApplicationSettings,
|
||||||
} from "@nativescript/core"
|
} from "@nativescript/core"
|
||||||
import { Mediafilepicker } from "nativescript-mediafilepicker"
|
import { Mediafilepicker } from "nativescript-mediafilepicker"
|
||||||
|
|
||||||
|
@ -276,10 +271,11 @@ 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 { create } from "domain"
|
import * as Permissions from "@nativescript-community/perms"
|
||||||
|
import * as Toast from "nativescript-toast"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["recipeIndex", "recipeID", "selectedCategory"],
|
props: ["recipeIndex", "recipeID", "selectedCategory", "openAppSettingsPage"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: "New recipe",
|
title: "New recipe",
|
||||||
|
@ -519,14 +515,64 @@ export default {
|
||||||
}).then((action) => {
|
}).then((action) => {
|
||||||
this.blockModal = false
|
this.blockModal = false
|
||||||
if (action) {
|
if (action) {
|
||||||
this.imagePicker()
|
this.permissionCheck(
|
||||||
|
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.imagePicker()
|
this.permissionCheck(
|
||||||
|
this.imagePickerPermissionConfirmation,
|
||||||
|
this.imagePicker
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
imagePickerPermissionConfirmation() {
|
||||||
|
return this.$showModal(ConfirmDialog, {
|
||||||
|
props: {
|
||||||
|
title: "Grant permission",
|
||||||
|
description:
|
||||||
|
"EnRecipes requires storage and camera permission in order to set recipe photo.",
|
||||||
|
cancelButtonText: "NOT NOW",
|
||||||
|
okButtonText: "CONTINUE",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
permissionCheck(confirmation, action) {
|
||||||
|
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
||||||
|
confirmation().then((e) => {
|
||||||
|
if (e) {
|
||||||
|
Permissions.request("camera").then((res) => {
|
||||||
|
let status = res[Object.keys(res)[0]]
|
||||||
|
if (status === "authorized") action()
|
||||||
|
if (status === "never_ask_again")
|
||||||
|
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
||||||
|
if (status === "denied")
|
||||||
|
Toast.makeText("Permission denied").show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Permissions.check("camera").then((res) => {
|
||||||
|
if (res[0] !== "authorized") {
|
||||||
|
confirmation().then((e) => {
|
||||||
|
e && this.openAppSettingsPage()
|
||||||
|
})
|
||||||
|
} 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() {
|
||||||
|
@ -541,6 +587,7 @@ export default {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
mediafilepicker.on("getFiles", (image) => {
|
mediafilepicker.on("getFiles", (image) => {
|
||||||
|
ApplicationSettings.setBoolean("storagePermissionAsked", true)
|
||||||
vm.recipeContent.imageSrc = image.object.get("results")[0].file
|
vm.recipeContent.imageSrc = image.object.get("results")[0].file
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -611,7 +658,10 @@ export default {
|
||||||
},
|
},
|
||||||
imageSaveOperation() {
|
imageSaveOperation() {
|
||||||
let imgSavedToPath = path.join(
|
let imgSavedToPath = path.join(
|
||||||
knownFolders.documents().getFolder("EnRecipes").path,
|
knownFolders
|
||||||
|
.documents()
|
||||||
|
.getFolder("EnRecipes")
|
||||||
|
.getFolder("Images").path,
|
||||||
`${this.getRandomID()}.jpg`
|
`${this.getRandomID()}.jpg`
|
||||||
)
|
)
|
||||||
let workerService = new WorkerService()
|
let workerService = new WorkerService()
|
||||||
|
|
|
@ -76,6 +76,8 @@
|
||||||
v-if="recipe.imageSrc"
|
v-if="recipe.imageSrc"
|
||||||
:src="recipe.imageSrc"
|
:src="recipe.imageSrc"
|
||||||
stretch="aspectFill"
|
stretch="aspectFill"
|
||||||
|
decodeWidth="112"
|
||||||
|
decodeHeight="112"
|
||||||
/>
|
/>
|
||||||
<Label
|
<Label
|
||||||
row="0"
|
row="0"
|
||||||
|
@ -118,7 +120,7 @@
|
||||||
class="noResult"
|
class="noResult"
|
||||||
v-if="!recipes.length && !filterFavorites && !filterTrylater"
|
v-if="!recipes.length && !filterFavorites && !filterTrylater"
|
||||||
>
|
>
|
||||||
<Label class="bx icon" :text="icon.plusCircle" textWrap="true" />
|
<Image class="logo" src="res://icon_gray" stretch="aspectFit" />
|
||||||
<Label
|
<Label
|
||||||
class="title orkm"
|
class="title orkm"
|
||||||
text="Start adding your recipes!"
|
text="Start adding your recipes!"
|
||||||
|
@ -199,10 +201,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { Utils, AndroidApplication } from "@nativescript/core"
|
||||||
Utils,
|
|
||||||
AndroidApplication,
|
|
||||||
} from "@nativescript/core"
|
|
||||||
|
|
||||||
import EditRecipe from "./EditRecipe.vue"
|
import EditRecipe from "./EditRecipe.vue"
|
||||||
import ViewRecipe from "./ViewRecipe.vue"
|
import ViewRecipe from "./ViewRecipe.vue"
|
||||||
|
@ -218,6 +217,7 @@ export default {
|
||||||
"showDrawer",
|
"showDrawer",
|
||||||
"hijackGlobalBackEvent",
|
"hijackGlobalBackEvent",
|
||||||
"releaseGlobalBackEvent",
|
"releaseGlobalBackEvent",
|
||||||
|
"openAppSettingsPage",
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
EditRecipe,
|
EditRecipe,
|
||||||
|
@ -434,6 +434,7 @@ export default {
|
||||||
// },
|
// },
|
||||||
props: {
|
props: {
|
||||||
selectedCategory: this.selectedCategory,
|
selectedCategory: this.selectedCategory,
|
||||||
|
openAppSettingsPage: this.openAppSettingsPage,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,23 +22,46 @@
|
||||||
>
|
>
|
||||||
<Label verticalAlignment="center" class="bx" :text="icon.theme" />
|
<Label verticalAlignment="center" class="bx" :text="icon.theme" />
|
||||||
<StackLayout>
|
<StackLayout>
|
||||||
<Label text="Theme" class="option-title" />
|
<Label text="Theme" />
|
||||||
<Label :text="appTheme" class="option-info" textWrap="true" />
|
<Label :text="appTheme" class="option-info" textWrap="true" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout class="hr m-10"></StackLayout>
|
<StackLayout class="hr m-10"></StackLayout>
|
||||||
<Label text="Backup/Restore" class="group-header" />
|
<Label text="Database" class="group-header" />
|
||||||
<StackLayout orientation="horizontal" class="option" @tap="backupCheck">
|
<StackLayout orientation="horizontal" class="option" @tap="backupCheck">
|
||||||
<Label class="bx" :text="icon.save" />
|
<Label class="bx" :text="icon.export" />
|
||||||
<Label text="Backup data" />
|
<StackLayout>
|
||||||
|
<Label text="Export a full backup" />
|
||||||
|
<GridLayout
|
||||||
|
class="progressContainer"
|
||||||
|
v-if="backupInProgress"
|
||||||
|
columns="*, 64"
|
||||||
|
>
|
||||||
|
<Progress col="0" :value="backupProgress" />
|
||||||
|
<Label col="1" :text="` ${backupProgress}%`" />
|
||||||
|
</GridLayout>
|
||||||
|
<Label
|
||||||
|
v-else
|
||||||
|
text="Generates a zip file that contains all your data. This file can be imported back."
|
||||||
|
class="option-info"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<StackLayout
|
<StackLayout
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
class="option"
|
class="option"
|
||||||
@tap="restoreCheck"
|
@tap="restoreCheck"
|
||||||
>
|
>
|
||||||
<Label class="bx" :text="icon.restore" />
|
<Label class="bx" :text="icon.import" />
|
||||||
<Label text="Restore data" />
|
<StackLayout>
|
||||||
|
<Label text="Import from backup" />
|
||||||
|
<Label
|
||||||
|
text="Supports full backups exported by this app."
|
||||||
|
class="option-info"
|
||||||
|
textWrap="true"
|
||||||
|
/>
|
||||||
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -64,7 +87,6 @@ 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 { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
const recipesDB = new Couchbase("EnRecipes")
|
|
||||||
import { mapState, mapActions } from "vuex"
|
import { mapState, mapActions } from "vuex"
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
@ -73,11 +95,14 @@ export default {
|
||||||
"restartApp",
|
"restartApp",
|
||||||
"hijackGlobalBackEvent",
|
"hijackGlobalBackEvent",
|
||||||
"releaseGlobalBackEvent",
|
"releaseGlobalBackEvent",
|
||||||
|
"openAppSettingsPage",
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
viewIsScrolled: false,
|
viewIsScrolled: false,
|
||||||
appTheme: "Light",
|
appTheme: "Light",
|
||||||
|
backupProgress: 0,
|
||||||
|
backupInProgress: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -90,7 +115,12 @@ export default {
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(["setCurrentComponentAction"]),
|
...mapActions([
|
||||||
|
"setCurrentComponentAction",
|
||||||
|
"importCategoriesAction",
|
||||||
|
"importYieldUnitsAction",
|
||||||
|
"importRecipesAction",
|
||||||
|
]),
|
||||||
initializePage() {
|
initializePage() {
|
||||||
this.setCurrentComponentAction("Settings")
|
this.setCurrentComponentAction("Settings")
|
||||||
this.releaseGlobalBackEvent()
|
this.releaseGlobalBackEvent()
|
||||||
|
@ -112,9 +142,9 @@ export default {
|
||||||
if (action && action !== "Cancel" && this.appTheme !== action) {
|
if (action && action !== "Cancel" && this.appTheme !== action) {
|
||||||
this.$showModal(ConfirmDialog, {
|
this.$showModal(ConfirmDialog, {
|
||||||
props: {
|
props: {
|
||||||
title: "App Reload Required",
|
title: "Reload required",
|
||||||
description:
|
description:
|
||||||
"The app needs to be reloaded for the theme change to take effect.",
|
"EnRecipes needs to be reloaded for the theme change to take effect.",
|
||||||
cancelButtonText: "CANCEL",
|
cancelButtonText: "CANCEL",
|
||||||
okButtonText: "RELOAD",
|
okButtonText: "RELOAD",
|
||||||
},
|
},
|
||||||
|
@ -130,26 +160,22 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
writeFile(file, data) {
|
writeFile(file, data) {
|
||||||
file
|
file.writeText(JSON.stringify(data))
|
||||||
.writeText(JSON.stringify(data))
|
|
||||||
.then((res) => {
|
|
||||||
file.readText().then((res) => {
|
|
||||||
// console.log("Data: ", res)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
BackupDataFiles(option) {
|
BackupDataFiles(option) {
|
||||||
const folder = path.join(knownFolders.documents().path, "EnRecipes")
|
const folder = path.join(knownFolders.documents().path, "EnRecipes")
|
||||||
const EnRecipesFile = File.fromPath(path.join(folder, "EnRecipes.json"))
|
const EnRecipesFile = File.fromPath(path.join(folder, "EnRecipes.json"))
|
||||||
const userCategoriesFile = File.fromPath(
|
let userCategoriesFile, userYieldUnitsFile
|
||||||
path.join(folder, "userCategories.json")
|
if (this.userCategories.length) {
|
||||||
)
|
userCategoriesFile = File.fromPath(
|
||||||
const userYieldUnitsFile = File.fromPath(
|
path.join(folder, "userCategories.json")
|
||||||
path.join(folder, "userYieldUnits.json")
|
)
|
||||||
)
|
}
|
||||||
|
if (this.userYieldUnits.length) {
|
||||||
|
userYieldUnitsFile = File.fromPath(
|
||||||
|
path.join(folder, "userYieldUnits.json")
|
||||||
|
)
|
||||||
|
}
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case "create":
|
case "create":
|
||||||
this.writeFile(EnRecipesFile, this.recipes)
|
this.writeFile(EnRecipesFile, this.recipes)
|
||||||
|
@ -199,28 +225,34 @@ export default {
|
||||||
sdDownloadPath,
|
sdDownloadPath,
|
||||||
`EnRecipes-Backup_${formattedDate}.zip`
|
`EnRecipes-Backup_${formattedDate}.zip`
|
||||||
)
|
)
|
||||||
|
this.backupInProgress = true
|
||||||
Zip.zip({
|
Zip.zip({
|
||||||
directory: fromPath,
|
directory: fromPath,
|
||||||
archive: destPath,
|
archive: destPath,
|
||||||
|
onProgress: (progress) => {
|
||||||
|
this.backupProgress = progress
|
||||||
|
if (progress == 100) {
|
||||||
|
setTimeout((e) => {
|
||||||
|
this.backupInProgress = false
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).then((success) => {
|
||||||
|
Toast.makeText(
|
||||||
|
"Backup file successfully saved to Downloads",
|
||||||
|
"long"
|
||||||
|
).show()
|
||||||
|
this.BackupDataFiles("delete")
|
||||||
})
|
})
|
||||||
.then((success) => {
|
|
||||||
Toast.makeText(
|
|
||||||
"Backup file successfully saved to Downloads",
|
|
||||||
"long"
|
|
||||||
).show()
|
|
||||||
console.log("success:" + success)
|
|
||||||
this.BackupDataFiles("delete")
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
backupCheck(args) {
|
backupCheck(args) {
|
||||||
let btn = args.object
|
let btn = args.object
|
||||||
this.highlight(args)
|
this.highlight(args)
|
||||||
|
|
||||||
if (!this.recipes.length) {
|
if (!this.recipes.length) {
|
||||||
Toast.makeText("To perform a backup, add at least one recipe").show()
|
Toast.makeText(
|
||||||
|
"Add at least one recipe to perform a backup",
|
||||||
|
"long"
|
||||||
|
).show()
|
||||||
} else {
|
} else {
|
||||||
this.permissionCheck(this.backupPermissionConfirmation, this.backupData)
|
this.permissionCheck(this.backupPermissionConfirmation, this.backupData)
|
||||||
}
|
}
|
||||||
|
@ -237,7 +269,6 @@ export default {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
restoreData() {},
|
|
||||||
restoreCheck(args) {
|
restoreCheck(args) {
|
||||||
let btn = args.object
|
let btn = args.object
|
||||||
this.highlight(args)
|
this.highlight(args)
|
||||||
|
@ -258,58 +289,77 @@ export default {
|
||||||
let zipPath = result
|
let zipPath = result
|
||||||
let dest = knownFolders.documents().path
|
let dest = knownFolders.documents().path
|
||||||
this.validateZipContent(zipPath)
|
this.validateZipContent(zipPath)
|
||||||
// Zip.unzip({
|
})
|
||||||
// archive: zipPath,
|
},
|
||||||
// directory: dest,
|
importDataToDB(data, db, zipPath) {
|
||||||
// overwrite: true,
|
switch (db) {
|
||||||
// })
|
case "EnRecipesDB":
|
||||||
// .then((success) => {
|
this.copyImages(zipPath)
|
||||||
// this.restoreDataInDB()
|
this.importRecipesAction(data)
|
||||||
// Toast.makeText("Restore successful!").show()
|
break
|
||||||
// })
|
case "userCategoriesDB":
|
||||||
// .catch((err) => {
|
this.importCategoriesAction(data)
|
||||||
// console.log(err)
|
break
|
||||||
// })
|
case "userYieldUnitsDB":
|
||||||
|
this.importYieldUnitsAction(data)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isImportedDataValid(file) {
|
||||||
|
file.forEach((file, i) => {
|
||||||
|
if (File.exists(file.path)) {
|
||||||
|
File.fromPath(file.path)
|
||||||
|
.readText()
|
||||||
|
.then((data) => {
|
||||||
|
Array.isArray(JSON.parse(data)) &&
|
||||||
|
this.importDataToDB(JSON.parse(data), file.db, file.zipPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
validateZipContent(zipPath) {
|
validateZipContent(zipPath) {
|
||||||
Zip.unzip({
|
Zip.unzip({
|
||||||
archive: zipPath,
|
archive: zipPath,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
}).then((success) => {
|
}).then((extractedFolderPath) => {
|
||||||
let cacheFolderPath = success + "/EnRecipes"
|
let cacheFolderPath = extractedFolderPath + "/EnRecipes"
|
||||||
const EnRecipesFilePath = cacheFolderPath + "/EnRecipes.json"
|
const EnRecipesFilePath = cacheFolderPath + "/EnRecipes.json"
|
||||||
const userCategoriesFilePath = cacheFolderPath + "/userCategories.json"
|
const userCategoriesFilePath = cacheFolderPath + "/userCategories.json"
|
||||||
const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json"
|
const userYieldUnitsFilePath = cacheFolderPath + "/userYieldUnits.json"
|
||||||
if (
|
if (Folder.exists(cacheFolderPath)) {
|
||||||
Folder.exists(cacheFolderPath) &&
|
this.isImportedDataValid([
|
||||||
File.exists(EnRecipesFilePath) &&
|
{
|
||||||
File.exists(userCategoriesFilePath) &&
|
zipPath,
|
||||||
File.exists(userCategoriesFilePath)
|
path: EnRecipesFilePath,
|
||||||
) {
|
db: "EnRecipesDB",
|
||||||
console.log("Zip intact")
|
},
|
||||||
// Check if EnRecipes.json is of type array
|
{ zipPath, path: userCategoriesFilePath, db: "userCategoriesDB" },
|
||||||
File.fromPath(EnRecipesFilePath)
|
{ zipPath, path: userYieldUnitsFilePath, db: "userYieldUnitsDB" },
|
||||||
.readText()
|
])
|
||||||
.then((data) => {
|
|
||||||
let EnRecipesData = JSON.parse(data)
|
|
||||||
console.log(Array.isArray(EnRecipesData))
|
|
||||||
EnRecipesData.forEach(recipe => {
|
|
||||||
|
|
||||||
})
|
|
||||||
console.log(EnRecipesData)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Folder.fromPath(success).remove()
|
Folder.fromPath(extractedFolderPath).remove()
|
||||||
console.log("Zip modified externally or incorrect file")
|
Toast.makeText(
|
||||||
|
"Zip modified externally or incorrect file",
|
||||||
|
"long"
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
if (Folder.exists(cacheFolderPath + "/Images")) {
|
||||||
|
this.copyImages(cacheFolderPath + "/Images")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
restoreDataInDB() {
|
copyImages(sourcePath) {
|
||||||
// recipesDB.android
|
let dest = knownFolders.documents().path
|
||||||
// recipesDB.android.destroyDatabase()
|
Zip.unzip({
|
||||||
|
archive: sourcePath,
|
||||||
|
directory: dest,
|
||||||
|
overwrite: true,
|
||||||
|
}).then((res) => {
|
||||||
|
Toast.makeText("Import successful!", "long").show()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
permissionCheck(confirmation, action) {
|
permissionCheck(confirmation, action) {
|
||||||
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
if (!ApplicationSettings.getBoolean("storagePermissionAsked", false)) {
|
||||||
confirmation().then((e) => {
|
confirmation().then((e) => {
|
||||||
|
@ -334,18 +384,6 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openAppSettingsPage() {
|
|
||||||
const intent = new android.content.Intent(
|
|
||||||
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
|
||||||
)
|
|
||||||
intent.addCategory(android.content.Intent.CATEGORY_DEFAULT)
|
|
||||||
intent.setData(
|
|
||||||
android.net.Uri.parse(
|
|
||||||
"package:" + Application.android.context.getPackageName()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Application.android.foregroundActivity.startActivity(intent)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
|
this.appTheme = ApplicationSettings.getString("appTheme", "Light")
|
||||||
|
|
|
@ -474,7 +474,6 @@ export default {
|
||||||
: 1
|
: 1
|
||||||
},
|
},
|
||||||
isLightMode() {
|
isLightMode() {
|
||||||
console.log(Application.systemAppearance())
|
|
||||||
return Application.systemAppearance() === "light"
|
return Application.systemAppearance() === "light"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -555,9 +554,7 @@ export default {
|
||||||
shareRecipe() {
|
shareRecipe() {
|
||||||
let overview = `${
|
let overview = `${
|
||||||
this.recipe.title
|
this.recipe.title
|
||||||
}\n\nTime required: ${this.formattedTime(
|
}\n\nTime required: ${this.formattedTime(this.recipe.timeRequired)}\n`
|
||||||
this.recipe.timeRequired
|
|
||||||
)}\n`
|
|
||||||
let shareContent = overview
|
let shareContent = overview
|
||||||
if (this.recipe.ingredients.length) {
|
if (this.recipe.ingredients.length) {
|
||||||
let ingredients = `\n\nIngredients for ${
|
let ingredients = `\n\nIngredients for ${
|
||||||
|
|
89
app/store.js
|
@ -2,7 +2,7 @@ import Vue from "vue"
|
||||||
import Vuex from "vuex"
|
import Vuex from "vuex"
|
||||||
import { Couchbase } from "nativescript-couchbase-plugin"
|
import { Couchbase } from "nativescript-couchbase-plugin"
|
||||||
import { getFileAccess } from "@nativescript/core"
|
import { getFileAccess } from "@nativescript/core"
|
||||||
const recipesDB = new Couchbase("EnRecipes")
|
const EnRecipesDB = new Couchbase("EnRecipes")
|
||||||
const userCategoriesDB = new Couchbase("userCategories")
|
const userCategoriesDB = new Couchbase("userCategories")
|
||||||
const userYieldUnitsDB = new Couchbase("userYieldUnits")
|
const userYieldUnitsDB = new Couchbase("userYieldUnits")
|
||||||
|
|
||||||
|
@ -163,7 +163,6 @@ export default new Vuex.Store({
|
||||||
share: "\uedf3",
|
share: "\uedf3",
|
||||||
edit: "\uedba",
|
edit: "\uedba",
|
||||||
theme: "\uecaa",
|
theme: "\uecaa",
|
||||||
restore: "\uea72",
|
|
||||||
link: "\ueaa0",
|
link: "\ueaa0",
|
||||||
file: "\ued02",
|
file: "\ued02",
|
||||||
user: "\uee33",
|
user: "\uee33",
|
||||||
|
@ -179,12 +178,14 @@ export default new Vuex.Store({
|
||||||
item: "\ue99d",
|
item: "\ue99d",
|
||||||
step: "\ue948",
|
step: "\ue948",
|
||||||
source: "\ueaa0",
|
source: "\ueaa0",
|
||||||
|
export: "\ued07",
|
||||||
|
import: "\ued0c",
|
||||||
},
|
},
|
||||||
currentComponent: "EnRecipes",
|
currentComponent: "EnRecipes",
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
initializeRecipes(state) {
|
initializeRecipes(state) {
|
||||||
let a = recipesDB.query({ select: [] })
|
let a = EnRecipesDB.query({ select: [] })
|
||||||
a.forEach((e) => {
|
a.forEach((e) => {
|
||||||
state.recipes.push(e)
|
state.recipes.push(e)
|
||||||
})
|
})
|
||||||
|
@ -228,7 +229,45 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
addRecipe(state, { id, recipe }) {
|
addRecipe(state, { id, recipe }) {
|
||||||
state.recipes.push(recipe)
|
state.recipes.push(recipe)
|
||||||
recipesDB.createDocument(recipe, id)
|
EnRecipesDB.createDocument(recipe, id)
|
||||||
|
},
|
||||||
|
importRecipes(state, recipes) {
|
||||||
|
console.log("hello")
|
||||||
|
let localRecipesIDs, partition
|
||||||
|
if (state.recipes.length) {
|
||||||
|
localRecipesIDs = state.recipes.map((e) => e.id)
|
||||||
|
partition = recipes.reduce(
|
||||||
|
(result, recipe, i) => {
|
||||||
|
localRecipesIDs.indexOf(recipe.id) < 0
|
||||||
|
? result[0].push(recipe) // create candidates
|
||||||
|
: result[1].push(recipe) // update candidates
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
[[], []]
|
||||||
|
)
|
||||||
|
if (partition[0].length) createDocuments(partition[0])
|
||||||
|
if (partition[1].length) updateDocuments(partition[1])
|
||||||
|
} else {
|
||||||
|
createDocuments(recipes)
|
||||||
|
}
|
||||||
|
function createDocuments(data) {
|
||||||
|
console.log("creating")
|
||||||
|
state.recipes = [...state.recipes, ...data]
|
||||||
|
data.forEach((recipe) => {
|
||||||
|
EnRecipesDB.createDocument(recipe, recipe.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function updateDocuments(data) {
|
||||||
|
console.log("updating")
|
||||||
|
data.forEach((recipe) => {
|
||||||
|
let recipeIndex = state.recipes
|
||||||
|
.map((e, i) => (e.id === recipe.id ? i : -1))
|
||||||
|
.filter((e) => e >= 0)[0]
|
||||||
|
console.log(recipeIndex)
|
||||||
|
Object.assign(state.recipes[recipeIndex], recipe)
|
||||||
|
EnRecipesDB.updateDocument(recipe.id, recipe)
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
addCategory(state, category) {
|
addCategory(state, category) {
|
||||||
let lowercase = state.categories.map((e) => e.toLowerCase())
|
let lowercase = state.categories.map((e) => e.toLowerCase())
|
||||||
|
@ -241,33 +280,48 @@ export default new Vuex.Store({
|
||||||
state.categories.sort()
|
state.categories.sort()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addYieldUnit(state, unit) {
|
importCategories(state, categories) {
|
||||||
|
state.userCategories = new Set([...state.userCategories, ...categories])
|
||||||
|
userCategoriesDB.updateDocument("userCategories", {
|
||||||
|
userCategories: [...state.userCategories],
|
||||||
|
})
|
||||||
|
state.categories = [...defaultCategories, ...state.userCategories]
|
||||||
|
state.categories.sort()
|
||||||
|
},
|
||||||
|
addYieldUnit(state, yieldUnit) {
|
||||||
let lowercase = state.yieldUnits.map((e) => e.toLowerCase())
|
let lowercase = state.yieldUnits.map((e) => e.toLowerCase())
|
||||||
if (lowercase.indexOf(unit.toLowerCase()) == -1) {
|
if (lowercase.indexOf(yieldUnit.toLowerCase()) == -1) {
|
||||||
state.userYieldUnits.push(unit)
|
state.userYieldUnits.push(yieldUnit)
|
||||||
userYieldUnitsDB.updateDocument("userYieldUnits", {
|
userYieldUnitsDB.updateDocument("userYieldUnits", {
|
||||||
userYieldUnits: [...state.userYieldUnits],
|
userYieldUnits: [...state.userYieldUnits],
|
||||||
})
|
})
|
||||||
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
|
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
importYieldUnits(state, yieldUnits) {
|
||||||
|
state.userYieldUnits = new Set([...state.userYieldUnits, ...yieldUnits])
|
||||||
|
userYieldUnitsDB.updateDocument("userYieldUnits", {
|
||||||
|
userYieldUnits: [...state.userYieldUnits],
|
||||||
|
})
|
||||||
|
state.yieldUnits = [...defaultYieldUnits, ...state.userYieldUnits]
|
||||||
|
},
|
||||||
overwriteRecipe(state, { index, id, recipe }) {
|
overwriteRecipe(state, { index, id, recipe }) {
|
||||||
Object.assign(state.recipes[index], recipe)
|
Object.assign(state.recipes[index], recipe)
|
||||||
recipesDB.updateDocument(id, recipe)
|
EnRecipesDB.updateDocument(id, recipe)
|
||||||
},
|
},
|
||||||
deleteRecipe(state, { index, id }) {
|
deleteRecipe(state, { index, id }) {
|
||||||
getFileAccess().deleteFile(state.recipes[index].imageSrc)
|
getFileAccess().deleteFile(state.recipes[index].imageSrc)
|
||||||
state.recipes.splice(index, 1)
|
state.recipes.splice(index, 1)
|
||||||
recipesDB.deleteDocument(id)
|
EnRecipesDB.deleteDocument(id)
|
||||||
},
|
},
|
||||||
toggleState(state, { index, id, recipe, key, setDate }) {
|
toggleState(state, { index, id, recipe, key, setDate }) {
|
||||||
state.recipes[index][key] = !state.recipes[index][key]
|
state.recipes[index][key] = !state.recipes[index][key]
|
||||||
if (setDate) state.recipes[index].lastTried = new Date()
|
if (setDate) state.recipes[index].lastTried = new Date()
|
||||||
recipesDB.updateDocument(id, recipe)
|
EnRecipesDB.updateDocument(id, recipe)
|
||||||
},
|
},
|
||||||
setLastTriedDate(state, index) {
|
setLastTriedDate(state, index) {
|
||||||
state.recipes[index].lastTried = new Date()
|
state.recipes[index].lastTried = new Date()
|
||||||
recipesDB.updateDocument(state.recipes[index].id, state.recipes[index])
|
EnRecipesDB.updateDocument(state.recipes[index].id, state.recipes[index])
|
||||||
},
|
},
|
||||||
setCurrentComponent(state, comp) {
|
setCurrentComponent(state, comp) {
|
||||||
state.currentComponent = comp
|
state.currentComponent = comp
|
||||||
|
@ -285,8 +339,8 @@ export default new Vuex.Store({
|
||||||
state.recipes.forEach((e, i) => {
|
state.recipes.forEach((e, i) => {
|
||||||
if (e.category == current) {
|
if (e.category == current) {
|
||||||
state.recipes[i].category = updated
|
state.recipes[i].category = updated
|
||||||
recipesDB.inBatch(() => {
|
EnRecipesDB.inBatch(() => {
|
||||||
recipesDB.updateDocument(state.recipes[i].id, state.recipes[i])
|
EnRecipesDB.updateDocument(state.recipes[i].id, state.recipes[i])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -305,12 +359,21 @@ export default new Vuex.Store({
|
||||||
addRecipeAction({ commit }, recipe) {
|
addRecipeAction({ commit }, recipe) {
|
||||||
commit("addRecipe", recipe)
|
commit("addRecipe", recipe)
|
||||||
},
|
},
|
||||||
|
importRecipesAction({ commit }, recipes) {
|
||||||
|
commit("importRecipes", recipes)
|
||||||
|
},
|
||||||
addCategoryAction({ commit }, category) {
|
addCategoryAction({ commit }, category) {
|
||||||
commit("addCategory", category)
|
commit("addCategory", category)
|
||||||
},
|
},
|
||||||
|
importCategoriesAction({ commit }, categories) {
|
||||||
|
commit("importCategories", categories)
|
||||||
|
},
|
||||||
addYieldUnitAction({ commit }, yieldUnit) {
|
addYieldUnitAction({ commit }, yieldUnit) {
|
||||||
commit("addYieldUnit", yieldUnit)
|
commit("addYieldUnit", yieldUnit)
|
||||||
},
|
},
|
||||||
|
importYieldUnitsAction({ commit }, yieldUnits) {
|
||||||
|
commit("importYieldUnits", yieldUnits)
|
||||||
|
},
|
||||||
overwriteRecipeAction({ commit }, updatedRecipe) {
|
overwriteRecipeAction({ commit }, updatedRecipe) {
|
||||||
commit("overwriteRecipe", updatedRecipe)
|
commit("overwriteRecipe", updatedRecipe)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
require("tns-core-modules/globals")
|
require("tns-core-modules/globals")
|
||||||
import { ImageSource } from "@nativescript/core"
|
import { ImageSource, ImageAsset } from "@nativescript/core"
|
||||||
|
|
||||||
global.onmessage = function({ data }) {
|
global.onmessage = function({ data }) {
|
||||||
let imgFile = data.imgFile
|
|
||||||
let imgSavedToPath = data.imgSavedToPath
|
let imgSavedToPath = data.imgSavedToPath
|
||||||
ImageSource.fromFile(imgFile).then((imgData) => {
|
let imgAsset = new ImageAsset(data.imgFile)
|
||||||
if (imgData.saveToFile(imgSavedToPath, "jpg")) {
|
imgAsset.options = {
|
||||||
|
width: 1200,
|
||||||
|
height: 1200,
|
||||||
|
keepAspectRatio: true,
|
||||||
|
}
|
||||||
|
ImageSource.fromAsset(imgAsset).then((imgData) => {
|
||||||
|
if (imgData.saveToFile(imgSavedToPath, "jpg", 75)) {
|
||||||
global.postMessage("savedToFile")
|
global.postMessage("savedToFile")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|