Compare commits
96 commits
Author | SHA1 | Date | |
---|---|---|---|
|
e7ba5042ee | ||
|
4e436c70ce | ||
|
350da61d17 | ||
|
f6ab4c1e4e | ||
|
1b0d12eb65 | ||
|
f1244c4fbd | ||
|
62dda58723 | ||
|
03c04c94d1 | ||
|
91b81b1054 | ||
|
84dc016cb4 | ||
|
ca629c760d | ||
|
d11464883c | ||
|
244ee01e2b | ||
|
0a798516d1 | ||
|
311ed12770 | ||
|
10ed53b92f | ||
|
c536146abb | ||
|
691eebd416 | ||
|
e3a1961773 | ||
|
5210141b9c | ||
|
475146a8a0 | ||
|
0fd54cf17f | ||
|
57577d257d | ||
|
8ca3a493c6 | ||
|
b4ada90d22 | ||
|
043d5b3462 | ||
|
4e5134bdaf | ||
|
2128a7b9ae | ||
|
26d28e811f | ||
|
f8bfdcf52e | ||
|
94bd973730 | ||
|
75caab2976 | ||
|
59791dfb42 | ||
|
f5dd413a93 | ||
|
68dbecdbee | ||
|
6812279341 | ||
|
ae1a4847d0 | ||
|
3f4a9220d9 | ||
|
b9d329bd13 | ||
|
90ebc52537 | ||
|
3a42fb84ef | ||
|
01d67ec2a8 | ||
|
493bfd2d64 | ||
|
1575d7ec92 | ||
|
41de9c763e | ||
|
262459f1e1 | ||
|
04949d2bf9 | ||
|
c1c8a2171e | ||
|
7a6c4115f3 | ||
|
fe2833c41b | ||
|
bede343db9 | ||
|
f87717efb2 | ||
|
d4b42cb09a | ||
|
b4e42d1528 | ||
|
1291878921 | ||
|
f38b266dde | ||
|
525eb600a3 | ||
|
dd41e28c28 | ||
|
1830a78c54 | ||
|
d21f5d98b9 | ||
|
6f29f52a96 | ||
|
28e21f7de2 | ||
|
fd5517767b | ||
|
a7ba31fe45 | ||
|
01de9b31c9 | ||
|
9263e05a2d | ||
|
c3eece4717 | ||
|
92d355ae1c | ||
|
20e105c68f | ||
|
0e1661fe4b | ||
|
4112190dbc | ||
|
6aa3746f09 | ||
|
786528f52b | ||
|
1975b9a6f7 | ||
|
484004ce1f | ||
|
63ea056c2a | ||
|
438768d7b7 | ||
|
f2bde77358 | ||
|
570de3a8df | ||
|
0b7a624ba9 | ||
|
3363600ea9 | ||
|
521445c3e3 | ||
|
cf2cb349c9 | ||
|
d3d154ea54 | ||
|
df225cc67e | ||
|
53034c6077 | ||
|
7f4c827772 | ||
|
628ff95151 | ||
|
a6a73d21e9 | ||
|
598536896c | ||
|
f5f24ce3ff | ||
|
9be426a274 | ||
|
1929325572 | ||
|
fe1422a370 | ||
|
f9c5752fc9 | ||
|
5c6add7f3e |
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
|
57
README.md
|
@ -20,13 +20,13 @@
|
|||
|
||||
## About
|
||||
|
||||
Simple QR is a FOSS app to scan, create and store QR codes with a simple UI and experience. No backend service connected. No data collected. No ads.
|
||||
Simple QR is an open-source app to scan, create and store QR codes with a simple UI and experience. No backend service connected. No data collected. No ads.
|
||||
|
||||
It's now available on the following platforms.
|
||||
|
||||
| App Store | Google Play | GitHub | IzzyOnDroid |
|
||||
|:-:|:-:|:-:|:-:|
|
||||
| [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/appstore-badge.png" height="50">](https://apps.apple.com/us/app/simple-qr-by-tom-fong/id1621121553) | [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=com.tomfong.simpleqr) | [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/github-badge.png" height="50">](https://github.com/tomfong/simple-qr/releases/latest) | [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/IzzyOnDroid-badge.png" height="50">](https://apt.izzysoft.de/fdroid/index/apk/com.tomfong.simpleqr) |
|
||||
| Google Play | GitHub | IzzyOnDroid |
|
||||
|:-:|:-:|:-:|
|
||||
| [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=com.tomfong.simpleqr) | [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/github-badge.png" height="50">](https://github.com/tomfong/simple-qr/releases/latest) | [<img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/IzzyOnDroid-badge.png" height="50">](https://apt.izzysoft.de/fdroid/index/apk/com.tomfong.simpleqr) |
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -36,7 +36,7 @@ By using the app, you can
|
|||
|
||||
2. Import image files and scan the QR Code on it.
|
||||
|
||||
3. Create QR code from templates, which includes Free Text, URL, vCard Contact, Phone Number, Message, Email and Wi-Fi.
|
||||
3. Create QR code from templates, which includes Free Text, URL, vCard Contact, Phone Number, Message, Email, Wi-Fi and Geolocation.
|
||||
|
||||
4. Automatically log results that you scan, create or view again. These logged records can be bookmarked for quick access, and also backupable.
|
||||
|
||||
|
@ -46,11 +46,12 @@ By using the app, you can
|
|||
* Execute base64 encoding/decoding on it.
|
||||
* Use it as a content to generate a new shareable QR code.
|
||||
* Do corresponding tasks if it is a
|
||||
* URL: Browse website
|
||||
* URL: Browse website / Open application
|
||||
* vCard contact: Add contact
|
||||
* Phone number: Phone call, add contact
|
||||
* Message: Send message, add contact
|
||||
* Email: Send email
|
||||
* Geolocation: Open map
|
||||
|
||||
6. Customize the generated QR code, e.g. error correction level, color, margin and screen brightness.
|
||||
|
||||
|
@ -63,11 +64,13 @@ By using the app, you can
|
|||
### Languages Supported
|
||||
|
||||
* English (en)
|
||||
* Traditional Chinese 正體中文 (zh)
|
||||
* Simplified Chinese 简体中文 (zh-CN)
|
||||
* Chinese (Hong Kong) 中文 (香港) (zh-HK)
|
||||
* Chinese (Simplified) 简体中文 (zh-CN)
|
||||
* German Deutsch (de)
|
||||
* French Français (fr)
|
||||
* Italian Italiano (it)
|
||||
* Portuguese (Brazil) (pt-BR)
|
||||
* Russian Русский (ru)
|
||||
|
||||
You are welcomed to help translate the app into more languages (refer to this <a href="#how-to-help-translate">section</a>)
|
||||
|
||||
|
@ -75,10 +78,8 @@ You are welcomed to help translate the app into more languages (refer to this <a
|
|||
|
||||
* Sponsor the project.
|
||||
|
||||
<div>
|
||||
<a href="https://linktr.ee/tomfonghk"><img src="https://raw.githubusercontent.com/tomfong/simple-qr/main/.github/images/Paypal-badge.png" width="170" alt="tomfong"/></a>
|
||||
<a href="https://www.buymeacoffee.com/tomfong"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="180" alt="tomfong" /></a>
|
||||
</div>
|
||||
[](https://github.com/sponsors/tomfong?frequency=one-time)
|
||||
[](https://www.buymeacoffee.com/tomfong)
|
||||
|
||||
* Star the project.
|
||||
|
||||
|
@ -86,7 +87,7 @@ You are welcomed to help translate the app into more languages (refer to this <a
|
|||
|
||||
* Open issues to report bugs or share any new ideas.
|
||||
|
||||
[](https://github.com/tomfong/simple-qr/issues)
|
||||
[](https://github.com/tomfong/simple-qr/issues)
|
||||
|
||||
* Translate the app into different languages.
|
||||
|
||||
|
@ -103,11 +104,10 @@ You are welcomed to help translate the app into more languages (refer to this <a
|
|||
* <b>DO NOT</b> change the order.
|
||||
4. Email the JSON to me (tomfong.dev@gmail.com) after you finish.
|
||||
|
||||
### Build the project (Android)
|
||||
### Build the project
|
||||
|
||||
1. Run ```npm install``` to install all dependencies.
|
||||
2. Run ```npm run build:an``` or ```npm run build:ios``` (for first time).
|
||||
3. Run ```npm run sync``` and ```npm run copy:an``` or ```npm run copy:ios```.
|
||||
2. Run ```npm run build```
|
||||
|
||||
### Contributors
|
||||
|
||||
|
@ -117,24 +117,23 @@ Thank you the following contributors who have made the app better!
|
|||
|:-:|:-:|:-:|
|
||||
| mondstern | [mondlicht-und-sterne](https://github.com/mondlicht-und-sterne) | German language translation |
|
||||
| Valentino Bocchetti | [luftmensch-luftmensch](https://github.com/luftmensch-luftmensch) | Italian language translation |
|
||||
| Smooth-E | [Smooth-E](https://github.com/Smooth-E) | Russian language translation |
|
||||
| Daniel Ribeiro | [drcsj](https://github.com/drcsj) | Portuguese (Brazil) language translation |
|
||||
|
||||
## Framework
|
||||
|
||||
```sh
|
||||
Ionic CLI : 6.20.1
|
||||
Ionic Framework : @ionic/angular 6.2.8
|
||||
@angular-devkit/build-angular : 14.2.3
|
||||
@angular-devkit/schematics : 13.3.9
|
||||
@angular/cli : 14.2.3
|
||||
@ionic/angular-toolkit : 6.1.0
|
||||
Ionic CLI : 7.2.0
|
||||
Ionic Framework : @ionic/angular 7.8.2
|
||||
@angular-devkit/build-angular : 16.2.13
|
||||
@angular-devkit/schematics : 16.2.13
|
||||
@angular/cli : 16.2.13
|
||||
@ionic/angular-toolkit : 9.0.0
|
||||
|
||||
Capacitor CLI : 4.3.0
|
||||
@capacitor/android : 4.3.0
|
||||
@capacitor/core : 4.3.0
|
||||
@capacitor/ios : 4.3.0
|
||||
|
||||
NodeJS : v16.15.1
|
||||
npm : 8.11.0
|
||||
Capacitor CLI : 5.7.4
|
||||
@capacitor/android : 5.7.4
|
||||
@capacitor/core : 5.7.4
|
||||
@capacitor/ios : 5.7.4
|
||||
```
|
||||
|
||||
## Privacy Policy
|
||||
|
|
2
android/.idea/compiler.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
6
android/.idea/misc.xml
generated
|
@ -3,11 +3,15 @@
|
|||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="app/src/main/res/drawable/ic_baseline_qr_code_24.xml" value="0.2485" />
|
||||
<entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.2485" />
|
||||
<entry key="app/src/main/res/drawable/splash_background.xml" value="0.2485" />
|
||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.2485" />
|
||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.2485" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
namespace "com.tomfong.simpleqr"
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "com.tomfong.simpleqr"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 3000000
|
||||
versionName "3.0.0"
|
||||
versionCode 4010000
|
||||
versionName "4.1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
android {
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ dependencies {
|
|||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-haptics')
|
||||
implementation project(':capacitor-keyboard')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-splash-screen')
|
||||
implementation project(':capacitor-status-bar')
|
||||
implementation project(':capacitor-toast')
|
||||
|
|
20
android/app/release/output-metadata.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.tomfong.simpleqr",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 4010000,
|
||||
"versionName": "4.1.0",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File"
|
||||
}
|
|
@ -1,7 +1,16 @@
|
|||
<?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="com.tomfong.simpleqr">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" >
|
||||
|
||||
<application android:hardwareAccelerated="true" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true" android:largeHeap="true">
|
||||
<application
|
||||
android:hardwareAccelerated="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:largeHeap="true">
|
||||
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:name="com.tomfong.simpleqr.MainActivity" android:label="@string/title_activity_main" android:theme="@style/AppTheme.NoActionBarLaunch" android:launchMode="singleTask" android:exported="true">
|
||||
|
||||
|
@ -30,8 +39,14 @@
|
|||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="true" />
|
||||
</manifest>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
},
|
||||
{
|
||||
"pkg": "@capacitor-community/contacts",
|
||||
"classpath": "ch.byrds.capacitor.contacts.Contacts"
|
||||
"classpath": "getcapacitor.community.contacts.ContactsPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor-community/screen-brightness",
|
||||
|
@ -39,6 +39,10 @@
|
|||
"pkg": "@capacitor/keyboard",
|
||||
"classpath": "com.capacitorjs.plugins.keyboard.KeyboardPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/preferences",
|
||||
"classpath": "com.capacitorjs.plugins.preferences.PreferencesPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/splash-screen",
|
||||
"classpath": "com.capacitorjs.plugins.splashscreen.SplashScreenPlugin"
|
||||
|
|
|
@ -11,6 +11,8 @@ import androidx.annotation.RequiresApi;
|
|||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public class MyQSTileService extends TileService {
|
||||
|
||||
public MyQSTileService() {}
|
||||
|
||||
// Called when the user adds your tile.
|
||||
@Override
|
||||
public void onTileAdded() {
|
||||
|
|
5
android/app/src/main/res/drawable/splash_background.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/colorPrimary"/>
|
||||
<item android:gravity="center" android:drawable="@drawable/splash"/>
|
||||
</layer-list>
|
6
android/app/src/main/res/values-ru/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
7
android/app/src/main/res/values-ru/strings.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">Simple QR</string>
|
||||
<string name="title_activity_main">Simple QR</string>
|
||||
<string name="package_name">com.tomfong.simpleqr</string>
|
||||
<string name="custom_url_scheme">com.tomfong.simpleqr</string>
|
||||
</resources>
|
22
android/app/src/main/res/values-ru/styles.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
6
android/app/src/main/res/values-zh-rCN/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
|
@ -16,6 +16,7 @@
|
|||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
6
android/app/src/main/res/values-zh-rSG/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
|
@ -15,8 +15,8 @@
|
|||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
6
android/app/src/main/res/values-zh-rTW/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
|
@ -15,8 +15,8 @@
|
|||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
6
android/app/src/main/res/values-zh/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
|
@ -15,8 +15,8 @@
|
|||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
6
android/app/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color tools:ignore="UnusedResources" name="colorPrimary">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorPrimaryDark">#00a5aa</color>
|
||||
<color tools:ignore="UnusedResources" name="colorAccent">#00a5aa</color>
|
||||
</resources>
|
|
@ -15,8 +15,8 @@
|
|||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<item name="android:background">@drawable/splash_background</item>
|
||||
<item name="android:windowBackground">@drawable/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
@ -7,8 +7,8 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath 'com.google.gms:google-services:4.3.13'
|
||||
classpath 'com.android.tools.build:gradle:8.0.2'
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
|
@ -32,6 +32,9 @@ project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/
|
|||
include ':capacitor-keyboard'
|
||||
project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
|
||||
|
||||
include ':capacitor-preferences'
|
||||
project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')
|
||||
|
||||
include ':capacitor-splash-screen'
|
||||
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
|
||||
|
||||
|
|
|
@ -20,5 +20,4 @@ org.gradle.jvmargs=-Xmx1536m
|
|||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
ext {
|
||||
minSdkVersion = 22
|
||||
compileSdkVersion = 32
|
||||
targetSdkVersion = 32
|
||||
androidxActivityVersion = '1.4.0'
|
||||
androidxAppCompatVersion = '1.4.2'
|
||||
compileSdkVersion = 33
|
||||
targetSdkVersion = 33
|
||||
androidxActivityVersion = '1.7.0'
|
||||
androidxAppCompatVersion = '1.6.1'
|
||||
androidxCoordinatorLayoutVersion = '1.2.0'
|
||||
androidxCoreVersion = '1.8.0'
|
||||
androidxFragmentVersion = '1.4.1'
|
||||
androidxCoreVersion = '1.10.0'
|
||||
androidxFragmentVersion = '1.5.6'
|
||||
junitVersion = '4.13.2'
|
||||
androidxJunitVersion = '1.1.3'
|
||||
androidxEspressoCoreVersion = '3.4.0'
|
||||
androidxJunitVersion = '1.1.5'
|
||||
androidxEspressoCoreVersion = '3.5.1'
|
||||
cordovaAndroidVersion = '10.1.1'
|
||||
coreSplashScreenVersion = '1.0.0-rc01'
|
||||
androidxWebkitVersion = '1.4.0'
|
||||
coreSplashScreenVersion = '1.0.0'
|
||||
androidxWebkitVersion = '1.6.1'
|
||||
}
|
||||
|
|
32
angular.json
|
@ -30,7 +30,10 @@
|
|||
"output": "./svg"
|
||||
}
|
||||
],
|
||||
"styles": ["src/theme/variables.scss", "src/global.scss"],
|
||||
"styles": [
|
||||
"src/theme/variables.scss",
|
||||
"src/global.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"aot": false,
|
||||
"vendorChunk": true,
|
||||
|
@ -79,8 +82,7 @@
|
|||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
},
|
||||
"ci": {
|
||||
}
|
||||
"ci": {}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
|
@ -132,30 +134,6 @@
|
|||
"devServerTarget": "app:serve:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-build": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-build",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-serve": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-serve",
|
||||
"options": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build",
|
||||
"devServerTarget": "app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build:production",
|
||||
"devServerTarget": "app:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ Mit der App ist das möglich
|
|||
|
||||
* QR-Code und andere Barcodes in Sekundenschnelle zu scannen, einschließlich UPC, EAN, Code 39/128, ITF, Codabar, Aztec, Data Matrix, PDF417, MaxiCode und GS1 DataBar.
|
||||
* Bilddateien zu importieren und den darauf befindlichen QR-Code zu scannen.
|
||||
* QR-Codes aus Vorlagen,die Freitext, URL, vCard-Kontakt, Telefonnummer, Nachricht, E-Mail und WLAN enthalten, zu erstellen.
|
||||
* QR-Codes aus Vorlagen,die Freitext, URL, vCard-Kontakt, Telefonnummer, Nachricht, Geolokalisierung, E-Mail und WLAN enthalten, zu erstellen.
|
||||
* Gescannte Ergebnissen, die gescannt wurden, erstellt oder erneut angezeigt wurden zu protokollieren. Diese protokollierten Aufzeichnungen können für schnellen Zugriff mit einem Lesezeichen versehen und auch gesichert werden.
|
||||
* Aufgaben auf dem Ergebnis mit einem Fingertipp zu erledigen, einschließlich, aber nicht beschränkt auf
|
||||
* Verwenden als Schlüsselwort für die Websuche.
|
||||
|
@ -19,5 +19,6 @@ Mit der App ist das möglich
|
|||
* Telefonnummer: Telefonanruf, Kontakt hinzufügen
|
||||
* Nachricht: Nachricht senden, Kontakt hinzufügen
|
||||
* E-Mail: E-Mail senden
|
||||
* Geolokalisierung: Karte öffnen
|
||||
* Passen Sie den generierten QR-Code an, z. Fehlerkorrekturstufe, Farbe, Rand und Bildschirmhelligkeit.
|
||||
* Die App anzupassen, z.B. App-Startseite, Sprache und Farbthema etc.
|
||||
|
|
1
fastlane/metadata/android/en-US/changelogs/3000100.txt
Normal file
|
@ -0,0 +1 @@
|
|||
* Bug fix
|
3
fastlane/metadata/android/en-US/changelogs/3010000.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
* Support Ecosia
|
||||
* Support CSV export
|
||||
* Bug fix
|
2
fastlane/metadata/android/en-US/changelogs/3020000.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
* Support Open Food Facts
|
||||
* Bug fix
|
3
fastlane/metadata/android/en-US/changelogs/3030000.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
* Support Russian language
|
||||
* Allow user to manually save a record if auto logging is off
|
||||
* Minor update on UI
|
4
fastlane/metadata/android/en-US/changelogs/4000000.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
* Upgrade framework, improve performance and fix known bugs
|
||||
* Support Brave Search
|
||||
* Support open URL automatically
|
||||
* Allow user to further edit QR code content
|
1
fastlane/metadata/android/en-US/changelogs/4000100.txt
Normal file
|
@ -0,0 +1 @@
|
|||
* Fix import image issue
|
3
fastlane/metadata/android/en-US/changelogs/4010000.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
* Support geolocation QR code
|
||||
* Support Portuguese (Brazil) language
|
||||
* Disable auto URL opening by default
|
|
@ -1,12 +1,12 @@
|
|||
<i>Simple QR</i> is a FOSS app to scan, create and store QR codes with a simple UI and experience. No backend service connected. No data collected. No ads.
|
||||
<i>Simple QR</i> is an open-source app to scan, create and store QR codes with a simple UI and experience. No backend service connected. No data collected. No ads.
|
||||
|
||||
English, French, German, Itanlian, Traditional Chinese and Simplified Chinese are supported.
|
||||
English, French, German, Itanlian, Russian, Traditional Chinese and Simplified Chinese are supported.
|
||||
|
||||
By using the app, you can:
|
||||
|
||||
* Scan QR Code and other barcodes in a second, including UPC, EAN, Code 39/128, ITF, Codabar, Aztec, Data Matrix, PDF417, MaxiCode and GS1 DataBar.
|
||||
* Import image files and scan the QR Code on it.
|
||||
* Create QR code from templates, which includes Free Text, URL, vCard Contact, Phone Number, Message, Email and Wi-Fi.
|
||||
* Create QR code from templates, which includes Free Text, URL, vCard Contact, Phone Number, Message, Email, Wi-Fi and Geolocation.
|
||||
* Automatically log results that you scan, create or view again. These logged records can be bookmarked for quick access, and also backupable.
|
||||
* Do tasks on the result with a tap, including but not limited to
|
||||
* Use it as a keyword to do web search.
|
||||
|
@ -14,10 +14,11 @@ By using the app, you can:
|
|||
* Execute base64 encoding/decoding on it.
|
||||
* Generate a new shareable QR code by using it as the content.
|
||||
* Do corresponding tasks if it is a
|
||||
* URL: Browse website
|
||||
* URL: Browse website / Open application
|
||||
* vCard contact: Add contact
|
||||
* Phone number: Phone call, add contact
|
||||
* Message: Send message, add contact
|
||||
* Email: Send email
|
||||
* Geolocation: Open map
|
||||
* Customize the generated QR code, e.g. error correction level, color, margin and screen brightness.
|
||||
* Customize the app, e.g. app initial page, language and color theme etc.
|
||||
|
|
2
ios/.gitignore
vendored
|
@ -1,9 +1,9 @@
|
|||
App/build
|
||||
App/Pods
|
||||
App/Podfile.lock
|
||||
App/App/public
|
||||
DerivedData
|
||||
xcuserdata
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-ios-plugins
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1B75189429375EAB00800D38 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -160,6 +161,7 @@
|
|||
de,
|
||||
fr,
|
||||
it,
|
||||
ru,
|
||||
);
|
||||
mainGroup = 504EC2FB1FED79650016851F;
|
||||
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
||||
|
@ -268,6 +270,7 @@
|
|||
D26FE7F9283D1E6C002A61AE /* fr */,
|
||||
D26FE7FA283D1E76002A61AE /* de */,
|
||||
D29D2E2A2847C31D00566DFF /* it */,
|
||||
1B75189429375EAB00800D38 /* ru */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
|
@ -396,7 +399,7 @@
|
|||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
MARKETING_VERSION = 4.1.0;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.tomfong.simpleqr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -419,7 +422,7 @@
|
|||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
MARKETING_VERSION = 4.1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.tomfong.simpleqr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Simple QR";
|
||||
|
|
Before Width: | Height: | Size: 588 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 743 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,116 +1,14 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"scale" : "1x"
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
6
ios/App/App/ru.lproj/InfoPlist.strings
Normal file
|
@ -0,0 +1,6 @@
|
|||
"CFBundleDisplayName" = "Simple QR";
|
||||
"CFBundleName" = "Simple QR";
|
||||
"NSCameraUsageDescription" = "Simple QR использует камеру для сканирования QR-кода и штрих-кодов";
|
||||
"NSContactsUsageDescription" = "Simple QR использует Контакты для добавления контакта";
|
||||
"NSPhotoLibraryAddUsageDescription" = "Simple QR использует библиотеку фотографий для сохранения изображения QR-кода";
|
||||
"NSPhotoLibraryUsageDescription" = "Simple QR использует библиотеку фотографий для импорта изображений и сканирования QR-кода.";
|
|
@ -21,6 +21,7 @@ def capacitor_pods
|
|||
pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
|
||||
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
|
||||
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
|
||||
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
||||
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
||||
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
|
||||
pod 'CapacitorToast', :path => '../../node_modules/@capacitor/toast'
|
||||
|
|
112
ios/App/Podfile.lock
Normal file
|
@ -0,0 +1,112 @@
|
|||
PODS:
|
||||
- Capacitor (5.7.4):
|
||||
- CapacitorCordova
|
||||
- CapacitorApp (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorCamera (5.0.9):
|
||||
- Capacitor
|
||||
- CapacitorClipboard (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorCommunityBarcodeScanner (4.0.1):
|
||||
- Capacitor
|
||||
- CapacitorCommunityContacts (5.0.5):
|
||||
- Capacitor
|
||||
- CapacitorCommunityScreenBrightness (5.0.0):
|
||||
- Capacitor
|
||||
- CapacitorCordova (5.7.4)
|
||||
- CapacitorDevice (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorFilesystem (5.2.1):
|
||||
- Capacitor
|
||||
- CapacitorHaptics (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorKeyboard (5.0.8):
|
||||
- Capacitor
|
||||
- CapacitorPreferences (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorSplashScreen (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorStatusBar (5.0.7):
|
||||
- Capacitor
|
||||
- CapacitorToast (5.0.7):
|
||||
- Capacitor
|
||||
- CordovaPlugins (5.7.4):
|
||||
- CapacitorCordova
|
||||
|
||||
DEPENDENCIES:
|
||||
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
|
||||
- "CapacitorApp (from `../../node_modules/@capacitor/app`)"
|
||||
- "CapacitorCamera (from `../../node_modules/@capacitor/camera`)"
|
||||
- "CapacitorClipboard (from `../../node_modules/@capacitor/clipboard`)"
|
||||
- "CapacitorCommunityBarcodeScanner (from `../../node_modules/@capacitor-community/barcode-scanner`)"
|
||||
- "CapacitorCommunityContacts (from `../../node_modules/@capacitor-community/contacts`)"
|
||||
- "CapacitorCommunityScreenBrightness (from `../../node_modules/@capacitor-community/screen-brightness`)"
|
||||
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
|
||||
- "CapacitorDevice (from `../../node_modules/@capacitor/device`)"
|
||||
- "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)"
|
||||
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
|
||||
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
|
||||
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
|
||||
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
|
||||
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
|
||||
- "CapacitorToast (from `../../node_modules/@capacitor/toast`)"
|
||||
- CordovaPlugins (from `../capacitor-cordova-ios-plugins`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Capacitor:
|
||||
:path: "../../node_modules/@capacitor/ios"
|
||||
CapacitorApp:
|
||||
:path: "../../node_modules/@capacitor/app"
|
||||
CapacitorCamera:
|
||||
:path: "../../node_modules/@capacitor/camera"
|
||||
CapacitorClipboard:
|
||||
:path: "../../node_modules/@capacitor/clipboard"
|
||||
CapacitorCommunityBarcodeScanner:
|
||||
:path: "../../node_modules/@capacitor-community/barcode-scanner"
|
||||
CapacitorCommunityContacts:
|
||||
:path: "../../node_modules/@capacitor-community/contacts"
|
||||
CapacitorCommunityScreenBrightness:
|
||||
:path: "../../node_modules/@capacitor-community/screen-brightness"
|
||||
CapacitorCordova:
|
||||
:path: "../../node_modules/@capacitor/ios"
|
||||
CapacitorDevice:
|
||||
:path: "../../node_modules/@capacitor/device"
|
||||
CapacitorFilesystem:
|
||||
:path: "../../node_modules/@capacitor/filesystem"
|
||||
CapacitorHaptics:
|
||||
:path: "../../node_modules/@capacitor/haptics"
|
||||
CapacitorKeyboard:
|
||||
:path: "../../node_modules/@capacitor/keyboard"
|
||||
CapacitorPreferences:
|
||||
:path: "../../node_modules/@capacitor/preferences"
|
||||
CapacitorSplashScreen:
|
||||
:path: "../../node_modules/@capacitor/splash-screen"
|
||||
CapacitorStatusBar:
|
||||
:path: "../../node_modules/@capacitor/status-bar"
|
||||
CapacitorToast:
|
||||
:path: "../../node_modules/@capacitor/toast"
|
||||
CordovaPlugins:
|
||||
:path: "../capacitor-cordova-ios-plugins"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Capacitor: 4fe9adf012caceb4c71ffea2f1f4d005cdcbeea7
|
||||
CapacitorApp: 17fecd0e6cb23feafac7eb0939417389038b0979
|
||||
CapacitorCamera: 4892c5c392f60039d853dde78bc50ba19fbd113e
|
||||
CapacitorClipboard: 45e5e25f2271f98712985d422776cdc5a779cca1
|
||||
CapacitorCommunityBarcodeScanner: 7feb206489c8555a8ca0c74c57ddf49ead774eb8
|
||||
CapacitorCommunityContacts: e8fbc4d669c9478a29f1e104818b4c16e158b2e0
|
||||
CapacitorCommunityScreenBrightness: b2d9c6fffee6b684994cd69f727f2090e2f05c6d
|
||||
CapacitorCordova: a6e87fccc0307dee7aec1560ec9398485f2b0ce7
|
||||
CapacitorDevice: fc91bdb484dc0e70755e9b621cd557afe642613a
|
||||
CapacitorFilesystem: 9f3e3c7fea2fff12f46dd5b07a2914f2103e4cfc
|
||||
CapacitorHaptics: 7c7c206f0c96a628fed073830c96d28c4b2e772e
|
||||
CapacitorKeyboard: aec619a578235c6ce279075009a2689c2cf5c42c
|
||||
CapacitorPreferences: 77ac427e98db83bace772455f8ba447430382c4c
|
||||
CapacitorSplashScreen: dd3de3f3644710fa2a697cfb91ec262eece4d242
|
||||
CapacitorStatusBar: f390fbb49b82ffb754ea4b3cf71dc8b048baf3e7
|
||||
CapacitorToast: c8bb89eeb59a23c1fc298f138cc06c8ff4d90ac1
|
||||
CordovaPlugins: 5495649167d6829fea7bc7eacd2034646aee5bd1
|
||||
|
||||
PODFILE CHECKSUM: dc80e3587547d0d302dad43090af30e2a96d6c5a
|
||||
|
||||
COCOAPODS: 1.11.3
|
24574
package-lock.json
generated
133
package.json
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "simple-qr",
|
||||
"version": "3.0.0",
|
||||
"version": "4.1.0",
|
||||
"author": "Tom Fong",
|
||||
"homepage": "https://tomfong.github.io",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"build:an": "ionic cap build android --prod",
|
||||
"build:ios": "ionic cap build ios --prod",
|
||||
"build:an": "ionic cap build android --prod --no-open",
|
||||
"build:ios": "ionic cap build ios --prod --no-open",
|
||||
"build": "ionic cap build android --prod --no-open && ionic cap build ios --prod --no-open",
|
||||
"sync": "ionic cap sync --prod --no-build",
|
||||
"copy:an": "ionic cap copy android --prod",
|
||||
"copy:ios": "ionic cap copy ios --prod",
|
||||
|
@ -16,91 +16,90 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^14.2.3",
|
||||
"@angular/cdk": "^14.2.2",
|
||||
"@angular/common": "^14.2.3",
|
||||
"@angular/core": "^14.2.3",
|
||||
"@angular/forms": "^14.2.3",
|
||||
"@angular/localize": "^14.2.3",
|
||||
"@angular/material": "^14.2.2",
|
||||
"@angular/material-moment-adapter": "^14.2.2",
|
||||
"@angular/platform-browser": "^14.2.3",
|
||||
"@angular/platform-browser-dynamic": "^14.2.3",
|
||||
"@angular/router": "^14.2.3",
|
||||
"@awesome-cordova-plugins/aes-256": "^5.45.0",
|
||||
"@awesome-cordova-plugins/chooser": "^5.45.0",
|
||||
"@awesome-cordova-plugins/core": "^5.45.0",
|
||||
"@awesome-cordova-plugins/screen-orientation": "^5.45.0",
|
||||
"@awesome-cordova-plugins/sms": "^5.45.0",
|
||||
"@awesome-cordova-plugins/social-sharing": "^5.45.0",
|
||||
"@awesome-cordova-plugins/theme-detection": "^5.45.0",
|
||||
"@capacitor-community/barcode-scanner": "^3.0.0",
|
||||
"@capacitor-community/contacts": "^2.0.0-0",
|
||||
"@capacitor-community/screen-brightness": "^2.0.0-0",
|
||||
"@capacitor/android": "^4.3.0",
|
||||
"@capacitor/app": "^4.0.1",
|
||||
"@capacitor/camera": "^4.1.1",
|
||||
"@capacitor/clipboard": "^4.0.1",
|
||||
"@capacitor/core": "^4.3.0",
|
||||
"@capacitor/device": "^4.0.1",
|
||||
"@capacitor/filesystem": "^4.1.1",
|
||||
"@capacitor/haptics": "^4.0.1",
|
||||
"@capacitor/ios": "^4.3.0",
|
||||
"@capacitor/keyboard": "^4.0.1",
|
||||
"@capacitor/splash-screen": "^4.0.1",
|
||||
"@capacitor/status-bar": "^4.0.1",
|
||||
"@capacitor/toast": "^4.0.1",
|
||||
"@ionic/angular": "^6.2.8",
|
||||
"@ionic/storage": "^3.0.6",
|
||||
"@ionic/storage-angular": "^3.0.6",
|
||||
"@ng-bootstrap/ng-bootstrap": "^11.0.1",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@techiediaries/ngx-qrcode": "^9.1.0",
|
||||
"bootstrap": "^4.6.2",
|
||||
"@angular/animations": "^16.1.3",
|
||||
"@angular/cdk": "^16.1.3",
|
||||
"@angular/common": "^16.1.3",
|
||||
"@angular/core": "^16.1.3",
|
||||
"@angular/forms": "^16.2.12",
|
||||
"@angular/localize": "^16.2.12",
|
||||
"@angular/material": "^16.1.3",
|
||||
"@angular/material-moment-adapter": "^16.2.14",
|
||||
"@angular/platform-browser": "^16.1.3",
|
||||
"@angular/platform-browser-dynamic": "^16.2.12",
|
||||
"@angular/router": "^16.2.12",
|
||||
"@awesome-cordova-plugins/aes-256": "^6.6.0",
|
||||
"@awesome-cordova-plugins/chooser": "^6.6.0",
|
||||
"@awesome-cordova-plugins/core": "^6.6.0",
|
||||
"@awesome-cordova-plugins/screen-orientation": "^6.6.0",
|
||||
"@awesome-cordova-plugins/sms": "^6.6.0",
|
||||
"@awesome-cordova-plugins/social-sharing": "^6.6.0",
|
||||
"@awesome-cordova-plugins/theme-detection": "^6.6.0",
|
||||
"@capacitor-community/barcode-scanner": "^4.0.1",
|
||||
"@capacitor-community/contacts": "^5.0.5",
|
||||
"@capacitor-community/screen-brightness": "^5.0.0",
|
||||
"@capacitor/android": "^5.7.4",
|
||||
"@capacitor/app": "^5.0.7",
|
||||
"@capacitor/camera": "^5.0.9",
|
||||
"@capacitor/clipboard": "^5.0.7",
|
||||
"@capacitor/core": "^5.7.4",
|
||||
"@capacitor/device": "^5.0.7",
|
||||
"@capacitor/filesystem": "^5.2.1",
|
||||
"@capacitor/haptics": "^5.0.7",
|
||||
"@capacitor/ios": "^5.7.4",
|
||||
"@capacitor/keyboard": "^5.0.8",
|
||||
"@capacitor/preferences": "^5.0.7",
|
||||
"@capacitor/splash-screen": "^5.0.7",
|
||||
"@capacitor/status-bar": "^5.0.7",
|
||||
"@capacitor/toast": "^5.0.7",
|
||||
"@ionic/angular": "^7.8.2",
|
||||
"@ionic/storage": "^4.0.0",
|
||||
"@ionic/storage-angular": "^4.0.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "^15.1.2",
|
||||
"@ngx-translate/core": "^15.0.0",
|
||||
"@ngx-translate/http-loader": "^8.0.0",
|
||||
"angularx-qrcode": "^16.0.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
"cordova-plugin-aes256-encryption": "^2.0.1",
|
||||
"cordova-plugin-chooser": "^1.3.2",
|
||||
"cordova-plugin-screen-orientation": "^3.0.2",
|
||||
"cordova-plugin-screen-orientation": "^3.0.4",
|
||||
"cordova-plugin-theme-detection": "^1.3.0",
|
||||
"cordova-plugin-x-socialsharing": "^6.0.4",
|
||||
"cordova-sms-plugin": "^1.0.2",
|
||||
"cordova-sms-plugin": "^1.0.3",
|
||||
"date-fns": "2.29.3",
|
||||
"es6-promise-plugin": "^4.2.2",
|
||||
"human-signals": "^2.1.0",
|
||||
"jsqr": "^1.4.0",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"osenv": "^0.1.5",
|
||||
"properties-parser": "^0.3.1",
|
||||
"rxjs": "^6.6.7",
|
||||
"rxjs": "^7.8.1",
|
||||
"strip-final-newline": "^2.0.0",
|
||||
"tslib": "^2.4.0",
|
||||
"tslib": "^2.6.2",
|
||||
"uuid": "^8.3.2",
|
||||
"zone.js": "^0.11.8"
|
||||
"zone.js": "^0.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^14.2.3",
|
||||
"@angular/cli": "^14.2.3",
|
||||
"@angular/compiler": "^14.2.3",
|
||||
"@angular/compiler-cli": "^14.2.3",
|
||||
"@angular/language-service": "^14.2.3",
|
||||
"@capacitor/cli": "^4.3.0",
|
||||
"@ionic/angular-toolkit": "^6.1.0",
|
||||
"@types/jasmine": "^3.10.6",
|
||||
"@types/jasminewd2": "^2.0.10",
|
||||
"@angular-devkit/build-angular": "^16.2.13",
|
||||
"@angular/cli": "^16.2.13",
|
||||
"@angular/compiler": "^16.1.3",
|
||||
"@angular/compiler-cli": "^16.1.3",
|
||||
"@angular/language-service": "^16.2.12",
|
||||
"@capacitor/cli": "^5.7.4",
|
||||
"@ionic/angular-toolkit": "^9.0.0",
|
||||
"@ionic/cli": "^7.2.0",
|
||||
"@types/jasmine": "^3.10.18",
|
||||
"@types/jasminewd2": "^2.0.13",
|
||||
"@types/node": "^12.20.55",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "^6.4.1",
|
||||
"karma-chrome-launcher": "^3.1.1",
|
||||
"karma": "^6.4.3",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "^4.0.2",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.8.3"
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
|
@ -48,6 +48,10 @@ const routes: Routes = [
|
|||
path: 'setting-auto-brightness',
|
||||
loadChildren: () => import('./pages/setting-auto-brightness/setting-auto-brightness.module').then(m => m.SettingAutoBrightnessPageModule)
|
||||
},
|
||||
{
|
||||
path: 'setting-auto-open-url',
|
||||
loadChildren: () => import('./pages/setting-auto-open-url/setting-auto-open-url.module').then(m => m.SettingAutoOpenUrlPageModule)
|
||||
},
|
||||
{
|
||||
path: 'setting-start-page',
|
||||
loadChildren: () => import('./pages/setting-start-page/setting-start-page.module').then(m => m.SettingStartPagePageModule)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { App } from '@capacitor/app';
|
||||
import { SplashScreen } from '@capacitor/splash-screen';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { Platform } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { EnvService } from './services/env.service';
|
||||
|
@ -17,5 +20,29 @@ export class AppComponent {
|
|||
) {
|
||||
translate.addLangs(this.env.languages);
|
||||
translate.setDefaultLang('en');
|
||||
if (this.platform.is('ios')) {
|
||||
App.addListener('appStateChange', async ({ isActive }) => {
|
||||
if (env.isDebugging) {
|
||||
this.presentToast(`App state changed. Is active?: ${isActive}`, "short", "bottom");
|
||||
}
|
||||
if (isActive) {
|
||||
setTimeout(async () => {
|
||||
await SplashScreen.hide();
|
||||
}, 300);
|
||||
} else {
|
||||
await SplashScreen.show({
|
||||
autoHide: false
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async presentToast(msg: string, duration: "short" | "long", pos: "top" | "center" | "bottom") {
|
||||
await Toast.show({
|
||||
text: msg,
|
||||
duration: duration,
|
||||
position: pos
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,12 @@ import { ScreenOrientation } from '@awesome-cordova-plugins/screen-orientation/n
|
|||
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { HistoryTutorialPageModule } from './modals/history-tutorial/history-tutorial.module';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { EnvService } from './services/env.service';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BookmarkTutorialPageModule } from './modals/bookmark-tutorial/bookmark-tutorial.module';
|
||||
import { QrCodePageModule } from './modals/qr-code/qr-code.module';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
|
@ -39,7 +37,7 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
|||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(),
|
||||
IonicModule.forRoot({ innerHTMLTemplatesEnabled: true }),
|
||||
AppRoutingModule,
|
||||
HttpClientModule,
|
||||
FormsModule,
|
||||
|
@ -51,8 +49,6 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
|||
}
|
||||
}),
|
||||
IonicStorageModule.forRoot(),
|
||||
HistoryTutorialPageModule,
|
||||
BookmarkTutorialPageModule,
|
||||
QrCodePageModule,
|
||||
BrowserAnimationsModule,
|
||||
MatFormFieldModule,
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { BookmarkTutorialPage } from './bookmark-tutorial.page';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
TranslateModule.forChild({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
],
|
||||
declarations: [BookmarkTutorialPage]
|
||||
})
|
||||
export class BookmarkTutorialPageModule {}
|
|
@ -1,57 +0,0 @@
|
|||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar [color]="color">
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content [color]="color" #content>
|
||||
|
||||
<ion-list-header class="mt-4 ml-3" style="font-size: x-large;">{{ 'TUTORIAL' | translate }}</ion-list-header>
|
||||
|
||||
<ion-item class="content-item ion-no-padding" lines="none" [color]="color">
|
||||
<ion-icon class="ion-padding-horizontal" src="assets/icon/swipe-left.svg"
|
||||
[color]="'primary'"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.TUTORIAL_SWIPE_LEFT' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="content-item ion-no-padding" lines="none" [color]="color">
|
||||
<ion-icon class="ion-padding-horizontal" src="assets/icon/swipe-right.svg"
|
||||
[color]="'primary'"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.BOOKMARK_TUTORIAL_SWIPE_RIGHT' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
|
||||
<ion-item lines="none" [color]="color" style="--ripple-color: transparent;">
|
||||
<ion-checkbox class="ion-margin-horizontal" [(ngModel)]="env.notShowBookmarkTutorial"
|
||||
[color]="'primary'" (ionChange)="saveBookmarkTutorialShowing()"></ion-checkbox>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.TUTORIAL_NOT_SHOW_AGAIN' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-toolbar [color]="color" style="border: none;">
|
||||
<ion-row class="d-flex align-items-center justify-content-end">
|
||||
<ion-button class="ion-margin-horizontal ion-margin-bottom" fill="clear" (click)="tapHaptic(); closeModal()" color="primary">
|
||||
{{ 'OK' | translate }}
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
</ion-toolbar>
|
||||
|
||||
</ion-footer>
|
|
@ -1,18 +0,0 @@
|
|||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-item {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
ion-footer {
|
||||
&.footer-md::before {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-ios ion-toolbar:first-of-type {
|
||||
--border-width: 0 !important;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
import { Component, ViewChild } from '@angular/core';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { ModalController } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookmark-tutorial',
|
||||
templateUrl: './bookmark-tutorial.page.html',
|
||||
styleUrls: ['./bookmark-tutorial.page.scss'],
|
||||
})
|
||||
export class BookmarkTutorialPage {
|
||||
|
||||
@ViewChild('content') contentEl: HTMLIonContentElement;
|
||||
|
||||
constructor(
|
||||
public modalController: ModalController,
|
||||
public translate: TranslateService,
|
||||
public env: EnvService,
|
||||
) {
|
||||
setTimeout(
|
||||
() => {
|
||||
this.contentEl.scrollToBottom(500);
|
||||
}, 750
|
||||
);
|
||||
}
|
||||
|
||||
async saveBookmarkTutorialShowing() {
|
||||
if (this.env.notShowBookmarkTutorial === true) {
|
||||
await this.env.storageSet("not-show-bookmark-tutorial", 'yes');
|
||||
} else {
|
||||
await this.env.storageSet("not-show-bookmark-tutorial", 'no');
|
||||
}
|
||||
}
|
||||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeModal(): void {
|
||||
this.modalController.dismiss();
|
||||
}
|
||||
|
||||
get color() {
|
||||
switch (this.env.colorTheme) {
|
||||
case 'dark':
|
||||
return 'dark';
|
||||
case 'light':
|
||||
return 'white';
|
||||
case 'black':
|
||||
return 'black';
|
||||
default:
|
||||
return 'white';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { HistoryTutorialPage } from './history-tutorial.page';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
TranslateModule.forChild({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
],
|
||||
declarations: [HistoryTutorialPage]
|
||||
})
|
||||
export class HistoryTutorialPageModule {}
|
|
@ -1,57 +0,0 @@
|
|||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar [color]="color">
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content [color]="color" #content>
|
||||
|
||||
<ion-list-header class="mt-4 ml-3" style="font-size: x-large;">{{ 'TUTORIAL' | translate }}</ion-list-header>
|
||||
|
||||
<ion-item class="content-item ion-no-padding" lines="none" [color]="color">
|
||||
<ion-icon class="ion-padding-horizontal" src="assets/icon/swipe-left.svg"
|
||||
[color]="'primary'"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.TUTORIAL_SWIPE_LEFT' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="content-item ion-no-padding" lines="none" [color]="color">
|
||||
<ion-icon class="ion-padding-horizontal" src="assets/icon/swipe-right.svg"
|
||||
[color]="'primary'"></ion-icon>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.TUTORIAL_SWIPE_RIGHT' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
|
||||
<ion-item lines="none" [color]="color" style="--ripple-color: transparent;">
|
||||
<ion-checkbox class="ion-margin-horizontal" [(ngModel)]="env.notShowHistoryTutorial"
|
||||
[color]="'primary'" (ionChange)="saveHistoryTutorialShowing()"></ion-checkbox>
|
||||
<ion-label>
|
||||
<p class="ion-padding">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
{{ 'MSG.TUTORIAL_NOT_SHOW_AGAIN' | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-toolbar [color]="color" style="border: none;">
|
||||
<ion-row class="d-flex align-items-center justify-content-end">
|
||||
<ion-button class="ion-margin-horizontal ion-margin-bottom" fill="clear" (click)="tapHaptic(); closeModal()" color="primary">
|
||||
{{ 'OK' | translate }}
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
</ion-toolbar>
|
||||
|
||||
</ion-footer>
|
|
@ -1,18 +0,0 @@
|
|||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-item {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
ion-footer {
|
||||
&.footer-md::before {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-ios ion-toolbar:first-of-type {
|
||||
--border-width: 0 !important;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
import { Component, ViewChild } from '@angular/core';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { ModalController, ToastController } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-history-tutorial',
|
||||
templateUrl: './history-tutorial.page.html',
|
||||
styleUrls: ['./history-tutorial.page.scss'],
|
||||
})
|
||||
export class HistoryTutorialPage {
|
||||
|
||||
@ViewChild('content') contentEl: HTMLIonContentElement;
|
||||
|
||||
constructor(
|
||||
public modalController: ModalController,
|
||||
public translate: TranslateService,
|
||||
public env: EnvService,
|
||||
) {
|
||||
setTimeout(
|
||||
() => {
|
||||
this.contentEl.scrollToBottom(500);
|
||||
}, 750
|
||||
);
|
||||
}
|
||||
|
||||
async saveHistoryTutorialShowing() {
|
||||
if (this.env.notShowHistoryTutorial === true) {
|
||||
await this.env.storageSet("not-show-history-tutorial", 'yes');
|
||||
} else {
|
||||
await this.env.storageSet("not-show-history-tutorial", 'no');
|
||||
}
|
||||
}
|
||||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeModal(): void {
|
||||
this.modalController.dismiss();
|
||||
}
|
||||
|
||||
get color() {
|
||||
switch (this.env.colorTheme) {
|
||||
case 'dark':
|
||||
return 'dark';
|
||||
case 'light':
|
||||
return 'white';
|
||||
case 'black':
|
||||
return 'black';
|
||||
default:
|
||||
return 'white';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -8,11 +8,7 @@ import { QrCodePage } from './qr-code.page';
|
|||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
|
||||
import { QRCodeModule } from 'angularx-qrcode';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
|
@ -23,7 +19,7 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
|||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
NgxQRCodeModule,
|
||||
QRCodeModule,
|
||||
TranslateModule.forChild({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
<div class="d-flex align-items-center justify-content-top flex-column" style="height: 100%;">
|
||||
<ion-row>
|
||||
<ion-col class="ion-text-center ion-padding" style="max-width: 100% !important;">
|
||||
<ngx-qrcode [elementType]="qrElementType" [value]="qrCodeContent" [width]="defaultWidth"
|
||||
<qrcode [elementType]="qrElementType" [qrdata]="qrCodeContent" [width]="defaultWidth"
|
||||
[errorCorrectionLevel]="errorCorrectionLevel" [colorDark]="qrColorDark" [colorLight]="qrColorLight"
|
||||
[margin]="env.qrCodeMargin" #qrcode [hidden]="isSharing">
|
||||
</ngx-qrcode>
|
||||
</qrcode>
|
||||
<div class="d-flex flex-column align-items-center" *ngIf="isSharing">
|
||||
<ion-spinner class="my-3"></ion-spinner>
|
||||
</div>
|
||||
|
|
|
@ -6,10 +6,11 @@ import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
|||
import { Toast } from '@capacitor/toast';
|
||||
import { LoadingController, ModalController, Platform } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NgxQrcodeElementTypes, NgxQrcodeErrorCorrectionLevels, QrcodeComponent } from '@techiediaries/ngx-qrcode';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
import { ScreenBrightness } from '@capacitor-community/screen-brightness';
|
||||
import { rgbToHex } from 'src/app/utils/helpers';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { QRCodeComponent, QRCodeElementType } from 'angularx-qrcode';
|
||||
|
||||
@Component({
|
||||
selector: 'app-qr-code',
|
||||
|
@ -20,11 +21,11 @@ export class QrCodePage {
|
|||
|
||||
modal: HTMLIonModalElement;
|
||||
|
||||
@ViewChild('qrcode') qrcodeElement: QrcodeComponent;
|
||||
@ViewChild('qrcode') qrcodeElement: QRCodeComponent;
|
||||
|
||||
@Input() qrCodeContent: string;
|
||||
qrElementType: NgxQrcodeElementTypes = NgxQrcodeElementTypes.CANVAS;
|
||||
errorCorrectionLevel: NgxQrcodeErrorCorrectionLevels;
|
||||
qrElementType: QRCodeElementType = "canvas";
|
||||
errorCorrectionLevel: 'low' | 'medium' | 'quartile' | 'high' | 'L' | 'M' | 'Q' | 'H';
|
||||
scale: number = 0.8;
|
||||
readonly MAX_WIDTH = 350;
|
||||
defaultWidth: number = window.innerHeight * 0.32 > this.MAX_WIDTH ? this.MAX_WIDTH : window.innerHeight * 0.32;
|
||||
|
@ -63,7 +64,6 @@ export class QrCodePage {
|
|||
if (this.qrcodeElement.width > this.MAX_WIDTH) {
|
||||
this.qrcodeElement.width = this.MAX_WIDTH;
|
||||
}
|
||||
this.qrcodeElement.createQRCode();
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,6 @@ export class QrCodePage {
|
|||
if (this.qrcodeElement.width > this.MAX_WIDTH) {
|
||||
this.qrcodeElement.width = this.MAX_WIDTH;
|
||||
}
|
||||
this.qrcodeElement.createQRCode();
|
||||
}
|
||||
})
|
||||
this.modal.onDidDismiss().then(
|
||||
|
@ -131,25 +130,25 @@ export class QrCodePage {
|
|||
setErrorCorrectionLevel() {
|
||||
switch (this.env.errorCorrectionLevel) {
|
||||
case 'L':
|
||||
this.errorCorrectionLevel = NgxQrcodeErrorCorrectionLevels.LOW;
|
||||
this.errorCorrectionLevel = 'low';
|
||||
break;
|
||||
case 'M':
|
||||
this.errorCorrectionLevel = NgxQrcodeErrorCorrectionLevels.MEDIUM;
|
||||
this.errorCorrectionLevel = 'medium';
|
||||
break;
|
||||
case 'Q':
|
||||
this.errorCorrectionLevel = NgxQrcodeErrorCorrectionLevels.QUARTILE;
|
||||
this.errorCorrectionLevel = 'quartile';
|
||||
break;
|
||||
case 'H':
|
||||
this.errorCorrectionLevel = NgxQrcodeErrorCorrectionLevels.HIGH;
|
||||
this.errorCorrectionLevel = 'high';
|
||||
break;
|
||||
default:
|
||||
this.errorCorrectionLevel = NgxQrcodeErrorCorrectionLevels.MEDIUM;
|
||||
this.errorCorrectionLevel = 'medium';
|
||||
}
|
||||
}
|
||||
|
||||
async onErrorCorrectionLevelChange() {
|
||||
this.setErrorCorrectionLevel();
|
||||
await this.env.storageSet("error-correction-level", this.env.errorCorrectionLevel);
|
||||
await Preferences.set({ key: this.env.KEY_ERROR_CORRECTION_LEVEL, value: this.env.errorCorrectionLevel });
|
||||
if (this.qrcodeElement != null) {
|
||||
this.qrcodeElement.errorCorrectionLevel = this.errorCorrectionLevel;
|
||||
} else {
|
||||
|
@ -169,7 +168,6 @@ export class QrCodePage {
|
|||
this.isSharing = true;
|
||||
const currentWidth = this.qrcodeElement.width;
|
||||
this.qrcodeElement.width = 1000;
|
||||
this.qrcodeElement.createQRCode();
|
||||
setTimeout(async () => {
|
||||
const canvases = document.querySelectorAll("canvas") as NodeListOf<HTMLCanvasElement>;
|
||||
const canvas = canvases[canvases.length - 1];
|
||||
|
@ -182,7 +180,6 @@ export class QrCodePage {
|
|||
await this.socialSharing.share(this.translate.instant('MSG.SHARE_QR'), this.translate.instant('SIMPLE_QR'), this.qrImageDataUrl, null).then(
|
||||
_ => {
|
||||
this.qrcodeElement.width = currentWidth;
|
||||
this.qrcodeElement.createQRCode();
|
||||
delete this.qrImageDataUrl;
|
||||
this.isSharing = false;
|
||||
loading2.dismiss();
|
||||
|
@ -193,7 +190,6 @@ export class QrCodePage {
|
|||
this.presentToast("Error when call SocialSharing.share: " + JSON.stringify(err), "long", "top");
|
||||
}
|
||||
this.qrcodeElement.width = currentWidth;
|
||||
this.qrcodeElement.createQRCode();
|
||||
delete this.qrImageDataUrl;
|
||||
this.isSharing = false;
|
||||
loading2.dismiss();
|
||||
|
@ -241,7 +237,7 @@ export class QrCodePage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-toolbar [color]="env.colorTheme === 'black'? 'black' : 'dark'">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button text="">
|
||||
<ion-back-button text="" defaultHref="tabs/setting">
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'ABOUT' | translate }}</ion-title>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { AlertController, Platform } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
@ -89,7 +90,7 @@ export class AboutPage {
|
|||
if (this.env.debugMode != 'on') {
|
||||
if (this.tapAppVersionTimes >= 5) {
|
||||
this.env.debugMode = 'on';
|
||||
await this.env.storageSet("debug-mode-on", 'on');
|
||||
await Preferences.set({ key: this.env.KEY_DEBUG_MODE, value: 'on' });
|
||||
await Toast.show({
|
||||
text: this.translate.instant("MSG.DEBUG_MODE_ON"),
|
||||
duration: "short",
|
||||
|
|
|
@ -25,20 +25,22 @@
|
|||
|
||||
<ion-row class="ion-padding-horizontal">
|
||||
<ion-col>
|
||||
<mat-form-field [class]="ngMatThemeClass" color="accent" appearance="legacy">
|
||||
<mat-form-field [class]="ngMatThemeClass" color="accent" appearance="outline" [floatLabel]="'always'">
|
||||
<mat-label>{{ 'CONTENT_TYPE' | translate}}</mat-label>
|
||||
<mat-select [(ngModel)]="contentType">
|
||||
<mat-select-trigger>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<mat-icon style="margin-right: 16px; vertical-align: middle;">
|
||||
{{ getIcon(contentType) }}
|
||||
<div class="d-flex">
|
||||
<mat-icon class="me-3" [fontIcon]="getIcon(contentType)">
|
||||
</mat-icon>
|
||||
<span>{{ getText(contentType) }}</span>
|
||||
</div>
|
||||
</mat-select-trigger>
|
||||
<mat-option [value]="type.value" *ngFor="let type of contentTypes">
|
||||
<mat-icon>{{ getIcon(type.value) }}</mat-icon>
|
||||
<div class="d-flex">
|
||||
<mat-icon class="me-3" [fontIcon]="getIcon(type.value)">
|
||||
</mat-icon>
|
||||
<span>{{ type.text }}</span>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
@ -69,7 +71,7 @@
|
|||
<mat-label>{{ 'EMAIL_RECIPIENT' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="toEmails[i]" type="email" maxlength="254" #emailToInput>
|
||||
<mat-hint align="end">{{ emailToInput.value?.length || 0 }}/254</mat-hint>
|
||||
<mat-icon matSuffix color="accent">alternate_email</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="alternate_email"></mat-icon>
|
||||
<mat-hint>{{'MSG.EMAIL_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
|
@ -98,7 +100,7 @@
|
|||
<mat-label>{{ 'CC' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="ccEmails[i]" type="email" maxlength="254" #emailCcInput>
|
||||
<mat-hint align="end">{{ emailCcInput.value?.length || 0 }}/254</mat-hint>
|
||||
<mat-icon matSuffix color="accent">alternate_email</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="alternate_email"></mat-icon>
|
||||
<mat-hint>{{'MSG.EMAIL_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
|
@ -127,7 +129,7 @@
|
|||
<mat-label>{{ 'BCC' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="bccEmails[i]" type="email" maxlength="254" #emailBccInput>
|
||||
<mat-hint align="end">{{ emailBccInput.value?.length || 0 }}/254</mat-hint>
|
||||
<mat-icon matSuffix color="accent">alternate_email</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="alternate_email"></mat-icon>
|
||||
<mat-hint>{{'MSG.EMAIL_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
|
@ -182,7 +184,7 @@
|
|||
<mat-label>{{ 'EMAIL_RECIPIENT' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="toEmails[0]" type="email" maxlength="254" #emailToInput>
|
||||
<mat-hint align="end">{{ emailToInput.value?.length || 0 }}/254</mat-hint>
|
||||
<mat-icon matSuffix color="accent">alternate_email</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="alternate_email"></mat-icon>
|
||||
<mat-hint>{{'MSG.EMAIL_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
|
@ -213,13 +215,32 @@
|
|||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="contentType === 'geo'">
|
||||
<ion-row class="ion-padding-horizontal" [@inAnimation]>
|
||||
<ion-col>
|
||||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'LATITUDE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="latitude" type="number" #latitudeInput>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="ion-padding-horizontal" [@inAnimation]>
|
||||
<ion-col>
|
||||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'LONGITUDE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="longitude" type="number" #longitudeInput>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="contentType === 'phone'">
|
||||
<ion-row class="ion-padding-horizontal" [@inAnimation]>
|
||||
<ion-col>
|
||||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'PHONE_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="phoneNumber" type="tel" #phoneNumberInput>
|
||||
<mat-icon matSuffix color="accent">call</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="call"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -231,7 +252,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'PHONE_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="phoneNumber" type="tel" #phoneNumberInput>
|
||||
<mat-icon matSuffix color="accent">call</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="call"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -254,7 +275,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'URL' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="url" type="url" #urlInput maxlength="1817">
|
||||
<mat-icon matSuffix color="accent">link</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="link"></mat-icon>
|
||||
<mat-hint align="end">{{ (urlInput.value?.length) || 0 }}/1817</mat-hint>
|
||||
<mat-hint>{{'MSG.CREATE_QRCODE_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
@ -278,7 +299,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'FIRST_NAME' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="firstName" #firstNameInput />
|
||||
<mat-icon matSuffix color="accent">badge</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="badge"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -287,7 +308,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'LAST_NAME' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="lastName" #lastNameInput />
|
||||
<mat-icon matSuffix color="accent">badge</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="badge"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -306,7 +327,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'MOBILE_PHONE_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="mobilePhoneNumber" #mobilePhoneInput type="tel" />
|
||||
<mat-icon matSuffix color="accent">call</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="call"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -315,7 +336,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'HOME_PHONE_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="homePhoneNumber" #homePhoneInput type="tel" />
|
||||
<mat-icon matSuffix color="accent">call</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="call"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -324,7 +345,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'WORK_PHONE_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="workPhoneNumber" #workPhoneInput type="tel" />
|
||||
<mat-icon matSuffix color="accent">call</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="call"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -333,7 +354,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'FAX_NUMBER' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="faxNumber" #faxInput type="tel" />
|
||||
<mat-icon matSuffix color="accent">print</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="print"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -342,7 +363,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'EMAIL_ADDRESS' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="email" #emailInput type="email" />
|
||||
<mat-icon matSuffix color="accent">alternate_email</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="alternate_email"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -361,7 +382,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'ORGANIZATION' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="organization" #organizationInput type="text" />
|
||||
<mat-icon matSuffix color="accent">business</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="business"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -370,7 +391,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'JOB_TITLE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="jobTitle" #jobTitleInput type="text" />
|
||||
<mat-icon matSuffix color="accent">business</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="business"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -389,7 +410,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'STREET' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="street" #streetInput type="text" />
|
||||
<mat-icon matSuffix color="accent">home</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="home"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -398,7 +419,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'CITY' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="city" #cityInput type="text" />
|
||||
<mat-icon matSuffix color="accent">home</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="home"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -407,7 +428,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'STATE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="state" #stateInput type="text" />
|
||||
<mat-icon matSuffix color="accent">home</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="home"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -416,7 +437,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'POSTAL_CODE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="postalCode" #postalCodeInput type="text" />
|
||||
<mat-icon matSuffix color="accent">home</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="home"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -425,7 +446,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'COUNTRY' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="country" #countryInput type="text" />
|
||||
<mat-icon matSuffix color="accent">home</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="home"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -445,7 +466,7 @@
|
|||
<mat-label>{{ 'DATE_OF_BIRTH' | translate}}</mat-label>
|
||||
<input [ngModel]="birthday | date:'yyyy-MM-dd'" (ngModelChange)="birthday = $event" matInput type="date"
|
||||
[max]="today">
|
||||
<mat-icon matSuffix color="accent">cake</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="cake"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -466,7 +487,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'WEBSITE' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="personalUrl" type="url" #personalUrlInput>
|
||||
<mat-icon matSuffix color="accent">link</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="link"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
@ -478,7 +499,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'WIFI_SSID' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="ssid" #ssidInput maxlength="32">
|
||||
<mat-icon matSuffix color="accent">wifi</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="wifi"></mat-icon>
|
||||
<mat-hint align="end">{{ (ssidInput.value?.length) || 0 }}/32</mat-hint>
|
||||
<mat-hint>{{'MSG.SSID_MAX_LENGTH' | translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
|
@ -489,7 +510,7 @@
|
|||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent">
|
||||
<mat-label>{{ 'PASSWORD' | translate}}</mat-label>
|
||||
<input matInput [(ngModel)]="wifiPassword" #wifiPasswordInput type="password">
|
||||
<mat-icon matSuffix color="accent">lock</mat-icon>
|
||||
<mat-icon matSuffix color="accent" fontIcon="lock"></mat-icon>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
|
|
@ -4,8 +4,8 @@ import { Router } from '@angular/router';
|
|||
import { Haptics, ImpactStyle, NotificationType } from '@capacitor/haptics';
|
||||
import { AlertController, LoadingController, ToastController } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import * as moment from 'moment';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
import { format } from 'date-fns';
|
||||
import { EnvService, QrCreateContentTypeType } from 'src/app/services/env.service';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { fadeIn } from 'src/app/utils/animations';
|
||||
import { SplashScreen } from '@capacitor/splash-screen';
|
||||
|
@ -23,6 +23,7 @@ export class GeneratePage {
|
|||
freeTxtText: string = "Free Text";
|
||||
urlText: string = "URL";
|
||||
contactText: string = "vCard Contact";
|
||||
geolocationText: string = "Geolocation";
|
||||
phoneText: string = "Phone";
|
||||
smsText: string = "Message";
|
||||
emailW3CText: string = "Email (W3C Standard)";
|
||||
|
@ -37,6 +38,9 @@ export class GeneratePage {
|
|||
emailSubject: string = "";
|
||||
emailBody: string = "";
|
||||
|
||||
latitude: number = 0;
|
||||
longitude: number = 0;
|
||||
|
||||
phoneNumber: string = "";
|
||||
|
||||
smsMessage: string = "";
|
||||
|
@ -57,7 +61,7 @@ export class GeneratePage {
|
|||
state: string = "";
|
||||
postalCode: string = "";
|
||||
country: string = "";
|
||||
birthday: Date;
|
||||
birthday: string;
|
||||
gender: "M" | "F" | "O" = "O";
|
||||
personalUrl: string = "";
|
||||
|
||||
|
@ -84,17 +88,18 @@ export class GeneratePage {
|
|||
{ text: this.wpaText, value: "WPA" },
|
||||
]
|
||||
|
||||
contentTypes: { text: string, value: "freeText" | "url" | "contact" | "phone" | "sms" | "emailW3C" | "emailDocomo" | "wifi" }[] = [
|
||||
contentTypes: { text: string, value: QrCreateContentTypeType }[] = [
|
||||
{ text: this.freeTxtText, value: 'freeText' },
|
||||
{ text: this.emailW3CText, value: 'emailW3C' },
|
||||
{ text: this.emailDocomoText, value: 'emailDocomo' },
|
||||
{ text: this.geolocationText, value: 'geo' },
|
||||
{ text: this.phoneText, value: 'phone' },
|
||||
{ text: this.smsText, value: 'sms' },
|
||||
{ text: this.urlText, value: 'url' },
|
||||
{ text: this.contactText, value: 'contact' },
|
||||
{ text: this.wifiText, value: 'wifi' },
|
||||
];
|
||||
contentType: "freeText" | "url" | "contact" | "phone" | "sms" | "emailW3C" | "emailDocomo" | "wifi" = "freeText";
|
||||
contentType: QrCreateContentTypeType = "freeText";
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
|
@ -106,9 +111,14 @@ export class GeneratePage {
|
|||
|
||||
async ionViewDidEnter() {
|
||||
await SplashScreen.hide()
|
||||
if (this.env.editingContent) {
|
||||
this.qrCodeContent = this.env.resultContent;
|
||||
this.env.editingContent = false;
|
||||
}
|
||||
this.freeTxtText = this.translate.instant("FREE_TEXT");
|
||||
this.urlText = this.translate.instant("URL");
|
||||
this.contactText = this.translate.instant("VCARD_CONTACT");
|
||||
this.geolocationText = this.translate.instant("GEOLOCATION");
|
||||
this.phoneText = this.translate.instant("PHONE_NO");
|
||||
this.smsText = this.translate.instant("MESSAGE");
|
||||
this.emailW3CText = this.translate.instant("EMAIL_W3C_STANDARD");
|
||||
|
@ -118,6 +128,7 @@ export class GeneratePage {
|
|||
{ text: this.freeTxtText, value: 'freeText' },
|
||||
{ text: this.emailW3CText, value: 'emailW3C' },
|
||||
{ text: this.emailDocomoText, value: 'emailDocomo' },
|
||||
{ text: this.geolocationText, value: 'geo' },
|
||||
{ text: this.phoneText, value: 'phone' },
|
||||
{ text: this.smsText, value: 'sms' },
|
||||
{ text: this.urlText, value: 'url' },
|
||||
|
@ -191,6 +202,9 @@ export class GeneratePage {
|
|||
this.emailSubject = "";
|
||||
this.emailBody = "";
|
||||
|
||||
this.latitude = 0;
|
||||
this.longitude = 0;
|
||||
|
||||
this.phoneNumber = "";
|
||||
|
||||
this.smsMessage = "";
|
||||
|
@ -259,6 +273,9 @@ export class GeneratePage {
|
|||
this.qrCodeContent = `MATMSG:TO:${this.toEmails[0]};SUB:${this.emailSubject};BODY:${this.emailBody};;`;
|
||||
this.qrCodeContent = encodeURI(this.qrCodeContent);
|
||||
break;
|
||||
case "geo":
|
||||
this.qrCodeContent = `geo:${this.latitude},${this.longitude}`;
|
||||
break;
|
||||
case "phone":
|
||||
this.qrCodeContent = "tel:";
|
||||
this.qrCodeContent += this.phoneNumber;
|
||||
|
@ -295,8 +312,8 @@ export class GeneratePage {
|
|||
}
|
||||
|
||||
async processQrCode(loading: HTMLIonLoadingElement): Promise<void> {
|
||||
this.env.result = this.qrCodeContent;
|
||||
this.env.resultFormat = "";
|
||||
this.env.resultContent = this.qrCodeContent;
|
||||
this.env.resultContentFormat = "";
|
||||
this.qrCodeContent = '';
|
||||
this.env.recordSource = "create";
|
||||
this.env.detailedRecordSource = "create";
|
||||
|
@ -320,9 +337,10 @@ export class GeneratePage {
|
|||
vCard += `ORG:${this.organization.trim()}\n`;
|
||||
vCard += `TITLE:${this.jobTitle.trim()}\n`;
|
||||
vCard += `ADR:;;${this.street.trim()};${this.city.trim()};${this.state.trim()};${this.postalCode.trim()};${this.country.trim()}\n`;
|
||||
console.log("birthday => " + this.birthday)
|
||||
if (this.birthday && this.birthday !== null && this.birthday !== undefined) {
|
||||
vCard += `BDAY:${moment(this.birthday).format('YYYYMMDD')}\n`;
|
||||
if (this.birthday != null) {
|
||||
const find = '-';
|
||||
const re = new RegExp(find, 'g');
|
||||
vCard += `BDAY:${this.birthday.replace(re, "")}\n`;
|
||||
}
|
||||
vCard += `URL:${this.personalUrl.trim()}\n`;
|
||||
vCard += `GENDER:${this.gender}\n`;
|
||||
|
@ -340,10 +358,10 @@ export class GeneratePage {
|
|||
}
|
||||
|
||||
get today() {
|
||||
return moment().format("YYYY-MM-DD");
|
||||
return format(new Date(), "yyyy-MM-dd");
|
||||
}
|
||||
|
||||
getIcon(type: "freeText" | "url" | "contact" | "phone" | "sms" | "emailW3C" | "emailDocomo" | "wifi"): string {
|
||||
getIcon(type: QrCreateContentTypeType): string {
|
||||
switch (type) {
|
||||
case "freeText":
|
||||
return "format_align_left";
|
||||
|
@ -351,6 +369,8 @@ export class GeneratePage {
|
|||
return "link";
|
||||
case "contact":
|
||||
return "contact_phone";
|
||||
case "geo":
|
||||
return "location_on";
|
||||
case "phone":
|
||||
return "call";
|
||||
case "sms":
|
||||
|
@ -366,7 +386,7 @@ export class GeneratePage {
|
|||
}
|
||||
}
|
||||
|
||||
getText(type: "freeText" | "url" | "contact" | "phone" | "sms" | "emailW3C" | "emailDocomo" | "wifi"): string {
|
||||
getText(type: QrCreateContentTypeType): string {
|
||||
switch (type) {
|
||||
case "freeText":
|
||||
return this.freeTxtText;
|
||||
|
@ -374,6 +394,8 @@ export class GeneratePage {
|
|||
return this.urlText;
|
||||
case "contact":
|
||||
return this.contactText;
|
||||
case "geo":
|
||||
return this.geolocationText;
|
||||
case "phone":
|
||||
return this.phoneText;
|
||||
case "sms":
|
||||
|
@ -442,7 +464,7 @@ export class GeneratePage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<ion-title>{{ 'SIMPLE_QR' | translate}}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="tapHaptic(); goSetting()" fill="clear">
|
||||
{{ 'SETTING' | translate }}
|
||||
{{ 'MORE' | translate }}
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<ion-title *ngIf="segmentModel === 'bookmarks'">{{ 'BOOKMARKS' | translate }}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="tapHaptic(); goSetting()" fill="clear" color="primary">
|
||||
{{ 'SETTING' | translate }}
|
||||
{{ 'MORE' | translate }}
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
|
|
@ -2,14 +2,13 @@ import { ChangeDetectorRef, Component } from '@angular/core';
|
|||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AlertController, IonItemSliding, LoadingController, ModalController, PopoverController, ToastController } from '@ionic/angular';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
import * as moment from 'moment';
|
||||
import { format, Locale } from 'date-fns';
|
||||
import { de, enUS, fr, it, ptBR, ru, zhCN, zhHK } from 'date-fns/locale';
|
||||
import { ScanRecord } from 'src/app/models/scan-record';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Bookmark } from 'src/app/models/bookmark';
|
||||
import { HistoryTutorialPage } from 'src/app/modals/history-tutorial/history-tutorial.page';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { BookmarkTutorialPage } from 'src/app/modals/bookmark-tutorial/bookmark-tutorial.page';
|
||||
import { fastFadeIn, flyOut } from 'src/app/utils/animations';
|
||||
import { SplashScreen } from '@capacitor/splash-screen';
|
||||
|
||||
|
@ -99,19 +98,6 @@ export class HistoryPage {
|
|||
async ionViewDidEnter() {
|
||||
await SplashScreen.hide()
|
||||
this.segmentModel = this.env.historyPageStartSegment;
|
||||
if (this.segmentModel == 'history') {
|
||||
if (this.env.notShowHistoryTutorial === false) {
|
||||
this.env.notShowHistoryTutorial = true;
|
||||
this.env.storageSet("not-show-history-tutorial", 'yes');
|
||||
await this.showHistoryTutorial();
|
||||
}
|
||||
} else if (this.segmentModel == 'bookmarks') {
|
||||
if (this.env.notShowBookmarkTutorial === false) {
|
||||
this.env.notShowBookmarkTutorial = true;
|
||||
this.env.storageSet("not-show-bookmark-tutorial", 'yes');
|
||||
await this.showBookmarkTutorial();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ionViewWillLeave() {
|
||||
|
@ -134,41 +120,46 @@ export class HistoryPage {
|
|||
return bookmark.id;
|
||||
}
|
||||
|
||||
async showHistoryTutorial() {
|
||||
const modal = await this.modalController.create({
|
||||
component: HistoryTutorialPage,
|
||||
componentProps: {
|
||||
}
|
||||
});
|
||||
modal.present();
|
||||
}
|
||||
|
||||
async showBookmarkTutorial() {
|
||||
const modal = await this.modalController.create({
|
||||
component: BookmarkTutorialPage,
|
||||
componentProps: {
|
||||
}
|
||||
});
|
||||
modal.present();
|
||||
}
|
||||
|
||||
maskDatetimeAndSource(date: Date, source: 'create' | 'view' | 'scan' | undefined): string {
|
||||
if (!date) {
|
||||
return "-";
|
||||
}
|
||||
const momentObj = moment(date);
|
||||
if (this.env.language != 'en') {
|
||||
momentObj.locale(this.env.language.toLowerCase());
|
||||
let locale: Locale;
|
||||
switch (this.env.language) {
|
||||
case "de":
|
||||
locale = de;
|
||||
break;
|
||||
case "en":
|
||||
locale = enUS;
|
||||
break;
|
||||
case "fr":
|
||||
locale = fr;
|
||||
break;
|
||||
case "it":
|
||||
locale = it;
|
||||
break;
|
||||
case "pt-BR":
|
||||
locale = ptBR;
|
||||
break;
|
||||
case "ru":
|
||||
locale = ru;
|
||||
break;
|
||||
case "zh-CN":
|
||||
locale = zhCN;
|
||||
break;
|
||||
case "zh-HK":
|
||||
locale = zhHK;
|
||||
break;
|
||||
default:
|
||||
locale = enUS;
|
||||
}
|
||||
switch (source) {
|
||||
case 'create':
|
||||
return `${this.translate.instant("CREATED")} ${this.translate.instant("AT")} ${momentObj.format("ll LTS")}`;
|
||||
return `${this.translate.instant("CREATED")} ${this.translate.instant("AT")} ${format(date, "PP pp", { locale: locale })}`;
|
||||
case 'view':
|
||||
return `${this.translate.instant("VIEWED")} ${this.translate.instant("AT")} ${momentObj.format("ll LTS")}`;
|
||||
return `${this.translate.instant("VIEWED")} ${this.translate.instant("AT")} ${format(date, "PP pp", { locale: locale })}`;
|
||||
case 'scan':
|
||||
return `${this.translate.instant("SCANNED")} ${this.translate.instant("AT")} ${momentObj.format("ll LTS")}`;
|
||||
default:
|
||||
return momentObj.format("ll LTS");
|
||||
return `${this.translate.instant("SCANNED")} ${this.translate.instant("AT")} ${format(date, "PP pp", { locale: locale })}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +204,7 @@ export class HistoryPage {
|
|||
case "RSS_EXPANDED":
|
||||
return this.translate.instant("BARCODE_TYPE.RSS").trim();
|
||||
default:
|
||||
return this.env.resultFormat;
|
||||
return this.env.resultContentFormat;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,8 +216,8 @@ export class HistoryPage {
|
|||
this.changeDetectorRef.detectChanges();
|
||||
this.changeDetectorRef.reattach();
|
||||
const loading = await this.presentLoading(this.translate.instant('PLEASE_WAIT'));
|
||||
this.env.result = data;
|
||||
this.env.resultFormat = "";
|
||||
this.env.resultContent = data;
|
||||
this.env.resultContentFormat = "";
|
||||
this.env.recordSource = "view";
|
||||
this.env.detailedRecordSource = source;
|
||||
this.env.viewResultFrom = "/tabs/history";
|
||||
|
@ -238,19 +229,6 @@ export class HistoryPage {
|
|||
}
|
||||
|
||||
async segmentChanged(ev: any) {
|
||||
if (ev?.detail?.value == 'history') {
|
||||
if (this.env.notShowHistoryTutorial === false) {
|
||||
this.env.notShowHistoryTutorial = true;
|
||||
this.env.storageSet("not-show-history-tutorial", 'yes');
|
||||
await this.showHistoryTutorial();
|
||||
}
|
||||
} else if (ev?.detail?.value == 'bookmarks') {
|
||||
if (this.env.notShowBookmarkTutorial === false) {
|
||||
this.env.notShowBookmarkTutorial = true;
|
||||
this.env.storageSet("not-show-bookmark-tutorial", 'yes');
|
||||
await this.showBookmarkTutorial();
|
||||
}
|
||||
}
|
||||
this.firstLoadItems();
|
||||
}
|
||||
|
||||
|
@ -530,7 +508,7 @@ export class HistoryPage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -9,7 +9,6 @@ import { ImportImagePageRoutingModule } from './import-image-routing.module';
|
|||
import { ImportImagePage } from './import-image.page';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
|
@ -29,7 +28,6 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
|||
}
|
||||
}),
|
||||
ImportImagePageRoutingModule,
|
||||
MatButtonModule,
|
||||
],
|
||||
declarations: [ImportImagePage]
|
||||
})
|
||||
|
|
|
@ -96,13 +96,21 @@ export class ImportImagePage {
|
|||
});
|
||||
await alert.present();
|
||||
}
|
||||
},
|
||||
async err => {
|
||||
getPictureLoading.dismiss();
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Camera.requestPermissions: ' + JSON.stringify(err), position: "bottom", duration: "long" })
|
||||
} else {
|
||||
Toast.show({ text: 'Unknown Error', position: "bottom", duration: "short" })
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async processQrCode(scannedData: string, loading: HTMLIonLoadingElement): Promise<void> {
|
||||
this.env.result = scannedData;
|
||||
this.env.resultFormat = "QR_CODE";
|
||||
this.env.resultContent = scannedData;
|
||||
this.env.resultContentFormat = "QR_CODE";
|
||||
this.env.recordSource = "scan";
|
||||
this.env.detailedRecordSource = "scan-image";
|
||||
this.env.viewResultFrom = "/tabs/import-image";
|
||||
|
@ -196,7 +204,7 @@ export class ImportImagePage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { AlertController, IonRouterOutlet, Platform } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
@ -50,10 +51,26 @@ export class LandingPage {
|
|||
}
|
||||
|
||||
async confirmExitApp(): Promise<void> {
|
||||
if (this.env.showExitAppAlert == "on") {
|
||||
const alert = await this.alertController.create({
|
||||
header: this.translate.instant('EXIT_APP'),
|
||||
message: this.translate.instant('MSG.EXIT_APP'),
|
||||
cssClass: ['alert-bg'],
|
||||
inputs: [
|
||||
{
|
||||
type: "checkbox",
|
||||
label: this.translate.instant("MSG.TUTORIAL_NOT_SHOW_AGAIN"),
|
||||
checked: false,
|
||||
handler: async (result) => {
|
||||
if (result.checked) {
|
||||
this.env.showExitAppAlert = "off";
|
||||
} else {
|
||||
this.env.showExitAppAlert = "on";
|
||||
}
|
||||
await Preferences.set({ key: this.env.KEY_SHOW_EXIT_APP_ALERT, value: this.env.showExitAppAlert });
|
||||
}
|
||||
}
|
||||
],
|
||||
cssClass: ['alert-bg', 'alert-input-no-border'],
|
||||
buttons: [
|
||||
{
|
||||
text: this.translate.instant('EXIT'),
|
||||
|
@ -70,6 +87,9 @@ export class LandingPage {
|
|||
]
|
||||
});
|
||||
await alert.present();
|
||||
} else {
|
||||
navigator['app'].exitApp();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import { IonicModule } from '@ionic/angular';
|
|||
import { ResultPageRoutingModule } from './result-routing.module';
|
||||
|
||||
import { ResultPage } from './result.page';
|
||||
import { NgxQRCodeModule } from '@techiediaries/ngx-qrcode';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
<ion-col>
|
||||
<ion-badge class="p-2" color="primary">
|
||||
<div class="d-flex align-items-center">
|
||||
<mat-icon *ngIf="contentTypeIcon != ''" style="margin-right: 16px;">
|
||||
{{ contentTypeIcon }}
|
||||
<mat-icon class="me-2" *ngIf="contentTypeIcon != ''" [fontIcon]="contentTypeIcon">
|
||||
</mat-icon>
|
||||
<span>{{ contentTypeText }}</span>
|
||||
</div>
|
||||
|
@ -28,7 +27,7 @@
|
|||
</ion-row>
|
||||
|
||||
<ng-container *ngIf="qrCodeContent && qrCodeContent.trim().length > 0" [ngTemplateOutlet]="contentBlock"
|
||||
[ngTemplateOutletContext]="{ label: barcodeFormat + ('CONTENT' | translate), content: qrCodeContent, hint: env.resultFormat }">
|
||||
[ngTemplateOutletContext]="{ label: barcodeFormat + ('CONTENT' | translate), content: qrCodeContent, hint: env.resultContentFormat, showEdit: true }">
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="base64Encoded && qrCodeContent && qrCodeContent.trim().length > 0"
|
||||
|
@ -97,6 +96,15 @@
|
|||
[ngTemplateOutletContext]="{ label: 'HIDDEN_NETWORK_?' | translate, content: wifiHidden === true? ('YES' | translate) : ('NO' | translate) }">
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="contentType === 'geo' && qrCodeContent && qrCodeContent.trim().length > 0 && latitude != null"
|
||||
[ngTemplateOutlet]="contentBlock" [ngTemplateOutletContext]="{ label: 'LATITUDE' | translate, content: latitude }">
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="contentType === 'geo' && qrCodeContent && qrCodeContent.trim().length > 0 && longitude != null"
|
||||
[ngTemplateOutlet]="contentBlock"
|
||||
[ngTemplateOutletContext]="{ label: 'LONGITUDE' | translate, content: longitude }">
|
||||
</ng-container>
|
||||
|
||||
<div class="ion-padding-horizontal ion-margin-horizontal ion-padding-bottom">
|
||||
</div>
|
||||
|
||||
|
@ -106,18 +114,34 @@
|
|||
[ngStyle]="env.colorTheme === 'dark'? {'background-color': '#222428'} : (env.colorTheme === 'black'? {'background-color': '#000000'} : {'background-color': '#F0F0F0'})">
|
||||
|
||||
<ng-container *ngIf="env.resultPageButtons === 'icon-only'">
|
||||
<ion-row *ngIf="contentType === 'url' && env.showBrowseButton === 'on' && isHttp" class="d-flex justify-content-center">
|
||||
<ion-row *ngIf="contentType === 'freeText' && env.showOpenFoodFactsButton === 'on' && isValidEan"
|
||||
class="d-flex justify-content-center">
|
||||
<ion-button (click)="tapHaptic(); searchOpenFoodFacts()" [color]="'primary'" fill="clear">
|
||||
<ion-icon name="fast-food"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngIf="contentType === 'url' && env.showBrowseButton === 'on' && isHttp"
|
||||
class="d-flex justify-content-center">
|
||||
<ion-button (click)="tapHaptic(); browseWebsite()" [color]="'primary'" fill="clear">
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngIf="contentType === 'url' && env.showOpenUrlButton === 'on' && !isHttp" class="d-flex justify-content-center">
|
||||
<ion-button *ngIf="" (click)="tapHaptic(); openLink()" [color]="'primary'" fill="clear">
|
||||
<ion-row *ngIf="contentType === 'url' && env.showOpenUrlButton === 'on' && !isHttp"
|
||||
class="d-flex justify-content-center">
|
||||
<ion-button (click)="tapHaptic(); openLink()" [color]="'primary'" fill="clear">
|
||||
<ion-icon name="open"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngIf="contentType === 'geo' && env.showOpenUrlButton === 'on'"
|
||||
class="d-flex justify-content-center">
|
||||
<ion-button (click)="tapHaptic(); openLink()" [color]="'primary'" fill="clear">
|
||||
<ion-icon name="map"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-row>
|
||||
|
||||
<ion-row *ngIf="contentType === 'contact' && env.showAddContactButton === 'on'"
|
||||
class="d-flex justify-content-center">
|
||||
<ion-button (click)="tapHaptic(); addContact()" [color]="'primary'" fill="clear">
|
||||
|
@ -164,7 +188,13 @@
|
|||
</ion-button>
|
||||
</ion-row>
|
||||
|
||||
<ion-row class="ion-padding-horizontal justify-content-around">
|
||||
<ion-row class="ion-padding-horizontal">
|
||||
<div class="d-flex justify-content-between detailed-action-button-container">
|
||||
<ion-button
|
||||
*ngIf="!resultSaved && this.env.scanRecordLogging == 'off' && this.qrCodeContent != null && this.qrCodeContent != '' "
|
||||
(click)="tapHaptic(); saveRecord()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="clear">
|
||||
<ion-icon slot="icon-only" src="assets/icon/history.svg"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-button *ngIf="env.showSearchButton === 'on'" (click)="tapHaptic(); webSearch()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="clear"
|
||||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
|
@ -178,6 +208,10 @@
|
|||
</ion-icon>
|
||||
<ion-icon *ngIf="env.searchEngine === 'yandex'" slot="icon-only" src="assets/icon/yandex.svg">
|
||||
</ion-icon>
|
||||
<ion-icon *ngIf="env.searchEngine === 'ecosia'" slot="icon-only" src="assets/icon/ecosia.svg">
|
||||
</ion-icon>
|
||||
<ion-icon *ngIf="env.searchEngine === 'brave'" slot="icon-only" src="assets/icon/brave-search.svg">
|
||||
</ion-icon>
|
||||
</ion-button>
|
||||
<ion-button *ngIf="env.showCopyButton === 'on'" (click)="tapHaptic(); copyText()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="clear"
|
||||
|
@ -199,89 +233,111 @@
|
|||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon slot="icon-only" name="bookmark"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
|
||||
</ion-row>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="env.resultPageButtons === 'detailed'">
|
||||
<ion-row class="ion-padding-horizontal py-2">
|
||||
<div class="d-flex justify-content-between detailed-action-button-container">
|
||||
<ion-button class="pr-1" *ngIf="contentType === 'url' && env.showBrowseButton === 'on' && isHttp"
|
||||
<ion-button class="pe-1"
|
||||
*ngIf="!resultSaved && this.env.scanRecordLogging == 'off' && this.qrCodeContent != null && this.qrCodeContent != '' "
|
||||
(click)="tapHaptic(); saveRecord()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pe-2" src="assets/icon/history.svg"></ion-icon>
|
||||
<ion-label>{{ 'SAVE' | translate }}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pe-1"
|
||||
*ngIf="contentType === 'freeText' && env.showOpenFoodFactsButton === 'on' && isValidEan"
|
||||
(click)="tapHaptic(); searchOpenFoodFacts()" [color]="env.colorTheme === 'light'? 'dark' : 'light'"
|
||||
fill="outline" shape="round" [@inAnimation]>
|
||||
<ion-icon class="pe-2" name="fast-food"></ion-icon>
|
||||
<ion-label>Facts</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pe-1" *ngIf="contentType === 'url' && env.showBrowseButton === 'on' && isHttp"
|
||||
(click)="tapHaptic(); browseWebsite()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="globe"></ion-icon>
|
||||
<ion-icon class="pe-2" name="globe"></ion-icon>
|
||||
<ion-label>{{ 'BROWSE' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="contentType === 'url' && env.showOpenUrlButton === 'on' && !isHttp"
|
||||
<ion-button class="pe-1"
|
||||
*ngIf="(contentType === 'url' || contentType === 'geo') && env.showOpenUrlButton === 'on' && !isHttp"
|
||||
(click)="tapHaptic(); openLink()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="open"></ion-icon>
|
||||
<ion-icon class="pe-2" [name]="contentType === 'geo'? 'map' : 'open'"></ion-icon>
|
||||
<ion-label>{{ 'OPEN' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1"
|
||||
<ion-button class="pe-1"
|
||||
*ngIf="(contentType === 'contact' || contentType === 'phone' || contentType === 'sms') && env.showAddContactButton === 'on'"
|
||||
(click)="tapHaptic(); addContact()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="person-add-sharp"></ion-icon>
|
||||
<ion-icon class="pe-2" name="person-add-sharp"></ion-icon>
|
||||
<ion-label>{{ 'ADD' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="contentType === 'phone' && env.showCallButton === 'on'"
|
||||
<ion-button class="pe-1" *ngIf="contentType === 'phone' && env.showCallButton === 'on'"
|
||||
(click)="tapHaptic(); callPhone()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="call"></ion-icon>
|
||||
<ion-icon class="pe-2" name="call"></ion-icon>
|
||||
<ion-label>{{ 'CALL' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="contentType === 'sms' && smsContent && env.showSendMessageButton === 'on'"
|
||||
<ion-button class="pe-1" *ngIf="contentType === 'sms' && smsContent && env.showSendMessageButton === 'on'"
|
||||
(click)="tapHaptic(); sendSms()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="send"></ion-icon>
|
||||
<ion-icon class="pe-2" name="send"></ion-icon>
|
||||
<ion-label>{{ 'SEND' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1"
|
||||
<ion-button class="pe-1"
|
||||
*ngIf="(contentType === 'emailW3C' || contentType === 'emailDocomo') && env.showSendEmailButton === 'on'"
|
||||
(click)="tapHaptic(); sendEmail()" [color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline"
|
||||
shape="round" [@inAnimation]>
|
||||
<ion-icon class="pr-2" name="mail"></ion-icon>
|
||||
<ion-icon class="pe-2" name="mail"></ion-icon>
|
||||
<ion-label>{{ 'SEND' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="env.showSearchButton === 'on'" (click)="tapHaptic(); webSearch()"
|
||||
<ion-button class="pe-1" *ngIf="env.showSearchButton === 'on'" (click)="tapHaptic(); webSearch()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline" shape="round" [@inAnimation]
|
||||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon class="pr-2" *ngIf="env.searchEngine === 'google'" slot="icon-only" name="logo-google">
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'google'" slot="icon-only" name="logo-google">
|
||||
</ion-icon>
|
||||
<ion-icon class="pr-2" *ngIf="env.searchEngine === 'bing'" slot="icon-only"
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'bing'" slot="icon-only"
|
||||
src="assets/icon/microsoft-bing.svg">
|
||||
</ion-icon>
|
||||
<ion-icon class="pr-2" *ngIf="env.searchEngine === 'yahoo'" slot="icon-only" src="assets/icon/yahoo.svg">
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'yahoo'" slot="icon-only" src="assets/icon/yahoo.svg">
|
||||
</ion-icon>
|
||||
<ion-icon class="pr-2" *ngIf="env.searchEngine === 'duckduckgo'" slot="icon-only"
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'duckduckgo'" slot="icon-only"
|
||||
src="assets/icon/duck-duck-go.svg">
|
||||
</ion-icon>
|
||||
<ion-icon class="pr-2" *ngIf="env.searchEngine === 'yandex'" slot="icon-only" src="assets/icon/yandex.svg">
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'yandex'" slot="icon-only" src="assets/icon/yandex.svg">
|
||||
</ion-icon>
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'ecosia'" slot="icon-only" src="assets/icon/ecosia.svg">
|
||||
</ion-icon>
|
||||
<ion-icon class="pe-2" *ngIf="env.searchEngine === 'brave'" slot="icon-only"
|
||||
src="assets/icon/brave-search.svg">
|
||||
</ion-icon>
|
||||
<ion-label>{{ 'SEARCH' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="env.showCopyButton === 'on'" (click)="tapHaptic(); copyText()"
|
||||
<ion-button class="pe-1" *ngIf="env.showCopyButton === 'on'" (click)="tapHaptic(); copyText()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline" shape="round" [@inAnimation]
|
||||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon class="pr-2" slot="icon-only" name="copy"></ion-icon>
|
||||
<ion-icon class="pe-2" slot="icon-only" name="copy"></ion-icon>
|
||||
<ion-label>{{ 'COPY' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="env.showBase64Button === 'on'" (click)="tapHaptic(); base64()"
|
||||
<ion-button class="pe-1" *ngIf="env.showBase64Button === 'on'" (click)="tapHaptic(); base64()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline" shape="round" [@inAnimation]
|
||||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon class="pr-2" slot="icon-only" name="code-working"></ion-icon>
|
||||
<ion-icon class="pe-2" slot="icon-only" name="code-working"></ion-icon>
|
||||
<ion-label>{{ 'BASE64' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button class="pr-1" *ngIf="env.showEnlargeButton === 'on'" (click)="tapHaptic(); enlarge()"
|
||||
<ion-button class="pe-1" *ngIf="env.showEnlargeButton === 'on'" (click)="tapHaptic(); enlarge()"
|
||||
[color]="env.colorTheme === 'light'? 'dark' : 'light'" fill="outline" shape="round" [@inAnimation]
|
||||
[disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon class="pr-2" slot="icon-only" name="qr-code-sharp"></ion-icon>
|
||||
<ion-icon class="pe-2" slot="icon-only" name="qr-code-sharp"></ion-icon>
|
||||
<ion-label>{{ 'SHOW' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
<ion-button *ngIf="env.showBookmarkButton === 'on'" (click)="tapHaptic(); handleBookmark()"
|
||||
[color]="!bookmarked? (env.colorTheme === 'light'? 'dark' : 'light') : 'warning'" fill="outline" shape="round"
|
||||
[@inAnimation] [disabled]="!qrCodeContent || (qrCodeContent && qrCodeContent.trim().length <= 0)">
|
||||
<ion-icon class="pr-2" slot="icon-only" name="bookmark"></ion-icon>
|
||||
<ion-icon class="pe-2" slot="icon-only" name="bookmark"></ion-icon>
|
||||
<ion-label *ngIf="!bookmarked">{{ 'BOOKMARK' | translate}}</ion-label>
|
||||
<ion-label *ngIf="bookmarked">{{ 'BOOKMARKED' | translate}}</ion-label>
|
||||
</ion-button>
|
||||
|
@ -291,7 +347,7 @@
|
|||
|
||||
</ion-footer>
|
||||
|
||||
<ng-template #contentBlock let-label="label" let-content="content" let-hint="hint">
|
||||
<ng-template #contentBlock let-label="label" let-content="content" let-hint="hint" let-showEdit="showEdit">
|
||||
<ion-row class="ion-padding-horizontal" [@inAnimation]>
|
||||
<ion-col>
|
||||
<mat-form-field [class]="ngMatThemeClass" appearance="outline" color="accent" [floatLabel]="'always'"
|
||||
|
@ -301,6 +357,10 @@
|
|||
[cdkAutosizeMaxRows]="20" readonly>
|
||||
</textarea>
|
||||
<mat-hint *ngIf="hint && hint != ''" style="opacity: 0.5;">{{ hint }}</mat-hint>
|
||||
<button mat-button color="primary" (click)="editContent()" *ngIf="showEdit" class="m-0 p-0 mt-3"
|
||||
style="background-color: transparent !important; color: var(--ion-color-primary) !important;">
|
||||
{{ 'EDIT' | translate }}
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Component, QueryList, ViewChildren } from '@angular/core';
|
||||
import { Clipboard } from '@capacitor/clipboard';
|
||||
import { Contacts, ContactType, EmailAddress, NewContact, PhoneNumber } from '@capacitor-community/contacts'
|
||||
import { ContactInput, Contacts, EmailInput, EmailType, PhoneInput, PhoneType } from '@capacitor-community/contacts';
|
||||
import { SMS } from '@awesome-cordova-plugins/sms/ngx';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { AlertController, LoadingController, ModalController, Platform } from '@ionic/angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NgxQrcodeElementTypes, NgxQrcodeErrorCorrectionLevels } from '@techiediaries/ngx-qrcode';
|
||||
import { VCardContact } from 'src/app/models/v-card-contact';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
import { EnvService, QrResultContentTypeType } from 'src/app/services/env.service';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';
|
||||
import { QrCodePage } from 'src/app/modals/qr-code/qr-code.page';
|
||||
import { fadeIn } from 'src/app/utils/animations';
|
||||
import { Router } from '@angular/router';
|
||||
import { QRCodeElementType } from 'angularx-qrcode';
|
||||
|
||||
@Component({
|
||||
selector: 'app-result',
|
||||
|
@ -23,11 +23,11 @@ import { Router } from '@angular/router';
|
|||
})
|
||||
export class ResultPage {
|
||||
|
||||
contentType: "freeText" | "url" | "contact" | "phone" | "sms" | "emailW3C" | "emailDocomo" | "wifi" = "freeText";
|
||||
contentType: QrResultContentTypeType = "freeText";
|
||||
|
||||
qrCodeContent: string;
|
||||
qrElementType: NgxQrcodeElementTypes = NgxQrcodeElementTypes.CANVAS;
|
||||
errorCorrectionLevel: NgxQrcodeErrorCorrectionLevels = NgxQrcodeErrorCorrectionLevels.LOW;
|
||||
qrElementType: QRCodeElementType = "canvas";
|
||||
errorCorrectionLevel: 'low' | 'medium' | 'quartile' | 'high' | 'L' | 'M' | 'Q' | 'H' = 'low';
|
||||
qrMargin: number = 3;
|
||||
|
||||
phoneNumber: string;
|
||||
|
@ -45,6 +45,9 @@ export class ResultPage {
|
|||
wifiEncryption: 'NONE' | 'WEP' | 'WPA';
|
||||
wifiHidden: boolean = false;
|
||||
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
|
||||
base64Encoded: boolean = false;
|
||||
base64EncodedText: string = "";
|
||||
base64Decoded: boolean = false;
|
||||
|
@ -54,6 +57,8 @@ export class ResultPage {
|
|||
|
||||
showQrFirst: boolean = false;
|
||||
|
||||
resultSaved: boolean = false;
|
||||
|
||||
@ViewChildren(MatFormField) formFields: QueryList<MatFormField>;
|
||||
|
||||
constructor(
|
||||
|
@ -81,18 +86,27 @@ export class ResultPage {
|
|||
this.showQrFirst = true;
|
||||
}
|
||||
}
|
||||
this.qrCodeContent = this.env.result;
|
||||
this.qrCodeContent = this.env.resultContent;
|
||||
this.setContentType();
|
||||
}
|
||||
|
||||
async ionViewDidEnter(): Promise<void> {
|
||||
if (this.showQrFirst) {
|
||||
if (this.contentType == 'url' && this.env.autoOpenUrl == 'on' && this.env.recordSource == 'scan') {
|
||||
setTimeout(() => {
|
||||
this.presentToast(this.translate.instant("AUTO_OPEN_URL"), "short", "bottom");
|
||||
if (this.isHttp) {
|
||||
this.browseWebsite();
|
||||
} else {
|
||||
this.openLink();
|
||||
}
|
||||
}, 300);
|
||||
} else if (this.showQrFirst) {
|
||||
this.showQrFirst = false;
|
||||
if (this.qrCodeContent && this.qrCodeContent.trim().length > 0) {
|
||||
await this.enlarge();
|
||||
}
|
||||
}
|
||||
if (this.env.scanRecordLogging == 'on') {
|
||||
if (this.env.scanRecordLogging == 'on' && this.qrCodeContent != null && this.qrCodeContent != "") {
|
||||
await this.env.saveScanRecord(this.qrCodeContent);
|
||||
}
|
||||
if (this.env.bookmarks.find(x => x.text == this.qrCodeContent)) {
|
||||
|
@ -104,6 +118,14 @@ export class ResultPage {
|
|||
this.reset();
|
||||
}
|
||||
|
||||
async saveRecord() {
|
||||
if (this.qrCodeContent != null && this.qrCodeContent != "") {
|
||||
await this.env.saveScanRecord(this.qrCodeContent);
|
||||
}
|
||||
this.resultSaved = true;
|
||||
this.presentToast(this.translate.instant("SAVED"), "short", "bottom");
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.contentType = "freeText";
|
||||
delete this.qrCodeContent;
|
||||
|
@ -119,12 +141,15 @@ export class ResultPage {
|
|||
delete this.wifiPassword
|
||||
delete this.wifiEncryption
|
||||
delete this.wifiHidden
|
||||
delete this.latitude
|
||||
delete this.longitude
|
||||
this.base64Encoded = false;
|
||||
this.base64EncodedText = "";
|
||||
this.base64Decoded = false;
|
||||
this.base64DecodedText = "";
|
||||
this.bookmarked = false;
|
||||
this.showQrFirst = false;
|
||||
this.resultSaved = false;
|
||||
delete this.env.recordSource;
|
||||
delete this.env.detailedRecordSource;
|
||||
delete this.env.viewResultFrom;
|
||||
|
@ -137,6 +162,7 @@ export class ResultPage {
|
|||
const emailW3CPrefix = "MAILTO:";
|
||||
const emailDoconoPrefix = "MATMSG:";
|
||||
const wifiPrefix = "WIFI:";
|
||||
const geoPrefix = "GEO:";
|
||||
const content0 = this.qrCodeContent.trim();
|
||||
const tContent = this.qrCodeContent.trim().toUpperCase();
|
||||
if (tContent.substr(0, contactPrefix.length) === contactPrefix) {
|
||||
|
@ -163,6 +189,10 @@ export class ResultPage {
|
|||
} else if (tContent.substr(0, wifiPrefix.length) === wifiPrefix) {
|
||||
this.contentType = "wifi";
|
||||
this.prepareWifi();
|
||||
} else if (tContent.substring(0, geoPrefix.length) === geoPrefix) {
|
||||
this.contentType = "geo";
|
||||
this.latitude = +tContent.substring(geoPrefix.length, tContent.indexOf(","));
|
||||
this.longitude = +tContent.substring(tContent.indexOf(",") + 1);
|
||||
} else if (this.isValidUrl(content0)) {
|
||||
this.contentType = "url";
|
||||
} else {
|
||||
|
@ -190,6 +220,15 @@ export class ResultPage {
|
|||
return "#ffffff";
|
||||
}
|
||||
|
||||
editContent() {
|
||||
this.env.editingContent = true;
|
||||
this.router.navigate(['tabs/generate'], { replaceUrl: true });
|
||||
}
|
||||
|
||||
searchOpenFoodFacts() {
|
||||
window.open(`https://world.openfoodfacts.org/product/${this.qrCodeContent}`, '_system', 'location=yes');
|
||||
}
|
||||
|
||||
browseWebsite() {
|
||||
window.open(this.qrCodeContent, '_system', 'location=yes');
|
||||
}
|
||||
|
@ -209,104 +248,130 @@ export class ResultPage {
|
|||
}
|
||||
|
||||
async addContact(): Promise<void> {
|
||||
let newContact = null;
|
||||
let contactInput: ContactInput = {};
|
||||
if (this.contentType === "contact") {
|
||||
const phoneNumbers = [];
|
||||
const phoneNumbers: PhoneInput[] = [];
|
||||
if (this.vCardContact?.defaultPhoneNumber != null) {
|
||||
const phoneNumber = { number: this.vCardContact?.defaultPhoneNumber } as PhoneNumber;
|
||||
const phoneNumber: PhoneInput = {
|
||||
type: PhoneType.Mobile,
|
||||
label: 'mobile',
|
||||
number: this.vCardContact?.defaultPhoneNumber,
|
||||
isPrimary: true,
|
||||
};
|
||||
phoneNumbers.push(phoneNumber);
|
||||
}
|
||||
if (this.vCardContact?.homePhoneNumber != null) {
|
||||
const phoneNumber = { number: this.vCardContact?.homePhoneNumber } as PhoneNumber;
|
||||
const phoneNumber: PhoneInput = {
|
||||
type: PhoneType.Home,
|
||||
label: 'home',
|
||||
number: this.vCardContact?.homePhoneNumber,
|
||||
};
|
||||
phoneNumbers.push(phoneNumber);
|
||||
}
|
||||
if (this.vCardContact?.workPhoneNumber != null) {
|
||||
const phoneNumber = { number: this.vCardContact?.homePhoneNumber } as PhoneNumber;
|
||||
const phoneNumber: PhoneInput = {
|
||||
type: PhoneType.Work,
|
||||
label: 'work',
|
||||
number: this.vCardContact?.workPhoneNumber,
|
||||
};
|
||||
phoneNumbers.push(phoneNumber);
|
||||
}
|
||||
if (this.vCardContact?.mobilePhoneNumber != null) {
|
||||
const phoneNumber = { number: this.vCardContact?.mobilePhoneNumber } as PhoneNumber;
|
||||
const phoneNumber: PhoneInput = {
|
||||
type: PhoneType.Mobile,
|
||||
label: 'mobile',
|
||||
number: this.vCardContact?.mobilePhoneNumber,
|
||||
};
|
||||
phoneNumbers.push(phoneNumber);
|
||||
}
|
||||
const emails = [];
|
||||
const emails: EmailInput[] = [];
|
||||
if (this.vCardContact?.defaultEmail != null) {
|
||||
const address = { address: this.vCardContact?.defaultEmail } as EmailAddress;
|
||||
emails.push(address);
|
||||
const emailInput: EmailInput = {
|
||||
type: EmailType.Home,
|
||||
label: 'home',
|
||||
isPrimary: true,
|
||||
address: this.vCardContact?.defaultEmail,
|
||||
};
|
||||
emails.push(emailInput);
|
||||
}
|
||||
if (this.vCardContact?.homeEmail != null) {
|
||||
const address = { address: this.vCardContact?.homeEmail } as EmailAddress;
|
||||
emails.push(address);
|
||||
const emailInput: EmailInput = {
|
||||
type: EmailType.Home,
|
||||
label: 'home',
|
||||
address: this.vCardContact?.homeEmail,
|
||||
};
|
||||
emails.push(emailInput);
|
||||
}
|
||||
if (this.vCardContact?.workEmail != null) {
|
||||
const address = { address: this.vCardContact?.workEmail } as EmailAddress;
|
||||
emails.push(address);
|
||||
const emailInput: EmailInput = {
|
||||
type: EmailType.Work,
|
||||
label: 'work',
|
||||
address: this.vCardContact?.workEmail,
|
||||
};
|
||||
emails.push(emailInput);
|
||||
}
|
||||
newContact = {
|
||||
contactType: ContactType.Person,
|
||||
givenName: this.vCardContact?.givenName ?? this.vCardContact?.fullName ?? '',
|
||||
familyName: this.vCardContact?.familyName,
|
||||
phoneNumbers: phoneNumbers,
|
||||
emailAddresses: emails
|
||||
} as NewContact;
|
||||
contactInput.phones = phoneNumbers;
|
||||
contactInput.emails = emails;
|
||||
contactInput.name = {
|
||||
given: this.vCardContact?.givenName ?? this.vCardContact?.fullName ?? '',
|
||||
family: this.vCardContact?.familyName,
|
||||
};
|
||||
} else if (this.contentType === "sms" || this.contentType === "phone") {
|
||||
const phoneNumbers = [];
|
||||
const phoneNumber = { number: this.phoneNumber } as PhoneNumber;
|
||||
phoneNumbers.push(phoneNumber);
|
||||
newContact = {
|
||||
contactType: ContactType.Person,
|
||||
phoneNumbers: phoneNumbers
|
||||
} as NewContact;
|
||||
const phones: PhoneInput[] = [
|
||||
{
|
||||
type: PhoneType.Mobile,
|
||||
label: 'mobile',
|
||||
number: this.phoneNumber,
|
||||
isPrimary: true,
|
||||
}
|
||||
];
|
||||
contactInput.phones = phones;
|
||||
}
|
||||
if (newContact != null) {
|
||||
if (this.platform.is('ios')) {
|
||||
await Contacts.getPermissions().then(
|
||||
async permission => {
|
||||
if (permission.granted) {
|
||||
await this.saveContact(newContact);
|
||||
} else {
|
||||
const alert = await this.alertController.create({
|
||||
header: this.translate.instant("PERMISSION_REQUIRED"),
|
||||
message: this.translate.instant("MSG.CONTACT_PERMISSION"),
|
||||
buttons: [
|
||||
{
|
||||
text: this.translate.instant("SETTING"),
|
||||
handler: () => {
|
||||
BarcodeScanner.openAppSettings();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
text: this.translate.instant("CLOSE"),
|
||||
handler: () => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
],
|
||||
cssClass: ['alert-bg']
|
||||
});
|
||||
await alert.present();
|
||||
}
|
||||
}
|
||||
);
|
||||
// TODO: iOS contact handling
|
||||
// await Contacts.checkPermissions().then(
|
||||
// async permission => {
|
||||
// if (permission.contacts == 'granted') {
|
||||
// await this.saveContact(newContact);
|
||||
// } else {
|
||||
// const alert = await this.alertController.create({
|
||||
// header: this.translate.instant("PERMISSION_REQUIRED"),
|
||||
// message: this.translate.instant("MSG.CONTACT_PERMISSION"),
|
||||
// buttons: [
|
||||
// {
|
||||
// text: this.translate.instant("SETTING"),
|
||||
// handler: () => {
|
||||
// BarcodeScanner.openAppSettings();
|
||||
// return true;
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// text: this.translate.instant("CLOSE"),
|
||||
// handler: () => {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// cssClass: ['alert-bg']
|
||||
// });
|
||||
// await alert.present();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
} else { // Android doesn't need to get permission
|
||||
await this.saveContact(newContact);
|
||||
}
|
||||
await this.saveContact(contactInput);
|
||||
}
|
||||
}
|
||||
|
||||
private async saveContact(newContact: any) {
|
||||
await Contacts.saveContact(newContact).then(
|
||||
private async saveContact(contactInput: ContactInput) {
|
||||
await Contacts.createContact({ contact: contactInput }).then(
|
||||
_ => {
|
||||
if (this.isIOS) {
|
||||
this.presentToast(this.translate.instant('MSG.SAVED_CONTACT'), "short", "bottom");
|
||||
} else {
|
||||
this.presentToast(this.translate.instant('MSG.SAVING_CONTACT'), "short", "bottom");
|
||||
}
|
||||
}
|
||||
).catch(
|
||||
err => {
|
||||
if (this.env.isDebugging) {
|
||||
this.presentToast("Error when call Contacts.saveContact: " + JSON.stringify(err), "long", "top");
|
||||
this.presentToast("Error when call Contacts.createContact: " + JSON.stringify(err), "long", "top");
|
||||
} else {
|
||||
this.presentToast(this.translate.instant('MSG.FAILED_SAVING_CONTACT'), "short", "bottom");
|
||||
}
|
||||
|
@ -397,6 +462,12 @@ export class ResultPage {
|
|||
case 'yandex':
|
||||
searchUrl = this.env.YANDEX_SEARCH_URL;
|
||||
break;
|
||||
case 'ecosia':
|
||||
searchUrl = this.env.ECOSIA_SEARCH_URL;
|
||||
break;
|
||||
case 'brave':
|
||||
searchUrl = this.env.BRAVE_SEARCH_URL;
|
||||
break;
|
||||
default:
|
||||
searchUrl = this.env.GOOGLE_SEARCH_URL;
|
||||
break;
|
||||
|
@ -578,7 +649,7 @@ export class ResultPage {
|
|||
} else if (!failEncoded && failDecoded) {
|
||||
await this.presentToast(this.translate.instant('MSG.NOT_BASE64_DE'), "short", "center");
|
||||
}
|
||||
setTimeout(() => this.formFields?.forEach(ff => ff.updateOutlineGap()), 100);
|
||||
// setTimeout(() => this.formFields?.forEach(ff => ff.updateOutlineGap()), 100);
|
||||
}
|
||||
|
||||
generateVCardContact(): void {
|
||||
|
@ -613,7 +684,6 @@ export class ResultPage {
|
|||
lines.forEach(
|
||||
line => {
|
||||
const tLine = line.trim();
|
||||
console.log(tLine);
|
||||
if (tLine.toUpperCase().substr(0, fullNameId1.length) === fullNameId1) {
|
||||
this.vCardContact.fullName = tLine.substr(fullNameId1.length);
|
||||
} else if (tLine.toUpperCase().substr(0, fullNameId2.length) === fullNameId2) {
|
||||
|
@ -810,15 +880,6 @@ export class ResultPage {
|
|||
await alert.present();
|
||||
}
|
||||
|
||||
// async removeBookmark() {
|
||||
// await this.env.deleteBookmark(this.qrCodeContent);
|
||||
// if (this.env.bookmarks.find(x => x.text === this.qrCodeContent)) {
|
||||
// this.bookmarked = true;
|
||||
// } else {
|
||||
// this.bookmarked = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
get contentTypeText(): string {
|
||||
switch (this.contentType) {
|
||||
case 'freeText':
|
||||
|
@ -829,6 +890,8 @@ export class ResultPage {
|
|||
return this.translate.instant("EMAIL_W3C_STANDARD");
|
||||
case 'emailDocomo':
|
||||
return this.translate.instant("EMAIL_NTT_DOCOMO");
|
||||
case 'geo':
|
||||
return this.translate.instant("GEOLOCATION");
|
||||
case 'phone':
|
||||
return this.translate.instant("PHONE_NO");
|
||||
case 'sms':
|
||||
|
@ -850,6 +913,8 @@ export class ResultPage {
|
|||
return "link";
|
||||
case "contact":
|
||||
return "contact_phone";
|
||||
case 'geo':
|
||||
return "location_on";
|
||||
case "phone":
|
||||
return "call";
|
||||
case "sms":
|
||||
|
@ -866,7 +931,7 @@ export class ResultPage {
|
|||
}
|
||||
|
||||
get barcodeFormat(): string {
|
||||
switch (this.env.resultFormat) {
|
||||
switch (this.env.resultContentFormat) {
|
||||
case "UPC_A":
|
||||
return this.translate.instant("BARCODE_TYPE.UPC");
|
||||
case "UPC_E":
|
||||
|
@ -906,10 +971,36 @@ export class ResultPage {
|
|||
case "RSS_EXPANDED":
|
||||
return this.translate.instant("BARCODE_TYPE.RSS");
|
||||
default:
|
||||
return this.env.resultFormat;
|
||||
return this.env.resultContentFormat;
|
||||
}
|
||||
}
|
||||
|
||||
get isValidEan(): boolean {
|
||||
if (this.qrCodeContent == null) {
|
||||
return false;
|
||||
}
|
||||
const isValidLength = this.qrCodeContent.length === 18 || this.qrCodeContent.length === 14 || this.qrCodeContent.length === 13 || this.qrCodeContent.length === 8 || this.qrCodeContent.length === 5;
|
||||
return isValidLength && /^\d+$/.test(this.qrCodeContent) && this.testEanChecksum(this.qrCodeContent);
|
||||
}
|
||||
|
||||
private testEanChecksum(text: string): boolean {
|
||||
const digits = text.slice(0, -1);
|
||||
const checkDigit = parseInt(text.slice(-1));
|
||||
if (isNaN(checkDigit)) {
|
||||
return false;
|
||||
}
|
||||
let sum = 0;
|
||||
for (let i = digits.length - 1; i >= 0; i--) {
|
||||
const digit = parseInt(digits.charAt(i));
|
||||
if (isNaN(digit)) {
|
||||
return false;
|
||||
}
|
||||
sum += (digit * (1 + (2 * (i % 2)))) | 0;
|
||||
}
|
||||
sum = (10 - (sum % 10)) % 10;
|
||||
return sum === checkDigit;
|
||||
}
|
||||
|
||||
get finalContactName(): string {
|
||||
if (!this.vCardContact) {
|
||||
return '';
|
||||
|
@ -968,7 +1059,7 @@ export class ResultPage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -109,7 +109,7 @@ export class ScanPage {
|
|||
async (result: ScanResult) => {
|
||||
if (result.hasContent) {
|
||||
const text = result.content;
|
||||
if (text === undefined || text === null || (text && text.trim().length <= 0) || text === "") {
|
||||
if (text == null || text?.trim()?.length <= 0 || text == "") {
|
||||
this.presentToast(this.translate.instant('MSG.QR_CODE_VALUE_NOT_EMPTY'), "short", "center");
|
||||
this.scanQr();
|
||||
return;
|
||||
|
@ -137,8 +137,8 @@ export class ScanPage {
|
|||
}
|
||||
|
||||
async processQrCode(scannedData: string, format: string, loading: HTMLIonLoadingElement): Promise<void> {
|
||||
this.env.result = scannedData;
|
||||
this.env.resultFormat = format;
|
||||
this.env.resultContent = scannedData;
|
||||
this.env.resultContentFormat = format;
|
||||
this.env.recordSource = "scan";
|
||||
this.env.detailedRecordSource = "scan-camera";
|
||||
this.env.viewResultFrom = "/tabs/scan";
|
||||
|
@ -205,7 +205,7 @@ export class ScanPage {
|
|||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-toolbar [color]="env.colorTheme === 'black'? 'black' : 'dark'">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button text="">
|
||||
<ion-back-button text="" defaultHref="tabs/setting">
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'AUTO_MAX_BRIGHTNESS' | translate }}</ion-title>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
||||
|
@ -14,19 +15,15 @@ export class SettingAutoBrightnessPage {
|
|||
public env: EnvService,
|
||||
) { }
|
||||
|
||||
async saveAutoMaxBrightness() {
|
||||
await this.env.storageSet("auto-max-brightness", this.env.autoMaxBrightness);
|
||||
}
|
||||
|
||||
async onAutoMaxBrightnessChange(ev: any) {
|
||||
this.env.autoMaxBrightness = ev ? 'on' : 'off';
|
||||
await this.env.storageSet("auto-max-brightness", this.env.autoMaxBrightness);
|
||||
await Preferences.set({ key: this.env.KEY_AUTO_MAX_BRIGHTNESS, value: this.env.autoMaxBrightness });
|
||||
await this.tapHaptic();
|
||||
}
|
||||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Medium })
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-toolbar [color]="env.colorTheme === 'black'? 'black' : 'dark'">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button text="">
|
||||
<ion-back-button text="" defaultHref="tabs/setting">
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'AUTO_KILL_BACKGROUND' | translate }}</ion-title>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
||||
@Component({
|
||||
|
@ -13,6 +14,6 @@ export class SettingAutoExitPage{
|
|||
) { }
|
||||
|
||||
async saveAutoExitAppMin() {
|
||||
await this.env.storageSet("autoExitAppMin", this.env.autoExitAppMin);
|
||||
await Preferences.set({ key: this.env.KEY_AUTO_EXIT_MIN, value: JSON.stringify(this.env.autoExitAppMin) });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { SettingAutoOpenUrlPage } from './setting-auto-open-url.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: SettingAutoOpenUrlPage
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class SettingAutoOpenUrlPageRoutingModule {}
|
|
@ -0,0 +1,30 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { SettingAutoOpenUrlPageRoutingModule } from './setting-auto-open-url-routing.module';
|
||||
|
||||
import { SettingAutoOpenUrlPage } from './setting-auto-open-url.page';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HttpLoaderFactory } from 'src/app/utils/helpers';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
SettingAutoOpenUrlPageRoutingModule
|
||||
],
|
||||
declarations: [SettingAutoOpenUrlPage]
|
||||
})
|
||||
export class SettingAutoOpenUrlPageModule {}
|
|
@ -0,0 +1,37 @@
|
|||
<ion-header>
|
||||
<ion-toolbar [color]="env.colorTheme === 'black'? 'black' : 'dark'">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button text="" defaultHref="tabs/setting">
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'AUTO_OPEN_URL' | translate }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
|
||||
<ion-item class="ion-no-padding" lines="none">
|
||||
<ion-label class="ion-padding-start">
|
||||
<p class="ion-padding-top ion-padding-horizontal">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="white-space: normal;">
|
||||
<div [innerHTML]="'MSG.AUTO_OPEN_URL_EXPLAIN' | translate">
|
||||
</div>
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-no-padding ripple-parent" detail="false" lines="none">
|
||||
<ion-label class="ion-padding-start">
|
||||
<p class="ion-padding pre-line">
|
||||
<ion-text [color]="env.colorTheme === 'light'? 'dark' : 'light'" style="font-size: large;">
|
||||
{{ (env.autoOpenUrl == 'on'? 'TURNED_ON' : 'TURNED_OFF') | translate }}
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
<ion-toggle class="ion-padding-end" slot="end" [ngModel]="env.autoOpenUrl == 'on'? true : false"
|
||||
(ngModelChange)="onAutoOpenUrlChange($event)">
|
||||
</ion-toggle>
|
||||
</ion-item>
|
||||
|
||||
</ion-content>
|
|
@ -0,0 +1,34 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { Toast } from '@capacitor/toast';
|
||||
import { EnvService } from 'src/app/services/env.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-setting-auto-open-url',
|
||||
templateUrl: './setting-auto-open-url.page.html',
|
||||
styleUrls: ['./setting-auto-open-url.page.scss'],
|
||||
})
|
||||
export class SettingAutoOpenUrlPage {
|
||||
|
||||
constructor(
|
||||
public env: EnvService,
|
||||
) { }
|
||||
|
||||
async onAutoOpenUrlChange(ev: any) {
|
||||
this.env.autoOpenUrl = ev ? 'on' : 'off';
|
||||
await Preferences.set({ key: this.env.KEY_AUTO_OPEN_URL, value: this.env.autoOpenUrl });
|
||||
await this.tapHaptic();
|
||||
}
|
||||
|
||||
async tapHaptic() {
|
||||
if (this.env.vibration === 'on' || this.env.vibration === 'on-haptic') {
|
||||
await Haptics.impact({ style: ImpactStyle.Light })
|
||||
.catch(async err => {
|
||||
if (this.env.debugMode === 'on') {
|
||||
await Toast.show({ text: 'Err when Haptics.impact: ' + JSON.stringify(err), position: "top", duration: "long" })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|