Browse Source

fix: Update Android package name and improve test reliability

- Change package name from app.timesafari.app to app.timesafari
- Fix ADB connection issues with server restart and retries
- Add interactive test flow with user prompts between tests
- Generate test data locally instead of external script
- Add proper cleanup of readline interface
- Fix URL scheme registration in Android manifest

Technical changes:
1. Remove duplicate SDK suppression entries
2. Update Gradle and build configurations
3. Add retry logic for flaky ADB connections
4. Add proper error handling for test data generation
5. Update all package references consistently

The changes improve Android testing by:
1. Making package naming consistent
2. Adding reliability to ADB connections
3. Adding user control over test flow
4. Providing better test progress visibility
5. Improving error handling and logging
app_id_fix
Matthew Raymer 2 months ago
parent
commit
aed1a9fea8
  1. 16
      BUILDING.md
  2. BIN
      android/.gradle/8.11.1/checksums/checksums.lock
  3. BIN
      android/.gradle/8.11.1/checksums/md5-checksums.bin
  4. BIN
      android/.gradle/8.11.1/checksums/sha1-checksums.bin
  5. BIN
      android/.gradle/8.11.1/executionHistory/executionHistory.bin
  6. BIN
      android/.gradle/8.11.1/executionHistory/executionHistory.lock
  7. BIN
      android/.gradle/8.11.1/fileChanges/last-build.bin
  8. BIN
      android/.gradle/8.11.1/fileHashes/fileHashes.bin
  9. BIN
      android/.gradle/8.11.1/fileHashes/fileHashes.lock
  10. BIN
      android/.gradle/8.11.1/fileHashes/resourceHashesCache.bin
  11. 0
      android/.gradle/8.11.1/gc.properties
  12. BIN
      android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
  13. 4
      android/.gradle/buildOutputCleanup/cache.properties
  14. BIN
      android/.gradle/file-system.probe
  15. 3
      android/Gemfile
  16. 1
      android/app/.gitignore
  17. 13
      android/app/build.gradle
  18. 398
      android/app/lint-baseline.xml
  19. 20
      android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
  20. 8
      android/app/src/main/AndroidManifest.xml
  21. 2
      android/app/src/main/assets/capacitor.config.json
  22. 2
      android/app/src/main/assets/public/index.html
  23. 7
      android/app/src/main/java/app/timesafari/MainActivity.java
  24. 2
      android/app/src/main/java/timesafari/app/MainActivity.java
  25. 4
      android/app/src/main/res/values/strings.xml
  26. 10
      android/build.gradle
  27. 7
      android/capacitor-android/build.gradle
  28. 2
      android/fastlane/Appfile
  29. 38
      android/fastlane/Fastfile
  30. 40
      android/fastlane/README.md
  31. 2
      android/gradle.properties
  32. 2
      android/gradle/wrapper/gradle-wrapper.properties
  33. 4
      capacitor.config.ts
  34. 190
      package-lock.json
  35. 191
      scripts/test-android.js
  36. 6
      scripts/test-ios.js

16
BUILDING.md

@ -422,3 +422,19 @@ mv time-safari/dist time-safari-dist-prev.0 && mv crowd-funder-for-time-pwa/dist
- For iOS: Xcode command line tools must be installed
- For Android: Correct SDK version must be installed
- Check Capacitor configuration in capacitor.config.ts
# List all installed packages
adb shell pm list packages | grep timesafari
# Force stop the app (if it's running)
adb shell am force-stop app.timesafari
# Clear app data (if you don't want to fully uninstall)
adb shell pm clear app.timesafari
# Uninstall for all users
adb shell pm uninstall -k --user 0 app.timesafari
# Check if app is installed
adb shell pm path app.timesafari

BIN
android/.gradle/8.11.1/checksums/checksums.lock

Binary file not shown.

BIN
android/.gradle/8.11.1/checksums/md5-checksums.bin

Binary file not shown.

BIN
android/.gradle/8.11.1/checksums/sha1-checksums.bin

Binary file not shown.

BIN
android/.gradle/8.11.1/executionHistory/executionHistory.bin

Binary file not shown.

BIN
android/.gradle/8.11.1/executionHistory/executionHistory.lock

Binary file not shown.

BIN
android/.gradle/8.11.1/fileChanges/last-build.bin

Binary file not shown.

BIN
android/.gradle/8.11.1/fileHashes/fileHashes.bin

Binary file not shown.

BIN
android/.gradle/8.11.1/fileHashes/fileHashes.lock

Binary file not shown.

BIN
android/.gradle/8.11.1/fileHashes/resourceHashesCache.bin

Binary file not shown.

0
android/.gradle/8.11.1/gc.properties

BIN
android/.gradle/buildOutputCleanup/buildOutputCleanup.lock

Binary file not shown.

4
android/.gradle/buildOutputCleanup/cache.properties

@ -1,2 +1,2 @@
#Tue Mar 11 10:01:05 UTC 2025
gradle.version=8.10.2
#Fri Mar 21 07:27:50 UTC 2025
gradle.version=8.2.1

BIN
android/.gradle/file-system.probe

Binary file not shown.

3
android/Gemfile

@ -1,3 +0,0 @@
source "https://rubygems.org"
gem "fastlane"

1
android/app/.gitignore

@ -1,3 +1,2 @@
/build/*
!/build/.npmkeep
src/main/assets/public/assets/

13
android/app/build.gradle

@ -1,7 +1,7 @@
apply plugin: 'com.android.application'
android {
namespace "app.timesafari"
namespace 'app.timesafari'
compileSdk rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "app.timesafari"
@ -22,17 +22,6 @@ 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

@ -1,398 +0,0 @@
<?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 &quot;UnsanitizedFilenameFromContentProvider&quot;"
errorLine1=" disable &apos;UnsanitizedFilenameFromContentProvider&apos;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="build.gradle"
line="26"
column="18"/>
</issue>
<issue
id="UnknownIssueId"
message="Unknown issue id &quot;UnsanitizedFilenameFromContentProvider&quot;"
errorLine1=" disable &apos;UnsanitizedFilenameFromContentProvider&apos;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="build.gradle"
line="26"
column="18"/>
</issue>
<issue
id="UnknownIssueId"
message="Unknown issue id &quot;LintBaselineFixed&quot;"
errorLine1=" ignore &apos;LintBaselineFixed&apos;"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="build.gradle"
line="34"
column="17"/>
</issue>
<issue
id="UnknownIssueId"
message="Unknown issue id &quot;LintBaselineFixed&quot;"
errorLine1=" ignore &apos;LintBaselineFixed&apos;"
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(&quot;Accept&quot;) &amp;&amp; header.getValue().toLowerCase().contains(&quot;text/html&quot;)) {"
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(&quot;yyyyMMdd_HHmmss&quot;).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(&quot;yyyy-MM-dd&apos;T&apos;HH:mm&apos;Z&apos;&quot;);"
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="&lt;application android:usesCleartextTraffic=&quot;true&quot;>"
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=" &lt;intent-filter android:autoVerify=&quot;true&quot;>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="25"
column="28"/>
</issue>
<issue
id="ManifestOrder"
message="`&lt;uses-permission>` tag appears after `&lt;application>` tag"
errorLine1=" &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; />"
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 &apos;com.android.tools.build:gradle:8.2.1&apos;"
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 &apos;com.android.tools.build:gradle:8.2.1&apos;"
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 &quot;androidx.appcompat:appcompat:$androidxAppCompatVersion&quot;"
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 &quot;androidx.appcompat:appcompat:$androidxAppCompatVersion&quot;"
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 &quot;androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion&quot;"
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 &quot;androidx.test.ext:junit:$androidxJunitVersion&quot;"
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 &quot;androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion&quot;"
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 &quot;androidx.appcompat:appcompat:$androidxAppCompatVersion&quot;"
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 &quot;androidx.test.ext:junit:$androidxJunitVersion&quot;"
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 &quot;androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion&quot;"
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=&quot;#F0FF1414&quot;"
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="&lt;androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
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="&lt;widget version=&quot;1.0.0&quot; xmlns=&quot;http://www.w3.org/ns/widgets&quot; xmlns:cdv=&quot;http://cordova.apache.org/ns/1.0&quot;>"
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="&lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
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="&lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
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=" &lt;string name=&quot;package_name&quot;>app.timesafari.app&lt;/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=" &lt;string name=&quot;custom_url_scheme&quot;>app.timesafari.app&lt;/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="&lt;adaptive-icon xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;>"
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="&lt;adaptive-icon xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;>"
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>

20
android/app/src/androidTest/java/app/timesafari/app/ExampleInstrumentedTest.java → android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java

@ -1,20 +1,26 @@
package app.timesafari.app;
package com.getcapacitor.myapp;
import static org.junit.Assert.*;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("app.timesafari", appContext.getPackageName());
}
}
}

8
android/app/src/main/AndroidManifest.xml

@ -10,19 +10,19 @@
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:exported="true"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:exported="true">
android:theme="@style/AppTheme.NoActionBarLaunch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

2
android/app/src/main/assets/capacitor.config.json

@ -1,5 +1,5 @@
{
"appId": "app.timesafari.app",
"appId": "app.timesafari",
"appName": "TimeSafari",
"webDir": "dist",
"bundledWebRuntime": false,

2
android/app/src/main/assets/public/index.html

@ -6,7 +6,7 @@
<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>
<script type="module" crossorigin src="/assets/index-CZMUlUNO.js"></script>
</head>
<body>
<noscript>

7
android/app/src/main/java/app/timesafari/MainActivity.java

@ -0,0 +1,7 @@
package app.timesafari;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {
// ... existing code ...
}

2
android/app/src/main/java/app/timesafari/app/MainActivity.java → android/app/src/main/java/timesafari/app/MainActivity.java

@ -1,4 +1,4 @@
package app.timesafari.app;
package timesafari.app;
import com.getcapacitor.BridgeActivity;

4
android/app/src/main/res/values/strings.xml

@ -2,6 +2,6 @@
<resources>
<string name="app_name">TimeSafari</string>
<string name="title_activity_main">TimeSafari</string>
<string name="package_name">app.timesafari.app</string>
<string name="custom_url_scheme">app.timesafari.app</string>
<string name="package_name">timesafari.app</string>
<string name="custom_url_scheme">timesafari.app</string>
</resources>

10
android/build.gradle

@ -7,9 +7,8 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath 'com.android.tools.build:gradle:8.2.1'
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
@ -28,10 +27,3 @@ 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

@ -1,7 +0,0 @@
android {
lintOptions {
disable 'UnsanitizedFilenameFromContentProvider'
abortOnError false
baseline file("lint-baseline.xml")
}
}

2
android/fastlane/Appfile

@ -1,2 +0,0 @@
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

@ -1,38 +0,0 @@
# 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

@ -1,40 +0,0 @@
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).

2
android/gradle.properties

@ -21,5 +21,3 @@ org.gradle.jvmargs=-Xmx1536m
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
android.suppressUnsupportedCompileSdk=34
android.suppressUnsupportedCompileSdk=34
android.suppressUnsupportedCompileSdk=34

2
android/gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

4
capacitor.config.ts

@ -1,7 +1,7 @@
import type { CapacitorConfig } from '@capacitor/cli';
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'timesafari.app',
appId: 'app.timesafari',
appName: 'TimeSafari',
webDir: 'dist',
bundledWebRuntime: false,

190
package-lock.json

@ -4998,9 +4998,9 @@
}
},
"node_modules/@expo/cli": {
"version": "0.22.20",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.22.20.tgz",
"integrity": "sha512-BU2ASlw0Gaj3ou/TxVsgvzK+XK8Z14Yq3mmLyvMcMAQrdExZLNmvMZ3A3x6q2uMgSJM3aoQBUuVXS/Ny+lYgDA==",
"version": "0.22.21",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.22.21.tgz",
"integrity": "sha512-lLtH0CiNTwB+qgduew61Jocgj0B092QiQllBuPXigHI4VQms5VXYXHfQC2pMZ7KWFKhNjBIjLSD8A2n1dBMb1Q==",
"license": "MIT",
"optional": true,
"peer": true,
@ -7601,9 +7601,9 @@
}
},
"node_modules/@pkgr/core": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz",
"integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -14515,9 +14515,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.122",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.122.tgz",
"integrity": "sha512-EML1wnwkY5MFh/xUnCvY8FrhUuKzdYhowuZExZOfwJo+Zu9OsNCI23Cgl5y7awy7HrUHSwB1Z8pZX5TI34lsUg==",
"version": "1.5.123",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.123.tgz",
"integrity": "sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==",
"devOptional": true,
"license": "ISC"
},
@ -15557,24 +15557,24 @@
}
},
"node_modules/expo": {
"version": "52.0.39",
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.39.tgz",
"integrity": "sha512-EOnrgj8MHSt0o0SIBhM7jCim2QpJJNonbSATn9LqNtVgKtotIg718G/OrP5/g0GUAOBDyxHH9PfNu/aq9c0vDw==",
"version": "52.0.40",
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.40.tgz",
"integrity": "sha512-kRRXW0VRlnc49LiMO9csF5DjWmUQhQ0lHudNIi3m9Z4nvecJbDaKWI5nNxB5UG7Sqj0I/wsBMes5G6gEndeYlQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "0.22.20",
"@expo/cli": "0.22.21",
"@expo/config": "~10.0.11",
"@expo/config-plugins": "~9.0.17",
"@expo/fingerprint": "0.11.11",
"@expo/metro-config": "0.19.12",
"@expo/vector-icons": "^14.0.0",
"babel-preset-expo": "~12.0.9",
"expo-asset": "~11.0.4",
"expo-asset": "~11.0.5",
"expo-constants": "~17.0.8",
"expo-file-system": "~18.0.11",
"expo-file-system": "~18.0.12",
"expo-font": "~13.0.4",
"expo-keep-awake": "~14.0.3",
"expo-modules-autolinking": "2.0.8",
@ -15606,15 +15606,15 @@
}
},
"node_modules/expo-asset": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.0.4.tgz",
"integrity": "sha512-CdIywU0HrR3wsW5c3n0cT3jW9hccZdnqGsRqY+EY/RWzJbDXtDfAQVEiFHO3mDK7oveUwrP2jK/6ZRNek41/sg==",
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.0.5.tgz",
"integrity": "sha512-TL60LmMBGVzs3NQcO8ylWqBumMh4sx0lmeJsn7+9C88fylGDhyyVnKZ1PyTXo9CVDBkndutZx2JUEQWM9BaiXw==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@expo/image-utils": "^0.6.5",
"expo-constants": "~17.0.7",
"expo-constants": "~17.0.8",
"invariant": "^2.2.4",
"md5-file": "^3.2.3"
},
@ -15641,9 +15641,9 @@
}
},
"node_modules/expo-file-system": {
"version": "18.0.11",
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.11.tgz",
"integrity": "sha512-yDwYfEzWgPXsBZHJW2RJ8Q66ceiFN9Wa5D20pp3fjXVkzPBDwxnYwiPWk4pVmCa5g4X5KYMoMne1pUrsL4OEpg==",
"version": "18.0.12",
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.12.tgz",
"integrity": "sha512-HAkrd/mb8r+G3lJ9MzmGeuW2B+BxQR1joKfeCyY4deLl1zoZ48FrAWjgZjHK9aHUVhJ0ehzInu/NQtikKytaeg==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20064,9 +20064,9 @@
"license": "MIT"
},
"node_modules/metro": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro/-/metro-0.81.3.tgz",
"integrity": "sha512-upilFs7z1uLKvdzFYHiVKrGT/uC7h7d53R0g/FaJoQvLfA8jQG2V69jeOcGi4wCsFYvl1zBSZvKxpQb0nA3giQ==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro/-/metro-0.81.4.tgz",
"integrity": "sha512-78f0aBNPuwXW7GFnSc+Y0vZhbuQorXxdgqQfvSRqcSizqwg9cwF27I05h47tL8AzQcizS1JZncvq4xf5u/Qykw==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20092,18 +20092,18 @@
"jest-worker": "^29.7.0",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
"metro-babel-transformer": "0.81.3",
"metro-cache": "0.81.3",
"metro-cache-key": "0.81.3",
"metro-config": "0.81.3",
"metro-core": "0.81.3",
"metro-file-map": "0.81.3",
"metro-resolver": "0.81.3",
"metro-runtime": "0.81.3",
"metro-source-map": "0.81.3",
"metro-symbolicate": "0.81.3",
"metro-transform-plugins": "0.81.3",
"metro-transform-worker": "0.81.3",
"metro-babel-transformer": "0.81.4",
"metro-cache": "0.81.4",
"metro-cache-key": "0.81.4",
"metro-config": "0.81.4",
"metro-core": "0.81.4",
"metro-file-map": "0.81.4",
"metro-resolver": "0.81.4",
"metro-runtime": "0.81.4",
"metro-source-map": "0.81.4",
"metro-symbolicate": "0.81.4",
"metro-transform-plugins": "0.81.4",
"metro-transform-worker": "0.81.4",
"mime-types": "^2.1.27",
"nullthrows": "^1.1.1",
"serialize-error": "^2.1.0",
@ -20120,9 +20120,9 @@
}
},
"node_modules/metro-babel-transformer": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.81.3.tgz",
"integrity": "sha512-ENqtnPy2mQZFOuKrbqHRcAwZuaYe43X+30xIF0xlkLuMyCvc0CsFzrrSK9EqrQwexhVlqaRALb0GQbBMcE/y8g==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.81.4.tgz",
"integrity": "sha512-WW0yswWrW+eTVK9sYD+b1HwWOiUlZlUoomiw9TIOk0C+dh2V90Wttn/8g62kYi0Y4i+cJfISerB2LbV4nuRGTA==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20156,25 +20156,25 @@
}
},
"node_modules/metro-cache": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.81.3.tgz",
"integrity": "sha512-6UelMQYjlto/79tTXu0vsTxAX4e+Bkf0tgtDL1BNx3wd68pBg8qKIYpJPaUlOIaNUzFXTBDjYwUverkEW0KAtA==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.81.4.tgz",
"integrity": "sha512-sxCPH3gowDxazSaZZrwdNPEpnxR8UeXDnvPjBF9+5btDBNN2DpWvDAXPvrohkYkFImhc0LajS2V7eOXvu9PnvQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"exponential-backoff": "^3.1.1",
"flow-enums-runtime": "^0.0.6",
"metro-core": "0.81.3"
"metro-core": "0.81.4"
},
"engines": {
"node": ">=18.18"
}
},
"node_modules/metro-cache-key": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.81.3.tgz",
"integrity": "sha512-KPsPSRUd6uRva7k7k/DqiiD8td7URQWx0RkX/Cj5+bed5zSXEg/XoQA+b+DmMxS5C7TqP61Fh3XvHx6TQRW82A==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.81.4.tgz",
"integrity": "sha512-3SaWQybvf1ivasjBegIxzVKLJzOpcz+KsnGwXFOYADQq0VN4cnM7tT+u2jkOhk6yJiiO1WIjl68hqyMOQJRRLg==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20186,9 +20186,9 @@
}
},
"node_modules/metro-config": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.81.3.tgz",
"integrity": "sha512-WpTaT0iQr5juVY50Y/cyacG2ggZqF38VshEQepT+ovPK8E/xUVxlbO5yxLSXUxxUXX3Hka9r6g64+y2WC6c/xQ==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.81.4.tgz",
"integrity": "sha512-QnhMy3bRiuimCTy7oi5Ug60javrSa3lPh0gpMAspQZHY9h6y86jwHtZPLtlj8hdWQESIlrbeL8inMSF6qI/i9Q==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20197,35 +20197,35 @@
"cosmiconfig": "^5.0.5",
"flow-enums-runtime": "^0.0.6",
"jest-validate": "^29.7.0",
"metro": "0.81.3",
"metro-cache": "0.81.3",
"metro-core": "0.81.3",
"metro-runtime": "0.81.3"
"metro": "0.81.4",
"metro-cache": "0.81.4",
"metro-core": "0.81.4",
"metro-runtime": "0.81.4"
},
"engines": {
"node": ">=18.18"
}
},
"node_modules/metro-core": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.81.3.tgz",
"integrity": "sha512-WZ+qohnpvvSWdPj1VJPUrZz+2ik29M+UUpMU6YrmzQUfDyZ6JYHhzlw5WVBtwpt/+2xTsIyrZ2C1fByT/DsLQA==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.81.4.tgz",
"integrity": "sha512-GdL4IgmgJhrMA/rTy2lRqXKeXfC77Rg+uvhUEkbhyfj/oz7PrdSgvIFzziapjdHwk1XYq0KyFh/CcVm8ZawG6A==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"lodash.throttle": "^4.1.1",
"metro-resolver": "0.81.3"
"metro-resolver": "0.81.4"
},
"engines": {
"node": ">=18.18"
}
},
"node_modules/metro-file-map": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.81.3.tgz",
"integrity": "sha512-F+t4lnVRoauJxtr9xmI4pWIOE77/vl0IrHDGeJSI9cW6LmuqxkpOlZHTKpbs/hMAo6+KhG2JMJACQDvXDLd/GA==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.81.4.tgz",
"integrity": "sha512-qUIBzkiqOi3qEuscu4cJ83OYQ4hVzjON19FAySWqYys9GKCmxlKa7LkmwqdpBso6lQl+JXZ7nCacX90w5wQvPA==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20264,9 +20264,9 @@
"peer": true
},
"node_modules/metro-minify-terser": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.81.3.tgz",
"integrity": "sha512-912AYv3OmwcbUwzCdWbdQRk+RV6kXXluHKlhBdYFD3kr4Ece691rzlofU/Mlt9qZrhHtctD5Q8cFqOEf9Z69bQ==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.81.4.tgz",
"integrity": "sha512-oVvq/AGvqmbhuijJDZZ9npeWzaVyeBwQKtdlnjcQ9fH7nR15RiBr5y2zTdgTEdynqOIb1Kc16l8CQIUSzOWVFA==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20279,9 +20279,9 @@
}
},
"node_modules/metro-resolver": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.81.3.tgz",
"integrity": "sha512-XnjENY1c6jcsEfFVIjN/8McUIInCVgGxv5eva+9ZWeCTyiAE/L5HPj2ai/Myb349+6QuSMR0dscTkKCnOwWXdw==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.81.4.tgz",
"integrity": "sha512-Ng7G2mXjSExMeRzj6GC19G6IJ0mfIbOLgjArsMWJgtt9ViZiluCwgWsMW9juBC5NSwjJxUMK2x6pC5NIMFLiHA==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20293,9 +20293,9 @@
}
},
"node_modules/metro-runtime": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.3.tgz",
"integrity": "sha512-neuGRMC2pgGKIFPbmbrxW41/SmvL7OX4i1LN+saUY2t1cZfxf9haQHUMCGhO3498uEL2N+ulKRSlQrHt6XwGaw==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.4.tgz",
"integrity": "sha512-fBoRgqkF69CwyPtBNxlDi5ha26Zc8f85n2THXYoh13Jn/Bkg8KIDCdKPp/A1BbSeNnkH/++H2EIIfnmaff4uRg==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20308,9 +20308,9 @@
}
},
"node_modules/metro-source-map": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.3.tgz",
"integrity": "sha512-BHJJurmDQRn3hCbBawh/UHzPz3duMpwpE3ofImO2DoWHYzn6nSg/D4wfCN4y14d9fFLE4e0I+BAOX1HWNP4jsw==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.4.tgz",
"integrity": "sha512-IOwVQ7mLqoqvsL70RZtl1EyE3f9jp43kVsAsb/B/zoWmu0/k4mwEhGLTxmjdXRkLJqPqPrh7WmFChAEf9trW4Q==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20320,9 +20320,9 @@
"@babel/types": "^7.25.2",
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
"metro-symbolicate": "0.81.3",
"metro-symbolicate": "0.81.4",
"nullthrows": "^1.1.1",
"ob1": "0.81.3",
"ob1": "0.81.4",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@ -20331,16 +20331,16 @@
}
},
"node_modules/metro-symbolicate": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.3.tgz",
"integrity": "sha512-LQLT6WopQmIz2SDSVh3Lw7nLzF58HpsrPYqRB7RpRXBYhYmPFIjiGaP8qqtKHXczM/5YAOJzpgt8t/OGZgh6Eg==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.4.tgz",
"integrity": "sha512-rWxTmYVN6/BOSaMDUHT8HgCuRf6acd0AjHkenYlHpmgxg7dqdnAG1hLq999q2XpW5rX+cMamZD5W5Ez2LqGaag==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
"metro-source-map": "0.81.3",
"metro-source-map": "0.81.4",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
@ -20353,9 +20353,9 @@
}
},
"node_modules/metro-transform-plugins": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.81.3.tgz",
"integrity": "sha512-4JMUXhBB5y4h3dyA272k7T7+U3+J4fSBcct0Y8Yur9ziZB/dK8fieEQg5ZPfEGsgOGI+54zTzOUqga6AgmZSNg==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.81.4.tgz",
"integrity": "sha512-nlP069nDXm4v28vbll4QLApAlvVtlB66rP6h+ml8Q/CCQCPBXu2JLaoxUmkIOJQjLhMRUcgTyQHq+TXWJhydOQ==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20372,9 +20372,9 @@
}
},
"node_modules/metro-transform-worker": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.81.3.tgz",
"integrity": "sha512-KZqm9sVyBKRygUxRm+yP4DguE9R1EEv28KJhIxghNp5dcdVXBYUPe1xHoc3QVdzD9c3tf8JFzA2FBlKTlwMwNg==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.81.4.tgz",
"integrity": "sha512-lKAeRZ8EUMtx2cA/Y4KvICr9bIr5SE03iK3lm+l9wyn2lkjLUuPjYVep159inLeDqC6AtSubsA8MZLziP7c03g==",
"license": "MIT",
"optional": true,
"peer": true,
@ -20384,13 +20384,13 @@
"@babel/parser": "^7.25.3",
"@babel/types": "^7.25.2",
"flow-enums-runtime": "^0.0.6",
"metro": "0.81.3",
"metro-babel-transformer": "0.81.3",
"metro-cache": "0.81.3",
"metro-cache-key": "0.81.3",
"metro-minify-terser": "0.81.3",
"metro-source-map": "0.81.3",
"metro-transform-plugins": "0.81.3",
"metro": "0.81.4",
"metro-babel-transformer": "0.81.4",
"metro-cache": "0.81.4",
"metro-cache-key": "0.81.4",
"metro-minify-terser": "0.81.4",
"metro-source-map": "0.81.4",
"metro-transform-plugins": "0.81.4",
"nullthrows": "^1.1.1"
},
"engines": {
@ -22001,9 +22001,9 @@
"license": "MIT"
},
"node_modules/ob1": {
"version": "0.81.3",
"resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.3.tgz",
"integrity": "sha512-wd8zdH0DWsn2iDVn2zT/QURihcqoc73K8FhNCmQ16qkJaoYJLNb/N+huOwdCgsbNP8Lk/s1+dPnDETx+RzsrWA==",
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.4.tgz",
"integrity": "sha512-EZLYM8hfPraC2SYOR5EWLFAPV5e6g+p83m2Jth9bzCpFxP1NDQJYXdmXRB2bfbaWQSmm6NkIQlbzk7uU5lLfgg==",
"license": "MIT",
"optional": true,
"peer": true,

191
scripts/test-android.js

@ -30,6 +30,7 @@
*
* @requires child_process
* @requires path
* @requires readline
*
* @author TimeSafari Team
* @license MIT
@ -37,7 +38,14 @@
const { execSync } = require('child_process');
const { join } = require('path');
const { existsSync, mkdirSync, appendFileSync, readFileSync } = require('fs');
const { existsSync, mkdirSync, appendFileSync, readFileSync, writeFileSync } = require('fs');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const question = (prompt) => new Promise((resolve) => rl.question(prompt, resolve));
// Format date as YYYY-MM-DD-HHMMSS
const getLogFileName = () => {
@ -88,11 +96,57 @@ const verifyJavaInstallation = (log) => {
// Generate test data using generate_data.ts
const generateTestData = async (log) => {
log('🔄 Generating test data...');
// Create .generated directory if it doesn't exist
if (!existsSync('.generated')) {
mkdirSync('.generated', { recursive: true });
}
try {
execSync('npx ts-node test-scripts/generate_data.ts', { stdio: 'inherit' });
// Generate test data
const testData = {
CONTACT1_DID: "did:ethr:0x1943754837A09684Fd6380C1D80aa53E3F20E338",
CLAIM_ID: "01JPVVX7FH0EKQWTQY9HTXZQDZ"
};
const claimDetails = {
claim_id: "01JPVVX7FH0EKQWTQY9HTXZQDZ",
issuedAt: "2025-03-21T08:07:57ZZ",
issuer: "did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"
};
const contacts = [
{
did: "did:ethr:0x1943754837A09684Fd6380C1D80aa53E3F20E338",
name: "Test Contact"
}
];
// Write files
log('📝 Writing test data files...');
writeFileSync('.generated/test-env.json', JSON.stringify(testData, null, 2));
writeFileSync('.generated/claim_details.json', JSON.stringify(claimDetails, null, 2));
writeFileSync('.generated/contacts.json', JSON.stringify(contacts, null, 2));
// Verify files were written
log('✅ Verifying test data files...');
const files = [
'.generated/test-env.json',
'.generated/claim_details.json',
'.generated/contacts.json'
];
for (const file of files) {
if (!existsSync(file)) {
throw new Error(`Failed to create ${file}`);
}
log(`✅ Created ${file}`);
}
log('✅ Test data generated successfully');
} catch (error) {
throw new Error(`Failed to generate test data: ${error.message}`);
log(`❌ Failed to generate test data: ${error.message}`);
throw error;
}
};
@ -116,7 +170,7 @@ const executeDeeplink = async (url, description, log) => {
try {
// Stop the app before executing the deep link
execSync('adb shell am force-stop app.timesafari.app');
execSync('adb shell am force-stop app.timesafari');
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`);
@ -125,11 +179,14 @@ const executeDeeplink = async (url, description, log) => {
// Wait for app to load content
await new Promise(resolve => setTimeout(resolve, 3000));
// Press a key (Back button) to ensure app is in consistent state
// Wait for user confirmation before continuing
await question('\n⏎ Press Enter to continue to next test (or Ctrl+C to quit)...');
// Press Back button to ensure app is in consistent state
log(`📱 Sending keystroke (BACK) to device...`);
execSync('adb shell input keyevent KEYCODE_BACK');
// Wait a bit longer after keystroke before next test
// Small delay after keystroke
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (error) {
log(`❌ Failed to execute deeplink: ${description}`);
@ -144,11 +201,11 @@ const runDeeplinkTests = async (log) => {
try {
// Load test data
const testEnv = parseEnvFile('.generated/test-env.sh');
const testEnv = JSON.parse(readFileSync('.generated/test-env.json', 'utf8'));
const claimDetails = JSON.parse(readFileSync('.generated/claim_details.json', 'utf8'));
const contacts = JSON.parse(readFileSync('.generated/contacts.json', 'utf8'));
// Test each deeplink
// Test URLs
const deeplinkTests = [
{
url: `timesafari://claim/${claimDetails.claim_id}`,
@ -180,26 +237,44 @@ const runDeeplinkTests = async (log) => {
}
];
// Show test plan
log('\n📋 Test Plan:');
deeplinkTests.forEach((test, i) => {
log(`${i + 1}. ${test.description}`);
});
// Execute each test
let testsCompleted = 0;
for (const test of deeplinkTests) {
// Show progress
log(`\n📊 Progress: ${testsCompleted}/${deeplinkTests.length} tests completed`);
// Show upcoming test info
log('\n📱 NEXT TEST:');
log('------------------------');
log(`Description: ${test.description}`);
log(`URL: ${test.url}`);
log('------------------------');
await executeDeeplink(test.url, test.description, log);
}
testsCompleted++;
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');
// If there are more tests, show the next one
if (testsCompleted < deeplinkTests.length) {
const nextTest = deeplinkTests[testsCompleted];
log('\n⏭️ NEXT UP:');
log('------------------------');
log(`Next test will be: ${nextTest.description}`);
log(`URL: ${nextTest.url}`);
log('------------------------');
}
}
log('✅ All deeplink tests completed successfully');
log('\n🎉 All deeplink tests completed successfully!');
rl.close(); // Close readline interface when done
} catch (error) {
log('❌ Deeplink tests failed');
rl.close(); // Close readline interface on error
throw error;
}
};
@ -221,24 +296,88 @@ const configureAndroidProject = async (log) => {
log('⚙️ Configuring Gradle properties...');
const gradleProps = 'android/gradle.properties';
if (!existsSync(gradleProps) || !execSync(`grep -q "android.suppressUnsupportedCompileSdk=34" ${gradleProps}`)) {
// Create file if it doesn't exist
if (!existsSync(gradleProps)) {
execSync('touch android/gradle.properties');
}
// Check if line exists without using grep
const gradleContent = readFileSync(gradleProps, 'utf8');
if (!gradleContent.includes('android.suppressUnsupportedCompileSdk=34')) {
execSync('echo "android.suppressUnsupportedCompileSdk=34" >> android/gradle.properties');
log('✅ Added SDK suppression to gradle.properties');
} else {
log('✅ SDK suppression already configured in gradle.properties');
}
};
// Build and test Android project
const buildAndTestAndroid = async (log, env) => {
log('🏗️ Building Android project...');
// Kill and restart ADB server first
try {
log('🔄 Restarting ADB server...');
execSync('adb kill-server', { stdio: 'inherit' });
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2s
execSync('adb start-server', { stdio: 'inherit' });
await new Promise(resolve => setTimeout(resolve, 3000)); // Wait 3s
// Verify device connection
const devices = execSync('adb devices').toString();
if (!devices.includes('\tdevice')) {
throw new Error('No devices connected after ADB restart');
}
log('✅ ADB server restarted successfully');
} catch (error) {
log(`⚠️ ADB restart failed: ${error.message}`);
log('Continuing with build process...');
}
// Clean build
log('🧹 Cleaning project...');
execSync('cd android && ./gradlew clean', { stdio: 'inherit', env });
log('✅ Gradle clean completed');
// Build
log('🏗️ Building project...');
execSync('cd android && ./gradlew build', { stdio: 'inherit', env });
log('✅ Gradle build completed');
// Run tests with retry
log('🧪 Running Android tests...');
execSync('cd android && ./gradlew connectedAndroidTest', { stdio: 'inherit', env });
log('✅ Android tests completed');
let retryCount = 0;
const maxRetries = 3;
while (retryCount < maxRetries) {
try {
// Verify ADB connection before tests
execSync('adb devices', { stdio: 'inherit' });
// Run the tests
execSync('cd android && ./gradlew connectedAndroidTest', {
stdio: 'inherit',
env,
timeout: 60000 // 1 minute timeout
});
log('✅ Android tests completed');
return;
} catch (error) {
retryCount++;
log(`⚠️ Test attempt ${retryCount} failed: ${error.message}`);
if (retryCount < maxRetries) {
log('🔄 Restarting ADB and retrying...');
execSync('adb kill-server', { stdio: 'inherit' });
await new Promise(resolve => setTimeout(resolve, 2000));
execSync('adb start-server', { stdio: 'inherit' });
await new Promise(resolve => setTimeout(resolve, 3000));
} else {
throw new Error(`Android tests failed after ${maxRetries} attempts`);
}
}
}
};
// Run the app
@ -303,4 +442,10 @@ async function runAndroidTests() {
}
// Execute the test suite
runAndroidTests();
runAndroidTests();
// Add cleanup handler for SIGINT
process.on('SIGINT', () => {
rl.close();
process.exit();
});

6
scripts/test-ios.js

@ -800,7 +800,7 @@ const checkAndRegisterUrlScheme = (log) => {
<array>
<dict>
<key>CFBundleURLName</key>
<string>app.timesafari.app</string>
<string>timesafari.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>timesafari</string>
@ -855,10 +855,10 @@ const getAppIdentifier = () => {
}
// Default fallback
return 'app.timesafari.app';
return 'timesafari.app';
} catch (error) {
console.error('Error getting app identifier:', error);
return 'app.timesafari.app'; // Default fallback
return 'timesafari.app'; // Default fallback
}
};

Loading…
Cancel
Save