Compare commits
65 Commits
side_step
...
deep_linki
| Author | SHA1 | Date | |
|---|---|---|---|
| ac58804cb5 | |||
| 49b82e6c44 | |||
| 6f4fbc697f | |||
| 42413045c5 | |||
| 245959d783 | |||
| ae376f4c81 | |||
|
|
a67094218d | ||
|
|
a215b1de72 | ||
|
|
d1acfb3c49 | ||
|
|
6773f512b9 | ||
|
|
df81bb6a95 | ||
|
|
611d318a7a | ||
|
|
2fbd42def5 | ||
|
|
9c8bf7997f | ||
|
|
6d4428668a | ||
|
|
eda4a6b25e | ||
|
|
87ef6f4186 | ||
|
|
e0aded04b4 | ||
|
|
8cae601148 | ||
| 562e82f176 | |||
| d53de5e79b | |||
|
|
b6213f5040 | ||
|
|
b590e41ec8 | ||
|
|
93219219ba | ||
|
|
8336b87bd0 | ||
|
|
a40420af16 | ||
|
|
21244efa73 | ||
|
|
02d6d220c7 | ||
|
|
5ed626b92f | ||
|
|
4562be3bac | ||
|
|
22de70a77d | ||
|
|
d6bf89ba57 | ||
|
|
b55b786738 | ||
|
|
879c00bd97 | ||
|
|
6cb1482b5f | ||
|
|
ad9b4836cd | ||
|
|
32f1f182d7 | ||
|
|
510f6a5faa | ||
|
|
1bb4e77714 | ||
|
|
cc10dab3a4 | ||
|
|
0a066dc99c | ||
|
|
eeddab506d | ||
|
|
bfd1aee27c | ||
|
|
2424d788d1 | ||
|
|
d14431161a | ||
| 8f993923a1 | |||
|
|
9edb3a255c | ||
|
|
b7b208407b | ||
|
|
a974ab4f51 | ||
|
|
bc971056e1 | ||
|
|
69b4b899c9 | ||
|
|
02747fb771 | ||
|
|
3dae8f7f7f | ||
|
|
9e6f0ab468 | ||
|
|
6685421ee8 | ||
|
|
4fcbb78450 | ||
| 9ffdb54c20 | |||
|
|
f4c5567471 | ||
|
|
86c1abb9be | ||
| e96617ca0f | |||
|
|
d700be9e5b | ||
|
|
317fb2c644 | ||
| b91f2a5df7 | |||
| f6871e139d | |||
| 61afba3bca |
6
.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# Admin DID credentials
|
||||
ADMIN_DID=did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F
|
||||
ADMIN_PRIVATE_KEY=2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b
|
||||
|
||||
# API Configuration
|
||||
ENDORSER_API_URL=https://test-api.endorser.ch/api/v2/claim
|
||||
27
.gitignore
vendored
@@ -39,4 +39,29 @@ pnpm-debug.log*
|
||||
/test-playwright-results/
|
||||
playwright-tests
|
||||
test-playwright
|
||||
dist-electron-packages
|
||||
dist-electron-packages
|
||||
ios
|
||||
.ruby-version
|
||||
+.env
|
||||
|
||||
# Generated test files
|
||||
.generated/
|
||||
|
||||
# Fastlane
|
||||
ios/fastlane/report.xml
|
||||
ios/fastlane/Preview.html
|
||||
ios/fastlane/screenshots
|
||||
ios/fastlane/test_output
|
||||
android/fastlane/report.xml
|
||||
android/fastlane/Preview.html
|
||||
android/fastlane/screenshots
|
||||
android/fastlane/test_output
|
||||
.env.default
|
||||
vendor/
|
||||
|
||||
# Build logs
|
||||
build_logs/
|
||||
|
||||
# Android generated assets
|
||||
android/app/src/main/assets/public/assets/
|
||||
|
||||
|
||||
133
BUILDING.md
@@ -105,28 +105,32 @@ Prerequisites: macOS with Xcode installed
|
||||
1. Build the web assets:
|
||||
|
||||
```bash
|
||||
npm run build -- --mode capacitor
|
||||
npm run build:capacitor
|
||||
```
|
||||
|
||||
2. Add iOS platform if not already added:
|
||||
|
||||
```bash
|
||||
npx cap add ios
|
||||
```
|
||||
|
||||
3. Update iOS project with latest build:
|
||||
2. Update iOS project with latest build:
|
||||
|
||||
```bash
|
||||
npx cap sync ios
|
||||
```
|
||||
|
||||
4. Open the project in Xcode:
|
||||
3. Open the project in Xcode:
|
||||
|
||||
```bash
|
||||
npx cap open ios
|
||||
```
|
||||
|
||||
5. Use Xcode to build and run on simulator or device.
|
||||
4. Use Xcode to build and run on simulator or device.
|
||||
|
||||
If you have forked this to make your own app, you'll want to customize the ios files:
|
||||
|
||||
```bash
|
||||
rm -rf ios
|
||||
npx cap add ios
|
||||
```
|
||||
|
||||
... and then repeat the steps above.
|
||||
|
||||
|
||||
### Android Build
|
||||
|
||||
@@ -135,37 +139,108 @@ Prerequisites: Android Studio with SDK installed
|
||||
1. Build the web assets:
|
||||
|
||||
```bash
|
||||
npm run build -- --mode capacitor
|
||||
rm -rf dist
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
```
|
||||
|
||||
2. Add Android platform if not already added:
|
||||
|
||||
```bash
|
||||
npx cap add android
|
||||
```
|
||||
|
||||
3. Update Android project with latest build:
|
||||
2. Update Android project with latest build:
|
||||
|
||||
```bash
|
||||
npx cap sync android
|
||||
```
|
||||
|
||||
4. Open the project in Android Studio:
|
||||
3. Open the project in Android Studio:
|
||||
|
||||
```bash
|
||||
npx cap open android
|
||||
```
|
||||
|
||||
5. Use Android Studio to build and run on emulator or device.
|
||||
3. Use Android Studio to build and run on emulator or device.
|
||||
|
||||
## Development
|
||||
|
||||
To run the application in development mode:
|
||||
|
||||
1. Start the development server:
|
||||
If you have forked this to make your own app, you'll want to customize the android files:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
rm -rf android
|
||||
npx cap add android
|
||||
```
|
||||
|
||||
... and then: repeat the steps above, and look below for the deep link configuration.
|
||||
|
||||
## Building Android from the console
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew clean
|
||||
./gradlew build -Dlint.baselines.continue=true
|
||||
cd ..
|
||||
npx cap run android
|
||||
```
|
||||
|
||||
## Configuring Android for deep links
|
||||
|
||||
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
|
||||
|
||||
```xml
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="timesafari" />
|
||||
</intent-filter>
|
||||
```
|
||||
|
||||
You must also add the following to the `android/app/build.gradle` file:
|
||||
|
||||
```gradle
|
||||
android {
|
||||
// ... existing config ...
|
||||
|
||||
lintOptions {
|
||||
disable 'UnsanitizedFilenameFromContentProvider'
|
||||
abortOnError false
|
||||
baseline file("lint-baseline.xml")
|
||||
|
||||
// Ignore Capacitor module issues
|
||||
ignore 'DefaultLocale'
|
||||
ignore 'UnsanitizedFilenameFromContentProvider'
|
||||
ignore 'LintBaseline'
|
||||
ignore 'LintBaselineFixed'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Modify `/android/build.gradle` to use a stable version of AGP and make sure Kotlin version is compatible.
|
||||
|
||||
```gradle
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
// Use a stable version of AGP
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
|
||||
// Make sure Kotlin version is compatible
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
// Add this to handle version conflicts
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib:1.8.0'
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## PyWebView Desktop Build
|
||||
@@ -260,11 +335,7 @@ Run local tests:
|
||||
npm run test-local
|
||||
```
|
||||
|
||||
Run all tests (includes building):
|
||||
|
||||
```bash
|
||||
npm run test-all
|
||||
```
|
||||
See [TESTING.md](test-playwright/TESTING.md) for more details.
|
||||
|
||||
## Linting
|
||||
|
||||
|
||||
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
|
||||
## [0.4.5] - 2025.02.23
|
||||
### Added
|
||||
- Total amounts of gives on project page
|
||||
### Changed in DB or environment
|
||||
- Requires Endorser.ch version 4.2.6+
|
||||
|
||||
|
||||
## [0.4.4] - 2025.02.17
|
||||
|
||||
### Fixed in 0.4.4
|
||||
|
||||
5
Gemfile
Normal file
@@ -0,0 +1,5 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
gem "cocoapods"
|
||||
|
||||
321
Gemfile.lock
Normal file
@@ -0,0 +1,321 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.7)
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
activesupport (7.2.2.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.2)
|
||||
aws-partitions (1.1066.0)
|
||||
aws-sdk-core (3.220.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.182.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
claide (1.1.0)
|
||||
cocoapods (1.16.2)
|
||||
addressable (~> 2.8)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.16.2)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 2.1, < 3.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.6.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (>= 2.3.0, < 3.0)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.8.0)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (>= 2.3.0, < 3.0)
|
||||
xcodeproj (>= 1.27.0, < 2.0)
|
||||
cocoapods-core (1.16.2)
|
||||
activesupport (>= 5.0, < 8)
|
||||
addressable (~> 2.8)
|
||||
algoliasearch (~> 1.0)
|
||||
concurrent-ruby (~> 1.1)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
netrc (~> 0.11)
|
||||
public_suffix (~> 4.0)
|
||||
typhoeus (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.5)
|
||||
cocoapods-downloader (2.1)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.1)
|
||||
cocoapods-trunk (1.6.0)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.2.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.0)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.7.0)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (2.8.1)
|
||||
drb (2.2.1)
|
||||
emoji_regex (3.2.3)
|
||||
escape (0.0.4)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.112.0)
|
||||
faraday (1.10.4)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-multipart (1.1.0)
|
||||
multipart-post (~> 2.0)
|
||||
faraday-net_http (1.0.2)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.1)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.4.0)
|
||||
fastlane (2.227.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored (~> 1.2)
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
fastlane-sirp (>= 1.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-env (>= 1.6.0, < 2.0.0)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
http-cookie (~> 1.0.5)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (>= 0.1.1, < 1.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.5)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (~> 3)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.4.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||
fastlane-sirp (1.0.0)
|
||||
sysrandom (~> 1.0)
|
||||
ffi (1.17.1)
|
||||
ffi (1.17.1-aarch64-linux-gnu)
|
||||
ffi (1.17.1-aarch64-linux-musl)
|
||||
ffi (1.17.1-arm-linux-gnu)
|
||||
ffi (1.17.1-arm-linux-musl)
|
||||
ffi (1.17.1-arm64-darwin)
|
||||
ffi (1.17.1-x86-linux-gnu)
|
||||
ffi (1.17.1-x86-linux-musl)
|
||||
ffi (1.17.1-x86_64-darwin)
|
||||
ffi (1.17.1-x86_64-linux-gnu)
|
||||
ffi (1.17.1-x86_64-linux-musl)
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.3)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.8.0)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.5.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.31.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.8.1)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.10.2)
|
||||
jwt (2.10.1)
|
||||
base64
|
||||
logger (1.6.6)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.5)
|
||||
molinillo (0.8.0)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.4.0)
|
||||
nap (1.1.0)
|
||||
naturally (2.2.1)
|
||||
netrc (0.11.0)
|
||||
nkf (0.2.0)
|
||||
optparse (0.6.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.2)
|
||||
public_suffix (4.0.7)
|
||||
rake (13.2.1)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.4.1)
|
||||
rouge (3.28.0)
|
||||
ruby-macho (2.5.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.4.1)
|
||||
securerandom (0.4.1)
|
||||
security (0.1.5)
|
||||
signet (0.19.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
sysrandom (1.0.5)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.2)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
typhoeus (1.4.1)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uber (0.1.0)
|
||||
unicode-display_width (2.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.27.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.4.0)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
xcpretty (0.4.0)
|
||||
rouge (~> 3.28.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux-gnu
|
||||
aarch64-linux-musl
|
||||
arm-linux-gnu
|
||||
arm-linux-musl
|
||||
arm64-darwin
|
||||
ruby
|
||||
x86-linux-gnu
|
||||
x86-linux-musl
|
||||
x86_64-darwin
|
||||
x86_64-linux-gnu
|
||||
x86_64-linux-musl
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
2.6.5
|
||||
23
README.md
@@ -17,23 +17,15 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
See the test locations for "IMAGE_API_SERVER" or "PARTNER_API_SERVER" below, or use <http://localhost:3000> for local endorser.ch
|
||||
See [BUILDING.md](BUILDING.md) for more details.
|
||||
|
||||
### Build the test & production app
|
||||
See the test locations for "IMAGE_API_SERVER" or "PARTNER_API_SERVER" below, or use http://localhost:3000 for local endorser.ch
|
||||
|
||||
```bash
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Lint and fix files
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Run all UI tests
|
||||
|
||||
Look below for the "test-all" instructions.
|
||||
Look at [BUILDING.md](BUILDING.md) for the "test-all" instructions and [TESTING.md](test-playwright/TESTING.md) for more details.
|
||||
|
||||
|
||||
### Compile and minify for test & production
|
||||
|
||||
@@ -79,10 +71,17 @@ TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.
|
||||
|
||||
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Tests
|
||||
|
||||
See [TESTING.md](test-playwright/TESTING.md) for detailed test instructions.
|
||||
|
||||
|
||||
|
||||
|
||||
## Icons
|
||||
|
||||
To add an icon, add to main.ts and reference with `fa` element and `icon` attribute with the hyphenated name.
|
||||
|
||||
BIN
android/.gradle/8.11.1/checksums/checksums.lock
Normal file
BIN
android/.gradle/8.11.1/checksums/md5-checksums.bin
Normal file
BIN
android/.gradle/8.11.1/checksums/sha1-checksums.bin
Normal file
BIN
android/.gradle/8.11.1/executionHistory/executionHistory.bin
Normal file
BIN
android/.gradle/8.11.1/executionHistory/executionHistory.lock
Normal file
BIN
android/.gradle/8.11.1/fileChanges/last-build.bin
Normal file
BIN
android/.gradle/8.11.1/fileHashes/fileHashes.bin
Normal file
BIN
android/.gradle/8.11.1/fileHashes/fileHashes.lock
Normal file
BIN
android/.gradle/8.11.1/fileHashes/resourceHashesCache.bin
Normal file
0
android/.gradle/8.11.1/gc.properties
Normal file
BIN
android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
2
android/.gradle/buildOutputCleanup/cache.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
#Tue Mar 11 10:01:05 UTC 2025
|
||||
gradle.version=8.10.2
|
||||
BIN
android/.gradle/file-system.probe
Normal file
0
android/.gradle/vcs-1/gc.properties
Normal file
3
android/Gemfile
Normal file
@@ -0,0 +1,3 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
1
android/app/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
/build/*
|
||||
!/build/.npmkeep
|
||||
src/main/assets/public/assets/
|
||||
@@ -1,10 +1,10 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
namespace "app.timesafari.app"
|
||||
namespace "app.timesafari"
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "app.timesafari.app"
|
||||
applicationId "app.timesafari"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
@@ -22,6 +22,17 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
disable 'UnsanitizedFilenameFromContentProvider'
|
||||
abortOnError false
|
||||
baseline file("lint-baseline.xml")
|
||||
|
||||
// Ignore Capacitor module issues
|
||||
ignore 'DefaultLocale'
|
||||
ignore 'UnsanitizedFilenameFromContentProvider'
|
||||
ignore 'LintBaseline'
|
||||
ignore 'LintBaselineFixed'
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
398
android/app/lint-baseline.xml
Normal file
@@ -0,0 +1,398 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="6" by="lint 8.1.0" type="baseline" client="gradle" dependencies="true" name="AGP (8.1.0)" variant="all" version="8.1.0">
|
||||
|
||||
<issue
|
||||
id="UnknownIssueId"
|
||||
message="Unknown issue id "UnsanitizedFilenameFromContentProvider""
|
||||
errorLine1=" disable 'UnsanitizedFilenameFromContentProvider'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="26"
|
||||
column="18"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnknownIssueId"
|
||||
message="Unknown issue id "UnsanitizedFilenameFromContentProvider""
|
||||
errorLine1=" disable 'UnsanitizedFilenameFromContentProvider'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="26"
|
||||
column="18"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnknownIssueId"
|
||||
message="Unknown issue id "LintBaselineFixed""
|
||||
errorLine1=" ignore 'LintBaselineFixed'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="34"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnknownIssueId"
|
||||
message="Unknown issue id "LintBaselineFixed""
|
||||
errorLine1=" ignore 'LintBaselineFixed'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="34"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `String.format(Locale, ...)` instead"
|
||||
errorLine1=" String msg = String.format("
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeWebChromeClient.java"
|
||||
line="467"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" return mask.toUpperCase().equals(string.toUpperCase());"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/util/HostMask.java"
|
||||
line="110"
|
||||
column="29"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" return mask.toUpperCase().equals(string.toUpperCase());"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/util/HostMask.java"
|
||||
line="110"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" if (header.getKey().equalsIgnoreCase("Accept") && header.getValue().toLowerCase().contains("text/html")) {"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/WebViewLocalServer.java"
|
||||
line="474"
|
||||
column="93"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SimpleDateFormat"
|
||||
message="To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, or `getTimeInstance()`, or use `new SimpleDateFormat(String template, Locale locale)` with for example `Locale.US` for ASCII dates."
|
||||
errorLine1=" String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeWebChromeClient.java"
|
||||
line="504"
|
||||
column="28"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SimpleDateFormat"
|
||||
message="To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, or `getTimeInstance()`, or use `new SimpleDateFormat(String template, Locale locale)` with for example `Locale.US` for ASCII dates."
|
||||
errorLine1=" DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/PluginResult.java"
|
||||
line="44"
|
||||
column="25"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedAttribute"
|
||||
message="Attribute `usesCleartextTraffic` is only used in API level 23 and higher (current min is 22)"
|
||||
errorLine1="<application android:usesCleartextTraffic="true">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="4"
|
||||
column="15"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedAttribute"
|
||||
message="Attribute `autoVerify` is only used in API level 23 and higher (current min is 22)"
|
||||
errorLine1=" <intent-filter android:autoVerify="true">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="25"
|
||||
column="28"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="ManifestOrder"
|
||||
message="`<uses-permission>` tag appears after `<application>` tag"
|
||||
errorLine1=" <uses-permission android:name="android.permission.INTERNET" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="47"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="AndroidGradlePluginVersion"
|
||||
message="A newer version of com.android.tools.build:gradle than 8.2.1 is available: 8.9.0. (There is also a newer version of 8.2.𝑥 available, if upgrading to 8.9.0 is difficult: 8.2.2)"
|
||||
errorLine1=" classpath 'com.android.tools.build:gradle:8.2.1'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="12"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="AndroidGradlePluginVersion"
|
||||
message="A newer version of com.android.tools.build:gradle than 8.2.1 is available: 8.9.0. (There is also a newer version of 8.2.𝑥 available, if upgrading to 8.9.0 is difficult: 8.2.2)"
|
||||
errorLine1=" classpath 'com.android.tools.build:gradle:8.2.1'"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="18"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.appcompat:appcompat than 1.6.1 is available: 1.7.0"
|
||||
errorLine1=" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="46"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.appcompat:appcompat than 1.6.1 is available: 1.7.0"
|
||||
errorLine1=" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="46"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.coordinatorlayout:coordinatorlayout than 1.2.0 is available: 1.3.0"
|
||||
errorLine1=" implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="47"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.test.ext:junit than 1.1.5 is available: 1.2.1"
|
||||
errorLine1=" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="51"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.test.espresso:espresso-core than 3.5.1 is available: 3.6.1"
|
||||
errorLine1=" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="52"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.appcompat:appcompat than 1.6.1 is available: 1.7.0"
|
||||
errorLine1=" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="75"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.test.ext:junit than 1.1.5 is available: 1.2.1"
|
||||
errorLine1=" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="77"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleDependency"
|
||||
message="A newer version of androidx.test.espresso:espresso-core than 3.5.1 is available: 3.6.1"
|
||||
errorLine1=" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="build.gradle"
|
||||
line="78"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Recycle"
|
||||
message="This `TypedArray` should be recycled after use with `#recycle()`"
|
||||
errorLine1=" TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.bridge_fragment);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeFragment.java"
|
||||
line="99"
|
||||
column="32"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `#F0FF1414` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)"
|
||||
errorLine1=" android:background="#F0FF1414""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/fragment_bridge.xml"
|
||||
line="5"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.layout.activity_main` appears to be unused"
|
||||
errorLine1="<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android""
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/layout/activity_main.xml"
|
||||
line="2"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.xml.config` appears to be unused"
|
||||
errorLine1="<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">"
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/xml/config.xml"
|
||||
line="2"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.drawable.ic_launcher_background` appears to be unused"
|
||||
errorLine1="<vector xmlns:android="http://schemas.android.com/apk/res/android""
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/drawable/ic_launcher_background.xml"
|
||||
line="2"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.drawable.ic_launcher_foreground` appears to be unused"
|
||||
errorLine1="<vector xmlns:android="http://schemas.android.com/apk/res/android""
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/drawable-v24/ic_launcher_foreground.xml"
|
||||
line="1"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.string.package_name` appears to be unused"
|
||||
errorLine1=" <string name="package_name">app.timesafari.app</string>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="5"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="UnusedResources"
|
||||
message="The resource `R.string.custom_url_scheme` appears to be unused"
|
||||
errorLine1=" <string name="custom_url_scheme">app.timesafari.app</string>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="6"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="MonochromeLauncherIcon"
|
||||
message="The application adaptive icon is missing a monochrome tag"
|
||||
errorLine1="<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">"
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/mipmap-anydpi-v26/ic_launcher.xml"
|
||||
line="2"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="MonochromeLauncherIcon"
|
||||
message="The application adaptive roundIcon is missing a monochrome tag"
|
||||
errorLine1="<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">"
|
||||
errorLine2="^">
|
||||
<location
|
||||
file="src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml"
|
||||
line="2"
|
||||
column="1"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="IconDipSize"
|
||||
message="The image `splash.png` varies significantly in its density-independent (dip) size across the various density versions: drawable-land-hdpi/splash.png: 533x320 dp (800x480 px), drawable-land-mdpi/splash.png: 480x320 dp (480x320 px), drawable-land-xhdpi/splash.png: 640x360 dp (1280x720 px), drawable-land-xxhdpi/splash.png: 533x320 dp (1600x960 px), drawable-land-xxxhdpi/splash.png: 480x320 dp (1920x1280 px)">
|
||||
<location
|
||||
file="src/main/res/drawable-land-mdpi/splash.png"/>
|
||||
<location
|
||||
file="src/main/res/drawable-land-xxxhdpi/splash.png"/>
|
||||
<location
|
||||
file="src/main/res/drawable-land-hdpi/splash.png"/>
|
||||
<location
|
||||
file="src/main/res/drawable-land-xxhdpi/splash.png"/>
|
||||
<location
|
||||
file="src/main/res/drawable-land-xhdpi/splash.png"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="IconDuplicatesConfig"
|
||||
message="The `splash.png` icon has identical contents in the following configuration folders: drawable-land-mdpi, drawable">
|
||||
<location
|
||||
file="src/main/res/drawable/splash.png"/>
|
||||
<location
|
||||
file="src/main/res/drawable-land-mdpi/splash.png"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="IconLocation"
|
||||
message="Found bitmap drawable `res/drawable/splash.png` in densityless folder">
|
||||
<location
|
||||
file="src/main/res/drawable/splash.png"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
@@ -1,26 +1,20 @@
|
||||
package com.getcapacitor.myapp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
package app.timesafari.app;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("com.getcapacitor.app", appContext.getPackageName());
|
||||
assertEquals("app.timesafari", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
21
android/app/src/main/assets/capacitor.config.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"appId": "app.timesafari.app",
|
||||
"appName": "TimeSafari",
|
||||
"webDir": "dist",
|
||||
"bundledWebRuntime": false,
|
||||
"server": {
|
||||
"cleartext": true
|
||||
},
|
||||
"plugins": {
|
||||
"App": {
|
||||
"appUrlOpen": {
|
||||
"handlers": [
|
||||
{
|
||||
"url": "timesafari://*",
|
||||
"autoVerify": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
android/app/src/main/assets/capacitor.plugins.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"pkg": "@capacitor/app",
|
||||
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
||||
}
|
||||
]
|
||||
0
android/app/src/main/assets/public/cordova.js
vendored
Normal file
0
android/app/src/main/assets/public/cordova_plugins.js
vendored
Normal file
BIN
android/app/src/main/assets/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 463 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 70 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 46 KiB |
BIN
android/app/src/main/assets/public/img/icons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2480 4005 c-25 -7 -58 -20 -75 -29 -16 -9 -40 -16 -52 -16 -17 0
|
||||
-24 -7 -28 -27 -3 -16 -14 -45 -24 -65 -21 -41 -13 -55 18 -38 25 13 67 13 92
|
||||
-1 15 -8 35 -4 87 17 99 39 130 41 197 10 64 -29 77 -31 107 -15 20 11 20 11
|
||||
-3 35 -12 13 -30 24 -38 24 -24 1 -132 38 -148 51 -8 7 -11 20 -7 32 12 37
|
||||
-40 47 -126 22z"/>
|
||||
<path d="M1450 3775 c-7 -8 -18 -15 -24 -15 -7 0 -31 -14 -54 -32 -29 -22 -38
|
||||
-34 -29 -40 17 -11 77 -10 77 1 0 5 16 16 35 25 60 29 220 19 290 -18 17 -9
|
||||
33 -16 37 -16 4 0 31 -15 60 -34 108 -70 224 -215 282 -353 30 -71 53 -190 42
|
||||
-218 -10 -27 -23 -8 -52 75 -30 90 -88 188 -120 202 -13 6 -26 9 -29 6 -3 -2
|
||||
11 -51 30 -108 28 -83 35 -119 35 -179 0 -120 -22 -127 -54 -17 -11 37 -13 21
|
||||
-18 -154 -5 -180 -8 -200 -32 -264 -51 -132 -129 -245 -199 -288 -21 -12 -79
|
||||
-49 -129 -80 -161 -102 -294 -141 -473 -141 -228 0 -384 76 -535 259 -81 99
|
||||
-118 174 -154 312 -31 121 -35 273 -11 437 19 127 19 125 -4 125 -23 0 -51
|
||||
-34 -87 -104 -14 -28 -33 -64 -41 -81 -19 -34 -22 -253 -7 -445 9 -106 12
|
||||
-119 44 -170 19 -30 42 -67 50 -81 64 -113 85 -140 130 -169 28 -18 53 -44 61
|
||||
-62 8 -20 36 -45 83 -76 62 -39 80 -46 151 -54 44 -5 96 -13 115 -18 78 -20
|
||||
238 -31 282 -19 24 6 66 8 95 5 76 -9 169 24 319 114 32 19 80 56 106 82 27
|
||||
26 52 48 58 48 5 0 27 26 50 58 48 66 56 70 132 71 62 1 165 29 238 64 112 55
|
||||
177 121 239 245 37 76 39 113 10 267 -12 61 -23 131 -26 156 -5 46 -5 47 46
|
||||
87 92 73 182 70 263 -8 l51 -49 -6 -61 c-4 -34 -13 -85 -21 -113 -28 -103 -30
|
||||
-161 -4 -228 16 -44 32 -67 55 -83 18 -11 39 -37 47 -58 10 -23 37 -53 73 -81
|
||||
32 -25 69 -57 82 -71 14 -14 34 -26 47 -26 12 0 37 -7 56 -15 20 -8 66 -17
|
||||
104 -20 107 -10 110 -11 150 -71 50 -75 157 -177 197 -187 18 -5 53 -24 78
|
||||
-42 71 -51 176 -82 304 -89 61 -4 127 -12 147 -18 29 -9 45 -8 77 6 23 9 50
|
||||
16 60 16 31 0 163 46 216 76 28 15 75 46 105 69 30 23 69 49 85 58 17 8 46 31
|
||||
64 51 19 20 40 36 47 36 18 0 77 70 100 120 32 66 45 108 55 173 5 32 16 71
|
||||
24 87 43 84 43 376 0 549 -27 105 -43 127 -135 188 -30 21 -65 46 -77 57 -13
|
||||
11 -23 17 -23 14 0 -3 21 -46 47 -94 79 -151 85 -166 115 -263 25 -83 28 -110
|
||||
28 -226 0 -144 -17 -221 -75 -335 -39 -77 -208 -244 -304 -299 -451 -263 -975
|
||||
-67 -1138 426 -23 70 -26 95 -28 254 -1 108 -7 183 -14 196 -6 12 -11 31 -11
|
||||
43 0 32 31 122 52 149 10 13 18 28 18 34 0 5 25 40 56 78 60 73 172 170 219
|
||||
190 30 12 30 13 6 17 -15 2 -29 -2 -37 -12 -6 -9 -16 -16 -22 -16 -6 0 -23
|
||||
-11 -39 -24 -15 -12 -33 -25 -40 -27 -17 -6 -82 -60 -117 -97 -65 -70 -75 -82
|
||||
-107 -133 -23 -34 -35 -46 -37 -35 -3 16 20 87 44 134 6 12 9 34 6 48 -4 22
|
||||
-8 25 -31 19 -14 -3 -38 -15 -53 -26 -34 -24 -34 -21 -6 28 65 112 184 206
|
||||
291 227 15 3 39 9 55 12 l27 6 -24 9 c-90 35 -304 -66 -478 -225 -39 -36 -74
|
||||
-66 -77 -66 -22 0 18 82 72 148 19 23 32 46 28 49 -4 4 -26 13 -49 19 -73 21
|
||||
-161 54 -171 64 -6 6 -20 10 -32 10 -21 0 -21 -1 -8 -40 45 -130 8 -247 -93
|
||||
-299 -25 -13 -31 0 -14 29 15 22 1 33 -22 17 -56 -36 -117 -22 -117 28 0 13
|
||||
-16 47 -35 76 -22 34 -33 60 -29 73 4 16 -3 26 -26 39 -16 10 -30 21 -30 25 1
|
||||
18 54 64 87 76 l38 13 -33 5 c-30 4 -115 -18 -154 -42 -13 -7 -20 -5 -27 8 -9
|
||||
16 -12 16 -53 1 -160 -61 -258 -104 -258 -114 0 -7 10 -20 21 -31 103 -91 217
|
||||
-297 249 -449 28 -135 41 -237 35 -276 -14 -91 -48 -170 -97 -220 -44 -47 -68
|
||||
-60 -68 -40 0 6 4 12 8 15 5 3 24 35 42 72 l33 67 -6 141 c-4 103 -11 158 -26
|
||||
205 -12 35 -21 70 -21 77 0 7 -20 56 -45 108 -82 173 -227 322 -392 401 -67
|
||||
33 -90 39 -163 42 -108 5 -130 10 -130 28 0 20 -63 20 -80 0z"/>
|
||||
<path d="M3710 3765 c0 -20 8 -28 39 -41 22 -8 42 -22 45 -30 5 -14 42 -19 70
|
||||
-8 10 4 -7 21 -58 55 -41 27 -79 49 -85 49 -6 0 -11 -11 -11 -25z"/>
|
||||
<path d="M3173 3734 c-9 -25 10 -36 35 -18 12 8 22 19 22 25 0 16 -50 10 -57
|
||||
-7z"/>
|
||||
<path d="M1982 3728 c6 -16 36 -34 44 -26 3 4 4 14 1 23 -7 17 -51 21 -45 3z"/>
|
||||
<path d="M1540 3620 c0 -5 7 -10 16 -10 8 0 12 5 9 10 -3 6 -10 10 -16 10 -5
|
||||
0 -9 -4 -9 -10z"/>
|
||||
<path d="M4467 3624 c-4 -4 23 -27 60 -50 84 -56 99 -58 67 -9 -28 43 -107 79
|
||||
-127 59z"/>
|
||||
<path d="M655 3552 c-11 -2 -26 -9 -33 -14 -7 -6 -27 -18 -45 -27 -36 -18 -58
|
||||
-64 -39 -83 9 -9 25 1 70 43 53 48 78 78 70 84 -2 1 -12 -1 -23 -3z"/>
|
||||
<path d="M1015 3460 c-112 -24 -247 -98 -303 -165 -53 -65 -118 -214 -136
|
||||
-311 -20 -113 -20 -145 -1 -231 20 -88 49 -153 102 -230 79 -113 186 -182 331
|
||||
-214 108 -24 141 -24 247 1 130 30 202 72 316 181 102 100 153 227 152 384 0
|
||||
142 -58 293 -150 395 -60 67 -180 145 -261 171 -75 23 -232 34 -297 19z m340
|
||||
-214 c91 -43 174 -154 175 -234 0 -18 -9 -51 -21 -73 -19 -37 -19 -42 -5 -64
|
||||
35 -54 12 -121 -48 -142 -22 -7 -47 -19 -55 -27 -9 -8 -41 -27 -71 -42 -50
|
||||
-26 -64 -29 -155 -29 -111 0 -152 14 -206 68 -49 49 -63 85 -64 162 0 59 4 78
|
||||
28 118 31 52 96 105 141 114 23 5 33 17 56 68 46 103 121 130 225 81z"/>
|
||||
<path d="M3985 3464 c-44 -7 -154 -44 -200 -67 -55 -28 -138 -96 -162 -132
|
||||
-10 -16 -39 -75 -64 -130 l-44 -100 0 -160 0 -160 45 -90 c53 -108 152 -214
|
||||
245 -264 59 -31 215 -71 281 -71 53 0 206 40 255 67 98 53 203 161 247 253 53
|
||||
113 74 193 74 280 -1 304 -253 564 -557 575 -49 2 -103 1 -120 -1z m311 -220
|
||||
c129 -68 202 -209 160 -309 -15 -35 -15 -42 -1 -72 26 -55 -3 -118 -59 -129
|
||||
-19 -3 -43 -15 -53 -26 -26 -29 -99 -64 -165 -78 -45 -10 -69 -10 -120 -1 -74
|
||||
15 -113 37 -161 91 -110 120 -50 331 109 385 24 8 44 23 52 39 6 14 18 38 25
|
||||
53 33 72 127 93 213 47z"/>
|
||||
<path d="M487 3394 c-21 -12 -27 -21 -25 -40 2 -14 7 -26 12 -27 14 -3 48 48
|
||||
44 66 -3 14 -6 14 -31 1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 705 KiB |
17
android/app/src/main/assets/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>TimeSafari</title>
|
||||
<script type="module" crossorigin src="/assets/index-CI0bMoT0.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but TimeSafari doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
Model Information:
|
||||
* title: Lupine Plant
|
||||
* source: https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439
|
||||
* author: rufusrockwell (https://sketchfab.com/rufusrockwell)
|
||||
|
||||
Model License:
|
||||
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
* requirements: Author must be credited. Commercial use is allowed.
|
||||
|
||||
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||
This work is based on "Lupine Plant" (https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439) by rufusrockwell (https://sketchfab.com/rufusrockwell) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
BIN
android/app/src/main/assets/public/models/lupine_plant/scene.bin
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 2,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
41.3074951171875,
|
||||
40.37548828125,
|
||||
87.85917663574219
|
||||
],
|
||||
"min": [
|
||||
-35.245540618896484,
|
||||
-36.895416259765625,
|
||||
-0.9094290137290955
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 33108,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9999382495880127,
|
||||
0.9986748695373535,
|
||||
0.9985831379890442
|
||||
],
|
||||
"min": [
|
||||
-0.9998949766159058,
|
||||
-0.9975876212120056,
|
||||
-0.411094069480896
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9987699389457703,
|
||||
0.9998998045921326,
|
||||
0.9577858448028564,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-0.9987726807594299,
|
||||
-0.9990445971488953,
|
||||
-0.999801516532898,
|
||||
1.0
|
||||
],
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
1.0061479806900024,
|
||||
0.9993550181388855
|
||||
],
|
||||
"min": [
|
||||
0.00279300007969141,
|
||||
0.0011620000004768372
|
||||
],
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5125,
|
||||
"count": 6378,
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"extras": {
|
||||
"author": "rufusrockwell (https://sketchfab.com/rufusrockwell)",
|
||||
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
|
||||
"source": "https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439",
|
||||
"title": "Lupine Plant"
|
||||
},
|
||||
"generator": "Sketchfab-12.68.0",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 25512,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 22072,
|
||||
"byteOffset": 25512,
|
||||
"byteStride": 8,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 66216,
|
||||
"byteOffset": 47584,
|
||||
"byteStride": 12,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 44144,
|
||||
"byteOffset": 113800,
|
||||
"byteStride": 16,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 157944,
|
||||
"uri": "scene.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "textures/lambert2SG_baseColor.png"
|
||||
},
|
||||
{
|
||||
"uri": "textures/lambert2SG_normal.png"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"alphaCutoff": 0.2,
|
||||
"alphaMode": "MASK",
|
||||
"doubleSided": true,
|
||||
"name": "lambert2SG",
|
||||
"normalTexture": {
|
||||
"index": 1
|
||||
},
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"name": "Object_0",
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 0,
|
||||
"TANGENT": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 4,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
2.220446049250313e-16,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
2.220446049250313e-16,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "Sketchfab_model"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
2
|
||||
],
|
||||
"name": "LupineSF.obj.cleaner.materialmerger.gles"
|
||||
},
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": "Object_2"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9987,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"name": "Sketchfab_Scene",
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 4.7 MiB |
2
android/app/src/main/assets/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
6
android/app/src/main/res/xml/config.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<access origin="*" />
|
||||
|
||||
|
||||
</widget>
|
||||
@@ -7,8 +7,9 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.8.1'
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
classpath 'com.google.gms:google-services:4.4.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
@@ -27,3 +28,10 @@ allprojects {
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib:1.8.0'
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0'
|
||||
}
|
||||
}
|
||||
|
||||
7
android/capacitor-android/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
||||
android {
|
||||
lintOptions {
|
||||
disable 'UnsanitizedFilenameFromContentProvider'
|
||||
abortOnError false
|
||||
baseline file("lint-baseline.xml")
|
||||
}
|
||||
}
|
||||
59
android/capacitor-cordova-android-plugins/build.gradle
Normal file
@@ -0,0 +1,59 @@
|
||||
ext {
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
|
||||
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '10.1.1'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace "capacitor.cordova.android.plugins"
|
||||
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
|
||||
defaultConfig {
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
flatDir{
|
||||
dirs 'src/main/libs', 'libs'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'src/main/libs', include: ['*.jar'])
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
|
||||
// SUB-PROJECT DEPENDENCIES START
|
||||
|
||||
// SUB-PROJECT DEPENDENCIES END
|
||||
}
|
||||
|
||||
// PLUGIN GRADLE EXTENSIONS START
|
||||
apply from: "cordova.variables.gradle"
|
||||
// PLUGIN GRADLE EXTENSIONS END
|
||||
|
||||
for (def func : cdvPluginPostBuildExtras) {
|
||||
func()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
ext {
|
||||
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
|
||||
// Plugin gradle extensions can append to this to have code run at the end.
|
||||
cdvPluginPostBuildExtras = []
|
||||
cordovaConfig = [:]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:amazon="http://schemas.amazon.com/apk/res/android">
|
||||
<application android:usesCleartextTraffic="true">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
2
android/fastlane/Appfile
Normal file
@@ -0,0 +1,2 @@
|
||||
json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
|
||||
package_name("app.timesafari.app") # e.g. com.krausefx.app
|
||||
38
android/fastlane/Fastfile
Normal file
@@ -0,0 +1,38 @@
|
||||
# This file contains the fastlane.tools configuration
|
||||
# You can find the documentation at https://docs.fastlane.tools
|
||||
#
|
||||
# For a list of all available actions, check out
|
||||
#
|
||||
# https://docs.fastlane.tools/actions
|
||||
#
|
||||
# For a list of all available plugins, check out
|
||||
#
|
||||
# https://docs.fastlane.tools/plugins/available-plugins
|
||||
#
|
||||
|
||||
# Uncomment the line if you want fastlane to automatically update itself
|
||||
# update_fastlane
|
||||
|
||||
default_platform(:android)
|
||||
|
||||
platform :android do
|
||||
desc "Build and deploy Android app"
|
||||
lane :beta do
|
||||
gradle(
|
||||
task: "clean assembleRelease"
|
||||
)
|
||||
upload_to_play_store(
|
||||
track: 'beta',
|
||||
aab: '../app/build/outputs/bundle/release/app-release.aab'
|
||||
)
|
||||
end
|
||||
|
||||
lane :release do
|
||||
gradle(
|
||||
task: "clean assembleRelease"
|
||||
)
|
||||
upload_to_play_store(
|
||||
aab: '../app/build/outputs/bundle/release/app-release.aab'
|
||||
)
|
||||
end
|
||||
end
|
||||
40
android/fastlane/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
fastlane documentation
|
||||
----
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
## Android
|
||||
|
||||
### android beta
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android beta
|
||||
```
|
||||
|
||||
Build and deploy Android app
|
||||
|
||||
### android release
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android release
|
||||
```
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
@@ -20,3 +20,6 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
|
||||
8
android/local.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
## This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
#
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Sun Mar 09 06:14:41 UTC 2025
|
||||
sdk.dir=/opt/android-sdk
|
||||
13
ios/.gitignore
vendored
@@ -1,13 +0,0 @@
|
||||
App/build
|
||||
App/Pods
|
||||
App/output
|
||||
App/App/public
|
||||
DerivedData
|
||||
xcuserdata
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-ios-plugins
|
||||
|
||||
# Generated Config files
|
||||
App/App/capacitor.config.json
|
||||
App/App/config.xml
|
||||
@@ -1,408 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
|
||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
504EC3011FED79650016851F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC2FB1FED79650016851F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
504EC3061FED79650016851F /* App */,
|
||||
504EC3051FED79650016851F /* Products */,
|
||||
7F8756D8B27F46E3366F6CEA /* Pods */,
|
||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3051FED79650016851F /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
504EC3041FED79650016851F /* App.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3061FED79650016851F /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */,
|
||||
504EC30B1FED79650016851F /* Main.storyboard */,
|
||||
504EC30E1FED79650016851F /* Assets.xcassets */,
|
||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
||||
504EC3131FED79650016851F /* Info.plist */,
|
||||
2FAD9762203C412B000D30F8 /* config.xml */,
|
||||
50B271D01FEDC1A000F3C39B /* public */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7F8756D8B27F46E3366F6CEA /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
|
||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
504EC3031FED79650016851F /* App */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
|
||||
buildPhases = (
|
||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
|
||||
504EC3001FED79650016851F /* Sources */,
|
||||
504EC3011FED79650016851F /* Frameworks */,
|
||||
504EC3021FED79650016851F /* Resources */,
|
||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = App;
|
||||
productName = App;
|
||||
productReference = 504EC3041FED79650016851F /* App.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
504EC2FC1FED79650016851F /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 0920;
|
||||
TargetAttributes = {
|
||||
504EC3031FED79650016851F = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 504EC2FB1FED79650016851F;
|
||||
packageReferences = (
|
||||
);
|
||||
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
504EC3031FED79650016851F /* App */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
504EC3021FED79650016851F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
504EC3001FED79650016851F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
504EC30B1FED79650016851F /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
504EC30C1FED79650016851F /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
504EC3111FED79650016851F /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
504EC3141FED79650016851F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
504EC3151FED79650016851F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
504EC3171FED79650016851F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
504EC3181FED79650016851F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
504EC3141FED79650016851F /* Debug */,
|
||||
504EC3151FED79650016851F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
504EC3171FED79650016851F /* Debug */,
|
||||
504EC3181FED79650016851F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 504EC2FC1FED79650016851F /* Project object */;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,49 +0,0 @@
|
||||
import UIKit
|
||||
import Capacitor
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// 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.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// 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.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
// Called when the app was launched with a url. Feel free to add additional processing here,
|
||||
// but if you want the App API to support tracking app url opens, make sure to keep this call
|
||||
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
// Called when the app was launched with an activity, including Universal Links.
|
||||
// Feel free to add additional processing here, but if you want the App API to support
|
||||
// tracking app url opens, make sure to keep this call
|
||||
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 108 KiB |
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-2.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</imageView>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Splash" width="1366" height="1366"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Bridge View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>TimeSafari</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>timesafari</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,24 +0,0 @@
|
||||
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
|
||||
|
||||
platform :ios, '13.0'
|
||||
use_frameworks!
|
||||
|
||||
# workaround to avoid Xcode caching of Pods that requires
|
||||
# Product -> Clean Build Folder after new Cordova plugins installed
|
||||
# Requires CocoaPods 1.6 or newer
|
||||
install! 'cocoapods', :disable_input_output_paths => true
|
||||
|
||||
def capacitor_pods
|
||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
|
||||
end
|
||||
|
||||
target 'App' do
|
||||
capacitor_pods
|
||||
# Add your Pods here
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
assertDeploymentTarget(installer)
|
||||
end
|
||||
2020
package-lock.json
generated
25
package.json
@@ -8,12 +8,19 @@
|
||||
"scripts": {
|
||||
"dev": "vite --config vite.config.dev.mts",
|
||||
"serve": "vite preview",
|
||||
"build": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build",
|
||||
"build": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.mts",
|
||||
"lint": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src",
|
||||
"lint-fix": "eslint --ext .js,.ts,.vue --ignore-path .gitignore --fix src",
|
||||
"prebuild": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src && node sw_combine.js",
|
||||
"test-local": "npx playwright test -c playwright.config-local.ts --trace on",
|
||||
"test-all": "npm run build && npx playwright test -c playwright.config-local.ts --trace on",
|
||||
"test-all": "npm run test:prerequisites && npm run build && npm run test:web && npm run test:mobile",
|
||||
"test:prerequisites": "node scripts/check-prerequisites.js",
|
||||
"test:web": "npx playwright test -c playwright.config-local.ts --trace on",
|
||||
"test:mobile": "npm run build:capacitor && npm run test:android && npm run test:ios",
|
||||
"test:android": "node scripts/test-android.js",
|
||||
"test:ios": "node scripts/test-ios.js",
|
||||
"check:android-device": "adb devices | grep -w 'device' || (echo 'No Android device connected' && exit 1)",
|
||||
"check:ios-device": "xcrun xctrace list devices 2>&1 | grep -w 'Booted' || (echo 'No iOS simulator running' && exit 1)",
|
||||
"clean:electron": "rimraf dist-electron",
|
||||
"build:pywebview": "vite build --config vite.config.pywebview.mts",
|
||||
"build:electron": "npm run clean:electron && vite build --config vite.config.electron.mts && node scripts/build-electron.js",
|
||||
@@ -29,7 +36,11 @@
|
||||
"pywebview:build": "vite build --config vite.config.pywebview.mts && .venv/bin/python src/pywebview/main.py",
|
||||
"pywebview:package-linux": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py",
|
||||
"pywebview:package-win": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/Scripts/python -m PyInstaller --name TimeSafari --add-data 'dist;www' src/pywebview/main.py",
|
||||
"pywebview:package-mac": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py"
|
||||
"pywebview:package-mac": "vite build --mode pywebview --config vite.config.pywebview.mts && .venv/bin/python -m PyInstaller --name TimeSafari --add-data 'dist:www' src/pywebview/main.py",
|
||||
"fastlane:ios:beta": "cd ios && fastlane beta",
|
||||
"fastlane:ios:release": "cd ios && fastlane release",
|
||||
"fastlane:android:beta": "cd android && fastlane beta",
|
||||
"fastlane:android:release": "cd android && fastlane release"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/android": "^6.2.0",
|
||||
@@ -40,6 +51,7 @@
|
||||
"@dicebear/collection": "^5.4.1",
|
||||
"@dicebear/core": "^5.4.1",
|
||||
"@ethersproject/hdnode": "^5.7.0",
|
||||
"@ethersproject/wallet": "^5.8.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.6",
|
||||
@@ -69,6 +81,7 @@
|
||||
"dexie-export-import": "^4.1.4",
|
||||
"did-jwt": "^7.4.7",
|
||||
"did-resolver": "^4.1.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"ethereum-cryptography": "^2.1.3",
|
||||
"ethereumjs-util": "^7.1.5",
|
||||
"jdenticon": "^3.2.0",
|
||||
@@ -91,6 +104,7 @@
|
||||
"reflect-metadata": "^0.1.14",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"simple-vue-camera": "^1.1.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"three": "^0.156.1",
|
||||
"ua-parser-js": "^1.0.37",
|
||||
@@ -105,11 +119,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.45.2",
|
||||
"@types/dom-webcodecs": "^0.1.7",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/leaflet": "^1.9.8",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.14.11",
|
||||
"@types/node-fetch": "^2.6.12",
|
||||
"@types/ramda": "^0.29.11",
|
||||
"@types/sqlite3": "^3.1.11",
|
||||
"@types/three": "^0.155.1",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
@@ -138,7 +155,7 @@
|
||||
},
|
||||
"main": "./dist-electron/main.js",
|
||||
"build": {
|
||||
"appId": "org.timesafari.app",
|
||||
"appId": "app.timesafari",
|
||||
"productName": "TimeSafari",
|
||||
"directories": {
|
||||
"output": "dist-electron-packages"
|
||||
|
||||
5
pkgx.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
- gradle
|
||||
- java
|
||||
|
||||
# other dependencies are discovered via package.json & requirements.txt & Gemfile (I'm guessing).
|
||||
@@ -75,11 +75,6 @@ export default defineConfig({
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: "webkit",
|
||||
use: { ...devices["Desktop Safari"] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
|
||||
{
|
||||
@@ -104,8 +99,9 @@ export default defineConfig({
|
||||
],
|
||||
|
||||
/* Configure global timeout; default is 30000 milliseconds */
|
||||
// the image upload will often not succeed at 5 seconds
|
||||
timeout: 30000, // various tests fail at various times with 25000
|
||||
// the image upload will often not succeed in 5 seconds
|
||||
// 33-record-gift-x10.spec.ts:90:5 > Record 9 new gifts will often not succeed in 30 seconds
|
||||
timeout: 35000, // various tests fail at various times with 25000
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
eth_keys
|
||||
pywebview
|
||||
pyinstaller>=6.12.0
|
||||
# For development
|
||||
|
||||
185
scripts/check-prerequisites.js
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @fileoverview Prerequisites checker for mobile development environment
|
||||
*
|
||||
* This script verifies that all necessary tools and configurations are in place
|
||||
* for mobile app development, including both Android and iOS platforms.
|
||||
*
|
||||
* Features:
|
||||
* - Validates development environment setup
|
||||
* - Checks required command-line tools
|
||||
* - Verifies Android SDK and device connectivity
|
||||
* - Confirms iOS development tools and simulator status
|
||||
*
|
||||
* Prerequisites checked:
|
||||
* - Node.js and npm installation
|
||||
* - Gradle for Android builds
|
||||
* - Xcode and command line tools for iOS
|
||||
* - ANDROID_HOME environment variable
|
||||
* - Android platform files
|
||||
* - Connected Android devices/emulators
|
||||
* - iOS platform files
|
||||
* - Running iOS simulators
|
||||
*
|
||||
* Exit codes:
|
||||
* - 0: All checks passed
|
||||
* - 1: One or more checks failed
|
||||
*
|
||||
* @example
|
||||
* // Run directly
|
||||
* node scripts/check-prerequisites.js
|
||||
*
|
||||
* // Run via npm script
|
||||
* npm run test:prerequisites
|
||||
*
|
||||
* @author TimeSafari Team
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { existsSync } = require('fs');
|
||||
|
||||
/**
|
||||
* Checks if a command-line tool is available by attempting to run its --version command
|
||||
*
|
||||
* @param {string} command - The command to check (e.g., 'node', 'npm', 'gradle')
|
||||
* @param {string} errorMessage - The error message to display if the command is not available
|
||||
* @returns {boolean} - True if the command exists and is executable, false otherwise
|
||||
*
|
||||
* @example
|
||||
* checkCommand('node', 'Node.js is required')
|
||||
* // Returns true if node is available, false otherwise
|
||||
*/
|
||||
function checkCommand(command, errorMessage) {
|
||||
try {
|
||||
execSync(command + ' --version', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`❌ ${errorMessage}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies Android development environment setup
|
||||
*
|
||||
* Checks for:
|
||||
* 1. ANDROID_HOME environment variable
|
||||
* 2. Android platform files in project
|
||||
* 3. Connected Android devices or running emulators
|
||||
*
|
||||
* @returns {boolean} - True if Android setup is complete and valid, false otherwise
|
||||
*
|
||||
* @example
|
||||
* if (!checkAndroidSetup()) {
|
||||
* console.error('Android prerequisites not met');
|
||||
* }
|
||||
*/
|
||||
function checkAndroidSetup() {
|
||||
// Check ANDROID_HOME environment variable
|
||||
// This is required for Android SDK tools access
|
||||
if (!process.env.ANDROID_HOME) {
|
||||
console.error('❌ ANDROID_HOME environment variable not set');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if Android platform was added to the project
|
||||
// The 'android' directory should exist if platform was added via 'npx cap add android'
|
||||
if (!existsSync('android')) {
|
||||
console.error('❌ Android platform not added. Run: npx cap add android');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for connected devices or running emulators
|
||||
// Uses ADB (Android Debug Bridge) to list connected devices
|
||||
try {
|
||||
const devices = execSync('adb devices').toString();
|
||||
// Parse ADB output - looking for lines ending with 'device' (not 'offline' or 'unauthorized')
|
||||
if (!devices.split('\n').slice(1).some(line => line.includes('device'))) {
|
||||
console.error('❌ No Android devices connected');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('❌ ADB not available');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies iOS development environment setup
|
||||
*
|
||||
* Checks for:
|
||||
* 1. iOS platform files in project
|
||||
* 2. Running iOS simulators
|
||||
* 3. Xcode command line tools availability
|
||||
*
|
||||
* @returns {boolean} - True if iOS setup is complete and valid, false otherwise
|
||||
*
|
||||
* @example
|
||||
* if (!checkIosSetup()) {
|
||||
* console.error('iOS prerequisites not met');
|
||||
* }
|
||||
*/
|
||||
function checkIosSetup() {
|
||||
// Check if iOS platform was added to the project
|
||||
// The 'ios' directory should exist if platform was added via 'npx cap add ios'
|
||||
if (!existsSync('ios')) {
|
||||
console.error('❌ iOS platform not added. Run: npx cap add ios');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for available and running iOS simulators
|
||||
// Uses xcrun simctl to list simulator devices
|
||||
try {
|
||||
const simulators = execSync('xcrun simctl list devices available').toString();
|
||||
if (!simulators.includes('Booted')) {
|
||||
console.error('❌ No iOS simulator running');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('❌ Xcode command line tools not available');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function to check all prerequisites for mobile development
|
||||
*
|
||||
* Verifies:
|
||||
* 1. Required command line tools (node, npm, gradle, xcodebuild)
|
||||
* 2. Android development setup
|
||||
* 3. iOS development setup
|
||||
*
|
||||
* Exits with code 1 if any checks fail
|
||||
*
|
||||
* @example
|
||||
* // Run from package.json script:
|
||||
* // "test:prerequisites": "node scripts/check-prerequisites.js"
|
||||
*/
|
||||
function main() {
|
||||
let success = true;
|
||||
|
||||
// Check required command line tools
|
||||
// These are essential for building and testing the application
|
||||
success &= checkCommand('node', 'Node.js is required');
|
||||
success &= checkCommand('npm', 'npm is required');
|
||||
success &= checkCommand('gradle', 'Gradle is required for Android builds');
|
||||
success &= checkCommand('xcodebuild', 'Xcode is required for iOS builds');
|
||||
|
||||
// Check platform-specific development environments
|
||||
success &= checkAndroidSetup();
|
||||
success &= checkIosSetup();
|
||||
|
||||
// Exit with error if any checks failed
|
||||
if (!success) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✅ All prerequisites met!');
|
||||
}
|
||||
|
||||
// Execute the checks
|
||||
main();
|
||||
132
scripts/run-available-mobile-tests.js
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @fileoverview Runs mobile tests based on available platforms and devices
|
||||
*
|
||||
* This script intelligently detects available mobile platforms and their
|
||||
* associated devices/simulators, then runs tests only for the available
|
||||
* configurations. This allows for flexible testing across different
|
||||
* development environments without failing when a platform is unavailable.
|
||||
*
|
||||
* Platform detection:
|
||||
* - Android: Checks for SDK and connected devices/emulators
|
||||
* - iOS: Checks for macOS, Xcode, and running simulators
|
||||
*
|
||||
* Features:
|
||||
* - Smart platform detection
|
||||
* - Graceful handling of unavailable platforms
|
||||
* - Clear logging of test execution
|
||||
* - Comprehensive error reporting
|
||||
*
|
||||
* Exit codes:
|
||||
* - 0: Tests completed successfully on available platforms
|
||||
* - 1: Tests failed or no platforms available
|
||||
*
|
||||
* @example
|
||||
* // Run directly
|
||||
* node scripts/run-available-mobile-tests.js
|
||||
*
|
||||
* // Run via npm script
|
||||
* npm run test:mobile:available
|
||||
*
|
||||
* @requires child_process
|
||||
* @requires fs
|
||||
*
|
||||
* @author TimeSafari Team
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { existsSync } = require('fs');
|
||||
|
||||
/**
|
||||
* Executes mobile tests on available platforms
|
||||
*
|
||||
* This function performs the following steps:
|
||||
* 1. Checks Android environment and device availability
|
||||
* 2. Checks iOS environment and simulator availability (on macOS)
|
||||
* 3. Runs tests on available platforms
|
||||
* 4. Reports results and handles errors
|
||||
*
|
||||
* Platform-specific checks:
|
||||
* Android:
|
||||
* - ANDROID_HOME environment variable
|
||||
* - Android platform files existence
|
||||
* - Connected devices via ADB
|
||||
*
|
||||
* iOS:
|
||||
* - macOS operating system
|
||||
* - iOS platform files existence
|
||||
* - Running simulators via xcrun
|
||||
*
|
||||
* @async
|
||||
* @throws {Error} If tests fail or no platforms are available
|
||||
*
|
||||
* @example
|
||||
* runAvailableMobileTests().catch(error => {
|
||||
* console.error('Test execution failed:', error);
|
||||
* process.exit(1);
|
||||
* });
|
||||
*/
|
||||
async function runAvailableMobileTests() {
|
||||
try {
|
||||
// Check Android availability
|
||||
// Requires both SDK (ANDROID_HOME) and platform files
|
||||
const androidAvailable = existsSync('android') && process.env.ANDROID_HOME;
|
||||
let androidDeviceAvailable = false;
|
||||
|
||||
if (androidAvailable) {
|
||||
try {
|
||||
// Check for connected devices using ADB
|
||||
const devices = execSync('adb devices').toString();
|
||||
// Parse ADB output for actually connected devices
|
||||
// Filters out unauthorized or offline devices
|
||||
androidDeviceAvailable = devices.split('\n').slice(1).some(line => line.includes('device'));
|
||||
} catch (e) {
|
||||
console.log('⚠️ Android SDK available but no devices connected');
|
||||
}
|
||||
}
|
||||
|
||||
// Check iOS availability
|
||||
// Only possible on macOS with Xcode installed
|
||||
const iosAvailable = process.platform === 'darwin' && existsSync('ios');
|
||||
let iosSimulatorAvailable = false;
|
||||
|
||||
if (iosAvailable) {
|
||||
try {
|
||||
// Check for running simulators using xcrun
|
||||
const simulators = execSync('xcrun simctl list devices available').toString();
|
||||
// Look for 'Booted' state in simulator list
|
||||
iosSimulatorAvailable = simulators.includes('Booted');
|
||||
} catch (e) {
|
||||
console.log('⚠️ iOS platform available but no simulator running');
|
||||
}
|
||||
}
|
||||
|
||||
// Execute tests for available platforms
|
||||
if (androidDeviceAvailable) {
|
||||
console.log('🤖 Running Android tests...');
|
||||
// Run Android tests via npm script
|
||||
execSync('npm run test:android', { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
if (iosSimulatorAvailable) {
|
||||
console.log('🍎 Running iOS tests...');
|
||||
// Run iOS tests via npm script
|
||||
execSync('npm run test:ios', { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
// Error if no platforms are available for testing
|
||||
if (!androidDeviceAvailable && !iosSimulatorAvailable) {
|
||||
console.error('❌ No mobile platforms available for testing');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✅ Available mobile tests completed successfully');
|
||||
} catch (error) {
|
||||
// Handle any errors during test execution
|
||||
console.error('❌ Mobile tests failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the test runner
|
||||
runAvailableMobileTests();
|
||||
299
scripts/test-android.js
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* @fileoverview Android test runner for Capacitor-based mobile app
|
||||
*
|
||||
* This script handles the build, installation, and testing of the Android app.
|
||||
* It ensures the app is properly synced, built, installed on a device/emulator,
|
||||
* and runs the test suite.
|
||||
*
|
||||
* Process flow:
|
||||
* 1. Sync Capacitor project with latest web build
|
||||
* 2. Build debug APK
|
||||
* 3. Install APK on connected device/emulator
|
||||
* 4. Run instrumented tests
|
||||
*
|
||||
* Prerequisites:
|
||||
* - Android SDK installed and ANDROID_HOME set
|
||||
* - Gradle installed and in PATH
|
||||
* - Connected Android device or running emulator
|
||||
* - Capacitor Android platform added to project
|
||||
*
|
||||
* Exit codes:
|
||||
* - 0: Tests completed successfully
|
||||
* - 1: Build, installation, or test failure
|
||||
*
|
||||
* @example
|
||||
* // Run directly
|
||||
* node scripts/test-android.js
|
||||
*
|
||||
* // Run via npm script
|
||||
* npm run test:android
|
||||
*
|
||||
* @requires child_process
|
||||
* @requires path
|
||||
*
|
||||
* @author TimeSafari Team
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { join } = require('path');
|
||||
const { existsSync, mkdirSync, appendFileSync, readFileSync } = require('fs');
|
||||
|
||||
// Format date as YYYY-MM-DD-HHMMSS
|
||||
const getLogFileName = () => {
|
||||
const now = new Date();
|
||||
const date = now.toISOString().split('T')[0];
|
||||
const time = now.toTimeString().split(' ')[0].replace(/:/g, '');
|
||||
return `build_logs/android-build-${date}-${time}.log`;
|
||||
};
|
||||
|
||||
// Create logger function
|
||||
const createLogger = (logFile) => {
|
||||
return (message) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `[${timestamp}] ${message}\n`;
|
||||
console.log(message);
|
||||
appendFileSync(logFile, logMessage);
|
||||
};
|
||||
};
|
||||
|
||||
// Check for connected Android devices
|
||||
const checkConnectedDevices = async (log) => {
|
||||
log('🔍 Checking for Android devices...');
|
||||
const devices = execSync('adb devices').toString();
|
||||
const connectedDevices = devices.split('\n')
|
||||
.slice(1)
|
||||
.filter(line => line.includes('device'))
|
||||
.map(line => line.split('\t')[0])
|
||||
.filter(Boolean);
|
||||
|
||||
if (connectedDevices.length === 0) {
|
||||
throw new Error('No Android devices or emulators connected. Please connect a device or start an emulator.');
|
||||
}
|
||||
|
||||
log(`📱 Found ${connectedDevices.length} device(s): ${connectedDevices.join(', ')}`);
|
||||
return connectedDevices;
|
||||
};
|
||||
|
||||
// Verify Java installation
|
||||
const verifyJavaInstallation = (log) => {
|
||||
log('🔍 Checking Java...');
|
||||
const javaHome = process.env.JAVA_HOME;
|
||||
if (!existsSync(javaHome)) {
|
||||
throw new Error(`Required Java not found at ${javaHome}. Please install OpenJDK.`);
|
||||
}
|
||||
log('✅ Java found');
|
||||
};
|
||||
|
||||
// Generate test data using generate_data.ts
|
||||
const generateTestData = async (log) => {
|
||||
log('🔄 Generating test data...');
|
||||
try {
|
||||
execSync('npx ts-node test-scripts/generate_data.ts', { stdio: 'inherit' });
|
||||
log('✅ Test data generated successfully');
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to generate test data: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Parse shell environment file
|
||||
const parseEnvFile = (filePath) => {
|
||||
const content = readFileSync(filePath, 'utf8');
|
||||
const env = {};
|
||||
content.split('\n').forEach(line => {
|
||||
const match = line.match(/^export\s+(\w+)="(.+)"$/);
|
||||
if (match) {
|
||||
env[match[1]] = match[2];
|
||||
}
|
||||
});
|
||||
return env;
|
||||
};
|
||||
|
||||
// Run individual deeplink test
|
||||
const executeDeeplink = async (url, description, log) => {
|
||||
log(`\n🔗 Testing deeplink: ${description}`);
|
||||
log(`URL: ${url}`);
|
||||
|
||||
try {
|
||||
// Stop the app before executing the deep link
|
||||
execSync('adb shell am force-stop app.timesafari.app');
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1s
|
||||
|
||||
execSync(`adb shell am start -W -a android.intent.action.VIEW -d "${url}" -c android.intent.category.BROWSABLE`);
|
||||
log(`✅ Successfully executed: ${description}`);
|
||||
|
||||
// Wait between deeplink tests
|
||||
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
|
||||
} catch (error) {
|
||||
log(`❌ Failed to execute deeplink: ${description}`);
|
||||
log(`Error: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Run all deeplink tests
|
||||
const runDeeplinkTests = async (log) => {
|
||||
log('🔗 Starting deeplink tests...');
|
||||
|
||||
try {
|
||||
// Load test data
|
||||
const testEnv = parseEnvFile('.generated/test-env.sh');
|
||||
const claimDetails = JSON.parse(readFileSync('.generated/claim_details.json', 'utf8'));
|
||||
const contacts = JSON.parse(readFileSync('.generated/contacts.json', 'utf8'));
|
||||
|
||||
// Test each deeplink
|
||||
const deeplinkTests = [
|
||||
{
|
||||
url: `timesafari://claim/${claimDetails.claim_id}`,
|
||||
description: 'Claim view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-cert/${claimDetails.claim_id}`,
|
||||
description: 'Claim certificate view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-add-raw/${claimDetails.claim_id}`,
|
||||
description: 'Raw claim addition'
|
||||
},
|
||||
{
|
||||
url: 'timesafari://did/test',
|
||||
description: 'DID view with test identifier'
|
||||
},
|
||||
{
|
||||
url: `timesafari://did/${testEnv.CONTACT1_DID}`,
|
||||
description: 'DID view with contact DID'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contact-edit/${testEnv.CONTACT1_DID}`,
|
||||
description: 'Contact editing'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contacts/import?contacts=${encodeURIComponent(JSON.stringify(contacts))}`,
|
||||
description: 'Contacts import'
|
||||
}
|
||||
];
|
||||
|
||||
// Execute each test
|
||||
for (const test of deeplinkTests) {
|
||||
await executeDeeplink(test.url, test.description, log);
|
||||
}
|
||||
|
||||
let succeeded = true;
|
||||
try {
|
||||
await executeDeeplink('timesafari://contactJunk', 'Non-existent deeplink', log);
|
||||
} catch (error) {
|
||||
log('✅ Non-existent deeplink failed as expected');
|
||||
succeeded = false;
|
||||
} finally {
|
||||
if (succeeded) {
|
||||
throw new Error('Non-existent deeplink should have failed');
|
||||
}
|
||||
}
|
||||
|
||||
log('✅ All deeplink tests completed successfully');
|
||||
} catch (error) {
|
||||
log('❌ Deeplink tests failed');
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Build web assets
|
||||
const buildWebAssets = async (log) => {
|
||||
log('🌐 Building web assets...');
|
||||
execSync('rm -rf dist', { stdio: 'inherit' });
|
||||
execSync('npm run build:web', { stdio: 'inherit' });
|
||||
execSync('npm run build:capacitor', { stdio: 'inherit' });
|
||||
log('✅ Web assets built successfully');
|
||||
};
|
||||
|
||||
// Configure Android project
|
||||
const configureAndroidProject = async (log) => {
|
||||
log('📱 Syncing Capacitor project...');
|
||||
execSync('npx cap sync android', { stdio: 'inherit' });
|
||||
log('✅ Capacitor sync completed');
|
||||
|
||||
log('⚙️ Configuring Gradle properties...');
|
||||
const gradleProps = 'android/gradle.properties';
|
||||
if (!existsSync(gradleProps) || !execSync(`grep -q "android.suppressUnsupportedCompileSdk=34" ${gradleProps}`)) {
|
||||
execSync('echo "android.suppressUnsupportedCompileSdk=34" >> android/gradle.properties');
|
||||
log('✅ Added SDK suppression to gradle.properties');
|
||||
}
|
||||
};
|
||||
|
||||
// Build and test Android project
|
||||
const buildAndTestAndroid = async (log, env) => {
|
||||
log('🏗️ Building Android project...');
|
||||
execSync('cd android && ./gradlew clean', { stdio: 'inherit', env });
|
||||
log('✅ Gradle clean completed');
|
||||
|
||||
execSync('cd android && ./gradlew build', { stdio: 'inherit', env });
|
||||
log('✅ Gradle build completed');
|
||||
|
||||
log('🧪 Running Android tests...');
|
||||
execSync('cd android && ./gradlew connectedAndroidTest', { stdio: 'inherit', env });
|
||||
log('✅ Android tests completed');
|
||||
};
|
||||
|
||||
// Run the app
|
||||
const runAndroidApp = async (log, env) => {
|
||||
log('📱 Running app on device...');
|
||||
execSync('npx cap run android', { stdio: 'inherit', env });
|
||||
log('✅ App launched successfully');
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs the complete Android test suite including build, installation, and testing
|
||||
*
|
||||
* The function performs the following steps:
|
||||
* 1. Checks for connected devices/emulators
|
||||
* 2. Ensures correct Java version is used
|
||||
* 3. Checks if app is already installed
|
||||
* 4. Syncs the Capacitor project with latest build
|
||||
* 5. Builds and runs instrumented Android tests
|
||||
*
|
||||
* @async
|
||||
* @throws {Error} If any step in the build or test process fails
|
||||
*
|
||||
* @example
|
||||
* runAndroidTests().catch(error => {
|
||||
* console.error('Test execution failed:', error);
|
||||
* process.exit(1);
|
||||
* });
|
||||
*/
|
||||
async function runAndroidTests() {
|
||||
// Create build_logs directory if it doesn't exist
|
||||
if (!existsSync('build_logs')) {
|
||||
mkdirSync('build_logs');
|
||||
}
|
||||
|
||||
const logFile = getLogFileName();
|
||||
const log = createLogger(logFile);
|
||||
|
||||
try {
|
||||
log('🚀 Starting Android build and test process...');
|
||||
|
||||
// Generate test data first
|
||||
await generateTestData(log);
|
||||
|
||||
await checkConnectedDevices(log);
|
||||
await verifyJavaInstallation(log);
|
||||
await buildWebAssets(log);
|
||||
await configureAndroidProject(log);
|
||||
const env = process.env;
|
||||
await buildAndTestAndroid(log, env);
|
||||
await runAndroidApp(log, env);
|
||||
|
||||
// Run deeplink tests after app is installed
|
||||
await runDeeplinkTests(log);
|
||||
|
||||
log('🎉 Android build and test process completed successfully');
|
||||
log(`📝 Full build log available at: ${logFile}`);
|
||||
} catch (error) {
|
||||
log(`❌ Android tests failed: ${error.message}`);
|
||||
log(`📝 Check build log for details: ${logFile}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the test suite
|
||||
runAndroidTests();
|
||||
652
scripts/test-ios.js
Normal file
@@ -0,0 +1,652 @@
|
||||
/**
|
||||
* @fileoverview iOS test runner for Capacitor-based mobile app
|
||||
*
|
||||
* This script handles the build and testing of the iOS app using Xcode's
|
||||
* command-line tools. It ensures the app is properly synced with the latest
|
||||
* web build and runs the test suite on a specified iOS simulator.
|
||||
*
|
||||
* Process flow:
|
||||
* 1. Sync Capacitor project with latest web build
|
||||
* 2. Build app for iOS simulator
|
||||
* 3. Run XCTest suite
|
||||
*
|
||||
* Prerequisites:
|
||||
* - macOS operating system
|
||||
* - Xcode installed with command line tools
|
||||
* - iOS simulator available
|
||||
* - Capacitor iOS platform added to project
|
||||
* - Valid iOS development certificates
|
||||
*
|
||||
* Exit codes:
|
||||
* - 0: Tests completed successfully
|
||||
* - 1: Build or test failure
|
||||
*
|
||||
* @example
|
||||
* // Run directly
|
||||
* node scripts/test-ios.js
|
||||
*
|
||||
* // Run via npm script
|
||||
* npm run test:ios
|
||||
*
|
||||
* @requires child_process
|
||||
* @requires path
|
||||
* @requires fs
|
||||
*
|
||||
* @author TimeSafari Team
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { join } = require('path');
|
||||
const { existsSync, mkdirSync, appendFileSync, readFileSync } = require('fs');
|
||||
|
||||
// Format date as YYYY-MM-DD-HHMMSS
|
||||
const getLogFileName = () => {
|
||||
const now = new Date();
|
||||
const date = now.toISOString().split('T')[0];
|
||||
const time = now.toTimeString().split(' ')[0].replace(/:/g, '');
|
||||
return `build_logs/ios-build-${date}-${time}.log`;
|
||||
};
|
||||
|
||||
// Create logger function
|
||||
const createLogger = (logFile) => {
|
||||
return (message) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `[${timestamp}] ${message}\n`;
|
||||
console.log(message);
|
||||
appendFileSync(logFile, logMessage);
|
||||
};
|
||||
};
|
||||
|
||||
// Check for iOS simulator
|
||||
const checkSimulator = async (log) => {
|
||||
log('🔍 Checking for iOS simulator...');
|
||||
const simulatorsOutput = execSync('xcrun simctl list devices available -j').toString();
|
||||
const simulatorsData = JSON.parse(simulatorsOutput);
|
||||
|
||||
// Get all available devices/simulators with their UDIDs
|
||||
const allDevices = [];
|
||||
|
||||
// Process all runtime groups (iOS versions)
|
||||
Object.entries(simulatorsData.devices).forEach(([runtime, devices]) => {
|
||||
devices.forEach(device => {
|
||||
allDevices.push({
|
||||
name: device.name,
|
||||
udid: device.udid,
|
||||
state: device.state,
|
||||
runtime: runtime,
|
||||
isIphone: device.name.includes('iPhone'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Check for booted simulators first
|
||||
const bootedDevices = allDevices.filter(device => device.state === 'Booted');
|
||||
|
||||
if (bootedDevices.length > 0) {
|
||||
log(`📱 Found ${bootedDevices.length} running simulator(s): ${bootedDevices.map(d => d.name).join(', ')}`);
|
||||
return bootedDevices;
|
||||
}
|
||||
|
||||
// No booted devices found, try to boot one
|
||||
log('⚠️ No running iOS simulator found. Attempting to boot one...');
|
||||
|
||||
// Prefer iPhone devices, especially newer models
|
||||
const preferredDevices = [
|
||||
'iPhone 15', 'iPhone 14', 'iPhone 13', 'iPhone 12', 'iPhone', // Prefer newer iPhones first
|
||||
'iPad' // Then iPads if no iPhones available
|
||||
];
|
||||
|
||||
let deviceToLaunch = null;
|
||||
|
||||
// Try to find a device from our preferred list
|
||||
for (const preferredName of preferredDevices) {
|
||||
const matchingDevices = allDevices.filter(device =>
|
||||
device.name.includes(preferredName) && device.state === 'Shutdown');
|
||||
|
||||
if (matchingDevices.length > 0) {
|
||||
// Sort by runtime to prefer newer iOS versions
|
||||
matchingDevices.sort((a, b) => b.runtime.localeCompare(a.runtime));
|
||||
deviceToLaunch = matchingDevices[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no preferred device found, take any available device
|
||||
if (!deviceToLaunch && allDevices.length > 0) {
|
||||
const availableDevices = allDevices.filter(device => device.state === 'Shutdown');
|
||||
if (availableDevices.length > 0) {
|
||||
deviceToLaunch = availableDevices[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!deviceToLaunch) {
|
||||
throw new Error('No available iOS simulators found. Please create a simulator in Xcode first.');
|
||||
}
|
||||
|
||||
// Boot the selected simulator
|
||||
log(`🚀 Booting iOS simulator: ${deviceToLaunch.name} (${deviceToLaunch.runtime})`);
|
||||
execSync(`xcrun simctl boot ${deviceToLaunch.udid}`);
|
||||
|
||||
// Wait for simulator to fully boot
|
||||
log('⏳ Waiting for simulator to boot completely...');
|
||||
// Give the simulator time to fully boot before proceeding
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
|
||||
log(`✅ Successfully booted simulator: ${deviceToLaunch.name}`);
|
||||
|
||||
return [{ name: deviceToLaunch.name, udid: deviceToLaunch.udid }];
|
||||
};
|
||||
|
||||
// Verify Xcode installation
|
||||
const verifyXcodeInstallation = (log) => {
|
||||
log('🔍 Checking Xcode installation...');
|
||||
try {
|
||||
execSync('xcode-select -p');
|
||||
log('✅ Xcode command line tools found');
|
||||
} catch (error) {
|
||||
throw new Error('Xcode command line tools not found. Please install Xcode first.');
|
||||
}
|
||||
};
|
||||
|
||||
// Generate test data using generate_data.ts
|
||||
const generateTestData = async (log) => {
|
||||
log('🔄 Generating test data...');
|
||||
|
||||
// Check if test-scripts directory exists
|
||||
if (!existsSync('test-scripts')) {
|
||||
log('⚠️ test-scripts directory not found');
|
||||
log('⚠️ Current directory: ' + process.cwd());
|
||||
|
||||
// List directories to help debug
|
||||
const { readdirSync } = require('fs');
|
||||
log('📂 Directories in current path:');
|
||||
try {
|
||||
const files = readdirSync('.');
|
||||
files.forEach(file => {
|
||||
const isDir = existsSync(file) && require('fs').statSync(file).isDirectory();
|
||||
log(`${isDir ? '📁' : '📄'} ${file}`);
|
||||
});
|
||||
} catch (err) {
|
||||
log(`⚠️ Error listing directory: ${err.message}`);
|
||||
}
|
||||
} else {
|
||||
log('✅ Found test-scripts directory');
|
||||
|
||||
// Check if generate_data.ts exists
|
||||
if (existsSync('test-scripts/generate_data.ts')) {
|
||||
log('✅ Found generate_data.ts');
|
||||
} else {
|
||||
log('⚠️ generate_data.ts not found in test-scripts directory');
|
||||
|
||||
// List files in test-scripts to help debug
|
||||
const { readdirSync } = require('fs');
|
||||
log('📂 Files in test-scripts:');
|
||||
try {
|
||||
const files = readdirSync('test-scripts');
|
||||
files.forEach(file => {
|
||||
log(`📄 ${file}`);
|
||||
});
|
||||
} catch (err) {
|
||||
log(`⚠️ Error listing test-scripts: ${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create .generated directory if it doesn't exist
|
||||
if (!existsSync('.generated')) {
|
||||
log('📁 Creating .generated directory');
|
||||
mkdirSync('.generated', { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to generate test data using the script
|
||||
log('🔄 Running test data generation script...');
|
||||
execSync('npx ts-node test-scripts/generate_data.ts', { stdio: 'inherit' });
|
||||
log('✅ Test data generation script completed');
|
||||
|
||||
// Verify the generated files exist
|
||||
const requiredFiles = [
|
||||
'.generated/test-env.json',
|
||||
'.generated/claim_details.json',
|
||||
'.generated/contacts.json'
|
||||
];
|
||||
|
||||
log('🔍 Verifying generated files:');
|
||||
for (const file of requiredFiles) {
|
||||
if (!existsSync(file)) {
|
||||
log(`⚠️ Required file ${file} was not generated`);
|
||||
throw new Error(`Required file ${file} was not generated`);
|
||||
} else {
|
||||
log(`✅ ${file} exists`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log(`⚠️ Failed to generate test data: ${error.message}`);
|
||||
log('⚠️ Creating fallback test data...');
|
||||
|
||||
// Create minimal fallback test data
|
||||
const fallbackTestEnv = {
|
||||
"CONTACT1_DID": "did:example:123456789",
|
||||
"APP_URL": "https://app.timesafari.example"
|
||||
};
|
||||
|
||||
const fallbackClaimDetails = {
|
||||
"claim_id": "claim_12345",
|
||||
"title": "Test Claim",
|
||||
"description": "This is a test claim"
|
||||
};
|
||||
|
||||
const fallbackContacts = [
|
||||
{
|
||||
"id": "contact1",
|
||||
"name": "Test Contact",
|
||||
"did": "did:example:123456789"
|
||||
}
|
||||
];
|
||||
|
||||
// Use writeFileSync to overwrite any existing files
|
||||
const { writeFileSync } = require('fs');
|
||||
writeFileSync('.generated/test-env.json', JSON.stringify(fallbackTestEnv, null, 2));
|
||||
writeFileSync('.generated/claim_details.json', JSON.stringify(fallbackClaimDetails, null, 2));
|
||||
writeFileSync('.generated/contacts.json', JSON.stringify(fallbackContacts, null, 2));
|
||||
|
||||
log('✅ Fallback test data created');
|
||||
|
||||
// Verify files were created
|
||||
const requiredFiles = [
|
||||
'.generated/test-env.json',
|
||||
'.generated/claim_details.json',
|
||||
'.generated/contacts.json'
|
||||
];
|
||||
|
||||
log('🔍 Verifying fallback files:');
|
||||
for (const file of requiredFiles) {
|
||||
if (!existsSync(file)) {
|
||||
log(`⚠️ Failed to create ${file}`);
|
||||
} else {
|
||||
log(`✅ Created ${file}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Build web assets
|
||||
const buildWebAssets = async (log) => {
|
||||
log('🌐 Building web assets...');
|
||||
execSync('rm -rf dist', { stdio: 'inherit' });
|
||||
execSync('npm run build:web', { stdio: 'inherit' });
|
||||
execSync('npm run build:capacitor', { stdio: 'inherit' });
|
||||
log('✅ Web assets built successfully');
|
||||
};
|
||||
|
||||
// Configure iOS project
|
||||
const configureIosProject = async (log) => {
|
||||
log('📱 Syncing Capacitor project...');
|
||||
try {
|
||||
execSync('npx cap sync ios', { stdio: 'inherit' });
|
||||
log('✅ Capacitor sync completed');
|
||||
} catch (error) {
|
||||
log('⚠️ Capacitor sync encountered issues. Attempting to continue...');
|
||||
}
|
||||
|
||||
// Register URL scheme for deeplink tests
|
||||
log('🔗 Configuring URL scheme for deeplink tests...');
|
||||
if (checkAndRegisterUrlScheme(log)) {
|
||||
log('✅ URL scheme configuration completed');
|
||||
}
|
||||
|
||||
log('⚙️ Installing CocoaPods dependencies...');
|
||||
try {
|
||||
// Try to run pod install normally first
|
||||
execSync('cd ios/App && pod install', { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
// If that fails, try using sudo (requires password)
|
||||
log('⚠️ CocoaPods installation failed. Trying with sudo...');
|
||||
try {
|
||||
execSync('cd ios/App && sudo pod install', { stdio: 'inherit' });
|
||||
} catch (sudoError) {
|
||||
// If both methods fail, alert the user
|
||||
log('❌ CocoaPods installation failed.');
|
||||
log('Please run one of the following commands manually:');
|
||||
log('1. cd ios/App && pod install');
|
||||
log('2. cd ios/App && sudo pod install');
|
||||
log('3. Install CocoaPods through Homebrew: brew install cocoapods');
|
||||
throw new Error('CocoaPods installation failed. See log for details.');
|
||||
}
|
||||
}
|
||||
log('✅ CocoaPods installation completed');
|
||||
};
|
||||
|
||||
// Build and test iOS project
|
||||
const buildAndTestIos = async (log, simulator) => {
|
||||
const simulatorName = simulator[0].name;
|
||||
log('🏗️ Building iOS project...');
|
||||
execSync('cd ios/App && xcodebuild clean -workspace App.xcworkspace -scheme App', { stdio: 'inherit' });
|
||||
log('✅ Xcode clean completed');
|
||||
|
||||
log(`🏗️ Building for simulator: ${simulatorName}`);
|
||||
execSync(`cd ios/App && xcodebuild build -workspace App.xcworkspace -scheme App -destination "platform=iOS Simulator,name=${simulatorName}"`, { stdio: 'inherit' });
|
||||
log('✅ Xcode build completed');
|
||||
|
||||
// Check if the project is configured for testing by querying the scheme capabilities
|
||||
try {
|
||||
log(`🧪 Checking if scheme is configured for testing`);
|
||||
const schemeInfo = execSync(`cd ios/App && xcodebuild -scheme App -showBuildSettings | grep TEST`).toString();
|
||||
|
||||
if (schemeInfo.includes('ENABLE_TESTABILITY = YES')) {
|
||||
log(`🧪 Attempting to run tests on simulator: ${simulatorName}`);
|
||||
try {
|
||||
execSync(`cd ios/App && xcodebuild test -workspace App.xcworkspace -scheme App -destination "platform=iOS Simulator,name=${simulatorName}"`, { stdio: 'inherit' });
|
||||
log('✅ iOS tests completed successfully');
|
||||
} catch (testError) {
|
||||
log(`⚠️ Tests failed or scheme not properly configured for testing: ${testError.message}`);
|
||||
log('⚠️ This is normal if no test targets have been added to the project');
|
||||
log('⚠️ Skipping test step and continuing with the app launch');
|
||||
}
|
||||
} else {
|
||||
log('⚠️ Project does not have testing enabled in build settings');
|
||||
log('⚠️ Skipping test step and continuing with the app launch');
|
||||
}
|
||||
} catch (error) {
|
||||
log('⚠️ Unable to determine if testing is configured');
|
||||
log('⚠️ Skipping test step and continuing with the app launch');
|
||||
}
|
||||
};
|
||||
|
||||
// Run the app
|
||||
const runIosApp = async (log, simulator) => {
|
||||
const simulatorName = simulator[0].name;
|
||||
const simulatorUdid = simulator[0].udid;
|
||||
|
||||
log(`📱 Running app in simulator: ${simulatorName} (${simulatorUdid})...`);
|
||||
// Use the --target parameter to specify the device directly, avoiding the UI prompt
|
||||
execSync(`npx cap run ios --target="${simulatorUdid}"`, { stdio: 'inherit' });
|
||||
log('✅ App launched successfully');
|
||||
};
|
||||
|
||||
/**
|
||||
* Run deeplink tests
|
||||
* Optionally tests deeplinks if the test data is available
|
||||
*
|
||||
* @param {function} log - Logging function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const runDeeplinkTests = async (log) => {
|
||||
log('🔗 Starting deeplink tests...');
|
||||
|
||||
// Register URL scheme if needed
|
||||
checkAndRegisterUrlScheme(log);
|
||||
|
||||
// Check if test data files exist first
|
||||
const requiredFiles = [
|
||||
'.generated/test-env.json',
|
||||
'.generated/claim_details.json',
|
||||
'.generated/contacts.json'
|
||||
];
|
||||
|
||||
for (const file of requiredFiles) {
|
||||
if (!existsSync(file)) {
|
||||
log(`⚠️ Required file ${file} does not exist`);
|
||||
log('⚠️ Skipping deeplink tests');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Load test data
|
||||
log('📂 Loading test data from .generated directory');
|
||||
let testEnv, claimDetails, contacts;
|
||||
|
||||
try {
|
||||
const testEnvContent = readFileSync('.generated/test-env.json', 'utf8');
|
||||
testEnv = JSON.parse(testEnvContent);
|
||||
log('✅ Loaded test-env.json');
|
||||
} catch (error) {
|
||||
log(`⚠️ Failed to load test-env.json: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const claimDetailsContent = readFileSync('.generated/claim_details.json', 'utf8');
|
||||
claimDetails = JSON.parse(claimDetailsContent);
|
||||
log('✅ Loaded claim_details.json');
|
||||
} catch (error) {
|
||||
log(`⚠️ Failed to load claim_details.json: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const contactsContent = readFileSync('.generated/contacts.json', 'utf8');
|
||||
contacts = JSON.parse(contactsContent);
|
||||
log('✅ Loaded contacts.json');
|
||||
} catch (error) {
|
||||
log(`⚠️ Failed to load contacts.json: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the app URL scheme is registered in the simulator
|
||||
log('🔍 Checking if URL scheme is registered in simulator...');
|
||||
try {
|
||||
// Attempt to open a simple URL with the scheme
|
||||
execSync(`xcrun simctl openurl booted "timesafari://test"`, { stdio: 'pipe' });
|
||||
log('✅ URL scheme is registered and working');
|
||||
} catch (error) {
|
||||
const errorMessage = error.message || '';
|
||||
|
||||
// Check for the specific error code that indicates an unregistered URL scheme
|
||||
if (errorMessage.includes('OSStatus error -10814') || errorMessage.includes('NSOSStatusErrorDomain, code=-10814')) {
|
||||
log('⚠️ URL scheme "timesafari://" is not registered in the app or app is not running');
|
||||
log('⚠️ The scheme was added to Info.plist but the app may need to be rebuilt');
|
||||
log('⚠️ Trying to continue with tests, but they may fail');
|
||||
}
|
||||
}
|
||||
|
||||
// Test URLs
|
||||
const deeplinkTests = [
|
||||
{
|
||||
url: `timesafari://claim/${claimDetails.claim_id}`,
|
||||
description: 'Claim view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-cert/${claimDetails.claim_id}`,
|
||||
description: 'Claim certificate view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-add-raw/${claimDetails.claim_id}`,
|
||||
description: 'Raw claim addition'
|
||||
},
|
||||
{
|
||||
url: 'timesafari://did/test',
|
||||
description: 'DID view with test identifier'
|
||||
},
|
||||
{
|
||||
url: `timesafari://did/${testEnv.CONTACT1_DID}`,
|
||||
description: 'DID view with contact DID'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contact-edit/${testEnv.CONTACT1_DID}`,
|
||||
description: 'Contact editing'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contacts/import?contacts=${encodeURIComponent(JSON.stringify(contacts))}`,
|
||||
description: 'Contacts import'
|
||||
}
|
||||
];
|
||||
|
||||
// Execute each test
|
||||
let testsCompleted = 0;
|
||||
let testsSkipped = 0;
|
||||
|
||||
for (const test of deeplinkTests) {
|
||||
try {
|
||||
log(`\n🔗 Testing deeplink: ${test.description}`);
|
||||
log(`URL: ${test.url}`);
|
||||
|
||||
execSync(`xcrun simctl openurl booted "${test.url}"`, { stdio: 'pipe' });
|
||||
log(`✅ Successfully executed: ${test.description}`);
|
||||
testsCompleted++;
|
||||
|
||||
// Wait between tests
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
} catch (deeplinkError) {
|
||||
const errorMessage = deeplinkError.message || '';
|
||||
|
||||
// Handle specific error for URL scheme not registered
|
||||
if (errorMessage.includes('OSStatus error -10814') || errorMessage.includes('NSOSStatusErrorDomain, code=-10814')) {
|
||||
log(`⚠️ URL scheme not properly handled: ${test.description}`);
|
||||
testsSkipped++;
|
||||
} else {
|
||||
log(`⚠️ Failed to execute deeplink test: ${test.description}`);
|
||||
log(`⚠️ Error: ${errorMessage}`);
|
||||
}
|
||||
log('⚠️ Continuing with next test...');
|
||||
}
|
||||
}
|
||||
|
||||
log(`✅ Deeplink tests completed: ${testsCompleted} successful, ${testsSkipped} skipped`);
|
||||
|
||||
if (testsSkipped > 0) {
|
||||
log('\n📝 Note about skipped tests:');
|
||||
log('1. The app needs to have the URL scheme registered in Info.plist');
|
||||
log('2. The app needs to be rebuilt after registering the URL scheme');
|
||||
log('3. The app must be running in the foreground for deeplink tests to work');
|
||||
log('4. If these conditions are met and tests still fail, check URL handling in the app code');
|
||||
}
|
||||
} catch (error) {
|
||||
log(`❌ Deeplink tests setup failed: ${error.message}`);
|
||||
log('⚠️ Deeplink tests might be unavailable or test data is missing');
|
||||
// Don't rethrow the error to prevent halting the process
|
||||
}
|
||||
};
|
||||
|
||||
// Check and register URL scheme if needed
|
||||
const checkAndRegisterUrlScheme = (log) => {
|
||||
log('🔍 Checking if URL scheme is registered in Info.plist...');
|
||||
|
||||
const infoPlistPath = 'ios/App/App/Info.plist';
|
||||
|
||||
// Check if Info.plist exists
|
||||
if (!existsSync(infoPlistPath)) {
|
||||
log('⚠️ Info.plist not found at: ' + infoPlistPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read Info.plist content
|
||||
const infoPlistContent = readFileSync(infoPlistPath, 'utf8');
|
||||
|
||||
// Check if URL scheme is already registered
|
||||
if (infoPlistContent.includes('<string>timesafari</string>')) {
|
||||
log('✅ URL scheme "timesafari://" is already registered in Info.plist');
|
||||
return true;
|
||||
}
|
||||
|
||||
log('⚠️ URL scheme "timesafari://" is not registered in Info.plist');
|
||||
log('⚠️ Attempting to register the URL scheme automatically...');
|
||||
|
||||
try {
|
||||
// Look for the closing dict tag to insert our URL types
|
||||
const closingDictIndex = infoPlistContent.lastIndexOf('</dict>');
|
||||
if (closingDictIndex === -1) {
|
||||
log('⚠️ Could not find closing dict tag in Info.plist');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create URL types entry
|
||||
const urlTypesEntry = `
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>app.timesafari.app</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>timesafari</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>`;
|
||||
|
||||
// Insert URL types entry before closing dict
|
||||
const updatedPlistContent =
|
||||
infoPlistContent.substring(0, closingDictIndex) +
|
||||
urlTypesEntry +
|
||||
infoPlistContent.substring(closingDictIndex);
|
||||
|
||||
// Write updated content back to Info.plist
|
||||
const { writeFileSync } = require('fs');
|
||||
writeFileSync(infoPlistPath, updatedPlistContent, 'utf8');
|
||||
|
||||
log('✅ URL scheme "timesafari://" registered in Info.plist');
|
||||
log('⚠️ You will need to rebuild the app for changes to take effect');
|
||||
return true;
|
||||
} catch (error) {
|
||||
log(`⚠️ Failed to register URL scheme: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs the complete iOS test suite including build and testing
|
||||
*
|
||||
* The function performs the following steps:
|
||||
* 1. Syncs the Capacitor project with latest web build
|
||||
* 2. Builds the app using xcodebuild
|
||||
* 3. Optionally runs tests if configured
|
||||
* 4. Launches the app in the simulator
|
||||
*
|
||||
* If no simulator is running, it automatically selects and boots one.
|
||||
*
|
||||
* @async
|
||||
* @throws {Error} If any step in the build process fails
|
||||
*
|
||||
* @example
|
||||
* runIosTests().catch(error => {
|
||||
* console.error('Test execution failed:', error);
|
||||
* process.exit(1);
|
||||
* });
|
||||
*/
|
||||
async function runIosTests() {
|
||||
// Create build_logs directory if it doesn't exist
|
||||
if (!existsSync('build_logs')) {
|
||||
mkdirSync('build_logs');
|
||||
}
|
||||
|
||||
const logFile = getLogFileName();
|
||||
const log = createLogger(logFile);
|
||||
|
||||
try {
|
||||
log('🚀 Starting iOS build and test process...');
|
||||
|
||||
// Generate test data first
|
||||
await generateTestData(log);
|
||||
|
||||
// Verify Xcode installation
|
||||
verifyXcodeInstallation(log);
|
||||
|
||||
// Check for simulator or boot one if needed
|
||||
const simulator = await checkSimulator(log);
|
||||
|
||||
// Build web assets and configure iOS project
|
||||
await buildWebAssets(log);
|
||||
await configureIosProject(log);
|
||||
|
||||
// Build and test using the selected simulator
|
||||
await buildAndTestIos(log, simulator);
|
||||
|
||||
// Run the app in the simulator
|
||||
await runIosApp(log, simulator);
|
||||
|
||||
// Run deeplink tests after app is installed
|
||||
await runDeeplinkTests(log);
|
||||
|
||||
log('🎉 iOS build and test process completed successfully');
|
||||
log(`📝 Full build log available at: ${logFile}`);
|
||||
} catch (error) {
|
||||
log(`❌ iOS tests failed: ${error.message}`);
|
||||
log(`📝 Check build log for details: ${logFile}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the test suite
|
||||
runIosTests();
|
||||
64
src/App.vue
@@ -143,7 +143,8 @@
|
||||
|
||||
<!--
|
||||
This "group" of "modal" is the prompt for an answer.
|
||||
Set "type" as follows: "confirm" for yes/no, and "notification" ones: "-permission", "-mute", "-off"
|
||||
Set "type" as follows: "confirm" for yes/no, and "notification" ones:
|
||||
"-permission", "-mute", "-off"
|
||||
-->
|
||||
<NotificationGroup group="modal">
|
||||
<div class="fixed z-[100] top-0 inset-x-0 w-full">
|
||||
@@ -331,6 +332,7 @@
|
||||
import { Vue, Component } from "vue-facing-decorator";
|
||||
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "./db/index";
|
||||
import { NotificationIface } from "./constants/app";
|
||||
import { logger } from "./utils/logger";
|
||||
|
||||
interface Settings {
|
||||
notifyingNewActivityTime?: string;
|
||||
@@ -344,38 +346,38 @@ export default class App extends Vue {
|
||||
stopAsking = false;
|
||||
|
||||
// created() {
|
||||
// console.log(
|
||||
// logger.log(
|
||||
// "Component created: Reactivity set up.",
|
||||
// window.location.pathname,
|
||||
// );
|
||||
// }
|
||||
|
||||
// beforeCreate() {
|
||||
// console.log("Component beforeCreate: Instance initialized.");
|
||||
// logger.log("Component beforeCreate: Instance initialized.");
|
||||
// }
|
||||
|
||||
// beforeMount() {
|
||||
// console.log("Component beforeMount: Template is about to be rendered.");
|
||||
// logger.log("Component beforeMount: Template is about to be rendered.");
|
||||
// }
|
||||
|
||||
// mounted() {
|
||||
// console.log("Component mounted: Template is now rendered.");
|
||||
// logger.log("Component mounted: Template is now rendered.");
|
||||
// }
|
||||
|
||||
// beforeUpdate() {
|
||||
// console.log("Component beforeUpdate: DOM is about to be updated.");
|
||||
// logger.log("Component beforeUpdate: DOM is about to be updated.");
|
||||
// }
|
||||
|
||||
// updated() {
|
||||
// console.log("Component updated: DOM has been updated.");
|
||||
// logger.log("Component updated: DOM has been updated.");
|
||||
// }
|
||||
|
||||
// beforeUnmount() {
|
||||
// console.log("Component beforeUnmount: Cleaning up before removal.");
|
||||
// logger.log("Component beforeUnmount: Cleaning up before removal.");
|
||||
// }
|
||||
|
||||
// unmounted() {
|
||||
// console.log("Component unmounted: Component removed from the DOM.");
|
||||
// logger.log("Component unmounted: Component removed from the DOM.");
|
||||
// }
|
||||
|
||||
truncateLongWords(sentence: string) {
|
||||
@@ -388,42 +390,42 @@ export default class App extends Vue {
|
||||
async turnOffNotifications(
|
||||
notification: NotificationIface,
|
||||
): Promise<boolean> {
|
||||
console.log("Starting turnOffNotifications...");
|
||||
logger.log("Starting turnOffNotifications...");
|
||||
let subscription: PushSubscriptionJSON | null = null;
|
||||
let allGoingOff = false;
|
||||
|
||||
try {
|
||||
console.log("Retrieving settings for the active account...");
|
||||
logger.log("Retrieving settings for the active account...");
|
||||
const settings: Settings = await retrieveSettingsForActiveAccount();
|
||||
console.log("Retrieved settings:", settings);
|
||||
logger.log("Retrieved settings:", settings);
|
||||
|
||||
const notifyingNewActivity = !!settings?.notifyingNewActivityTime;
|
||||
const notifyingReminder = !!settings?.notifyingReminderTime;
|
||||
|
||||
if (!notifyingNewActivity || !notifyingReminder) {
|
||||
allGoingOff = true;
|
||||
console.log("Both notifications are being turned off.");
|
||||
logger.log("Both notifications are being turned off.");
|
||||
}
|
||||
|
||||
console.log("Checking service worker readiness...");
|
||||
logger.log("Checking service worker readiness...");
|
||||
await navigator.serviceWorker?.ready
|
||||
.then((registration) => {
|
||||
console.log("Service worker is ready. Fetching subscription...");
|
||||
logger.log("Service worker is ready. Fetching subscription...");
|
||||
return registration.pushManager.getSubscription();
|
||||
})
|
||||
.then(async (subscript: PushSubscription | null) => {
|
||||
if (subscript) {
|
||||
subscription = subscript.toJSON();
|
||||
console.log("PushSubscription retrieved:", subscription);
|
||||
logger.log("PushSubscription retrieved:", subscription);
|
||||
|
||||
if (allGoingOff) {
|
||||
console.log("Unsubscribing from push notifications...");
|
||||
logger.log("Unsubscribing from push notifications...");
|
||||
await subscript.unsubscribe();
|
||||
console.log("Successfully unsubscribed.");
|
||||
logger.log("Successfully unsubscribed.");
|
||||
}
|
||||
} else {
|
||||
logConsoleAndDb("Subscription object is not available.");
|
||||
console.log("No subscription found.");
|
||||
logger.log("No subscription found.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -432,11 +434,11 @@ export default class App extends Vue {
|
||||
JSON.stringify(error),
|
||||
true,
|
||||
);
|
||||
console.error("Error during subscription fetch:", error);
|
||||
logger.error("Error during subscription fetch:", error);
|
||||
});
|
||||
|
||||
if (!subscription) {
|
||||
console.log("No subscription available. Notifying user...");
|
||||
logger.log("No subscription available. Notifying user...");
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
@@ -446,7 +448,7 @@ export default class App extends Vue {
|
||||
},
|
||||
5000,
|
||||
);
|
||||
console.log("Exiting as there is no subscription to process.");
|
||||
logger.log("Exiting as there is no subscription to process.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -455,12 +457,12 @@ export default class App extends Vue {
|
||||
};
|
||||
if (!allGoingOff) {
|
||||
serverSubscription["notifyType"] = notification.title;
|
||||
console.log(
|
||||
logger.log(
|
||||
`Server subscription updated with notifyType: ${notification.title}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Sending unsubscribe request to the server...");
|
||||
logger.log("Sending unsubscribe request to the server...");
|
||||
const pushServerSuccess = await fetch("/web-push/unsubscribe", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -475,9 +477,9 @@ export default class App extends Vue {
|
||||
`Push server failed: ${response.status} ${errorBody}`,
|
||||
true,
|
||||
);
|
||||
console.error("Push server error response:", errorBody);
|
||||
logger.error("Push server error response:", errorBody);
|
||||
}
|
||||
console.log(`Server response status: ${response.status}`);
|
||||
logger.log(`Server response status: ${response.status}`);
|
||||
return response.ok;
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -485,14 +487,14 @@ export default class App extends Vue {
|
||||
"Push server communication failed: " + JSON.stringify(error),
|
||||
true,
|
||||
);
|
||||
console.error("Error during server communication:", error);
|
||||
logger.error("Error during server communication:", error);
|
||||
return false;
|
||||
});
|
||||
|
||||
const message = pushServerSuccess
|
||||
? "Notification is off."
|
||||
: "Notification is still on. Try to turn it off again.";
|
||||
console.log("Server response processed. Message:", message);
|
||||
logger.log("Server response processed. Message:", message);
|
||||
|
||||
this.$notify(
|
||||
{
|
||||
@@ -505,11 +507,11 @@ export default class App extends Vue {
|
||||
);
|
||||
|
||||
if (notification.callback) {
|
||||
console.log("Executing notification callback...");
|
||||
logger.log("Executing notification callback...");
|
||||
notification.callback(pushServerSuccess);
|
||||
}
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
"Completed turnOffNotifications with success:",
|
||||
pushServerSuccess,
|
||||
);
|
||||
@@ -519,7 +521,7 @@ export default class App extends Vue {
|
||||
"Error turning off notifications: " + JSON.stringify(error),
|
||||
true,
|
||||
);
|
||||
console.error("Critical error in turnOffNotifications:", error);
|
||||
logger.error("Critical error in turnOffNotifications:", error);
|
||||
|
||||
this.$notify(
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="w-fit" v-html="generateIcon()"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
||||
@@ -162,7 +162,7 @@ export default class GiftedDialog extends Vue {
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (err: any) {
|
||||
console.error("Error retrieving settings from database:", err);
|
||||
logger.error("Error retrieving settings from database:", err);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
@@ -311,7 +311,7 @@ export default class GiftedDialog extends Vue {
|
||||
this.isGiveCreationError(result.response)
|
||||
) {
|
||||
const errorMessage = this.getGiveCreationErrorMessage(result);
|
||||
console.error("Error with give creation result:", result);
|
||||
logger.error("Error with give creation result:", result);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
@@ -337,7 +337,7 @@ export default class GiftedDialog extends Vue {
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
console.error("Error with give recordation caught:", error);
|
||||
logger.error("Error with give recordation caught:", error);
|
||||
const errorMessage =
|
||||
error.userMessage ||
|
||||
serverMessageForUser(error) ||
|
||||
|
||||
@@ -74,7 +74,7 @@ export default class ImageViewer extends Vue {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Share failed, opening in new tab:", error);
|
||||
logger.warn("Share failed, opening in new tab:", error);
|
||||
window.open(this.imageUrl, "_blank");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,10 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<!-- always have at least one refresh button even without members in case the organizer changes the password -->
|
||||
<!--
|
||||
always have at least one refresh button even without members in case the organizer
|
||||
changes the password
|
||||
-->
|
||||
<button
|
||||
class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors"
|
||||
title="Refresh members list"
|
||||
|
||||