├── .eslintcache
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── android
├── .gitignore
├── .idea
│ ├── .gitignore
│ ├── compiler.xml
│ ├── deploymentTargetDropDown.xml
│ ├── jarRepositories.xml
│ └── misc.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── capacitor.build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── getcapacitor
│ │ │ └── myapp
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── capacitor.config.json
│ │ │ └── capacitor.plugins.json
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── jeep
│ │ │ │ └── app
│ │ │ │ └── ionic
│ │ │ │ └── react
│ │ │ │ └── MainActivity.java
│ │ └── res
│ │ │ ├── drawable-land-hdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-land-mdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-land-xhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-land-xxhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-land-xxxhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-port-hdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-port-mdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-port-xhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-port-xxhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-port-xxxhdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── splash.png
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ ├── config.xml
│ │ │ ├── data_extraction_rules.xml
│ │ │ └── file_paths.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── getcapacitor
│ │ └── myapp
│ │ └── ExampleUnitTest.java
├── build.gradle
├── capacitor.settings.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── variables.gradle
├── capacitor.config.ts
├── electron
├── .gitignore
├── assets
│ ├── appIcon.ico
│ ├── appIcon.png
│ ├── splash.gif
│ └── splash.png
├── capacitor.config.ts
├── electron-builder.config.json
├── live-runner.js
├── package-lock.json
├── package.json
├── resources
│ └── electron-publisher-custom.js
├── src
│ ├── index.ts
│ ├── preload.ts
│ ├── rt
│ │ ├── electron-plugins.js
│ │ └── electron-rt.ts
│ └── setup.ts
└── tsconfig.json
├── ionic.config.json
├── ios
├── .gitignore
└── App
│ ├── App.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── App.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── App
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── AppIcon-20x20@1x.png
│ │ │ ├── AppIcon-20x20@2x-1.png
│ │ │ ├── AppIcon-20x20@2x.png
│ │ │ ├── AppIcon-20x20@3x.png
│ │ │ ├── AppIcon-29x29@1x.png
│ │ │ ├── AppIcon-29x29@2x-1.png
│ │ │ ├── AppIcon-29x29@2x.png
│ │ │ ├── AppIcon-29x29@3x.png
│ │ │ ├── AppIcon-40x40@1x.png
│ │ │ ├── AppIcon-40x40@2x-1.png
│ │ │ ├── AppIcon-40x40@2x.png
│ │ │ ├── AppIcon-40x40@3x.png
│ │ │ ├── AppIcon-512@2x.png
│ │ │ ├── AppIcon-60x60@2x.png
│ │ │ ├── AppIcon-60x60@3x.png
│ │ │ ├── AppIcon-76x76@1x.png
│ │ │ ├── AppIcon-76x76@2x.png
│ │ │ ├── AppIcon-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ └── Splash.imageset
│ │ │ ├── Contents.json
│ │ │ ├── splash-2732x2732-1.png
│ │ │ ├── splash-2732x2732-2.png
│ │ │ └── splash-2732x2732.png
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── capacitor.config.json
│ └── config.xml
│ └── Podfile
├── package-lock.json
├── package.json
├── public
├── assets
│ ├── databases
│ │ ├── databases.json
│ │ ├── dbForCopy.db
│ │ └── myDBSQLite.db
│ ├── icon
│ │ ├── favicon.png
│ │ └── icon.png
│ ├── shapes.svg
│ └── sql-wasm.wasm
├── index.html
└── manifest.json
├── src
├── App.test.tsx
├── App.tsx
├── Utils
│ ├── base64Images.ts
│ ├── deleteDBUtil.ts
│ ├── encryptedSetUtils.ts
│ ├── importJsonUtils.ts
│ ├── noEncryptionUtils.ts
│ ├── upgrade-database-version.ts
│ └── upgradeVersionUtils.ts
├── components
│ ├── CopyFromAssets.css
│ ├── CopyFromAssets.tsx
│ ├── ExistingConnection.css
│ ├── ExistingConnection.tsx
│ ├── ExploreContainer.css
│ ├── ExploreContainer.tsx
│ ├── MessageListItem.css
│ ├── MessageListItem.tsx
│ ├── MigrateDB.css
│ ├── MigrateDB.tsx
│ ├── NoEncryption.css
│ ├── NoEncryption.tsx
│ ├── NonConformedDB.css
│ ├── NonConformedDB.tsx
│ ├── Test2dbs.css
│ ├── Test2dbs.tsx
│ ├── TestEncryption.css
│ ├── TestEncryption.tsx
│ ├── TestIssue184.css
│ ├── TestIssue184.tsx
│ ├── TestJsonImportExport.css
│ ├── TestJsonImportExport.tsx
│ ├── TestOutput.css
│ ├── TestOutput.tsx
│ ├── TestUpgradeVersion.css
│ └── TestUpgradeVersion.tsx
├── data
│ ├── messages.json
│ └── messages.ts
├── index.tsx
├── pages
│ ├── Tab1.css
│ ├── Tab1.tsx
│ ├── Tab2.css
│ ├── Tab2.tsx
│ ├── Tab3.css
│ ├── Tab3.tsx
│ ├── ViewMessage.css
│ ├── ViewMessage.tsx
│ ├── ViewTest.css
│ └── ViewTest.tsx
├── react-app-env.d.ts
├── reportWebVitals.ts
├── service-worker.ts
├── serviceWorkerRegistration.ts
├── services
│ └── DarkModeService.tsx
├── setupTests.ts
└── theme
│ └── variables.css
└── tsconfig.json
/.eslintcache:
--------------------------------------------------------------------------------
1 | [{"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/index.tsx":"1","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/serviceWorker.ts":"2","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/App.tsx":"3","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab1.tsx":"4","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab3.tsx":"5","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab2.tsx":"6","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/Test2dbs.tsx":"7","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/NoEncryption.tsx":"8","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/ExploreContainer.tsx":"9","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/ExistingConnection.tsx":"10","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestEncryption.tsx":"11","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestUpgradeVersion.tsx":"12","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/CopyFromAssets.tsx":"13","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestJsonImportExport.tsx":"14","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/noEncryptionUtils.ts":"15","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/deleteDBUtil.ts":"16","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/encryptedSetUtils.ts":"17","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/upgradeVersionUtils.ts":"18","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/importJsonUtils.ts":"19","/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/base64Images.ts":"20"},{"size":430,"mtime":1611823506292,"results":"21","hashOfConfig":"22"},{"size":5213,"mtime":1611823506294,"results":"23","hashOfConfig":"22"},{"size":3167,"mtime":1611823506284,"results":"24","hashOfConfig":"22"},{"size":672,"mtime":1611823506293,"results":"25","hashOfConfig":"22"},{"size":672,"mtime":1611823506293,"results":"26","hashOfConfig":"22"},{"size":2958,"mtime":1611823506293,"results":"27","hashOfConfig":"22"},{"size":6114,"mtime":1611823506290,"results":"28","hashOfConfig":"22"},{"size":6739,"mtime":1611823506289,"results":"29","hashOfConfig":"22"},{"size":434,"mtime":1611823506288,"results":"30","hashOfConfig":"22"},{"size":5781,"mtime":1611823506287,"results":"31","hashOfConfig":"22"},{"size":7560,"mtime":1611823506290,"results":"32","hashOfConfig":"22"},{"size":7489,"mtime":1611823506292,"results":"33","hashOfConfig":"22"},{"size":4914,"mtime":1611823506287,"results":"34","hashOfConfig":"22"},{"size":14680,"mtime":1611824132753,"results":"35","hashOfConfig":"22"},{"size":2611,"mtime":1611823506286,"results":"36","hashOfConfig":"22"},{"size":593,"mtime":1611823506285,"results":"37","hashOfConfig":"22"},{"size":2215,"mtime":1611823506285,"results":"38","hashOfConfig":"22"},{"size":2987,"mtime":1611823506286,"results":"39","hashOfConfig":"22"},{"size":5902,"mtime":1611823506285,"results":"40","hashOfConfig":"22"},{"size":2672,"mtime":1611823506284,"results":"41","hashOfConfig":"22"},{"filePath":"42","messages":"43","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},"11pfkhi",{"filePath":"45","messages":"46","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"47","messages":"48","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"49","messages":"50","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"51","messages":"52","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"53","messages":"54","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"55","messages":"56","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"57","messages":"58","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"59","messages":"60","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"61","messages":"62","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"63","messages":"64","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"65","messages":"66","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"67","messages":"68","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"69","messages":"70","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"71","messages":"72","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"73","messages":"74","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"75","messages":"76","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"77","messages":"78","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"79","messages":"80","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"81","messages":"82","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/index.tsx",[],["83","84"],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/serviceWorker.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/App.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab1.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab3.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/pages/Tab2.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/Test2dbs.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/NoEncryption.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/ExploreContainer.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/ExistingConnection.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestEncryption.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestUpgradeVersion.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/CopyFromAssets.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/components/TestJsonImportExport.tsx",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/noEncryptionUtils.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/deleteDBUtil.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/encryptedSetUtils.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/upgradeVersionUtils.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/importJsonUtils.ts",[],"/Users/queaujeanpierre/Development/react-sqlite-apps/react-sqlite-app-starter/src/Utils/base64Images.ts",[],{"ruleId":"85","replacedBy":"86"},{"ruleId":"87","replacedBy":"88"},"no-native-reassign",["89"],"no-negated-in-lhs",["90"],"no-global-assign","no-unsafe-negation"]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 | .vscode
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at jepi.queau@free.fr. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 QUEAU Jean Pierre
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ionic/React SQLite App Starter
4 | react-sqlite-app-starter
5 |
6 | A Ionic/React application demonstrating the use of the @capacitor-community/sqlite@latest
plugin and may be use as an application starter.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Maintainers
20 |
21 | | Maintainer | GitHub | Social |
22 | | ----------------- | ----------------------------------------- | ------ |
23 | | Quéau Jean Pierre | [jepiqueau](https://github.com/jepiqueau) | |
24 |
25 | ## Browser Support
26 |
27 | The plugin follows the guidelines from the `Capacitor Team`,
28 |
29 | - [Capacitor Browser Support](https://capacitorjs.com/docs/v3/web#browser-support)
30 |
31 | meaning that it will not work in IE11 without additional JavaScript transformations, e.g. with [Babel](https://babeljs.io/).
32 |
33 |
34 | ## Installation 🚧
35 |
36 | To start building your App using this Starter App, clone this repo to a new directory:
37 |
38 | ```bash
39 | git clone https://github.com/jepiqueau/react-sqlite-app-starter.git
40 | cd react-sqlite-app-starter
41 | git remote rm origin
42 | ```
43 |
44 | - then install it
45 |
46 | ```bash
47 | npm install
48 | ```
49 |
50 | - then go to the building process
51 |
52 | ```bash
53 | npm run build
54 | npx cap sync
55 | npm run build
56 | npx cap copy
57 | npx cap copy web
58 | ```
59 |
60 | the capacitor config parameters are:
61 |
62 | ```
63 | "appId": "com.example.app.capacitor",
64 | "appName": "react-sqlite-app-starter",
65 | ```
66 |
67 | ### Building Web Code
68 |
69 | The ```@capacitor-community/sqlite``` is not implemented for Web Browsers.
70 | if you run
71 |
72 | ```bash
73 | npx cap serve
74 | ```
75 | you will get the following messages:
76 | ```
77 | SQLite Plugin not available for Web Platform
78 | ```
79 |
80 | ### Building Native Project
81 |
82 | #### IOS
83 |
84 | ```bash
85 | npx cap open ios
86 | ```
87 | Once Xcode launches, you can build your finally app binary through the standard Xcode workflow.
88 |
89 | #### Android
90 |
91 | ```bash
92 | npx cap open android
93 | ```
94 | Once Android Studio launches, you can build your app through the standard Android Studio workflow.
95 |
96 | ## Usage
97 |
98 |
99 | The `@capacitor-community/sqlite` test is accessible in the Tab2 of the Application by clicking on several SQLite test button :
100 |
101 | - SQLite No Encryption Test
102 | - SQLite Two DBs Tests
103 | - SQLite Encryption Test (iOS && Android only)
104 | - SQLite Upgrade Version Test
105 | - SQLite Json Import Export Test
106 |
107 | After having run the `SQLite Two DBs Tests` another test becomes accessible `SQLite Existing Test` which is using the existing connections created in `SQLite Two DBs Tests`.
108 |
109 | The application uses the React Hook `react-sqlite-hook refactor` to access the `@capacitor-community/sqlite refactor` API.
110 |
111 | - [react-sqlite-hook](https://github.com/jepiqueau/react-sqlite-hook/blob/master/README.md)
112 |
113 | ## Contributors ✨
114 |
115 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
116 |
117 |
118 |
119 |
120 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | # Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
2 |
3 | # Built application files
4 | *.apk
5 | *.aar
6 | *.ap_
7 | *.aab
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 | # Uncomment the following line in case you need and you don't have the release build type files in your app
20 | # release/
21 |
22 | # Gradle files
23 | .gradle/
24 | build/
25 |
26 | # Local configuration file (sdk path, etc)
27 | local.properties
28 |
29 | # Proguard folder generated by Eclipse
30 | proguard/
31 |
32 | # Log Files
33 | *.log
34 |
35 | # Android Studio Navigation editor temp files
36 | .navigation/
37 |
38 | # Android Studio captures folder
39 | captures/
40 |
41 | # IntelliJ
42 | *.iml
43 | .idea/workspace.xml
44 | .idea/tasks.xml
45 | .idea/gradle.xml
46 | .idea/assetWizardSettings.xml
47 | .idea/dictionaries
48 | .idea/libraries
49 | # Android Studio 3 in .gitignore file.
50 | .idea/caches
51 | .idea/modules.xml
52 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
53 | .idea/navEditor.xml
54 |
55 | # Keystore files
56 | # Uncomment the following lines if you do not want to check your keystore files in.
57 | #*.jks
58 | #*.keystore
59 |
60 | # External native build folder generated in Android Studio 2.2 and later
61 | .externalNativeBuild
62 | .cxx/
63 |
64 | # Google Services (e.g. APIs or Firebase)
65 | # google-services.json
66 |
67 | # Freeline
68 | freeline.py
69 | freeline/
70 | freeline_project_description.json
71 |
72 | # fastlane
73 | fastlane/report.xml
74 | fastlane/Preview.html
75 | fastlane/screenshots
76 | fastlane/test_output
77 | fastlane/readme.md
78 |
79 | # Version control
80 | vcs.xml
81 |
82 | # lint
83 | lint/intermediates/
84 | lint/generated/
85 | lint/outputs/
86 | lint/tmp/
87 | # lint/reports/
88 |
89 | # Android Profiling
90 | *.hprof
91 |
92 | # Cordova plugins for Capacitor
93 | capacitor-cordova-android-plugins
94 |
95 | # Copied web assets
96 | app/src/main/assets/public
97 |
98 | # Generated Config files
99 | app/src/main/assets/capacitor.config.json
100 | app/src/main/assets/capacitor.plugins.json
101 | app/src/main/res/xml/config.xml
102 |
--------------------------------------------------------------------------------
/android/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/android/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/android/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build/*
2 | !/build/.npmkeep
3 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 | defaultConfig {
6 | applicationId "com.jeep.app.ionic.react"
7 | minSdkVersion rootProject.ext.minSdkVersion
8 | targetSdkVersion rootProject.ext.targetSdkVersion
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12 | aaptOptions {
13 | // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
14 | // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
15 | ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
16 | }
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | }
25 |
26 | repositories {
27 | flatDir{
28 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
35 | implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
36 | implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
37 | implementation project(':capacitor-android')
38 | testImplementation "junit:junit:$junitVersion"
39 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
40 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
41 | implementation project(':capacitor-cordova-android-plugins')
42 | }
43 |
44 | apply from: 'capacitor.build.gradle'
45 |
46 | try {
47 | def servicesJSON = file('google-services.json')
48 | if (servicesJSON.text) {
49 | apply plugin: 'com.google.gms.google-services'
50 | }
51 | } catch(Exception e) {
52 | logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
53 | }
54 |
--------------------------------------------------------------------------------
/android/app/capacitor.build.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 |
3 | android {
4 | compileOptions {
5 | sourceCompatibility JavaVersion.VERSION_11
6 | targetCompatibility JavaVersion.VERSION_11
7 | }
8 | }
9 |
10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
11 | dependencies {
12 | implementation project(':capacitor-community-sqlite')
13 | implementation project(':capacitor-dialog')
14 | implementation project(':capacitor-toast')
15 |
16 | }
17 |
18 |
19 | if (hasProperty('postBuildExtras')) {
20 | postBuildExtras()
21 | }
22 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import android.content.Context;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 | import androidx.test.platform.app.InstrumentationRegistry;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 |
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.getcapacitor.app", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
14 |
15 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "com.jeep.app.ionic.react",
3 | "appName": "react-sqlite-app-starter",
4 | "webDir": "build",
5 | "bundledWebRuntime": false,
6 | "plugins": {
7 | "CapacitorSQLite": {
8 | "iosDatabaseLocation": "Library/CapacitorDatabase",
9 | "iosIsEncryption": true,
10 | "iosKeychainPrefix": "react-sqlite-app-starter",
11 | "iosBiometric": {
12 | "biometricAuth": false,
13 | "biometricTitle": "Biometric login for capacitor sqlite"
14 | },
15 | "androidIsEncryption": true,
16 | "androidBiometric": {
17 | "biometricAuth": false,
18 | "biometricTitle": "Biometric login for capacitor sqlite",
19 | "biometricSubTitle": "Log in using your biometric"
20 | },
21 | "electronWindowsLocation": "C:\\ProgramData\\CapacitorDatabases",
22 | "electronMacLocation": "/Volumes/Development_Lacie/Development/CapacitorDatabases",
23 | "electronLinuxLocation": "Databases"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/capacitor.plugins.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pkg": "@capacitor-community/sqlite",
4 | "classpath": "com.getcapacitor.community.database.sqlite.CapacitorSQLitePlugin"
5 | },
6 | {
7 | "pkg": "@capacitor/dialog",
8 | "classpath": "com.capacitorjs.plugins.dialog.DialogPlugin"
9 | },
10 | {
11 | "pkg": "@capacitor/toast",
12 | "classpath": "com.capacitorjs.plugins.toast.ToastPlugin"
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/jeep/app/ionic/react/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jeep.app.ionic.react;
2 |
3 | import com.getcapacitor.BridgeActivity;
4 |
5 | public class MainActivity extends BridgeActivity {}
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-land-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-land-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-land-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-land-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-land-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-land-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-port-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-port-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-port-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-port-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-port-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable-port-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/drawable/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | react-sqlite-app-starter
4 | react-sqlite-app-starter
5 | com.jeep.app.ionic.react
6 | com.jeep.app.ionic.react
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.getcapacitor.myapp;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 |
14 | @Test
15 | public void addition_isCorrect() throws Exception {
16 | assertEquals(4, 2 + 2);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:7.2.2'
11 | classpath 'com.google.gms:google-services:4.3.13'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | apply from: "variables.gradle"
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | mavenCentral()
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/capacitor.settings.gradle:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
2 | include ':capacitor-android'
3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
4 |
5 | include ':capacitor-community-sqlite'
6 | project(':capacitor-community-sqlite').projectDir = new File('../node_modules/@capacitor-community/sqlite/android')
7 |
8 | include ':capacitor-dialog'
9 | project(':capacitor-dialog').projectDir = new File('../node_modules/@capacitor/dialog/android')
10 |
11 | include ':capacitor-toast'
12 | project(':capacitor-toast').projectDir = new File('../node_modules/@capacitor/toast/android')
13 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # AndroidX package structure to make it clearer which packages are bundled with the
20 | # Android operating system, and which are packaged with your app's APK
21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
22 | android.useAndroidX=true
23 | # Automatically convert third-party libraries to use AndroidX
24 | android.enableJetifier=true
25 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':capacitor-cordova-android-plugins'
3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
4 |
5 | apply from: 'capacitor.settings.gradle'
--------------------------------------------------------------------------------
/android/variables.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | minSdkVersion = 22
3 | compileSdkVersion = 33
4 | targetSdkVersion = 33
5 | androidxActivityVersion = '1.4.0'
6 | androidxAppCompatVersion = '1.6.1'
7 | androidxCoordinatorLayoutVersion = '1.2.0'
8 | androidxCoreVersion = '1.8.0'
9 | androidxFragmentVersion = '1.4.1'
10 | coreSplashScreenVersion = '1.0.0-rc01'
11 | androidxWebkitVersion = '1.4.0'
12 | junitVersion = '4.13.2'
13 | androidxJunitVersion = '1.1.5'
14 | androidxEspressoCoreVersion = '3.5.1'
15 | cordovaAndroidVersion = '10.1.1'
16 | }
--------------------------------------------------------------------------------
/capacitor.config.ts:
--------------------------------------------------------------------------------
1 | import { CapacitorConfig } from '@capacitor/cli';
2 |
3 | const config: CapacitorConfig = {
4 | appId: 'com.jeep.app.ionic.react',
5 | appName: 'react-sqlite-app-starter',
6 | webDir: 'build',
7 | bundledWebRuntime: false,
8 | plugins: {
9 | CapacitorSQLite: {
10 | iosDatabaseLocation: 'Library/CapacitorDatabase',
11 | iosIsEncryption: true,
12 | iosKeychainPrefix: 'react-sqlite-app-starter',
13 | iosBiometric: {
14 | biometricAuth: false,
15 | biometricTitle : "Biometric login for capacitor sqlite"
16 | },
17 | androidIsEncryption: true,
18 | androidBiometric: {
19 | biometricAuth : false,
20 | biometricTitle : "Biometric login for capacitor sqlite",
21 | biometricSubTitle : "Log in using your biometric"
22 | },
23 | electronWindowsLocation: "C:\\ProgramData\\CapacitorDatabases",
24 | electronMacLocation: "/Volumes/Development_Lacie/Development/CapacitorDatabases",
25 | electronLinuxLocation: "Databases"
26 | }
27 | }
28 | };
29 |
30 | export default config;
31 |
--------------------------------------------------------------------------------
/electron/.gitignore:
--------------------------------------------------------------------------------
1 | # NPM renames .gitignore to .npmignore
2 | # In order to prevent that, we remove the initial "."
3 | # And the CLI then renames it
4 | app
5 | node_modules
6 | build
7 | dist
8 | logs
9 |
--------------------------------------------------------------------------------
/electron/assets/appIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/electron/assets/appIcon.ico
--------------------------------------------------------------------------------
/electron/assets/appIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/electron/assets/appIcon.png
--------------------------------------------------------------------------------
/electron/assets/splash.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/electron/assets/splash.gif
--------------------------------------------------------------------------------
/electron/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/electron/assets/splash.png
--------------------------------------------------------------------------------
/electron/capacitor.config.ts:
--------------------------------------------------------------------------------
1 | import { CapacitorConfig } from '@capacitor/cli';
2 |
3 | const config: CapacitorConfig = {
4 | appId: 'com.jeep.app.ionic.react',
5 | appName: 'react-sqlite-app-starter',
6 | webDir: 'build',
7 | bundledWebRuntime: false,
8 | plugins: {
9 | CapacitorSQLite: {
10 | iosDatabaseLocation: 'Library/CapacitorDatabase',
11 | iosIsEncryption: true,
12 | iosKeychainPrefix: 'react-sqlite-app-starter',
13 | iosBiometric: {
14 | biometricAuth: false,
15 | biometricTitle : "Biometric login for capacitor sqlite"
16 | },
17 | androidIsEncryption: true,
18 | androidBiometric: {
19 | biometricAuth : false,
20 | biometricTitle : "Biometric login for capacitor sqlite",
21 | biometricSubTitle : "Log in using your biometric"
22 | },
23 | electronWindowsLocation: "C:\\ProgramData\\CapacitorDatabases",
24 | electronMacLocation: "/Volumes/Development_Lacie/Development/CapacitorDatabases",
25 | electronLinuxLocation: "Databases"
26 | }
27 | }
28 | };
29 |
30 | export default config;
31 |
--------------------------------------------------------------------------------
/electron/electron-builder.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "com.yourdoamnin.yourapp",
3 | "directories": {
4 | "buildResources": "resources"
5 | },
6 | "files": [
7 | "assets/**/*",
8 | "build/**/*",
9 | "capacitor.config.*",
10 | "app/**/*"
11 | ],
12 | "publish": {
13 | "provider": "github"
14 | },
15 | "nsis": {
16 | "allowElevation": true,
17 | "oneClick": false,
18 | "allowToChangeInstallationDirectory": true
19 | },
20 | "win": {
21 | "target": "nsis",
22 | "icon": "assets/appIcon.ico"
23 | },
24 | "mac": {
25 | "category": "your.app.category.type",
26 | "target": "dmg"
27 | }
28 | }
--------------------------------------------------------------------------------
/electron/live-runner.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable @typescript-eslint/no-var-requires */
3 | const cp = require('child_process');
4 | const chokidar = require('chokidar');
5 | const electron = require('electron');
6 |
7 | let child = null;
8 | const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
9 | const reloadWatcher = {
10 | debouncer: null,
11 | ready: false,
12 | watcher: null,
13 | restarting: false,
14 | };
15 |
16 | ///*
17 | function runBuild() {
18 | return new Promise((resolve, _reject) => {
19 | let tempChild = cp.spawn(npmCmd, ['run', 'build']);
20 | tempChild.once('exit', () => {
21 | resolve();
22 | });
23 | tempChild.stdout.pipe(process.stdout);
24 | });
25 | }
26 | //*/
27 |
28 | async function spawnElectron() {
29 | if (child !== null) {
30 | child.stdin.pause();
31 | child.kill();
32 | child = null;
33 | await runBuild();
34 | }
35 | child = cp.spawn(electron, ['--inspect=5858', './']);
36 | child.on('exit', () => {
37 | if (!reloadWatcher.restarting) {
38 | process.exit(0);
39 | }
40 | });
41 | child.stdout.pipe(process.stdout);
42 | }
43 |
44 | function setupReloadWatcher() {
45 | reloadWatcher.watcher = chokidar
46 | .watch('./src/**/*', {
47 | ignored: /[/\\]\./,
48 | persistent: true,
49 | })
50 | .on('ready', () => {
51 | reloadWatcher.ready = true;
52 | })
53 | .on('all', (_event, _path) => {
54 | if (reloadWatcher.ready) {
55 | clearTimeout(reloadWatcher.debouncer);
56 | reloadWatcher.debouncer = setTimeout(async () => {
57 | console.log('Restarting');
58 | reloadWatcher.restarting = true;
59 | await spawnElectron();
60 | reloadWatcher.restarting = false;
61 | reloadWatcher.ready = false;
62 | clearTimeout(reloadWatcher.debouncer);
63 | reloadWatcher.debouncer = null;
64 | reloadWatcher.watcher = null;
65 | setupReloadWatcher();
66 | }, 500);
67 | }
68 | });
69 | }
70 |
71 | (async () => {
72 | await runBuild();
73 | await spawnElectron();
74 | setupReloadWatcher();
75 | })();
76 |
--------------------------------------------------------------------------------
/electron/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-sqlite-app-starter",
3 | "version": "1.0.0",
4 | "description": "An Amazing Capacitor App",
5 | "author": {
6 | "name": "",
7 | "email": ""
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/jepiqueau/react-sqlite-app-starter.git"
12 | },
13 | "license": "MIT",
14 | "main": "build/src/index.js",
15 | "scripts": {
16 | "build": "tsc && electron-rebuild",
17 | "electron:start-live": "node ./live-runner.js",
18 | "electron:start": "npm run build && electron --inspect=5858 ./",
19 | "electron:pack": "npm run build && electron-builder build --dir -c ./electron-builder.config.json",
20 | "electron:make": "npm run build && electron-builder build -c ./electron-builder.config.json -p always"
21 | },
22 | "dependencies": {
23 | "@capacitor-community/electron": "^4.1.0",
24 | "@capacitor-community/sqlite": "^4.6.3-3",
25 | "chokidar": "~3.5.2",
26 | "electron-is-dev": "~2.0.0",
27 | "electron-serve": "~1.1.0",
28 | "electron-unhandled": "~3.0.2",
29 | "electron-updater": "~4.3.9",
30 | "electron-window-state": "~5.0.3",
31 | "jszip": "^3.10.1",
32 | "node-fetch": "^2.6.7",
33 | "sqlite3": "^5.1.2"
34 | },
35 | "devDependencies": {
36 | "@types/sqlite3": "^3.1.8",
37 | "ansi-regex": "^6.0.1",
38 | "electron": "^18.3.7",
39 | "electron-builder": "~24.0.0",
40 | "electron-rebuild": "^3.2.3",
41 | "typescript": "~4.3.5"
42 | },
43 | "keywords": [
44 | "capacitor",
45 | "electron"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/electron/resources/electron-publisher-custom.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable @typescript-eslint/no-var-requires */
3 | const electronPublish = require('electron-publish');
4 |
5 | class Publisher extends electronPublish.Publisher {
6 | async upload(task) {
7 | console.log('electron-publisher-custom', task.file);
8 | }
9 | }
10 | module.exports = Publisher;
11 |
--------------------------------------------------------------------------------
/electron/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { CapacitorElectronConfig } from '@capacitor-community/electron';
2 | import {
3 | getCapacitorElectronConfig,
4 | setupElectronDeepLinking,
5 | } from '@capacitor-community/electron';
6 | import type { MenuItemConstructorOptions } from 'electron';
7 | import { app, MenuItem } from 'electron';
8 | import electronIsDev from 'electron-is-dev';
9 | import unhandled from 'electron-unhandled';
10 | import { autoUpdater } from 'electron-updater';
11 |
12 | import {
13 | ElectronCapacitorApp,
14 | setupContentSecurityPolicy,
15 | setupReloadWatcher,
16 | } from './setup';
17 |
18 | // Graceful handling of unhandled errors.
19 | unhandled();
20 |
21 | // Define our menu templates (these are optional)
22 | const trayMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [
23 | new MenuItem({ label: 'Quit App', role: 'quit' }),
24 | ];
25 | const appMenuBarMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [
26 | { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' },
27 | { role: 'viewMenu' },
28 | ];
29 |
30 | // Get Config options from capacitor.config
31 | const capacitorFileConfig: CapacitorElectronConfig =
32 | getCapacitorElectronConfig();
33 |
34 | // Initialize our app. You can pass menu templates into the app here.
35 | // const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig);
36 | const myCapacitorApp = new ElectronCapacitorApp(
37 | capacitorFileConfig,
38 | trayMenuTemplate,
39 | appMenuBarMenuTemplate,
40 | );
41 |
42 | // If deeplinking is enabled then we will set it up here.
43 | if (capacitorFileConfig.electron?.deepLinkingEnabled) {
44 | setupElectronDeepLinking(myCapacitorApp, {
45 | customProtocol:
46 | capacitorFileConfig.electron.deepLinkingCustomProtocol ??
47 | 'mycapacitorapp',
48 | });
49 | }
50 |
51 | // If we are in Dev mode, use the file watcher components.
52 | if (electronIsDev) {
53 | setupReloadWatcher(myCapacitorApp);
54 | }
55 |
56 | // Run Application
57 | (async () => {
58 | // Wait for electron app to be ready.
59 | await app.whenReady();
60 | // Security - Set Content-Security-Policy based on whether or not we are in dev mode.
61 | setupContentSecurityPolicy(myCapacitorApp.getCustomURLScheme());
62 | // Initialize our app, build windows, and load content.
63 | await myCapacitorApp.init();
64 | // Check for updates if we are in a packaged app.
65 | autoUpdater.checkForUpdatesAndNotify();
66 | })();
67 |
68 | // Handle when all of our windows are close (platforms have their own expectations).
69 | app.on('window-all-closed', function () {
70 | // On OS X it is common for applications and their menu bar
71 | // to stay active until the user quits explicitly with Cmd + Q
72 | if (process.platform !== 'darwin') {
73 | app.quit();
74 | }
75 | });
76 |
77 | // When the dock icon is clicked.
78 | app.on('activate', async function () {
79 | // On OS X it's common to re-create a window in the app when the
80 | // dock icon is clicked and there are no other windows open.
81 | if (myCapacitorApp.getMainWindow().isDestroyed()) {
82 | await myCapacitorApp.init();
83 | }
84 | });
85 |
86 | // Place all ipc or other electron api calls and custom functionality under this line
87 |
--------------------------------------------------------------------------------
/electron/src/preload.ts:
--------------------------------------------------------------------------------
1 | require('./rt/electron-rt');
2 | //////////////////////////////
3 | // User Defined Preload scripts below
4 | console.log('User Preload!');
5 |
--------------------------------------------------------------------------------
/electron/src/rt/electron-plugins.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 | const CapacitorCommunitySqlite = require('../../../node_modules/@capacitor-community/sqlite/electron/dist/plugin.js');
3 |
4 | module.exports = {
5 | CapacitorCommunitySqlite,
6 | }
--------------------------------------------------------------------------------
/electron/src/rt/electron-rt.ts:
--------------------------------------------------------------------------------
1 | import { ipcRenderer, contextBridge } from 'electron';
2 |
3 | ////////////////////////////////////////////////////////
4 | // eslint-disable-next-line @typescript-eslint/no-var-requires
5 | const plugins = require('./electron-plugins');
6 |
7 | const contextApi: {
8 | [plugin: string]: { [functionName: string]: () => Promise };
9 | } = {};
10 | for (const pluginKey of Object.keys(plugins)) {
11 | for (const classKey of Object.keys(plugins[pluginKey]).filter(
12 | className => className !== 'default',
13 | )) {
14 | const functionList = Object.getOwnPropertyNames(
15 | plugins[pluginKey][classKey].prototype,
16 | ).filter(v => v !== 'constructor');
17 | if (!contextApi[classKey]) {
18 | contextApi[classKey] = {};
19 | }
20 | for (const functionName of functionList) {
21 | if (!contextApi[classKey][functionName]) {
22 | contextApi[classKey][functionName] = (...args) =>
23 | ipcRenderer.invoke(`${classKey}-${functionName}`, ...args);
24 | }
25 | }
26 | }
27 | }
28 | contextBridge.exposeInMainWorld('CapacitorCustomPlatform', {
29 | name: 'electron',
30 | plugins: contextApi,
31 | });
32 | ////////////////////////////////////////////////////////
33 |
--------------------------------------------------------------------------------
/electron/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "include": ["./src/**/*", "./capacitor.config.ts", "./capacitor.config.js"],
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "importHelpers": true,
7 | "target": "ES2017",
8 | "module": "CommonJS",
9 | "moduleResolution": "node",
10 | "esModuleInterop": true,
11 | "typeRoots": ["./node_modules/@types"],
12 | "allowJs": true,
13 | "rootDir": "."
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-sqlite-app-starter",
3 | "integrations": {
4 | "capacitor": {}
5 | },
6 | "type": "react"
7 | }
8 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | App/build
2 | App/Pods
3 | App/Podfile.lock
4 | App/App/public
5 | DerivedData
6 | xcuserdata
7 |
8 | # Cordova plugins for Capacitor
9 | capacitor-cordova-ios-plugins
10 |
11 | # Generated Config files
12 | App/App/capacitor.config.json
13 | App/App/config.xml
14 |
--------------------------------------------------------------------------------
/ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/App/App.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/App/App/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Capacitor
3 |
4 | @UIApplicationMain
5 | class AppDelegate: UIResponder, UIApplicationDelegate {
6 |
7 | var window: UIWindow?
8 |
9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
10 | // Override point for customization after application launch.
11 | return true
12 | }
13 |
14 | func applicationWillResignActive(_ application: UIApplication) {
15 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
16 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
17 | }
18 |
19 | func applicationDidEnterBackground(_ application: UIApplication) {
20 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
22 | }
23 |
24 | func applicationWillEnterForeground(_ application: UIApplication) {
25 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
26 | }
27 |
28 | func applicationDidBecomeActive(_ application: UIApplication) {
29 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
30 | }
31 |
32 | func applicationWillTerminate(_ application: UIApplication) {
33 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
34 | }
35 |
36 | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
37 | // Called when the app was launched with a url. Feel free to add additional processing here,
38 | // but if you want the App API to support tracking app url opens, make sure to keep this call
39 | return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
40 | }
41 |
42 | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
43 | // Called when the app was launched with an activity, including Universal Links.
44 | // Feel free to add additional processing here, but if you want the App API to support
45 | // tracking app url opens, make sure to keep this call
46 | return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "AppIcon-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "AppIcon-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "AppIcon-29x29@2x-1.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "AppIcon-29x29@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "AppIcon-40x40@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "AppIcon-40x40@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "AppIcon-60x60@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "AppIcon-60x60@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "AppIcon-20x20@1x.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "AppIcon-20x20@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "AppIcon-29x29@1x.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "AppIcon-29x29@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "AppIcon-40x40@1x.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "AppIcon-40x40@2x-1.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "AppIcon-76x76@1x.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "AppIcon-76x76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "AppIcon-83.5x83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "AppIcon-512@2x.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "splash-2732x2732-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "splash-2732x2732-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "splash-2732x2732.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
--------------------------------------------------------------------------------
/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
--------------------------------------------------------------------------------
/ios/App/App/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ios/App/App/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ios/App/App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | react-sqlite-app-starter
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UIViewControllerBasedStatusBarAppearance
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ios/App/App/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "com.jeep.app.ionic.react",
3 | "appName": "react-sqlite-app-starter",
4 | "webDir": "build",
5 | "bundledWebRuntime": false,
6 | "plugins": {
7 | "CapacitorSQLite": {
8 | "iosDatabaseLocation": "Library/CapacitorDatabase",
9 | "iosIsEncryption": true,
10 | "iosKeychainPrefix": "react-sqlite-app-starter",
11 | "iosBiometric": {
12 | "biometricAuth": false,
13 | "biometricTitle": "Biometric login for capacitor sqlite"
14 | },
15 | "androidIsEncryption": true,
16 | "androidBiometric": {
17 | "biometricAuth": false,
18 | "biometricTitle": "Biometric login for capacitor sqlite",
19 | "biometricSubTitle": "Log in using your biometric"
20 | },
21 | "electronWindowsLocation": "C:\\ProgramData\\CapacitorDatabases",
22 | "electronMacLocation": "/Volumes/Development_Lacie/Development/CapacitorDatabases",
23 | "electronLinuxLocation": "Databases"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ios/App/App/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/App/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
2 |
3 | platform :ios, '13.0'
4 | use_frameworks!
5 |
6 | # workaround to avoid Xcode caching of Pods that requires
7 | # Product -> Clean Build Folder after new Cordova plugins installed
8 | # Requires CocoaPods 1.6 or newer
9 | install! 'cocoapods', :disable_input_output_paths => true
10 |
11 | def capacitor_pods
12 | pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
13 | pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
14 | pod 'CapacitorCommunitySqlite', :path => '../../node_modules/@capacitor-community/sqlite'
15 | pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'
16 | pod 'CapacitorToast', :path => '../../node_modules/@capacitor/toast'
17 | end
18 |
19 | target 'App' do
20 | capacitor_pods
21 | # Add your Pods here
22 | end
23 |
24 | post_install do |installer|
25 | assertDeploymentTarget(installer)
26 | end
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-sqlite-app-starter",
3 | "version": "4.2.1",
4 | "private": true,
5 | "description": "Ionic/React SQLite Application Starter",
6 | "homepage": "./",
7 | "author": "Jean Pierre Quéau",
8 | "license": "MIT",
9 | "dependencies": {
10 | "@capacitor-community/electron": "^4.1.2",
11 | "@capacitor-community/sqlite": "^4.6.3-3",
12 | "@capacitor/android": "^4.6.3",
13 | "@capacitor/core": "^4.6.3",
14 | "@capacitor/dialog": "^4.0.1",
15 | "@capacitor/ios": "^4.6.3",
16 | "@capacitor/toast": "^4.0.1",
17 | "@ionic/pwa-elements": "^3.1.1",
18 | "@ionic/react": "^6.6.1",
19 | "@ionic/react-router": "^6.6.1",
20 | "@testing-library/jest-dom": "^5.11.9",
21 | "@testing-library/react": "^13.3.0",
22 | "@testing-library/user-event": "^12.6.3",
23 | "@types/jest": "^26.0.20",
24 | "@types/node": "^12.19.15",
25 | "@types/react": "^18.0.17",
26 | "@types/react-dom": "^18.0.6",
27 | "@types/react-router": "^5.1.11",
28 | "@types/react-router-dom": "^5.1.7",
29 | "ionicons": "^6.0.3",
30 | "react": "^18.2.0",
31 | "react-dom": "^18.2.0",
32 | "react-modal": "^3.15.1",
33 | "react-router": "^5.2.0",
34 | "react-router-dom": "^5.2.0",
35 | "react-scripts": "^5.0.1",
36 | "react-sqlite-hook": "^3.2.0",
37 | "typescript": "^4.4.4",
38 | "web-vitals": "^0.2.4",
39 | "workbox-background-sync": "^5.1.4",
40 | "workbox-broadcast-update": "^5.1.4",
41 | "workbox-cacheable-response": "^5.1.4",
42 | "workbox-core": "^5.1.4",
43 | "workbox-expiration": "^5.1.4",
44 | "workbox-google-analytics": "^5.1.4",
45 | "workbox-navigation-preload": "^5.1.4",
46 | "workbox-precaching": "^5.1.4",
47 | "workbox-range-requests": "^5.1.4",
48 | "workbox-routing": "^5.1.4",
49 | "workbox-strategies": "^5.1.4",
50 | "workbox-streams": "^5.1.4"
51 | },
52 | "scripts": {
53 | "update-jeep": "npm install --save @capacitor-community/sqlite@latest --save-dev react-sqlite-hook@latest",
54 | "update-capacitor": "npm install --save @capacitor/core@latest --save @capacitor/android@latest --save @capacitor/ios@latest --save-dev @capacitor/cli@latest",
55 | "start": "npm run copysqlwasm && react-scripts start",
56 | "build": "npm run copysqlwasm && react-scripts build",
57 | "test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",
58 | "eject": "react-scripts eject",
59 | "copysqlwasm": "copyfiles -u 3 node_modules/sql.js/dist/sql-wasm.wasm public/assets"
60 | },
61 | "eslintConfig": {
62 | "extends": [
63 | "react-app",
64 | "react-app/jest"
65 | ]
66 | },
67 | "browserslist": {
68 | "production": [
69 | ">0.2%",
70 | "not dead",
71 | "not op_mini all"
72 | ],
73 | "development": [
74 | "last 1 chrome version",
75 | "last 1 firefox version",
76 | "last 1 safari version"
77 | ]
78 | },
79 | "devDependencies": {
80 | "@capacitor/cli": "^4.6.3",
81 | "@types/react-modal": "^3.13.1",
82 | "copyfiles": "^2.4.1"
83 | },
84 | "repository": {
85 | "type": "git",
86 | "url": "https://github.com/jepiqueau/react-sqlite-app-starter.git"
87 | },
88 | "bugs": {
89 | "url": "https://github.com/jepiqueau/react-sqlite-app-starter.git/issues"
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/public/assets/databases/databases.json:
--------------------------------------------------------------------------------
1 | {
2 | "databaseList" : [
3 | "dbForCopy.db",
4 | "myDBSQLite.db"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/public/assets/databases/dbForCopy.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/public/assets/databases/dbForCopy.db
--------------------------------------------------------------------------------
/public/assets/databases/myDBSQLite.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/public/assets/databases/myDBSQLite.db
--------------------------------------------------------------------------------
/public/assets/icon/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/public/assets/icon/favicon.png
--------------------------------------------------------------------------------
/public/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/public/assets/icon/icon.png
--------------------------------------------------------------------------------
/public/assets/shapes.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/assets/sql-wasm.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/public/assets/sql-wasm.wasm
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic App
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Ionic App",
3 | "name": "My Ionic App",
4 | "icons": [
5 | {
6 | "src": "assets/icon/favicon.png",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "assets/icon/icon.png",
12 | "type": "image/png",
13 | "sizes": "512x512",
14 | "purpose": "maskable"
15 | }
16 | ],
17 | "start_url": ".",
18 | "display": "standalone",
19 | "theme_color": "#ffffff",
20 | "background_color": "#ffffff"
21 | }
22 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders without crashing', () => {
6 | const { baseElement } = render( );
7 | expect(baseElement).toBeDefined();
8 | });
9 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef } from 'react';
2 | import { Redirect, Route } from 'react-router-dom';
3 | import {
4 | IonApp,
5 | IonIcon,
6 | IonLabel,
7 | IonRouterOutlet,
8 | IonTabBar,
9 | IonTabButton,
10 | IonTabs,
11 | setupIonicReact,
12 | useIonModal
13 | } from '@ionic/react';
14 | import { IonReactRouter } from '@ionic/react-router';
15 | import { ellipse, square, triangle } from 'ionicons/icons';
16 | import Tab1 from './pages/Tab1';
17 | import Tab2 from './pages/Tab2';
18 | import Tab3 from './pages/Tab3';
19 | import ViewTest from './pages/ViewTest';
20 | import { SQLiteHook, useSQLite } from 'react-sqlite-hook';
21 | import ViewMessage from './pages/ViewMessage';
22 |
23 | /* Core CSS required for Ionic components to work properly */
24 | import '@ionic/react/css/core.css';
25 |
26 | /* Basic CSS for apps built with Ionic */
27 | import '@ionic/react/css/normalize.css';
28 | import '@ionic/react/css/structure.css';
29 | import '@ionic/react/css/typography.css';
30 |
31 | /* Optional CSS utils that can be commented out */
32 | import '@ionic/react/css/padding.css';
33 | import '@ionic/react/css/float-elements.css';
34 | import '@ionic/react/css/text-alignment.css';
35 | import '@ionic/react/css/text-transformation.css';
36 | import '@ionic/react/css/flex-utils.css';
37 | import '@ionic/react/css/display.css';
38 |
39 | /* Theme variables */
40 | import './theme/variables.css';
41 |
42 | interface JsonListenerInterface {
43 | jsonListeners: boolean,
44 | setJsonListeners: React.Dispatch>,
45 | }
46 | interface existingConnInterface {
47 | existConn: boolean,
48 | setExistConn: React.Dispatch>,
49 | }
50 |
51 | // Singleton SQLite Hook
52 | export let sqlite: SQLiteHook;
53 | // Existing Connections Store
54 | export let existingConn: existingConnInterface;
55 | // Is Json Listeners used
56 | export let isJsonListeners: JsonListenerInterface;
57 |
58 | setupIonicReact();
59 |
60 | const App: React.FC = () => {
61 | const [existConn, setExistConn] = useState(false);
62 | existingConn = {existConn: existConn, setExistConn: setExistConn};
63 |
64 | // !!!!! if you do not want to use the progress events !!!!!
65 | // since react-sqlite-hook 2.1.0
66 | // sqlite = useSQLite()
67 | // before
68 | // sqlite = useSQLite({})
69 | // !!!!! !!!!!
70 |
71 | sqlite = useSQLite();
72 | console.log(`$$$ in App sqlite.isAvailable ${sqlite.isAvailable} $$$`);
73 |
74 |
75 | return (
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | Tab 1
100 |
101 |
102 |
103 | Tab 2
104 |
105 |
106 |
107 | Tab 3
108 |
109 |
110 |
111 |
112 |
113 | );
114 | };
115 |
116 | export default App;
117 |
--------------------------------------------------------------------------------
/src/Utils/base64Images.ts:
--------------------------------------------------------------------------------
1 | export const Images: Array = [
2 | "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAkCAYAAAD7PHgWAAAEcElEQVRYR8WYP2hTQRzHfx10aQchi0JcLGpBSBcrlTrpIjoFiy6FDipOHVz8Q0HrUGxdg1N1KBRBackiVoQ6FMVIuzQgpEpdjOiSLUXQIfK9976X37t3l6RNxVuS3Hvv7nPf3+/3vcvraTQaDdlFK4z3yMT8rh7d0Ww97QAzfX12wFq9br4buOk7UpicaQm5F4toCajh9LKnLm23Bex0Ee3k7ArwS/mVvH5elqEzzWmGr0dhDwGGFs3ouMAdA7491y+Dhw5KZuG9UEEA1r6XZfhUPOxgQ0pzPQJIDTi11NtOKOkKkHCcpfDrjQlxaXnGdFE1fAcg2to7sWmgAfVYWCzbPwO06imNHt0Tyd/IyfDlrYRy7kI3fvyUsyvRPbsCxIPIGQ6MAdFWD5RbKnjxZhTSWn0+AqyuS2agEPWNjZhPjrUngBgQkABDQ3hNOJdnmvkXa5UZ6W2CxXBaRoBiLLR2cLgnUSRIbOSLlptVx8LQk7k5iHutah44Pks12+VfApBVh04YsAbV1yR7sslYXU+oSPUK46NWZWPmseJdATLfTJ5UJsxYBNXqoc+EeX7RgpbmRmX1pcjsSq95VkP5AM1czMl63ViS27iNen2QYSUoH+bWVq1WpTh5OAFp1ekbtz7JRVJBPH/+Sk6O5i4YQCxc57Sbq0i1loA2R6hKfDho7rFLqZWzYvXiqCKgSi/6LSC+o7l2ZCIWz5UChHqfH2alvPVVRp/sT4Q7P/1NstmssZ6okNKAyD803+5BICjohjm90qgnAajhcNEHiP7BgQHZqFQkK49FF40uDtyHrZAKEQ6/NWDIoAkcBAQcmpuHoZWG+l1IwlHBjgGp3rP1zchi4kpG3vi+7wQUkMgz5p8tKIwdnzHbhtiatALTRcLvtBnmmc/ANQCuo3JxLGMF6+tmHFUULqgJsUl6Bwy/jXr1elQUWlGnj37JyfQksBhWL/tpM/itK9kHanOQ3rd47bcZxxSIkl97ow67u2Lfouh/+l6EnIvXuU5/TNkMAAjnA7RhUf9RQkWkTRhh9TUCuuO6kUooCMBc/xHzzLG71ZYJjAUhPD6TDUERxoXTC7CRiqOXAIRBZ/J5e3/oXxvhdE6FqpA2g+sslFaA3iLRMmvfYz6l8ixWD/3adF0bwXUNiN87gcP9qfOg72jkepVWkIC6ELQZu5BdAWIwbSl6F9AWQEAXRB8GtOpaxa4BCan3Tp3cemJ3G9R+R/g9DbGenDtLCJQVHIL0AeqKb7fFkaWjdzMIrz4+afdvpWKoslks+Lx9YltufQy/hPICUj1OQAOHR9KGeABwAfk6xOeFOmdrxaI5c6Ktffgjs5/4VzV6QRVUkKcafRMHQh8hQ9udPrm4ChJQw7n3EJYp4D0PPl3YlKtjx+0K3UEAiZ3G9T3fATWRd5UJ8cEBCm3o9D47Fc8CKUCEEw/om/kUD7H4zY2e+Vh8UJb8/fTrDt+BA8/rfZ/j63m9gLSYUHL7Ks99ndZpdYZew3Fub4hbVd3/uvYXfqiMwjPten8AAAAASUVORK5CYII=",
3 | "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAU1QTFRFNjtAQEVK////bG9zSk9T/v7+/f39/f3+9vf3O0BETlJWNzxB/Pz8d3t+TFFVzM3O1NXX7u/vUldbRElNs7W3v8HCmZyeRkpPW19j8vLy7u7vvsDC9PT1cHR3Oj9Eo6WnxsjJR0tQOD1Bj5KVgYSHTVFWtri50dLUtLa4YmZqOT5D8vPzRUpOkZOWc3Z64uPjr7Gzuru95+jpX2NnaGxwPkNHp6mrioyPlZeadXh8Q0hNPEBFyszNh4qNc3d6eHx/OD1Cw8XGXGBkfoGEra+xxcbIgoaJu72/m52ggoWIZ2tu8/P0wcLE+vr7kZSXgIOGP0NIvr/BvL6/QUZKP0RJkpWYpKaoqKqtVVldmJqdl5qcZWhstbe5bHB0bnJ1UVVZwsTF5ubnT1RYcHN3oaSm3N3e3NzdQkdLnJ+h9fX1TlNX+Pj47/DwwsPFVFhcEpC44wAAAShJREFUeNq8k0VvxDAQhZOXDS52mRnKzLRlZmZm+v/HxmnUOlFaSz3su4xm/BkGzLn4P+XimOJZyw0FKufelfbfAe89dMmBBdUZ8G1eCJMba69Al+AABOOm/7j0DDGXtQP9bXjYN2tWGQfyA1Yg1kSu95x9GKHiIOBXLcAwUD1JJSBVfUbwGGi2AIvoneK4bCblSS8b0RwwRAPbCHx52kH60K1b9zQUjQKiULbMDbulEjGha/RQQFDE0/ezW8kR3C3kOJXmFcSyrcQR7FDAi55nuGABZkT5hqpk3xughDN7FOHHHd0LLU9qtV7r7uhsuRwt6pEJJFVLN4V5CT+SErpXt81DbHautkpBeHeaqNDRqUA0Uo5GkgXGyI3xDZ/q/wJMsb7/pwADAGqZHDyWkHd1AAAAAElFTkSuQmCC"
4 | ];
--------------------------------------------------------------------------------
/src/Utils/deleteDBUtil.ts:
--------------------------------------------------------------------------------
1 | import { SQLiteDBConnection } from '@capacitor-community/sqlite';
2 |
3 | export async function deleteDatabase(db: SQLiteDBConnection): Promise {
4 | try {
5 | let ret: any = await db.isExists();
6 | if(ret.result) {
7 | const dbName = db.getConnectionDBName();
8 | console.log("$$$ database " + dbName + " before delete");
9 | await db.delete();
10 | console.log("$$$ database " + dbName + " after delete " + ret.result);
11 | return Promise.resolve();
12 | } else {
13 | return Promise.resolve();
14 | }
15 | } catch (err) {
16 | return Promise.reject(err);
17 | }
18 | }
--------------------------------------------------------------------------------
/src/Utils/encryptedSetUtils.ts:
--------------------------------------------------------------------------------
1 | import { capSQLiteSet } from '@capacitor-community/sqlite';
2 | export const createSchemaContacts: string = `
3 | CREATE TABLE IF NOT EXISTS contacts (
4 | id INTEGER PRIMARY KEY NOT NULL,
5 | email TEXT UNIQUE NOT NULL,
6 | name TEXT,
7 | FirstName TEXT,
8 | company TEXT,
9 | size REAL,
10 | age INTEGER,
11 | MobileNumber TEXT,
12 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
13 | last_modified INTEGER DEFAULT (strftime('%s', 'now'))
14 | );
15 | CREATE INDEX IF NOT EXISTS contacts_index_name ON contacts (name);
16 | CREATE INDEX IF NOT EXISTS contacts_index_email ON contacts (email);
17 | PRAGMA user_version = 1;
18 | `;
19 | export const setContacts: Array = [
20 | { statement:"INSERT INTO contacts (name,FirstName,email,age,MobileNumber) VALUES (?,?,?,?,?);",
21 | values:["Simpson","Tom","Simpson@example.com",69,"4405060708"]
22 | },
23 | { statement:"INSERT INTO contacts (name,FirstName,email,age,MobileNumber) VALUES (?,?,?,?,?);",
24 | values:["Jones","David","Jones@example.com",42,"4404030201"]
25 | },
26 | { statement:"INSERT INTO contacts (name,FirstName,email,age,MobileNumber) VALUES (?,?,?,?,?);",
27 | values:["Whiteley","Dave","Whiteley@example.com",45,"4405162732"]
28 | },
29 | { statement:"INSERT INTO contacts (name,FirstName,email,age,MobileNumber) VALUES (?,?,?,?,?);",
30 | values:["Brown","John","Brown@example.com",35,"4405243853"]
31 | },
32 | { statement:"UPDATE contacts SET age = ? , MobileNumber = ? WHERE id = ?;",
33 | values:[51,"4404030202",2]
34 | }
35 | ];
36 | export const createSchemaMessages: string = `
37 | CREATE TABLE IF NOT EXISTS messages (
38 | id INTEGER PRIMARY KEY NOT NULL,
39 | contactid INTEGER,
40 | title TEXT NOT NULL,
41 | body TEXT NOT NULL,
42 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
43 | last_modified INTEGER DEFAULT (strftime('%s', 'now')),
44 | FOREIGN KEY (contactid) REFERENCES contacts(id) ON DELETE SET DEFAULT
45 | );
46 | CREATE INDEX IF NOT EXISTS messages_index_name ON messages (title);
47 | CREATE INDEX IF NOT EXISTS messages_index_last_modified ON messages (last_modified);
48 | `
49 | export const setMessages: Array = [
50 | { statement:"INSERT INTO messages (contactid,title,body) VALUES (?,?,?);",
51 | values:[1,"message 1","body message1"]
52 | },
53 | { statement:"INSERT INTO messages (contactid,title,body) VALUES (?,?,?);",
54 | values:[2,"message 2","body message2"]
55 | },
56 | { statement:"INSERT INTO messages (contactid,title,body) VALUES (?,?,?);",
57 | values:[1,"message 3","body message3"]
58 | },
59 | ]
--------------------------------------------------------------------------------
/src/Utils/noEncryptionUtils.ts:
--------------------------------------------------------------------------------
1 | import { capSQLiteSet } from '@capacitor-community/sqlite';
2 | export const createTablesNoEncryption: string = `-- testcomments
3 | CREATE TABLE IF NOT EXISTS users (
4 | /*
5 | * Author: jeepq
6 | * Purpose: To show a comment that spans multiple lines in your SQL
7 | * statement in SQLite.
8 | */
9 | id INTEGER PRIMARY KEY NOT NULL,
10 | email TEXT UNIQUE NOT NULL, -- email as key
11 | name TEXT,
12 | company TEXT,
13 | size FLOAT,
14 | age INTEGER,
15 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
16 | last_modified INTEGER DEFAULT (strftime('%s', 'now'))
17 | );
18 | `;
19 | export const createTablesNoEncryption1: string = `
20 | CREATE TABLE IF NOT EXISTS users (
21 | id INTEGER PRIMARY KEY NOT NULL,
22 | email TEXT UNIQUE NOT NULL,
23 | name TEXT,
24 | company TEXT,
25 | size FLOAT,
26 | age INTEGER,
27 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
28 | last_modified INTEGER DEFAULT (strftime('%s', 'now'))
29 | );
30 | CREATE TABLE IF NOT EXISTS messages (
31 | id INTEGER PRIMARY KEY NOT NULL,
32 | userid INTEGER,
33 | title TEXT NOT NULL,
34 | body TEXT NOT NULL,
35 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
36 | last_modified INTEGER DEFAULT (strftime('%s', 'now')),
37 | FOREIGN KEY (userid) REFERENCES users(id) ON DELETE SET DEFAULT
38 | );
39 | CREATE INDEX IF NOT EXISTS users_index_name ON users (name);
40 | CREATE INDEX IF NOT EXISTS users_index_last_modified ON users (last_modified);
41 | CREATE INDEX IF NOT EXISTS messages_index_last_modified ON messages (last_modified);
42 | CREATE TRIGGER IF NOT EXISTS users_trigger_last_modified
43 | AFTER UPDATE ON users
44 | FOR EACH ROW WHEN NEW.last_modified < OLD.last_modified
45 | BEGIN
46 | UPDATE users SET last_modified= (strftime('%s', 'now')) WHERE id=OLD.id;
47 | END;
48 | CREATE TRIGGER IF NOT EXISTS messages_trigger_last_modified AFTER UPDATE ON messages
49 | FOR EACH ROW WHEN NEW.last_modified < OLD.last_modified
50 | BEGIN
51 | UPDATE messages SET last_modified= (strftime('%s', 'now')) WHERE id=OLD.id;
52 | END;
53 | PRAGMA user_version = 1;
54 | `;
55 | export const importTwoUsers: string = `
56 | DELETE FROM users;
57 | INSERT INTO users (name,email,age) VALUES ("Whiteley","Whiteley.com",30);
58 | INSERT INTO users (name,email,age) VALUES ("Jones","Jones.com",44);
59 | `;
60 | export const importThreeMessages: string = `
61 | DELETE FROM messages;
62 | INSERT INTO messages (userid,title,body) VALUES (1,"test post 1","content test post 1");
63 | INSERT INTO messages (userid,title,body) VALUES (2,"test post 2","content test post 2");
64 | INSERT INTO messages (userid,title,body) VALUES (1,"test post 3","content test post 3");
65 | `;
66 | export const dropTablesTablesNoEncryption: string = `
67 | PRAGMA foreign_keys = OFF;
68 | DROP TABLE IF EXISTS users;
69 | DROP TABLE IF EXISTS messages;
70 | PRAGMA foreign_keys = ON;
71 | `;
72 |
73 | export const setUsers: Array = [
74 | { statement:"INSERT INTO users (name,email,age) VALUES (?,?,?);",
75 | values:["Jackson","Jackson@example.com",18]
76 | },
77 | { statement:"INSERT INTO users (name,email,age) VALUES (?,?,?);",
78 | values:["Kennedy","Kennedy@example.com",25]
79 | },
80 | { statement:"INSERT INTO users (name,email,age) VALUES (?,?,?);",
81 | values:["Bush","Bush@example.com",42]
82 | },
83 | ];
--------------------------------------------------------------------------------
/src/Utils/upgrade-database-version.ts:
--------------------------------------------------------------------------------
1 | export const versionUpgrades = [
2 | {
3 | toVersion: 1,
4 | statements: [
5 | `CREATE TABLE IF NOT EXISTS users (
6 | id INTEGER PRIMARY KEY NOT NULL,
7 | email TEXT UNIQUE NOT NULL,
8 | name TEXT,
9 | company TEXT,
10 | size REAL,
11 | age INTEGER,
12 | last_modified INTEGER DEFAULT (strftime('%s', 'now'))
13 | );`,
14 | `CREATE INDEX IF NOT EXISTS users_index_name ON users (name);`,
15 | `CREATE INDEX IF NOT EXISTS users_index_last_modified ON users (last_modified);`,
16 | `CREATE TRIGGER IF NOT EXISTS users_trigger_last_modified
17 | AFTER UPDATE ON users
18 | FOR EACH ROW WHEN NEW.last_modified < OLD.last_modified
19 | BEGIN
20 | UPDATE users SET last_modified= (strftime('%s', 'now')) WHERE id=OLD.id;
21 | END;`,
22 | `INSERT INTO users (name,email,age) VALUES ('Whiteley', 'whiteley@local.host', 30);`,
23 | `INSERT INTO users (name,email,age) VALUES ('Jones', 'jones@local.host', 44);`,
24 | ]
25 | },
26 | {
27 | toVersion: 2,
28 | statements: [
29 | `ALTER TABLE users ADD COLUMN country TEXT;`,
30 | `ALTER TABLE users ADD COLUMN sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1));`,
31 | `CREATE TABLE messages (
32 | id INTEGER PRIMARY KEY NOT NULL,
33 | userid INTEGER,
34 | title TEXT NOT NULL,
35 | body TEXT NOT NULL,
36 | sql_deleted BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1)),
37 | last_modified INTEGER DEFAULT (strftime('%s', 'now')),
38 | FOREIGN KEY (userid) REFERENCES users(id) ON DELETE SET DEFAULT
39 | );`,
40 | `CREATE INDEX messages_index_title ON messages (title);`,
41 | `CREATE INDEX messages_index_last_modified ON messages (last_modified);`,
42 | `INSERT INTO messages (userid,title,body) VALUES (1,'test message 1','content test message 1');`,
43 | `INSERT INTO messages (userid,title,body) VALUES (2,'test message 2','content test message 2');`,
44 | `INSERT INTO messages (userid,title,body) VALUES (1,'test message 3','content test message 3');`,
45 | `UPDATE users SET country = 'United Kingdom' WHERE id = 1;`,
46 | `UPDATE users SET country = 'Australia' WHERE id = 2;`,
47 | ]
48 | }
49 | ]
--------------------------------------------------------------------------------
/src/Utils/upgradeVersionUtils.ts:
--------------------------------------------------------------------------------
1 |
2 | export const userMessages = `
3 | SELECT users.name,messages.title,messages.body FROM users
4 | INNER JOIN messages ON users.id = messages.userid
5 | WHERE users.id = ?;
6 | `;
--------------------------------------------------------------------------------
/src/components/CopyFromAssets.css:
--------------------------------------------------------------------------------
1 | .container-copyfromassets {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/CopyFromAssets.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './CopyFromAssets.css';
3 | import TestOutput from './TestOutput';
4 |
5 | import { sqlite } from '../App';
6 | import { SQLiteDBConnection } from 'react-sqlite-hook';
7 | import { Dialog } from '@capacitor/dialog';
8 |
9 | const CopyFromAssets: React.FC = () => {
10 | const myRef = useRef(false);
11 | const myLog: string[] = [];
12 | const errMess = useRef("");
13 | const [output, setOutput] = useState({log: myLog});
14 | const showAlert = async (message: string) => {
15 | await Dialog.alert({
16 | title: 'Error Dialog',
17 | message: message,
18 | });
19 | };
20 | const testDatabaseCopyFromAssets = async (): Promise => {
21 | setOutput((output: { log: any; }) => ({log: output.log}));
22 |
23 | myLog.push("* Starting testDatabaseCopyFromAssets *\n");
24 | try {
25 |
26 | await sqlite.copyFromAssets();
27 | myLog.push("> copyFromAssets successful\n");
28 |
29 | // create a connection for myDB
30 | let db: SQLiteDBConnection = await sqlite.createConnection("myDB");
31 | myLog.push("> createConnection " +
32 | " 'myDb' successful\n");
33 | await db.open();
34 | myLog.push("> open 'myDb' successful\n");
35 | // Select all Users
36 | let res: any = await db.query("SELECT * FROM users");
37 | console.log(`@@@ res.values.length ${res.values.length}`)
38 | if(res.values.length !== 7 ||
39 | res.values[0].name !== "Whiteley" ||
40 | res.values[1].name !== "Jones" ||
41 | res.values[2].name !== "Simpson" ||
42 | res.values[3].name !== "Brown" ||
43 | res.values[4].name !== "Jackson" ||
44 | res.values[5].name !== "Kennedy" ||
45 | res.values[6].name !== "Bush") {
46 | errMess.current = `Query not returning 7 values`;
47 | return false;
48 | }
49 |
50 | myLog.push("> query 'myDb' successful\n");
51 |
52 |
53 | // Close Connection MyDB
54 | await sqlite.closeConnection("myDB");
55 | myLog.push("> closeConnection 'myDb' successful\n");
56 |
57 | // create a connection for dbForCopy
58 | db = await sqlite.createConnection("dbForCopy");
59 | myLog.push("> createConnection " +
60 | " 'dbForCopy' successful\n");
61 | await db.open();
62 | myLog.push("> open 'dbForCopy' successful\n");
63 | // Select all Users
64 | res = await db.query("SELECT * FROM areas");
65 | console.log(`@@@ res.values.length ${res.values.length}`)
66 | if(res.values.length !== 3 ||
67 | res.values[0].name !== "Access road" ||
68 | res.values[1].name !== "Accessway" ||
69 | res.values[2].name !== "Air handling system"){
70 | errMess.current = `Query Users not returning 3 values`;
71 | setOutput(() => ({log: myLog}));
72 | return false;
73 | }
74 |
75 | myLog.push("> query 'dbForCopy' successful\n");
76 | // Close Connection dbForCopy
77 | await sqlite.closeConnection("dbForCopy");
78 | myLog.push("> closeConnection 'dbForCopy' successful\n");
79 |
80 | myLog.push("* Ending testDatabaseCopyFromAssets *\n");
81 |
82 | return true;
83 | } catch (err: any) {
84 | errMess.current = `${err.message}`;
85 | setOutput(() => ({log: myLog}));
86 | return false;
87 | }
88 | }
89 |
90 | useEffect( () => {
91 | if(sqlite.isAvailable) {
92 | if (myRef.current === false) {
93 | myRef.current = true;
94 | testDatabaseCopyFromAssets().then(async res => {
95 | if(res) {
96 | myLog.push("\n* The set of tests was successful *\n");
97 | } else {
98 | myLog.push("\n* The set of tests failed *\n");
99 | await showAlert(errMess.current);
100 | }
101 | setOutput(() => ({log: myLog}));
102 | });
103 | }
104 | } else {
105 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
106 | myLog.push("\n* Not available for " +
107 | ret.platform + " platform *\n");
108 | await showAlert(errMess.current);
109 | setOutput(() => ({log: myLog}));
110 | });
111 | }
112 |
113 | });
114 |
115 | return (
116 |
117 | );
118 | };
119 |
120 | export default CopyFromAssets;
121 |
--------------------------------------------------------------------------------
/src/components/ExistingConnection.css:
--------------------------------------------------------------------------------
1 | .container-existingconnection {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/ExistingConnection.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './ExistingConnection.css';
3 | import TestOutput from './TestOutput';
4 |
5 | import { setUsers } from '../Utils/noEncryptionUtils';
6 | import { createSchemaMessages, setMessages } from '../Utils/encryptedSetUtils';
7 |
8 | import { sqlite, existingConn } from '../App';
9 | import { Dialog } from '@capacitor/dialog';
10 |
11 | const ExistingConnection: React.FC = () => {
12 | const myRef = useRef(false);
13 | const myLog: string[] = [];
14 | const errMess = useRef("");
15 | const [output, setOutput] = useState({log: myLog});
16 | const showAlert = async (message: string) => {
17 | await Dialog.alert({
18 | title: 'Error Dialog',
19 | message: message,
20 | });
21 | };
22 | const testExistingConns = async (): Promise => {
23 | setOutput((output: { log: any; }) => ({log: output.log}));
24 |
25 | myLog.push("* Starting testExistingConns *\n");
26 | try {
27 | // retrieve the connections
28 | const db = await sqlite.retrieveConnection("testNew")
29 | const db1 = await sqlite.retrieveConnection("testSet")
30 |
31 | // load setUsers in db
32 | var ret: any = await db.executeSet(setUsers);
33 | console.log('$$$ ret.changes.changes in db ' + ret.changes.changes)
34 | if (ret.changes.changes !== 3) {
35 | errMess.current = `ExecuteSet setUsers changes != 3`;
36 | setOutput(() => ({log: myLog}));
37 | return false;
38 | }
39 | // select all users in db
40 | ret = await db.query("SELECT * FROM users;");
41 | if(ret.values.length !== 7 || ret.values[0].name !== "Whiteley" ||
42 | ret.values[1].name !== "Jones" ||
43 | ret.values[2].name !== "Simpson" ||
44 | ret.values[3].name !== "Brown" ||
45 | ret.values[4].name !== "Jackson" ||
46 | ret.values[5].name !== "Kennedy" ||
47 | ret.values[6].name !== "Bush"
48 | ) {
49 | errMess.current = `Query users not returning 7 values`;
50 | setOutput(() => ({log: myLog}));
51 | return false;
52 | }
53 |
54 | // create table messages in db1
55 | ret = await db1.execute(createSchemaMessages);
56 | console.log('$$$ ret.changes.changes in db1 ' + ret.changes.changes)
57 | if (ret.changes.changes < 0) {
58 | errMess.current = `Execute createSchemaMessages changes < 0`;
59 | setOutput(() => ({log: myLog}));
60 | return false;
61 | }
62 |
63 | // load setMessages in db1
64 | ret = await db1.executeSet(setMessages);
65 | console.log('$$$ ret.changes.changes in db1 ' + ret.changes.changes)
66 | if (ret.changes.changes !== 3) {
67 | errMess.current = `ExecuteSet setMessages changes < 0`;
68 | setOutput(() => ({log: myLog}));
69 | return false;
70 | }
71 | // select all users in db
72 | ret = await db1.query("SELECT * FROM messages;");
73 | if(ret.values.length !== 3 || ret.values[0].title !== "message 1" ||
74 | ret.values[1].title !== "message 2" ||
75 | ret.values[2].title !== "message 3"
76 | ) {
77 | errMess.current = `Query messages not returning 3 values`;
78 | setOutput(() => ({log: myLog}));
79 | return false;
80 | }
81 |
82 | // test retrieve all connections
83 | var retDict: Map = await
84 | sqlite.retrieveAllConnections();
85 | if(!retDict.has("RW_testNew") || retDict.get("RW_testNew") !== db) {
86 | errMess.current = `retrieveAllConnections not returning "testNew"`;
87 | setOutput(() => ({log: myLog}));
88 | return false;
89 | }
90 | if(!retDict.has("RW_testSet") || retDict.get("RW_testSet") !== db1) {
91 | errMess.current = `retrieveAllConnections not returning "testSet"`;
92 | setOutput(() => ({log: myLog}));
93 | return false;
94 | }
95 |
96 | // close all connections
97 | sqlite.closeAllConnections();
98 |
99 | myLog.push("* Ending testExistingConns *\n");
100 | existingConn.setExistConn(false);
101 | return true;
102 | } catch (err: any) {
103 | errMess.current = `${err.message}`;
104 | setOutput(() => ({log: myLog}));
105 | return false;
106 | }
107 | }
108 |
109 | useEffect( () => {
110 | if(sqlite.isAvailable) {
111 | if (myRef.current === false) {
112 | myRef.current = true;
113 | testExistingConns().then(async res => {
114 | if(res) {
115 | myLog.push("\n* The set of tests was successful *\n");
116 | } else {
117 | myLog.push("\n* The set of tests failed *\n");
118 | await showAlert(errMess.current);
119 | }
120 | setOutput(() => ({log: myLog}));
121 | });
122 | }
123 | } else {
124 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
125 | myLog.push("\n* Not available for " +
126 | ret.platform + " platform *\n");
127 | await showAlert(errMess.current);
128 | setOutput(() => ({log: myLog}));
129 | });
130 | }
131 | });
132 |
133 | return (
134 |
135 | );
136 | };
137 |
138 | export default ExistingConnection;
139 |
--------------------------------------------------------------------------------
/src/components/ExploreContainer.css:
--------------------------------------------------------------------------------
1 | .container {
2 | text-align: center;
3 | position: absolute;
4 | left: 0;
5 | right: 0;
6 | top: 50%;
7 | transform: translateY(-50%);
8 | }
9 |
10 | .container strong {
11 | font-size: 20px;
12 | line-height: 26px;
13 | }
14 |
15 | .container p {
16 | font-size: 16px;
17 | line-height: 22px;
18 | color: #8c8c8c;
19 | margin: 0;
20 | }
21 |
22 | .container a {
23 | text-decoration: none;
24 | }
--------------------------------------------------------------------------------
/src/components/ExploreContainer.tsx:
--------------------------------------------------------------------------------
1 | import './ExploreContainer.css';
2 |
3 | interface ContainerProps {
4 | name: string;
5 | }
6 |
7 | const ExploreContainer: React.FC = ({ name }) => {
8 | return (
9 |
13 | );
14 | };
15 |
16 | export default ExploreContainer;
17 |
--------------------------------------------------------------------------------
/src/components/MessageListItem.css:
--------------------------------------------------------------------------------
1 | ion-item {
2 | --padding-start: 0;
3 | --inner-padding-end: 0;
4 | }
5 |
6 | ion-label {
7 | margin-top: 12px;
8 | margin-bottom: 12px;
9 | }
10 |
11 | ion-item h2 {
12 | font-weight: 600;
13 | margin: 0;
14 | }
15 |
16 | ion-item p {
17 | text-overflow: ellipsis;
18 | overflow: hidden;
19 | white-space: nowrap;
20 | width: 95%;
21 | }
22 |
23 | ion-item .date {
24 | float: right;
25 | align-items: center;
26 | display: flex;
27 | }
28 |
29 | ion-item ion-icon {
30 | color: #c9c9ca;
31 | }
32 |
33 | ion-item ion-note {
34 | font-size: 15px;
35 | margin-right: 8px;
36 | font-weight: normal;
37 | }
38 |
39 | ion-item ion-note.md {
40 | margin-right: 14px;
41 | }
42 |
43 | .dot {
44 | display: block;
45 | height: 12px;
46 | width: 12px;
47 | border-radius: 50%;
48 | align-self: start;
49 | margin: 16px 10px 16px 16px;
50 | }
51 |
52 | .dot-unread {
53 | background: var(--ion-color-primary);
54 | }
55 |
56 | ion-footer ion-title {
57 | font-size: 11px;
58 | font-weight: normal;
59 | }
--------------------------------------------------------------------------------
/src/components/MessageListItem.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | IonItem,
3 | IonLabel,
4 | IonNote
5 | } from '@ionic/react';
6 | import { Message } from '../data/messages';
7 | import './MessageListItem.css';
8 |
9 | interface MessageListItemProps {
10 | message: Message;
11 | }
12 |
13 | const MessageListItem: React.FC = ({ message }) => {
14 | return (
15 |
16 |
17 |
18 |
19 | {message.fromName}
20 |
21 | {message.date}
22 |
23 |
24 | {message.subject}
25 |
26 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
27 |
28 |
29 |
30 | );
31 | };
32 |
33 | export default MessageListItem;
34 |
--------------------------------------------------------------------------------
/src/components/MigrateDB.css:
--------------------------------------------------------------------------------
1 | .container-migratedb {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/NoEncryption.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/src/components/NoEncryption.css
--------------------------------------------------------------------------------
/src/components/NoEncryption.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useRef } from 'react';
2 | import TestOutput from './TestOutput';
3 | import './NoEncryption.css';
4 | import { sqlite } from '../App';
5 | import { SQLiteDBConnection} from 'react-sqlite-hook';
6 | import { createTablesNoEncryption, createTablesNoEncryption1, importTwoUsers,
7 | dropTablesTablesNoEncryption } from '../Utils/noEncryptionUtils';
8 | import { deleteDatabase } from '../Utils/deleteDBUtil';
9 | import { Dialog } from '@capacitor/dialog';
10 |
11 | const NoEncryption: React.FC = () => {
12 | const myRef = useRef(false);
13 | const myLog: string[] = [];
14 | const errMess = useRef("");
15 | const [output, setOutput] = useState({log: myLog});
16 | const showAlert = async (message: string) => {
17 | await Dialog.alert({
18 | title: 'Error Dialog',
19 | message: message,
20 | });
21 | };
22 |
23 | const testDatabaseNoEncryption = async (): Promise => {
24 | setOutput((output) => ({log: output.log}));
25 |
26 |
27 | myLog.push("* Starting testDatabaseNoEncryption *\n");
28 | try {
29 | // test the plugin with echo
30 | let res: any = await sqlite.echo("Hello from echo");
31 | if(res.value !== "Hello from echo"){
32 | errMess.current = `Echo not returning "Hello from echo"`;
33 | setOutput(() => ({log: myLog}));
34 | return false;
35 | }
36 | myLog.push("> Echo successful\n");
37 |
38 | // create a connection for NoEncryption
39 | let db: SQLiteDBConnection = await sqlite.createConnection("NoEncryption");
40 | // check if the databases exist
41 | // and delete it for multiple successive tests
42 | await deleteDatabase(db);
43 | // open NoEncryption
44 | await db.open();
45 | myLog.push("> open 'NoEncryption' successful\n");
46 |
47 | // Drop tables if exists
48 | res = await db.execute(dropTablesTablesNoEncryption);
49 | if(res.changes.changes !== 0 &&
50 | res.changes.changes !== 1){
51 | errMess.current = `Execute dropTablesTablesNoEncryption changes < 0`;
52 | setOutput(() => ({log: myLog}));
53 | return false;
54 | }
55 | myLog.push("> Execute1 successful\n");
56 |
57 | // Create tables
58 | console.log(`@@@@ createTablesNoEncryption: ${createTablesNoEncryption}`);
59 | res = await db.execute(createTablesNoEncryption);
60 | if (res.changes.changes < 0) {
61 | errMess.current = `Execute createTablesNoEncryption changes < 0`;
62 | setOutput(() => ({log: myLog}));
63 | return false;
64 | }
65 | res = await db.execute(createTablesNoEncryption1);
66 | if (res.changes.changes < 0) {
67 | errMess.current = `Execute createTablesNoEncryption changes < 0`;
68 | setOutput(() => ({log: myLog}));
69 | return false;
70 | }
71 | myLog.push("> Execute2 successful\n");
72 |
73 | // Insert two users with execute method
74 | res = await db.execute(importTwoUsers);
75 | if (res.changes.changes !== 2) {
76 | errMess.current = `Execute importTwoUsers changes != 2`;
77 | setOutput(() => ({log: myLog}));
78 | return false;
79 | }
80 | myLog.push("> Execute3 successful\n");
81 |
82 | // Select all Users
83 | res = await db.query("SELECT * FROM users");
84 | if(res.values.length !== 2 ||
85 | res.values[0].name !== "Whiteley" ||
86 | res.values[1].name !== "Jones") {
87 | errMess.current = `Query not returning 2 values`;
88 | setOutput(() => ({log: myLog}));
89 | return false;
90 | }
91 | myLog.push("> Select1 successful\n");
92 |
93 | // add one user with statement and values
94 | let sqlcmd = "INSERT INTO users (name,email,age) VALUES (?,?,?)";
95 | let values: Array = ["Simpson","Simpson@example.com",69];
96 | res = await db.run(sqlcmd,values);
97 | if(res.changes.changes !== 1 ||
98 | res.changes.lastId !== 3) {
99 | errMess.current = `Run lastId != 3`;
100 | setOutput(() => ({log: myLog}));
101 | return false;
102 | }
103 | myLog.push("> Run1 successful\n");
104 |
105 | // add one user with statement
106 | sqlcmd = `INSERT INTO users (name,email,age) VALUES `+
107 | `("Brown","Brown@example.com",15)`;
108 | res = await db.run(sqlcmd);
109 | if(res.changes.changes !== 1 ||
110 | res.changes.lastId !== 4) {
111 | errMess.current = `Run lastId != 4`;
112 | setOutput(() => ({log: myLog}));
113 | return false;
114 | }
115 | myLog.push("> Run2 successful\n");
116 |
117 | // Select all Users
118 | res = await db.query("SELECT * FROM users");
119 | if(res.values.length !== 4) {
120 | errMess.current = `Query not returning 4 values`;
121 | setOutput(() => ({log: myLog}));
122 | return false;
123 | }
124 | myLog.push("> Select2 successful\n");
125 |
126 | // Select Users with age > 35
127 | sqlcmd = "SELECT name,email,age FROM users WHERE age > ?";
128 | values = ["35"];
129 | res = await db.query(sqlcmd,values);
130 | if(res.values.length !== 2) {
131 | errMess.current = `Query > 35 not returning 2 values`;
132 | setOutput(() => ({log: myLog}));
133 | return false;
134 | }
135 | myLog.push("> Select3 successful\n");
136 |
137 | // Close Connection NoEncryption
138 | await sqlite.closeConnection("NoEncryption");
139 | myLog.push("> CloseConnection successful\n");
140 | myLog.push("* Ending testDatabaseNoEncryption *\n");
141 |
142 |
143 | return true;
144 | } catch (err: any) {
145 | errMess.current = `${err.message}`;
146 | setOutput(() => ({log: myLog}));
147 | return false;
148 | }
149 | }
150 |
151 | useEffect(() => {
152 | if(sqlite.isAvailable) {
153 | if (myRef.current === false) {
154 | myRef.current = true;
155 |
156 | testDatabaseNoEncryption().then(async res => {
157 | if(res) {
158 | myLog.push("\n* The set of tests was successful *\n");
159 | } else {
160 | myLog.push("\n* The set of tests failed *\n");
161 | await showAlert(errMess.current);
162 | }
163 | setOutput(() => ({log: myLog}));
164 |
165 | });
166 | }
167 | } else {
168 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
169 | myLog.push("\n* Not available for " +
170 | ret.platform + " platform *\n");
171 | await showAlert(errMess.current);
172 | setOutput(() => ({log: myLog}));
173 | });
174 | }
175 |
176 | });
177 |
178 | return (
179 |
180 | );
181 | };
182 |
183 | export default NoEncryption;
184 |
--------------------------------------------------------------------------------
/src/components/NonConformedDB.css:
--------------------------------------------------------------------------------
1 | .container-nonconformeddb {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/NonConformedDB.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './NonConformedDB.css';
3 | import TestOutput from './TestOutput';
4 | import { sqlite } from '../App';
5 | import { Dialog } from '@capacitor/dialog';
6 | import { SQLiteDBConnection } from 'react-sqlite-hook';
7 |
8 | const NonConformedDB: React.FC = () => {
9 | const myRef = useRef(false);
10 | const myLog: string[] = [];
11 | const errMess = useRef("");
12 | const [output, setOutput] = useState({log: myLog});
13 | const showAlert = async (message: string) => {
14 | await Dialog.alert({
15 | title: 'Error Dialog',
16 | message: message,
17 | });
18 | };
19 | const testNonConformedDB = async (): Promise => {
20 | setOutput((output: { log: any; }) => ({log: output.log}));
21 |
22 | myLog.push("* Starting testNonConformedDB *\n");
23 | try {
24 | const platform = (await sqlite.getPlatform()).platform;
25 | // Assuming non-conformed "testncbd.db" in the "directory" folder
26 | let directory: string = "files/databases";
27 | if(platform === "ios") directory = "Applications/Files/Databases"
28 | if(platform === "android" ) directory = "files/databases";
29 | if(platform === 'ios' || platform === 'android') {
30 | const databasePath = (await sqlite.getNCDatabasePath(directory,"testncdb.db")).path;
31 | if(databasePath !== undefined) {
32 | const isNCDbExists = (await sqlite.isNCDatabase(databasePath)).result;
33 | const ret = await sqlite.checkConnectionsConsistency();
34 | const isConn = (await sqlite.isNCConnection(databasePath)).result;
35 | let db: SQLiteDBConnection
36 | if (ret.result && isConn && isNCDbExists) {
37 | db = await sqlite.retrieveNCConnection(databasePath);
38 | } else {
39 | db = await sqlite.createNCConnection(databasePath, 1);
40 | }
41 | // open db testncdb.db
42 | await db.open();
43 | // get the database version
44 | let retVer = await db.getVersion();
45 | if (retVer.version !== 1) {
46 | errMess.current = `GetVersion: version failed`;
47 | setOutput(() => ({log: myLog}));
48 | return false;
49 | }
50 | const isDbOpen = await db.isDBOpen();
51 | if(!isDbOpen.result) {
52 | errMess.current = `IsDBOpen: database not opened`;
53 | setOutput(() => ({log: myLog}));
54 | return false;
55 | }
56 | // check if the table "contacts" exists
57 | const isTable = await db.isTable("contacts")
58 | if(!isTable.result) {
59 | errMess.current = `Table 'contacts' does not exist in ${databasePath}`;
60 | setOutput(() => ({log: myLog}));
61 | return false;
62 | }
63 | // select all contacts in db
64 | const retCts = await db.query("SELECT * FROM contacts;");
65 | if(retCts !== undefined && retCts.values !== undefined) {
66 | if(retCts.values.length !== 4 ||
67 | retCts.values[0].name !== "Simpson" ||
68 | retCts.values[1].name !== "Jones" ||
69 | retCts.values[2].name !== "Whiteley" ||
70 | retCts.values[3].name !== "Brown") {
71 | errMess.current = `Query Contacts failed`;
72 | setOutput(() => ({log: myLog}));
73 | return false;
74 | }
75 | await sqlite.closeNCConnection(databasePath);
76 | } else {
77 | errMess.current = `result of Query Contacts undefined"`;
78 | setOutput(() => ({log: myLog}));
79 | return false;
80 | }
81 | } else {
82 | errMess.current = `databasePath undefined"`;
83 | setOutput(() => ({log: myLog}));
84 | return false;
85 | }
86 | } else {
87 | console.log(`Not available on ${platform} platform`);
88 | }
89 | return true;
90 | } catch (err: any) {
91 | errMess.current = `${err.message}`;
92 | setOutput(() => ({log: myLog}));
93 | return false;
94 | }
95 | }
96 |
97 | useEffect( () => {
98 | if(sqlite.isAvailable) {
99 | if (myRef.current === false) {
100 | myRef.current = true;
101 | testNonConformedDB().then(async res => {
102 | if(res) {
103 | myLog.push("\n* The set of tests was successful *\n");
104 | } else {
105 | myLog.push("\n* The set of tests failed *\n");
106 | await showAlert(errMess.current);
107 | }
108 | setOutput(() => ({log: myLog}));
109 | });
110 | }
111 | } else {
112 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
113 | myLog.push("\n* Not available for " +
114 | ret.platform + " platform *\n");
115 | await showAlert(errMess.current);
116 | setOutput(() => ({log: myLog}));
117 | });
118 | }
119 |
120 | });
121 |
122 | return (
123 |
124 | );};
125 |
126 | export default NonConformedDB;
127 |
--------------------------------------------------------------------------------
/src/components/Test2dbs.css:
--------------------------------------------------------------------------------
1 | .container-test2dbs {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/Test2dbs.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './Test2dbs.css';
3 | import TestOutput from './TestOutput';
4 |
5 | import { createTablesNoEncryption, importTwoUsers } from '../Utils/noEncryptionUtils';
6 | import { createSchemaContacts, setContacts } from '../Utils/encryptedSetUtils';
7 | import { deleteDatabase } from '../Utils/deleteDBUtil';
8 |
9 | import { sqlite, existingConn } from '../App';
10 | import { Dialog } from '@capacitor/dialog';
11 |
12 | const Test2dbs: React.FC = () => {
13 | const myRef = useRef(false);
14 | const myLog: string[] = [];
15 | const errMess = useRef("");
16 | const [output, setOutput] = useState({log: myLog});
17 | const showAlert = async (message: string) => {
18 | await Dialog.alert({
19 | title: 'Error Dialog',
20 | message: message,
21 | });
22 | };
23 | const testtwodbs = async (): Promise => {
24 | setOutput((output: { log: any; }) => ({log: output.log}));
25 |
26 | myLog.push("* Starting testTwoDBS *\n");
27 | try {
28 | const platform = (await sqlite.getPlatform()).platform;
29 | // initialize the connection
30 | const db = await sqlite
31 | .createConnection("testNew", false, "no-encryption", 1);
32 | const db1 = await sqlite
33 | .createConnection("testSet", true, "secret", 1);
34 |
35 | // check if the databases exist
36 | // and delete it for multiple successive tests
37 | await deleteDatabase(db);
38 | await deleteDatabase(db1);
39 |
40 | // open db testNew
41 | await db.open();
42 | myLog.push("> open 'testNew' successful\n");
43 |
44 | // create tables in db
45 | let ret: any = await db.execute(createTablesNoEncryption);
46 | if (ret.changes.changes < 0) {
47 | errMess.current = `Execute changes < 0`;
48 | setOutput(() => ({log: myLog}));
49 | return false;
50 | }
51 |
52 | // create synchronization table
53 | ret = await db.createSyncTable();
54 | if (ret.changes.changes < 0) {
55 | errMess.current = `CreateSyncTable changes < 0`;
56 | setOutput(() => ({log: myLog}));
57 | return false;
58 | }
59 |
60 | // set the synchronization date
61 | const syncDate: string = "2020-11-25T08:30:25.000Z";
62 | await db.setSyncDate(syncDate);
63 |
64 | // add two users in db
65 | ret = await db.execute(importTwoUsers);
66 | if (ret.changes.changes !== 2) {
67 | errMess.current = `Execute importTwoUsers changes != 2`;
68 | setOutput(() => ({log: myLog}));
69 | return false;
70 | }
71 |
72 | // select all users in db
73 | ret = await db.query("SELECT * FROM users;");
74 |
75 | if(ret.values.length !== 2 || ret.values[0].name !== "Whiteley" ||
76 | ret.values[1].name !== "Jones") {
77 | errMess.current = `Query not returning 2 values`;
78 | setOutput(() => ({log: myLog}));
79 | return false;
80 | }
81 |
82 | // open db testSet
83 | await db1.open();
84 | myLog.push("> open 'testSet' successful\n");
85 | // create tables in db1
86 | ret = await db1.execute(createSchemaContacts);
87 | if (ret.changes.changes < 0) {
88 | errMess.current = `Execute createSchemaContacts changes < 0`;
89 | setOutput(() => ({log: myLog}));
90 | return false;
91 | }
92 | // load setContacts in db1
93 | ret = await db1.executeSet(setContacts);
94 | if (ret.changes.changes !== 5) {
95 | errMess.current = `ExecuteSet setContacts changes != 5`;
96 | setOutput(() => ({log: myLog}));
97 | return false;
98 | }
99 |
100 | // select users where company is NULL in db
101 | ret = await db.query("SELECT * FROM users WHERE company IS NULL;");
102 | if(ret.values.length !== 2 || ret.values[0].name !== "Whiteley" ||
103 | ret.values[1].name !== "Jones") {
104 | errMess.current = `Query Company is NULL not returning 2 values`;
105 | setOutput(() => ({log: myLog}));
106 | return false;
107 | }
108 | // add one user with statement and values
109 | let sqlcmd: string =
110 | "INSERT INTO users (name,email,age) VALUES (?,?,?)";
111 | let values: Array = ["Simpson","Simpson@example.com",69];
112 | ret = await db.run(sqlcmd,values);
113 | if(ret.changes.lastId !== 3) {
114 | errMess.current = `Run lastId != 3`;
115 | setOutput(() => ({log: myLog}));
116 | return false;
117 | }
118 | // add one user with statement
119 | sqlcmd = `INSERT INTO users (name,email,age) VALUES ` +
120 | `("Brown","Brown@example.com",15)`;
121 | ret = await db.run(sqlcmd);
122 | if(ret.changes.lastId !== 4) {
123 | errMess.current = `Run lastId != 4`;
124 | setOutput(() => ({log: myLog}));
125 | return false;
126 | }
127 | if (platform === "web") {
128 | await sqlite.saveToStore("testNew");
129 | await sqlite.saveToStore("testSet");
130 | }
131 | myLog.push("* Ending testTwoDBS *\n");
132 | existingConn.setExistConn(true);
133 | return true;
134 | } catch (err:any) {
135 | errMess.current = `${err.message}`;
136 | return false;
137 | }
138 | }
139 |
140 | useEffect(() => {
141 | if(sqlite.isAvailable) {
142 | if (myRef.current === false) {
143 | myRef.current = true;
144 |
145 | testtwodbs().then(async res => {
146 | if(res) {
147 | myLog.push("\n* The set of tests was successful *\n");
148 | } else {
149 | myLog.push("\n* The set of tests failed *\n");
150 | await showAlert(errMess.current);
151 | }
152 | setOutput(() => ({log: myLog}));
153 |
154 | });
155 | }
156 | } else {
157 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
158 | myLog.push("\n* Not available for " +
159 | ret.platform + " platform *\n");
160 | await showAlert(errMess.current);
161 | setOutput(() => ({log: myLog}));
162 | });
163 | }
164 |
165 | });
166 |
167 | return (
168 |
169 | );
170 | };
171 |
172 | export default Test2dbs;
173 |
--------------------------------------------------------------------------------
/src/components/TestEncryption.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/src/components/TestEncryption.css
--------------------------------------------------------------------------------
/src/components/TestIssue184.css:
--------------------------------------------------------------------------------
1 | .container-testissue184 {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/TestIssue184.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './TestIssue184.css';
3 | import TestOutput from './TestOutput';
4 |
5 | import { sqlite } from '../App';
6 | import { SQLiteDBConnection} from 'react-sqlite-hook';
7 | import { Dialog } from '@capacitor/dialog';
8 |
9 | const TestIssue184: React.FC = () => {
10 | const myRef = useRef(false);
11 | const myLog: string[] = [];
12 | const errMess = useRef("");
13 | const [output, setOutput] = useState({log: myLog});
14 | const showAlert = async (message: string) => {
15 | await Dialog.alert({
16 | title: 'Error Dialog',
17 | message: message,
18 | });
19 | };
20 | const testDatabaseIssue184 = async (): Promise => {
21 | setOutput((output: { log: any; }) => ({log: output.log}));
22 |
23 | myLog.push("* Starting testDatabaseIssue184 *\n");
24 | try {
25 | // create a connection for TestIssue184
26 | let db: SQLiteDBConnection = await sqlite.createConnection("steward");
27 | // open NoEncryption
28 | await db.open();
29 | myLog.push("> open 'steward' successful\n");
30 | myLog.push("executing create statements on next line\n");
31 | let res = await db.execute(`
32 | DROP TABLE IF EXISTS chores;
33 | DROP TABLE IF EXISTS items;
34 |
35 | CREATE TABLE IF NOT EXISTS chores (
36 | id INTEGER PRIMARY KEY,
37 | name TEXT,
38 | next_due DATE,
39 | completed BOOLEAN,
40 | repeats BOOLEAN,
41 | frequency INT
42 | );
43 |
44 | CREATE TABLE IF NOT EXISTS items (
45 | id INTEGER PRIMARY KEY,
46 | name TEXT,
47 | image TEXT,
48 | next_buy DATE,
49 | buy_from TEXT,
50 | supplied BOOLEAN
51 | );
52 | `);
53 | if(res.changes && res.changes.changes !== 0 &&
54 | res.changes.changes !== 1){
55 | errMess.current = `Execute create tables changes < 0`;
56 | setOutput(() => ({log: myLog}));
57 | return false;
58 | }
59 | myLog.push(" executed create statements\n");
60 |
61 | myLog.push(" executing insert on next line\n");
62 |
63 | res = await db.execute(
64 | "INSERT INTO chores (name,next_due,completed,repeats,frequency) VALUES ('Clean room 2', '2021-12-11', false, false, 1);"
65 | );
66 | if (res.changes && res.changes.changes !== 1) {
67 | errMess.current = `Execute Insert changes != 1`;
68 | setOutput(() => ({log: myLog}));
69 | return false;
70 | }
71 | myLog.push(" executed insert\n");
72 |
73 | // Select all chores
74 | myLog.push(" selecting from table\n");
75 | const resVal = await db.query("SELECT * FROM chores;");
76 | if(resVal.values && resVal.values.length !== 1) {
77 | errMess.current = `Query not returning 1 values`;
78 | setOutput(() => ({log: myLog}));
79 | return false;
80 | }
81 | myLog.push(" Select all from chores \n");
82 |
83 |
84 | // Close Connection steward
85 | await sqlite.closeConnection("steward");
86 |
87 | return true;
88 | } catch (err: any) {
89 | errMess.current = `${err.message}`;
90 | setOutput(() => ({log: myLog}));
91 | return false;
92 | }
93 | }
94 |
95 | useEffect( () => {
96 | if(sqlite.isAvailable) {
97 | if (myRef.current === false) {
98 | myRef.current = true;
99 | testDatabaseIssue184().then(async res => {
100 | if(res) {
101 | myLog.push("\n* The set of tests was successful *\n");
102 | } else {
103 | myLog.push("\n* The set of tests failed *\n");
104 | await showAlert(errMess.current);
105 | }
106 | setOutput(() => ({log: myLog}));
107 | });
108 | }
109 | } else {
110 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
111 | myLog.push("\n* Not available for " +
112 | ret.platform + " platform *\n");
113 | await showAlert(errMess.current);
114 | setOutput(() => ({log: myLog}));
115 | });
116 | }
117 |
118 | });
119 |
120 |
121 | return (
122 |
123 | );
124 | };
125 |
126 | export default TestIssue184;
127 |
--------------------------------------------------------------------------------
/src/components/TestJsonImportExport.css:
--------------------------------------------------------------------------------
1 | .container-import-export {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/TestOutput.css:
--------------------------------------------------------------------------------
1 | .container-testoutput {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/TestOutput.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './TestOutput.css';
3 | import { IonCard,IonCardContent } from '@ionic/react';
4 | const TestOutput = (props:{dataLog: string[], errMess: string}) => {
5 | return (
6 |
7 |
8 |
9 |
10 | {props.dataLog.map((log: string, index: number) => (
11 | {log}
12 | ))}
13 |
14 | {props.errMess.length > 0 && {props.errMess}
}
15 |
16 |
17 | );
18 |
19 | };
20 | export default TestOutput;
21 |
--------------------------------------------------------------------------------
/src/components/TestUpgradeVersion.css:
--------------------------------------------------------------------------------
1 | .container-upgradeversion {
2 | text-align: left;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/components/TestUpgradeVersion.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import './TestUpgradeVersion.css';
3 | import TestOutput from './TestOutput';
4 | import { userMessages } from '../Utils/upgradeVersionUtils';
5 | import { versionUpgrades } from '../Utils/upgrade-database-version';
6 |
7 | import { SQLiteDBConnection, VersionUpgrade } from 'react-sqlite-hook';
8 |
9 | import { sqlite } from '../App';
10 | import { deleteDatabase } from '../Utils/deleteDBUtil';
11 | import { Dialog } from '@capacitor/dialog';
12 |
13 | const TestUpgradeVersion: React.FC = () => {
14 | const myRef = useRef(false);
15 | const myLog: string[] = [];
16 | const errMess = useRef("");
17 | const [output, setOutput] = useState({log: myLog});
18 | const showAlert = async (message: string) => {
19 | await Dialog.alert({
20 | title: 'Error Dialog',
21 | message: message,
22 | });
23 | };
24 | const databaseUpgradeVersion = async (): Promise => {
25 | myLog.push("* Starting testDatabaseUpgradeVersion *\n");
26 | // ************************************************
27 | // Create Database Version 1 & Version 2
28 | // ************************************************
29 | myLog.push("* Starting Create Version 1 *\n");
30 | try {
31 | // initialize the connection for Database Version 1
32 | let db: SQLiteDBConnection = await sqlite
33 | .createConnection("test-updversion", false,
34 | "no-encryption", 1);
35 | // check if the databases exist
36 | // and delete it for multiple successive tests
37 | await deleteDatabase(db);
38 |
39 | // close connection to test-updversion
40 | await sqlite.closeConnection('test-updversion');
41 |
42 | for (const upgrade of versionUpgrades) {
43 | const vUpg: VersionUpgrade = {} as VersionUpgrade;
44 | vUpg.toVersion = upgrade.toVersion;
45 | vUpg.statements = upgrade.statements;
46 | await sqlite.addUpgradeStatement(
47 | 'test-updversion',
48 | vUpg
49 | );
50 | }
51 | db = await sqlite.createConnection("test-updversion", false,
52 | "no-encryption", 2);
53 |
54 | // open db test-updversion
55 | await db.open();
56 |
57 | // select all users in db
58 | let ret: any = await db.query("SELECT * FROM users;");
59 | if(ret.values.length !== 2 || ret.values[0].name !== "Whiteley" ||
60 | ret.values[1].name !== "Jones") {
61 | errMess.current = `Query users not returning 2 values`;
62 | setOutput(() => ({log: myLog}));
63 | return false;
64 | }
65 | // select all user's country in db
66 | ret = await db.query("SELECT country FROM users;");
67 | if(ret.values.length !== 2 ||
68 | ret.values[0].country !== "United Kingdom" ||
69 | ret.values[1].country !== "Australia") {
70 | errMess.current = `Query country not returning 2 values`;
71 | setOutput(() => ({log: myLog}));
72 | return false;
73 | }
74 | // select all messages for user 1
75 | ret = await db.query(userMessages,["1"]);
76 | if(ret.values.length !== 2 ||
77 | ret.values[0].name !== "Whiteley" ||
78 | ret.values[0].title !== "test message 1" ||
79 | ret.values[1].name !== "Whiteley" ||
80 | ret.values[1].title !== "test message 3") {
81 | errMess.current = `Query userMessages not returning 2 values`;
82 | setOutput(() => ({log: myLog}));
83 | return false;
84 | }
85 | // select all messages for user 2
86 | ret = await db.query(userMessages,["2"]);
87 | if(ret.values.length !== 1 ||
88 | ret.values[0].name !== "Jones" ||
89 | ret.values[0].title !== "test message 2") {
90 | errMess.current = `Query userMessages ["2"] not returning 1 values`;
91 | setOutput(() => ({log: myLog}));
92 | return false;
93 | }
94 | // close db test-updversion
95 | await db.close();
96 | // close connection to test-updversion
97 | await sqlite.closeConnection("test-updversion");
98 | myLog.push("* Ending Database Version 1&2 *\n");
99 |
100 | return true;
101 | } catch (err: any) {
102 | errMess.current = `${err.message}`;
103 | setOutput(() => ({log: myLog}));
104 | return false;
105 | }
106 | }
107 |
108 | useEffect( () => {
109 | if(sqlite.isAvailable) {
110 | if (myRef.current === false) {
111 | myRef.current = true;
112 | databaseUpgradeVersion().then(async res => {
113 | if(res) {
114 | myLog.push("\n* The set of tests was successful *\n");
115 | } else {
116 | myLog.push("\n* The set of tests failed *\n");
117 | await showAlert(errMess.current);
118 | }
119 | setOutput(() => ({log: myLog}));
120 | });
121 | }
122 | } else {
123 | sqlite.getPlatform().then(async (ret: { platform: string; }) => {
124 | myLog.push("\n* Not available for " +
125 | ret.platform + " platform *\n");
126 | await showAlert(errMess.current);
127 | setOutput(() => ({log: myLog}));
128 | });
129 | }
130 |
131 | });
132 |
133 | return (
134 |
135 | );
136 | };
137 |
138 | export default TestUpgradeVersion;
139 |
--------------------------------------------------------------------------------
/src/data/messages.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "fromName": "Matt Chorsey",
4 | "subject": "New event: Trip to Vegas",
5 | "date": "9:32 AM",
6 | "id": 0
7 | },
8 | {
9 | "fromName": "Lauren Ruthford",
10 | "subject": "Long time no chat",
11 | "date": "6:12 AM",
12 | "id": 1
13 | },
14 | {
15 | "fromName": "Jordan Firth",
16 | "subject": "Report Results",
17 | "date": "4:55 AM",
18 | "id": 2
19 |
20 | },
21 | {
22 | "fromName": "Bill Thomas",
23 | "subject": "The situation",
24 | "date": "Yesterday",
25 | "id": 3
26 | },
27 | {
28 | "fromName": "Joanne Pollan",
29 | "subject": "Updated invitation: Swim lessons",
30 | "date": "Yesterday",
31 | "id": 4
32 | },
33 | {
34 | "fromName": "Andrea Cornerston",
35 | "subject": "Last minute ask",
36 | "date": "Yesterday",
37 | "id": 5
38 | },
39 | {
40 | "fromName": "Moe Chamont",
41 | "subject": "Family Calendar - Version 1",
42 | "date": "Last Week",
43 | "id": 6
44 | },
45 | {
46 | "fromName": "Kelly Richardson",
47 | "subject": "Placeholder Headhots",
48 | "date": "Last Week",
49 | "id": 7
50 | }
51 | ]
52 |
--------------------------------------------------------------------------------
/src/data/messages.ts:
--------------------------------------------------------------------------------
1 | import MessagesJson from './messages.json';
2 |
3 |
4 | export interface Message {
5 | fromName: string;
6 | subject: string;
7 | date: string;
8 | id: number;
9 | }
10 |
11 | export const messagesImport: any = {
12 | database : "db-messages",
13 | version : 1,
14 | encrypted : false,
15 | mode : "full",
16 | tables :[
17 | {
18 | name: "messages",
19 | schema: [
20 | {column:"id", value: "INTEGER PRIMARY KEY NOT NULL"},
21 | {column:"fromName", value:"TEXT NOT NULL"},
22 | {column:"subject", value:"TEXT"},
23 | {column:"date", value:"TEXT"},
24 | {column:'sql_deleted', value:'BOOLEAN DEFAULT 0 CHECK (sql_deleted IN (0, 1))'},
25 | {column:'last_modified', value:'INTEGER DEFAULT (strftime(\'%s\', \'now\'))'}
26 | ],
27 | indexes: [
28 | {name: "index_user_on_fromName",value: "fromName"},
29 | {name: "index_user_on_last_modified",value: "last_modified DESC"}
30 | ]
31 | },
32 |
33 | ]
34 | };
35 |
36 | export const fetchMessages = () => {
37 | const messages: Message[] = MessagesJson;
38 | return messages;
39 | }
40 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import App from './App';
4 | import * as serviceWorkerRegistration from './serviceWorkerRegistration';
5 | import reportWebVitals from './reportWebVitals';
6 | import { defineCustomElements as jeepSqlite, applyPolyfills, JSX as LocalJSX } from "jeep-sqlite/loader";
7 | import { HTMLAttributes } from 'react';
8 | import { Capacitor } from '@capacitor/core';
9 | import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';
10 |
11 | type StencilToReact = {
12 | [P in keyof T]?: T[P] & Omit, 'className'> & {
13 | class?: string;
14 | };
15 | } ;
16 |
17 | declare global {
18 | export namespace JSX {
19 | interface IntrinsicElements extends StencilToReact {
20 | }
21 | }
22 | }
23 |
24 | applyPolyfills().then(() => {
25 | jeepSqlite(window);
26 | });
27 | window.addEventListener('DOMContentLoaded', async () => {
28 | console.log('$$$ in index $$$');
29 | const platform = Capacitor.getPlatform();
30 | const sqlite: SQLiteConnection = new SQLiteConnection(CapacitorSQLite)
31 | try {
32 | if(platform === "web") {
33 | const jeepEl = document.createElement("jeep-sqlite");
34 | document.body.appendChild(jeepEl);
35 | await customElements.whenDefined('jeep-sqlite');
36 | await sqlite.initWebStore();
37 | }
38 | const ret = await sqlite.checkConnectionsConsistency();
39 | const isConn = (await sqlite.isConnection("db_issue9", false)).result;
40 | var db: SQLiteDBConnection
41 | if (ret.result && isConn) {
42 | db = await sqlite.retrieveConnection("db_issue9", false);
43 | } else {
44 | db = await sqlite.createConnection("db_issue9", false, "no-encryption", 1, false);
45 | }
46 |
47 | await db.open();
48 | let query = `
49 | CREATE TABLE IF NOT EXISTS test (
50 | id INTEGER PRIMARY KEY NOT NULL,
51 | name TEXT NOT NULL
52 | );
53 | `
54 |
55 | const res: any = await db.execute(query);
56 | console.log(`res: ${JSON.stringify(res)}`);
57 | await db.close();
58 | await sqlite.closeConnection("db_issue9", false);
59 | const container = document.getElementById('root');
60 | const root = createRoot(container!);
61 | root.render(
62 |
63 |
64 |
65 | );
66 |
67 | // If you want your app to work offline and load faster, you can change
68 | // unregister() to register() below. Note this comes with some pitfalls.
69 | // Learn more about service workers: https://cra.link/PWA
70 | serviceWorkerRegistration.unregister();
71 |
72 | // If you want to start measuring performance in your app, pass a function
73 | // to log results (for example: reportWebVitals(console.log))
74 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
75 | reportWebVitals();
76 | } catch (err) {
77 | console.log(`Error: ${err}`);
78 | throw new Error(`Error: ${err}`)
79 | }
80 | });
81 |
--------------------------------------------------------------------------------
/src/pages/Tab1.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/src/pages/Tab1.css
--------------------------------------------------------------------------------
/src/pages/Tab1.tsx:
--------------------------------------------------------------------------------
1 | import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, useIonViewWillEnter } from '@ionic/react';
2 | //import ExploreContainer from '../components/ExploreContainer';
3 | import MessageListItem from '../components/MessageListItem';
4 | import { useState } from 'react';
5 | import { Message, messagesImport, fetchMessages } from '../data/messages';
6 | import { sqlite } from '../App';
7 | import { SQLiteDBConnection} from 'react-sqlite-hook';
8 | import './Tab1.css';
9 |
10 | const Tab1: React.FC = () => {
11 | const [messages, setMessages] = useState([]);
12 |
13 | useIonViewWillEnter(async () => {
14 | console.log(`in useIonViewWillEnter`)
15 |
16 | try {
17 | // check if database "db-messages" exists
18 | const isDB = (await sqlite.isDatabase('db-messages')).result;
19 | console.log(`$$$ isDB : ${isDB}`)
20 | if (!isDB) {
21 | // get messagesImport
22 | const jsonImport = messagesImport;
23 | console.log(`jsonImport: ${JSON.stringify(jsonImport)}`)
24 | // simulate a fetch to get messages
25 | const response = fetchMessages();
26 | console.log(`response: ${JSON.stringify(response)}`)
27 | // load the messages in jsonImport
28 | const mValues = [];
29 | for (const message of response) {
30 | console.log(`message: ${JSON.stringify(message)}`)
31 | const row = [];
32 | const timestamp = Math.floor(Date.now() / 1000);
33 | row.push(message.id);
34 | row.push(message.fromName);
35 | row.push(message.subject);
36 | row.push(message.date);
37 | row.push(0);
38 | row.push(timestamp);
39 | console.log(`row: ${JSON.stringify(row)}`)
40 | mValues.push(row);
41 | }
42 | jsonImport.tables[0].values = mValues;
43 | console.log(`jsonImport: ${JSON.stringify(jsonImport)}`)
44 | const isJsonValid = await sqlite.isJsonValid(JSON.stringify(jsonImport));
45 | console.log(`>> jsonImport: ${JSON.stringify(jsonImport)}`)
46 | if(!isJsonValid.result) {
47 | throw new Error(`Error: jsonImport Object not valid`);
48 | }
49 | const retImport: any = await sqlite.importFromJson(JSON.stringify(jsonImport));
50 | console.log(`full import result ${retImport.changes.changes}`);
51 | if(retImport.changes.changes === -1 ) {
52 | throw new Error(`Error: importFromJson failed`);
53 | }
54 | }
55 | // create a connection for "db-messages"
56 | const db: SQLiteDBConnection = await sqlite.createConnection("db-messages");
57 | await db.open();
58 | // query the messages
59 | const cmd = `--test comments
60 | SELECT *
61 | /*
62 | * Author: jeepq
63 | * Purpose: To show a comment that spans multiple lines in your SQL
64 | * statement in SQLite.
65 | */
66 | FROM messages;
67 | `;
68 | console.log(`&&&& cmd: ${cmd}`);
69 | const qValues = await db.query(cmd);
70 | const msgs = qValues.values
71 | if(msgs != null) {
72 | setMessages(msgs);
73 | }
74 | // Close Connection db-messages
75 | await sqlite.closeConnection("db-messages");
76 |
77 | } catch (err) {
78 | console.log(`Error: ${err}`);
79 | }
80 | });
81 |
82 | return (
83 |
84 |
85 |
86 | Tab 1
87 |
88 |
89 |
90 |
91 |
92 | Tab 1
93 |
94 |
95 |
96 | {messages.map(m => )}
97 |
98 |
99 |
100 | );
101 | };
102 |
103 | export default Tab1;
104 |
--------------------------------------------------------------------------------
/src/pages/Tab2.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/src/pages/Tab2.css
--------------------------------------------------------------------------------
/src/pages/Tab2.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonButton } from '@ionic/react';
3 | import './Tab2.css';
4 | import { sqlite } from '../App';
5 | import { existingConn } from '../App';
6 |
7 | const Tab2: React.FC = () => {
8 | const [isNative, setIsNative] = useState(false);
9 | sqlite.getPlatform().then((platform: any) => {
10 | if(platform.platform === "ios" || platform.platform === "android") {
11 | setIsNative(true);
12 | }
13 | });
14 |
15 | return (
16 |
17 |
18 |
19 | Tab 2
20 |
21 |
22 |
23 |
24 |
25 | Tab 2
26 |
27 |
28 |
29 |
30 | SQLite Two DBs Tests
31 |
32 | {existingConn.existConn &&
33 |
34 | SQLite Existing Test
35 |
36 | }
37 |
38 | SQLite No Encryption Test
39 |
40 | {isNative &&
41 |
42 | SQLite Encryption Test
43 |
44 | }
45 |
46 | SQLite Upgrade Version Test
47 |
48 |
49 | SQLite Json Import Export Test
50 |
51 |
52 | SQLite Copy From Assets Test
53 |
54 |
55 | Test Issue184
56 |
57 | {isNative &&
58 |
59 | Test Migrate DB
60 |
61 | }
62 | {isNative &&
63 |
64 | Test NC Database
65 |
66 | }
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default Tab2;
74 |
75 | /*
76 |
77 | */
--------------------------------------------------------------------------------
/src/pages/Tab3.css:
--------------------------------------------------------------------------------
1 | .container-tab3 {
2 | text-align: center;
3 | position: relative;
4 | left: 2px;
5 | right: 2px;
6 | top: 10px;
7 | }
--------------------------------------------------------------------------------
/src/pages/Tab3.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, useRef } from 'react';
2 | import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonText, useIonViewWillEnter, useIonViewWillLeave } from '@ionic/react';
3 | import './Tab3.css';
4 | import { SQLiteDBConnection } from 'react-sqlite-hook';
5 | import { sqlite } from '../App';
6 |
7 | const Tab3: React.FC = () => {
8 | const ref = useRef(false);
9 | const [tests, setTests] = useState([]);
10 | const initialize = async (): Promise => {
11 | console.log('Entering initialize');
12 | try {
13 | let db: SQLiteDBConnection = await sqlite.createConnection("db_issue9");
14 | await db.open();
15 | let randomText = (Math.random() + 1).toString(36).substring(7);
16 | console.log(`Inserting ${randomText}`);
17 | await db.run("INSERT INTO test (name) VALUES (?)", [randomText]);
18 | let res: any = await db.query("SELECT * FROM test");
19 | setTests(res.values);
20 | await db.close();
21 | sqlite.closeConnection("db_issue9");
22 | return ;
23 | }
24 | catch (err) {
25 | console.log(`Error: ${err}`);
26 | return ;
27 | }
28 | }
29 | useIonViewWillEnter(() => {
30 | if(ref.current === false) {
31 | initialize();
32 | ref.current = true;
33 | }
34 | });
35 |
36 | useIonViewWillLeave(() => {
37 | ref.current = false;
38 | });
39 | return (
40 |
41 |
42 |
43 | Tab 3
44 |
45 |
46 |
47 |
48 |
49 | Tab 3
50 |
51 |
52 |
53 | {tests.map((x: any, index: any) =>
54 |
55 | {index} {x.name}
56 |
57 |
58 | )}
59 |
60 |
61 |
62 | );
63 | };
64 |
65 | export default Tab3;
66 |
--------------------------------------------------------------------------------
/src/pages/ViewMessage.css:
--------------------------------------------------------------------------------
1 | #view-message-page ion-item {
2 | --inner-padding-end: 0;
3 | --background: transparent;
4 | }
5 |
6 | #view-message-page ion-label {
7 | margin-top: 12px;
8 | margin-bottom: 12px;
9 | }
10 |
11 | #view-message-page ion-item h2 {
12 | font-weight: 600;
13 | }
14 |
15 | #view-message-page ion-item .date {
16 | float: right;
17 | align-items: center;
18 | display: flex;
19 | }
20 |
21 | #view-message-page ion-item ion-icon {
22 | font-size: 42px;
23 | margin-right: 8px;
24 | }
25 |
26 | #view-message-page ion-item ion-note {
27 | font-size: 15px;
28 | margin-right: 12px;
29 | font-weight: normal;
30 | }
31 |
32 | #view-message-page h1 {
33 | margin: 0;
34 | font-weight: bold;
35 | font-size: 22px;
36 | }
37 |
38 | #view-message-page p {
39 | line-height: 22px;
40 | }
--------------------------------------------------------------------------------
/src/pages/ViewMessage.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import {
3 | IonBackButton,
4 | IonButtons,
5 | IonContent,
6 | IonHeader,
7 | IonIcon,
8 | IonItem,
9 | IonLabel,
10 | IonNote,
11 | IonPage,
12 | IonToolbar,
13 | useIonViewWillEnter,
14 | } from '@ionic/react';
15 | import { personCircle } from 'ionicons/icons';
16 | import { useParams } from 'react-router';
17 | import { Message } from '../data/messages';
18 | import { sqlite } from '../App';
19 | import { SQLiteDBConnection} from 'react-sqlite-hook';
20 | import './ViewMessage.css';
21 |
22 | function ViewMessage() {
23 | const [message, setMessage] = useState();
24 | const params = useParams<{ id: string }>();
25 |
26 | useIonViewWillEnter(async () => {
27 | try {
28 | const msg = await getMessage(parseInt(params.id, 10));
29 | setMessage(msg);
30 | } catch(err) {
31 | console.log(`Error: ${err}`);
32 | }
33 | });
34 |
35 | const getMessage = async (id: number): Promise => {
36 | let message: Message = {} as Message;
37 | let isConn = await sqlite.isConnection("db-messages");
38 | let db: SQLiteDBConnection;
39 | try {
40 | if(!isConn.result) {
41 | db = await sqlite.createConnection("db-messages");
42 | } else {
43 | db = await sqlite.retrieveConnection("db-messages");
44 | }
45 | await db.open();
46 | // query the messages
47 | const stmt = `SELECT * FROM messages where id=${id}`;
48 | const qValues = await db.query(stmt);
49 | if (qValues && qValues.values && qValues.values.length === 1) {
50 | message = qValues.values[0];
51 | }
52 | return Promise.resolve(message);
53 | } catch (err) {
54 | return Promise.reject(`Error: ${err}`);
55 | }
56 |
57 | }
58 | return (
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | {message ? (
70 | <>
71 |
72 |
73 |
74 |
75 | {message.fromName}
76 |
77 | {message.date}
78 |
79 |
80 |
81 | To: Me
82 |
83 |
84 |
85 |
86 |
87 |
{message.subject}
88 |
89 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
90 | eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
91 | enim ad minim veniam, quis nostrud exercitation ullamco laboris
92 | nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
93 | in reprehenderit in voluptate velit esse cillum dolore eu fugiat
94 | nulla pariatur. Excepteur sint occaecat cupidatat non proident,
95 | sunt in culpa qui officia deserunt mollit anim id est laborum.
96 |
97 |
98 | >
99 | ) : (
100 | Message not found
101 | )}
102 |
103 |
104 | );
105 | }
106 |
107 | export default ViewMessage;
108 |
--------------------------------------------------------------------------------
/src/pages/ViewTest.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jepiqueau/react-sqlite-app-starter/02809174e3b5bb355e506ed3bf20e1a92c74f860/src/pages/ViewTest.css
--------------------------------------------------------------------------------
/src/pages/ViewTest.tsx:
--------------------------------------------------------------------------------
1 | import { useParams } from 'react-router';
2 | import './ViewTest.css';
3 | import {
4 | IonBackButton,
5 | IonButtons,
6 | IonContent,
7 | IonHeader,
8 | IonPage,
9 | IonToolbar,
10 | } from '@ionic/react';
11 | import Test2dbs from '../components/Test2dbs';
12 | import ExistingConnection from '../components/ExistingConnection';
13 | import NoEncryption from '../components/NoEncryption';
14 | import TestEncryption from '../components/TestEncryption';
15 | import TestJsonImportExport from '../components/TestJsonImportExport';
16 | import CopyFromAssets from '../components/CopyFromAssets';
17 | import TestUpgradeVersion from '../components/TestUpgradeVersion';
18 | import TestIssue184 from '../components/TestIssue184';
19 | import MigrateDB from '../components/MigrateDB';
20 | import NonConformedDB from '../components/NonConformedDB';
21 |
22 |
23 | const ViewTest: React.FC = () => {
24 |
25 | const params = useParams<{ name: string }>();
26 |
27 | const setTestName = (testName:string) => {
28 | switch (testName) {
29 | case 'NoEncryption':
30 | return ( )
31 | case 'Test2dbs':
32 | return ( )
33 | case 'ExistingConnection':
34 | return ( )
35 | case 'TestEncryption':
36 | return ( )
37 | case 'TestJsonImportExport':
38 | return ( )
39 | case 'CopyFromAssets':
40 | return ( )
41 | case 'TestUpgradeVersion':
42 | return ( )
43 | case 'TestIssue184':
44 | return ( )
45 | case 'MigrateDB':
46 | return ( )
47 | case 'NonConformedDB':
48 | return ( )
49 | default:
50 | console.log(`Test name: ${testName} does not exist`);
51 | }
52 | }
53 | return (
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | {setTestName(params.name)}
65 |
66 |
67 | )
68 | };
69 | export default ViewTest;
70 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/service-worker.ts:
--------------------------------------------------------------------------------
1 | ///
2 | /* eslint-disable no-restricted-globals */
3 |
4 | // This service worker can be customized!
5 | // See https://developers.google.com/web/tools/workbox/modules
6 | // for the list of available Workbox modules, or add any other
7 | // code you'd like.
8 | // You can also remove this file if you'd prefer not to use a
9 | // service worker, and the Workbox build step will be skipped.
10 |
11 | import { clientsClaim } from 'workbox-core';
12 | import { ExpirationPlugin } from 'workbox-expiration';
13 | import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
14 | import { registerRoute } from 'workbox-routing';
15 | import { StaleWhileRevalidate } from 'workbox-strategies';
16 |
17 | declare const self: ServiceWorkerGlobalScope;
18 |
19 | clientsClaim();
20 |
21 | // Precache all of the assets generated by your build process.
22 | // Their URLs are injected into the manifest variable below.
23 | // This variable must be present somewhere in your service worker file,
24 | // even if you decide not to use precaching. See https://cra.link/PWA
25 | precacheAndRoute(self.__WB_MANIFEST);
26 |
27 | // Set up App Shell-style routing, so that all navigation requests
28 | // are fulfilled with your index.html shell. Learn more at
29 | // https://developers.google.com/web/fundamentals/architecture/app-shell
30 | const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
31 | registerRoute(
32 | // Return false to exempt requests from being fulfilled by index.html.
33 | ({ request, url }: { request: Request; url: URL }) => {
34 | // If this isn't a navigation, skip.
35 | if (request.mode !== 'navigate') {
36 | return false;
37 | }
38 |
39 | // If this is a URL that starts with /_, skip.
40 | if (url.pathname.startsWith('/_')) {
41 | return false;
42 | }
43 |
44 | // If this looks like a URL for a resource, because it contains
45 | // a file extension, skip.
46 | if (url.pathname.match(fileExtensionRegexp)) {
47 | return false;
48 | }
49 |
50 | // Return true to signal that we want to use the handler.
51 | return true;
52 | },
53 | createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
54 | );
55 |
56 | // An example runtime caching route for requests that aren't handled by the
57 | // precache, in this case same-origin .png requests like those from in public/
58 | registerRoute(
59 | // Add in any other file extensions or routing criteria as needed.
60 | ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'),
61 | // Customize this strategy as needed, e.g., by changing to CacheFirst.
62 | new StaleWhileRevalidate({
63 | cacheName: 'images',
64 | plugins: [
65 | // Ensure that once this runtime cache reaches a maximum size the
66 | // least-recently used images are removed.
67 | new ExpirationPlugin({ maxEntries: 50 }),
68 | ],
69 | })
70 | );
71 |
72 | // This allows the web app to trigger skipWaiting via
73 | // registration.waiting.postMessage({type: 'SKIP_WAITING'})
74 | self.addEventListener('message', (event) => {
75 | if (event.data && event.data.type === 'SKIP_WAITING') {
76 | self.skipWaiting();
77 | }
78 | });
79 |
80 | // Any other custom service worker logic can go here.
81 |
--------------------------------------------------------------------------------
/src/serviceWorkerRegistration.ts:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://cra.link/PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
19 | );
20 |
21 | type Config = {
22 | onSuccess?: (registration: ServiceWorkerRegistration) => void;
23 | onUpdate?: (registration: ServiceWorkerRegistration) => void;
24 | };
25 |
26 | export function register(config?: Config) {
27 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
28 | // The URL constructor is available in all browsers that support SW.
29 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
30 | if (publicUrl.origin !== window.location.origin) {
31 | // Our service worker won't work if PUBLIC_URL is on a different origin
32 | // from what our page is served on. This might happen if a CDN is used to
33 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
34 | return;
35 | }
36 |
37 | window.addEventListener('load', () => {
38 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
39 |
40 | if (isLocalhost) {
41 | // This is running on localhost. Let's check if a service worker still exists or not.
42 | checkValidServiceWorker(swUrl, config);
43 |
44 | // Add some additional logging to localhost, pointing developers to the
45 | // service worker/PWA documentation.
46 | navigator.serviceWorker.ready.then(() => {
47 | console.log(
48 | 'This web app is being served cache-first by a service ' +
49 | 'worker. To learn more, visit https://cra.link/PWA'
50 | );
51 | });
52 | } else {
53 | // Is not localhost. Just register service worker
54 | registerValidSW(swUrl, config);
55 | }
56 | });
57 | }
58 | }
59 |
60 | function registerValidSW(swUrl: string, config?: Config) {
61 | navigator.serviceWorker
62 | .register(swUrl)
63 | .then((registration) => {
64 | registration.onupdatefound = () => {
65 | const installingWorker = registration.installing;
66 | if (installingWorker == null) {
67 | return;
68 | }
69 | installingWorker.onstatechange = () => {
70 | if (installingWorker.state === 'installed') {
71 | if (navigator.serviceWorker.controller) {
72 | // At this point, the updated precached content has been fetched,
73 | // but the previous service worker will still serve the older
74 | // content until all client tabs are closed.
75 | console.log(
76 | 'New content is available and will be used when all ' +
77 | 'tabs for this page are closed. See https://cra.link/PWA.'
78 | );
79 |
80 | // Execute callback
81 | if (config && config.onUpdate) {
82 | config.onUpdate(registration);
83 | }
84 | } else {
85 | // At this point, everything has been precached.
86 | // It's the perfect time to display a
87 | // "Content is cached for offline use." message.
88 | console.log('Content is cached for offline use.');
89 |
90 | // Execute callback
91 | if (config && config.onSuccess) {
92 | config.onSuccess(registration);
93 | }
94 | }
95 | }
96 | };
97 | };
98 | })
99 | .catch((error) => {
100 | console.error('Error during service worker registration:', error);
101 | });
102 | }
103 |
104 | function checkValidServiceWorker(swUrl: string, config?: Config) {
105 | // Check if the service worker can be found. If it can't reload the page.
106 | fetch(swUrl, {
107 | headers: { 'Service-Worker': 'script' },
108 | })
109 | .then((response) => {
110 | // Ensure service worker exists, and that we really are getting a JS file.
111 | const contentType = response.headers.get('content-type');
112 | if (
113 | response.status === 404 ||
114 | (contentType != null && contentType.indexOf('javascript') === -1)
115 | ) {
116 | // No service worker found. Probably a different app. Reload the page.
117 | navigator.serviceWorker.ready.then((registration) => {
118 | registration.unregister().then(() => {
119 | window.location.reload();
120 | });
121 | });
122 | } else {
123 | // Service worker found. Proceed as normal.
124 | registerValidSW(swUrl, config);
125 | }
126 | })
127 | .catch(() => {
128 | console.log('No internet connection found. App is running in offline mode.');
129 | });
130 | }
131 |
132 | export function unregister() {
133 | if ('serviceWorker' in navigator) {
134 | navigator.serviceWorker.ready
135 | .then((registration) => {
136 | registration.unregister();
137 | })
138 | .catch((error) => {
139 | console.error(error.message);
140 | });
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/services/DarkModeService.tsx:
--------------------------------------------------------------------------------
1 |
2 | class DarkModeService {
3 |
4 | /**
5 | * Set the Dark/Light Mode
6 | * @param shouldEnable boolean
7 | */
8 | enableDarkTheme(shouldEnable:boolean) {
9 | document.body.classList.toggle("dark",shouldEnable);
10 | }
11 |
12 | }
13 | export {DarkModeService};
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
7 | // Mock matchmedia
8 | window.matchMedia = window.matchMedia || function() {
9 | return {
10 | matches: false,
11 | addListener: function() {},
12 | removeListener: function() {}
13 | };
14 | };
15 |
--------------------------------------------------------------------------------
/src/theme/variables.css:
--------------------------------------------------------------------------------
1 | /* Ionic Variables and Theming. For more info, please see:
2 | http://ionicframework.com/docs/theming/ */
3 |
4 | /** Ionic CSS Variables **/
5 | :root {
6 | /** primary **/
7 | --ion-color-primary: #3880ff;
8 | --ion-color-primary-rgb: 56, 128, 255;
9 | --ion-color-primary-contrast: #ffffff;
10 | --ion-color-primary-contrast-rgb: 255, 255, 255;
11 | --ion-color-primary-shade: #3171e0;
12 | --ion-color-primary-tint: #4c8dff;
13 |
14 | /** secondary **/
15 | --ion-color-secondary: #3dc2ff;
16 | --ion-color-secondary-rgb: 61, 194, 255;
17 | --ion-color-secondary-contrast: #ffffff;
18 | --ion-color-secondary-contrast-rgb: 255, 255, 255;
19 | --ion-color-secondary-shade: #36abe0;
20 | --ion-color-secondary-tint: #50c8ff;
21 |
22 | /** tertiary **/
23 | --ion-color-tertiary: #5260ff;
24 | --ion-color-tertiary-rgb: 82, 96, 255;
25 | --ion-color-tertiary-contrast: #ffffff;
26 | --ion-color-tertiary-contrast-rgb: 255, 255, 255;
27 | --ion-color-tertiary-shade: #4854e0;
28 | --ion-color-tertiary-tint: #6370ff;
29 |
30 | /** success **/
31 | --ion-color-success: #2dd36f;
32 | --ion-color-success-rgb: 45, 211, 111;
33 | --ion-color-success-contrast: #ffffff;
34 | --ion-color-success-contrast-rgb: 255, 255, 255;
35 | --ion-color-success-shade: #28ba62;
36 | --ion-color-success-tint: #42d77d;
37 |
38 | /** warning **/
39 | --ion-color-warning: #ffc409;
40 | --ion-color-warning-rgb: 255, 196, 9;
41 | --ion-color-warning-contrast: #000000;
42 | --ion-color-warning-contrast-rgb: 0, 0, 0;
43 | --ion-color-warning-shade: #e0ac08;
44 | --ion-color-warning-tint: #ffca22;
45 |
46 | /** danger **/
47 | --ion-color-danger: #eb445a;
48 | --ion-color-danger-rgb: 235, 68, 90;
49 | --ion-color-danger-contrast: #ffffff;
50 | --ion-color-danger-contrast-rgb: 255, 255, 255;
51 | --ion-color-danger-shade: #cf3c4f;
52 | --ion-color-danger-tint: #ed576b;
53 |
54 | /** dark **/
55 | --ion-color-dark: #222428;
56 | --ion-color-dark-rgb: 34, 36, 40;
57 | --ion-color-dark-contrast: #ffffff;
58 | --ion-color-dark-contrast-rgb: 255, 255, 255;
59 | --ion-color-dark-shade: #1e2023;
60 | --ion-color-dark-tint: #383a3e;
61 |
62 | /** medium **/
63 | --ion-color-medium: #92949c;
64 | --ion-color-medium-rgb: 146, 148, 156;
65 | --ion-color-medium-contrast: #ffffff;
66 | --ion-color-medium-contrast-rgb: 255, 255, 255;
67 | --ion-color-medium-shade: #808289;
68 | --ion-color-medium-tint: #9d9fa6;
69 |
70 | /** light **/
71 | --ion-color-light: #f4f5f8;
72 | --ion-color-light-rgb: 244, 245, 248;
73 | --ion-color-light-contrast: #000000;
74 | --ion-color-light-contrast-rgb: 0, 0, 0;
75 | --ion-color-light-shade: #d7d8da;
76 | --ion-color-light-tint: #f5f6f9;
77 | }
78 |
79 | @media (prefers-color-scheme: dark) {
80 | /*
81 | * Dark Colors
82 | * -------------------------------------------
83 | */
84 |
85 | body {
86 | --ion-color-primary: #428cff;
87 | --ion-color-primary-rgb: 66,140,255;
88 | --ion-color-primary-contrast: #ffffff;
89 | --ion-color-primary-contrast-rgb: 255,255,255;
90 | --ion-color-primary-shade: #3a7be0;
91 | --ion-color-primary-tint: #5598ff;
92 |
93 | --ion-color-secondary: #50c8ff;
94 | --ion-color-secondary-rgb: 80,200,255;
95 | --ion-color-secondary-contrast: #ffffff;
96 | --ion-color-secondary-contrast-rgb: 255,255,255;
97 | --ion-color-secondary-shade: #46b0e0;
98 | --ion-color-secondary-tint: #62ceff;
99 |
100 | --ion-color-tertiary: #6a64ff;
101 | --ion-color-tertiary-rgb: 106,100,255;
102 | --ion-color-tertiary-contrast: #ffffff;
103 | --ion-color-tertiary-contrast-rgb: 255,255,255;
104 | --ion-color-tertiary-shade: #5d58e0;
105 | --ion-color-tertiary-tint: #7974ff;
106 |
107 | --ion-color-success: #2fdf75;
108 | --ion-color-success-rgb: 47,223,117;
109 | --ion-color-success-contrast: #000000;
110 | --ion-color-success-contrast-rgb: 0,0,0;
111 | --ion-color-success-shade: #29c467;
112 | --ion-color-success-tint: #44e283;
113 |
114 | --ion-color-warning: #ffd534;
115 | --ion-color-warning-rgb: 255,213,52;
116 | --ion-color-warning-contrast: #000000;
117 | --ion-color-warning-contrast-rgb: 0,0,0;
118 | --ion-color-warning-shade: #e0bb2e;
119 | --ion-color-warning-tint: #ffd948;
120 |
121 | --ion-color-danger: #ff4961;
122 | --ion-color-danger-rgb: 255,73,97;
123 | --ion-color-danger-contrast: #ffffff;
124 | --ion-color-danger-contrast-rgb: 255,255,255;
125 | --ion-color-danger-shade: #e04055;
126 | --ion-color-danger-tint: #ff5b71;
127 |
128 | --ion-color-dark: #f4f5f8;
129 | --ion-color-dark-rgb: 244,245,248;
130 | --ion-color-dark-contrast: #000000;
131 | --ion-color-dark-contrast-rgb: 0,0,0;
132 | --ion-color-dark-shade: #d7d8da;
133 | --ion-color-dark-tint: #f5f6f9;
134 |
135 | --ion-color-medium: #989aa2;
136 | --ion-color-medium-rgb: 152,154,162;
137 | --ion-color-medium-contrast: #000000;
138 | --ion-color-medium-contrast-rgb: 0,0,0;
139 | --ion-color-medium-shade: #86888f;
140 | --ion-color-medium-tint: #a2a4ab;
141 |
142 | --ion-color-light: #222428;
143 | --ion-color-light-rgb: 34,36,40;
144 | --ion-color-light-contrast: #ffffff;
145 | --ion-color-light-contrast-rgb: 255,255,255;
146 | --ion-color-light-shade: #1e2023;
147 | --ion-color-light-tint: #383a3e;
148 | }
149 |
150 | /*
151 | * iOS Dark Theme
152 | * -------------------------------------------
153 | */
154 |
155 | .ios body {
156 | --ion-background-color: #000000;
157 | --ion-background-color-rgb: 0,0,0;
158 |
159 | --ion-text-color: #ffffff;
160 | --ion-text-color-rgb: 255,255,255;
161 |
162 | --ion-color-step-50: #0d0d0d;
163 | --ion-color-step-100: #1a1a1a;
164 | --ion-color-step-150: #262626;
165 | --ion-color-step-200: #333333;
166 | --ion-color-step-250: #404040;
167 | --ion-color-step-300: #4d4d4d;
168 | --ion-color-step-350: #595959;
169 | --ion-color-step-400: #666666;
170 | --ion-color-step-450: #737373;
171 | --ion-color-step-500: #808080;
172 | --ion-color-step-550: #8c8c8c;
173 | --ion-color-step-600: #999999;
174 | --ion-color-step-650: #a6a6a6;
175 | --ion-color-step-700: #b3b3b3;
176 | --ion-color-step-750: #bfbfbf;
177 | --ion-color-step-800: #cccccc;
178 | --ion-color-step-850: #d9d9d9;
179 | --ion-color-step-900: #e6e6e6;
180 | --ion-color-step-950: #f2f2f2;
181 |
182 | --ion-item-background: #000000;
183 |
184 | --ion-card-background: #1c1c1d;
185 | }
186 |
187 | .ios ion-modal {
188 | --ion-background-color: var(--ion-color-step-100);
189 | --ion-toolbar-background: var(--ion-color-step-150);
190 | --ion-toolbar-border-color: var(--ion-color-step-250);
191 | }
192 |
193 |
194 | /*
195 | * Material Design Dark Theme
196 | * -------------------------------------------
197 | */
198 |
199 | .md body {
200 | --ion-background-color: #121212;
201 | --ion-background-color-rgb: 18,18,18;
202 |
203 | --ion-text-color: #ffffff;
204 | --ion-text-color-rgb: 255,255,255;
205 |
206 | --ion-border-color: #222222;
207 |
208 | --ion-color-step-50: #1e1e1e;
209 | --ion-color-step-100: #2a2a2a;
210 | --ion-color-step-150: #363636;
211 | --ion-color-step-200: #414141;
212 | --ion-color-step-250: #4d4d4d;
213 | --ion-color-step-300: #595959;
214 | --ion-color-step-350: #656565;
215 | --ion-color-step-400: #717171;
216 | --ion-color-step-450: #7d7d7d;
217 | --ion-color-step-500: #898989;
218 | --ion-color-step-550: #949494;
219 | --ion-color-step-600: #a0a0a0;
220 | --ion-color-step-650: #acacac;
221 | --ion-color-step-700: #b8b8b8;
222 | --ion-color-step-750: #c4c4c4;
223 | --ion-color-step-800: #d0d0d0;
224 | --ion-color-step-850: #dbdbdb;
225 | --ion-color-step-900: #e7e7e7;
226 | --ion-color-step-950: #f3f3f3;
227 |
228 | --ion-item-background: #1e1e1e;
229 |
230 | --ion-toolbar-background: #1f1f1f;
231 |
232 | --ion-tab-bar-background: #1f1f1f;
233 |
234 | --ion-card-background: #1e1e1e;
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "react-jsx",
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": [
24 | "src/**/*.ts",
25 | "src/**/*.tsx",
26 | "./capacitor.config.ts",
27 | "./capacitor.config.js"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------