This commit is contained in:
Matt DiMeglio 2025-08-25 19:05:09 +00:00 committed by GitHub
commit 7a3d8d71df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
113 changed files with 7919 additions and 10066 deletions

View file

@ -0,0 +1,32 @@
<?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>API_KEY</key>
<string>AIzaSyClZkx4PFWhfIG3JDb6GD3g6Bl7-pWLNrU</string>
<key>GCM_SENDER_ID</key>
<string>917296693147</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.mattdimegs.tones</string>
<key>PROJECT_ID</key>
<string>tones-9f1d4</string>
<key>STORAGE_BUCKET</key>
<string>tones-9f1d4.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:917296693147:ios:73d6d426aa60e52b35ab3e</string>
<key>DATABASE_URL</key>
<string>https://tones-9f1d4-default-rtdb.firebaseio.com</string>
</dict>
</plist>

View file

@ -0,0 +1,30 @@
{
"project_info": {
"project_number": "917296693147",
"firebase_url": "https://tones-9f1d4-default-rtdb.firebaseio.com",
"project_id": "tones-9f1d4",
"storage_bucket": "tones-9f1d4.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:917296693147:android:9387809020ba083035ab3e",
"android_client_info": {
"package_name": "com.mattdimegs.tones"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAT0khB8fuAvWjz0WeWrdPAw1RD-v9ylNU"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View file

@ -14,18 +14,19 @@ react {
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc" hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
// Use Expo CLI to bundle the app, this ensures the Metro config // Use Expo CLI to bundle the app, this ensures the Metro config
// works correctly with Expo projects. // works correctly with Expo projects.
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim()) cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
bundleCommand = "export:embed" bundleCommand = "export:embed"
/* Folders */ /* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..' // The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../") // root = file("../../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native") // reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../node_modules/@react-native/codegen") // codegenDir = file("../../node_modules/@react-native/codegen")
/* Variants */ /* Variants */
// The list of variants to that are debuggable. For those we're going to // The list of variants to that are debuggable. For those we're going to
@ -57,6 +58,9 @@ react {
// //
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"] // hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
} }
/** /**
@ -75,7 +79,7 @@ def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInRelea
* give correct results when using with locales other than en-US. Note that * give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default. * this variant is about 6MiB larger per architecture than default.
*/ */
def jscFlavor = 'org.webkit:android-jsc:+' def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
android { android {
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
@ -83,13 +87,13 @@ android {
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion compileSdk rootProject.ext.compileSdkVersion
namespace 'com.anonymous.testapplication' namespace 'com.mattdimegs.tones'
defaultConfig { defaultConfig {
applicationId 'com.anonymous.testapplication' applicationId 'com.mattdimegs.tones'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 1
versionName "1.0.0" versionName "1.0.1"
} }
signingConfigs { signingConfigs {
debug { debug {
@ -110,6 +114,7 @@ android {
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
} }
} }
packagingOptions { packagingOptions {
@ -117,6 +122,9 @@ android {
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false) useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
} }
} }
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
}
} }
// Apply static values from `gradle.properties` to the `android.packagingOptions` // Apply static values from `gradle.properties` to the `android.packagingOptions`
@ -149,15 +157,15 @@ dependencies {
if (isGifEnabled) { if (isGifEnabled) {
// For animated gif support // For animated gif support
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}") implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
} }
if (isWebpEnabled) { if (isWebpEnabled) {
// For webp support // For webp support
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}") implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
if (isWebpAnimatedEnabled) { if (isWebpAnimatedEnabled) {
// Animated webp support // Animated webp support
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}") implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
} }
} }
@ -168,5 +176,4 @@ dependencies {
} }
} }
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); apply plugin: 'com.google.gms.google-services'
applyNativeModulesAppBuildGradle(project)

View file

@ -0,0 +1,30 @@
{
"project_info": {
"project_number": "917296693147",
"firebase_url": "https://tones-9f1d4-default-rtdb.firebaseio.com",
"project_id": "tones-9f1d4",
"storage_bucket": "tones-9f1d4.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:917296693147:android:9387809020ba083035ab3e",
"android_client_info": {
"package_name": "com.mattdimegs.tones"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAT0khB8fuAvWjz0WeWrdPAw1RD-v9ylNU"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View file

@ -3,5 +3,7 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" /> <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic">
<meta-data android:name="delivery_metrics_exported_to_big_query_enabled" android:value="false"/>
</application>
</manifest> </manifest>

View file

@ -11,7 +11,7 @@
<data android:scheme="https"/> <data android:scheme="https"/>
</intent> </intent>
</queries> </queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme"> <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/> <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
@ -25,9 +25,7 @@
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myapp"/> <data android:scheme="myapp"/>
<data android:scheme="com.anonymous.testapplication"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application> </application>
</manifest> </manifest>

View file

@ -1,4 +1,5 @@
package com.anonymous.testapplication package com.mattdimegs.tones
import expo.modules.splashscreen.SplashScreenManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -15,7 +16,10 @@ class MainActivity : ReactActivity() {
// Set the theme to AppTheme BEFORE onCreate to support // Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar. // coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen. // This is required for expo-splash-screen.
setTheme(R.style.AppTheme); // setTheme(R.style.AppTheme);
// @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af
SplashScreenManager.registerOnActivity(this)
// @generated end expo-splashscreen
super.onCreate(null) super.onCreate(null)
} }

View file

@ -1,4 +1,4 @@
package com.anonymous.testapplication package com.mattdimegs.tones
import android.app.Application import android.app.Application
import android.content.res.Configuration import android.content.res.Configuration
@ -10,6 +10,7 @@ import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher import expo.modules.ApplicationLifecycleDispatcher
@ -21,9 +22,10 @@ class MainApplication : Application(), ReactApplication {
this, this,
object : DefaultReactNativeHost(this) { object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> { override fun getPackages(): List<ReactPackage> {
val packages = PackageList(this).packages
// Packages that cannot be autolinked yet can be added manually here, for example: // Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage()); // packages.add(MyReactNativePackage())
return PackageList(this).packages return packages
} }
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry" override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
@ -40,7 +42,7 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
SoLoader.init(this, false) SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app. // If you opted-in for the New Architecture, we load the native entry point for this app.
load() load()

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,3 +1,6 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/splashscreen_background"/> <item android:drawable="@color/splashscreen_background"/>
<item>
<bitmap android:gravity="center" android:src="@drawable/splashscreen_logo"/>
</item>
</layer-list> </layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,5 +1,5 @@
<resources> <resources>
<string name="app_name">test-application</string> <string name="app_name">Tones</string>
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string> <string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string> <string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
<string name="expo_system_ui_user_interface_style" translatable="false">automatic</string> <string name="expo_system_ui_user_interface_style" translatable="false">automatic</string>

View file

@ -1,17 +1,13 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:textColor">@android:color/black</item>
<item name="android:editTextStyle">@style/ResetEditText</item>
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item> <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="android:statusBarColor">#ffffff</item> <item name="android:statusBarColor">#ffffff</item>
</style> </style>
<style name="ResetEditText" parent="@android:style/Widget.EditText"> <style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
<item name="android:padding">0dp</item> <item name="windowSplashScreenBackground">@color/splashscreen_background</item>
<item name="android:textColorHint">#c8c8c8</item> <item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_logo</item>
<item name="android:textColor">@android:color/black</item> <item name="postSplashScreenTheme">@style/AppTheme</item>
</style>
<style name="Theme.App.SplashScreen" parent="AppTheme">
<item name="android:windowBackground">@drawable/splashscreen</item>
</style> </style>
</resources> </resources>

View file

@ -1,37 +1,31 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext {
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34')
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23'
ndkVersion = "26.1.10909125"
}
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.google.gms:google-services:4.4.1'
classpath('com.android.tools.build:gradle') classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin') classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
} }
} }
apply plugin: "com.facebook.react.rootproject" def reactNativeAndroidDir = new File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('react-native/package.json')")
}.standardOutput.asText.get().trim(),
"../android"
)
allprojects { allprojects {
repositories { repositories {
maven { maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android')) url(reactNativeAndroidDir)
}
maven {
// Android JSC is installed from npm
url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
} }
google() google()
@ -39,3 +33,6 @@ allprojects {
maven { url 'https://www.jitpack.io' } maven { url 'https://www.jitpack.io' }
} }
} }
apply plugin: "expo-root-project"
apply plugin: "com.facebook.react.rootproject"

View file

@ -22,8 +22,8 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Enable AAPT2 PNG crunching
android.enableJetifier=true android.enablePngCrunchInReleaseBuilds=true
# Use this property to specify which architecture you want to build. # Use this property to specify which architecture you want to build.
# You can also override it from the CLI using # You can also override it from the CLI using
@ -35,7 +35,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# your application. You should enable this flag either if you want # your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that # to write custom TurboModules/Fabric components OR use libraries that
# are providing them. # are providing them.
newArchEnabled=false newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine. # Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead. # If set to false, you will be using JSC instead.
@ -54,3 +54,6 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
# Use legacy packaging to compress native libraries in the resulting APK. # Use legacy packaging to compress native libraries in the resulting APK.
expo.useLegacyPackaging=false expo.useLegacyPackaging=false
# Whether the app is configured to use edge-to-edge via the app config or `react-native-edge-to-edge` plugin
expo.edgeToEdgeEnabled=false

Binary file not shown.

View file

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

6
android/gradlew vendored Executable file → Normal file
View file

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

2
android/gradlew.bat vendored
View file

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################

View file

@ -1,18 +1,39 @@
rootProject.name = 'test-application' pluginManagement {
def reactNativeGradlePlugin = new File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
}.standardOutput.asText.get().trim()
).getParentFile().absolutePath
includeBuild(reactNativeGradlePlugin)
dependencyResolutionManagement { def expoPluginsPath = new File(
versionCatalogs { providers.exec {
reactAndroidLibs { workingDir(rootDir)
from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml"))) commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
} }.standardOutput.asText.get().trim(),
} "../android/expo-gradle-plugin"
).absolutePath
includeBuild(expoPluginsPath)
} }
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); plugins {
useExpoModules() id("com.facebook.react.settings")
id("expo-autolinking-settings")
}
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
applyNativeModulesSettingsGradle(settings) if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
ex.autolinkLibrariesFromCommand()
} else {
ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
}
}
expoAutolinking.useExpoModules()
rootProject.name = 'Tones'
expoAutolinking.useExpoVersionCatalog()
include ':app' include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile()) includeBuild(expoAutolinking.reactNativeGradlePlugin)

View file

@ -1,7 +1,7 @@
{ {
"expo": { "expo": {
"name": "Tones", "name": "Tones",
"slug": "Tones", "slug": "tones",
"version": "1.0.1", "version": "1.0.1",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/images/icon.png", "icon": "./assets/images/icon.png",
@ -13,22 +13,40 @@
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"ios": { "ios": {
"entitlements": {
"aps-environment": "production"
},
"infoPlist": {
"UIBackgroundModes": ["remote-notification"]
},
"supportsTablet": true, "supportsTablet": true,
"bundleIdentifier": "com.anonymous.testapplication" "bundleIdentifier": "com.mattdimegs.tones",
"googleServicesFile": "./GoogleServices/GoogleService-Info.plist"
}, },
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png", "foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"package": "com.anonymous.testapplication" "package": "com.mattdimegs.tones",
"googleServicesFile": "./GoogleServices/google-services.json"
}, },
"plugins": [ "plugins": [
"expo-router", "expo-router",
"expo-font" "expo-font",
"expo-web-browser"
], ],
"experiments": { "experiments": {
"typedRoutes": true "typedRoutes": true
} },
"extra": {
"router": {
"origin": false
},
"eas": {
"projectId": "6903a306-dafd-42ab-b010-f0c8205269ad"
}
},
"owner": "tones-bd"
} }
} }

72
app/_layout.jsx Normal file
View file

@ -0,0 +1,72 @@
import React, { useState, useEffect } from 'react';
import { router, Stack } from 'expo-router';
import { AuthProvider, GlobalVariablesProvider, WebSocketProvider } from '@/contexts';
import { useNotifications, useWebSocketContext } from '@/hooks';
import { useAuth } from '@/contexts/AuthContext';
function AppTest() {
const [ oldMessage, setOldMessage ] = useState(1);
const { user } = useAuth();
const { lastMessage } = useWebSocketContext();
const { schedulePushNotification } = useNotifications();
const [isReady, setIsReady] = useState(false);
useEffect(() => {
setIsReady(true);
}, []);
useEffect(() => {
if (isReady) {
if (user) {
// Ok to Leave Console Log... Displays the name so you know what you are signed in as.
console.log('user: ', user?.displayName || 'Not Found');
router.replace('./incidents');
} else {
router.replace('/login');
}
}
}, [isReady, user]);
const parseAddress = (data) => {
const { Address } = data;
const { StreetAddress, AddressApartment, Town, State } = Address;
const response = `${StreetAddress}${AddressApartment ? ` - ${AddressApartment}` : ''} ${Town}, ${State}`
return response;
}
useEffect(() => {
if (lastMessage) {
const parsedMessage = JSON?.parse(lastMessage);
if (parsedMessage?.data && new Date(oldMessage)?.getTime() < new Date(parsedMessage?.timestamp)?.getTime()) {
setOldMessage(new Date(parsedMessage?.timestamp)?.getTime());
schedulePushNotification(
`${parsedMessage?.data?.Response?.ServiceName} - ${parsedMessage?.data?.Incident?.IncNatureCode}`,
`${parsedMessage?.data?.Incident?.IncNature}\n${parseAddress(parsedMessage?.data)}`,
parsedMessage?.data
);
}
}
}, [lastMessage]);
return (
<Stack
screenOptions={{
gestureEnabled: false,
headerBackVisible: false,
headerShown: false
}}
/>
)
}
export default function App() {
return (
<GlobalVariablesProvider>
<WebSocketProvider>
<AuthProvider>
<AppTest />
</AuthProvider>
</WebSocketProvider>
</GlobalVariablesProvider>
);
}

View file

@ -1,26 +0,0 @@
import React, { useEffect } from 'react';
import { router, Stack } from 'expo-router';
import { WebSocketProvider } from '../contexts/WebSocketContext';
export const unstable_settings = {
initialRouteName: 'login',
};
export default function App() {
useEffect(() => {
router.replace('/login');
}, []);
return (
<WebSocketProvider>
<Stack
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="login" />
</Stack>
</WebSocketProvider>
);
}

View file

@ -1,8 +1,9 @@
import React, { useState, useRef, useEffect } from 'react'; import React, { useRef } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { router } from 'expo-router';
import { useCallFeed } from '../hooks/useCallFeed'; import { useCallFeed } from '../hooks/useCallFeed';
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native'; import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
import { useLocalSearchParams, router } from 'expo-router'; import { useLocalSearchParams } from 'expo-router';
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
@ -11,15 +12,19 @@ import { Phone } from "healthicons-react-native/dist/filled";
import { import {
PageHeader, PageHeader,
PageFooter, PageFooter,
} from '../components/generalHelpers.jsx'; } from '@/components/generalHelpers.jsx';
import ActionSheet from 'react-native-actions-sheet'; import ActionSheet from 'react-native-actions-sheet';
const DepartmentActionSheet = styled(ActionSheet)``; const DepartmentActionSheet = styled(ActionSheet)``;
function fromBase64Unicode(str) {
return new TextDecoder().decode(Uint8Array.from(atob(str), c => c.charCodeAt(0)));
}
export default function Call() { export default function Call() {
const { callDetails } = useLocalSearchParams(); const { callDetails } = useLocalSearchParams();
const actionSheetRef = useRef(null); const actionSheetRef = useRef(null);
const callFeed = useCallFeed(); const callFeed = useCallFeed(true);
const { const {
departments, departments,
@ -39,56 +44,56 @@ export default function Call() {
deptList, deptList,
} = departments; } = departments;
const decoded = atob(callDetails); const decoded = fromBase64Unicode(callDetails);
const { Incident, Address, Person, Response } = JSON.parse(decoded); const { incident, address, person, response } = JSON.parse(decoded);
const { CallThemes } = accountDetails; const { CallThemes } = accountDetails;
const { const {
IncID, incID,
IncNumber, incNumber,
JurisdictionNumber, jurisdictionNumber,
ServiceNumber, serviceNumber,
ServiceID, serviceID,
IncDate, incDate,
IncNature, incNature,
IncNatureCode, incNatureCode,
IncNatureCodeDesc, incNatureCodeDesc,
Notes, notes,
Status, status,
Origin, origin,
} = Incident; } = incident;
const { const {
StreetAddress, streetAddress,
AddressApartment, addressApartment,
Town, town,
State, state,
ZipCode, zipCode,
Latitude, latitude,
Longitude, longitude,
County, county,
Intersection1, intersection1,
Intersection2, intersection2,
LocationName, locationName,
WeatherCondition, weatherCondition,
} = Address; } = address;
const { const {
Name, name,
Age, age,
Gender, gender,
Statement, statement,
Conscious, conscious,
Breathing, breathing,
CallBackNumber, callBackNumber,
} = Person; } = person;
const { const {
Units units
} = Response; } = response;
const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency; const SelectedIcon = callIconMap[incNature] || AccidentAndEmergency;
const ownDepartmentResponse = Units?.map((unit) => { const ownDepartmentResponse = units?.map((unit) => {
if (unit?.Department === selectedDepartment?.dept || if (unit?.department === selectedDepartment?.dept ||
selectedDepartment?.addDepts?.includes(unit?.Department)) { selectedDepartment?.addDepts?.includes(unit?.department)) {
return unit; return unit;
} }
return null; return null;
@ -96,9 +101,9 @@ export default function Call() {
return filterItem; return filterItem;
}); });
const mutualAidDepartmentResponse = Units?.map((unit) => { const mutualAidDepartmentResponse = units?.map((unit) => {
if (unit?.Department !== selectedDepartment?.dept && if (unit?.department !== selectedDepartment?.dept &&
!selectedDepartment?.addDepts?.includes(unit?.Department)) { !selectedDepartment?.addDepts?.includes(unit?.department)) {
return unit; return unit;
} }
return null; return null;
@ -107,7 +112,7 @@ export default function Call() {
});; });;
const formatResponseTimes = (time) => { const formatResponseTimes = (time) => {
if (time === null) { if (time === null || time === undefined || time === '') {
return ''; return '';
} }
const initTime = new Date(time); const initTime = new Date(time);
@ -129,16 +134,17 @@ export default function Call() {
return ( return (
<React.Fragment> <React.Fragment>
<PageHeader> <PageHeader
<View leftHeader={ <View style={{ flex: 1, alignItems: 'flex-start' }}>
style={{ <TouchableOpacity
flexDirection: 'column', onPress={router.back}
height: 80, style={{ flexDirection: 'row', alignItems: 'center' }}
alignItems: 'center',
justifyContent: 'flex-end',
paddingBottom: 7
}}
> >
<Ionicons name="chevron-back-outline" size={22} color="red" style={{ paddingLeft: 10 }} />
<Text style={{ color: 'red', fontWeight: 600 }}>Back to Incidents</Text>
</TouchableOpacity>
</View>}
centerHeader={<View style={{ flex: 1, alignItems: 'center' }}>
<TouchableOpacity <TouchableOpacity
style={{ style={{
borderRadius: 6, borderRadius: 6,
@ -159,15 +165,15 @@ export default function Call() {
style={{ style={{
color: selectedDepartmentColorPicker(selectedDepartment?.type), color: selectedDepartmentColorPicker(selectedDepartment?.type),
fontWeight: 600, fontWeight: 600,
fontSize: '14' fontSize: 14
}} }}
> >
{selectedDepartment?.deptAbv} {selectedDepartment?.deptAbv}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>}
</PageHeader> />
<ScrollView> <ScrollView showsVerticalScrollIndicator={false}>
<StatusBar style="dark" /> <StatusBar style="dark" />
<SafeAreaView /> <SafeAreaView />
<View style={{ flexDirection: 'column', padding: 20 }}> <View style={{ flexDirection: 'column', padding: 20 }}>
@ -180,8 +186,8 @@ export default function Call() {
justifyContent: 'space-between' justifyContent: 'space-between'
}} }}
> >
<Text style={{ fontSize: 12 }}>{formatCallDateTime(IncDate)}</Text> <Text style={{ fontSize: 12 }}>{formatCallDateTime(incDate)}</Text>
<Text style={{ fontSize: 12 }}>{formatCallTimePast(IncDate)}</Text> <Text style={{ fontSize: 12 }}>{formatCallTimePast(incDate)}</Text>
</View> </View>
<View key="callDetails" style={{ padding: 2 }}> <View key="callDetails" style={{ padding: 2 }}>
<View <View
@ -191,9 +197,9 @@ export default function Call() {
backgroundColor: '#fff', backgroundColor: '#fff',
shadowOffset: { width: 0, height: 0 }, shadowOffset: { width: 0, height: 0 },
shadowColor: callColorSelector( shadowColor: callColorSelector(
IncNatureCode, incNatureCodeDesc,
IncNature, incNature,
Status status
), ),
shadowOpacity: 1, shadowOpacity: 1,
shadowRadius: 5, shadowRadius: 5,
@ -201,18 +207,18 @@ export default function Call() {
}} }}
> >
<View style={{ flexDirection: 'column' }}> <View style={{ flexDirection: 'column' }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}> <View style={{ flexDirection: 'row', alignItems: 'center', width: '100%' }}>
<SelectedIcon <SelectedIcon
color={callColorSelector( color={callColorSelector(
IncNatureCode, incNatureCodeDesc,
IncNature, incNature,
Status status
)} )}
opacity={0.3} opacity={0.3}
width={56} width={56}
height={56} height={56}
/> />
<View style={{ flexDirection: 'column' }}> <View style={{ flex: 1, flexDirection: 'column' }}>
<Text <Text
style={{ style={{
color: 'black', color: 'black',
@ -220,7 +226,7 @@ export default function Call() {
fontSize: 16 fontSize: 16
}} }}
> >
{`${IncNature}`} {`${incNature}`}
</Text> </Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text <Text
@ -228,20 +234,20 @@ export default function Call() {
color: 'black', color: 'black',
fontSize: 12, fontSize: 12,
textShadowColor: callColorSelector( textShadowColor: callColorSelector(
IncNatureCode, incNatureCodeDesc,
IncNature, incNature,
Status status
), ),
textShadowRadius: 1 textShadowRadius: 1
}} }}
> >
{`${IncNatureCodeDesc}`} {`${incNatureCodeDesc}`}
</Text> </Text>
</View> </View>
</View> </View>
</View> </View>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
{Status === 'CLOSED' ? ( {status.toLowerCase() === 'closed' ? (
<Text <Text
style={{ style={{
fontSize: 12, fontSize: 12,
@ -258,7 +264,7 @@ export default function Call() {
textAlign: 'right' textAlign: 'right'
}} }}
> >
{`Incident #: ${ServiceNumber}`} {`Incident #: ${serviceNumber}`}
</Text> </Text>
</View> </View>
</View> </View>
@ -285,8 +291,8 @@ export default function Call() {
justifyContent: 'space-between' justifyContent: 'space-between'
}} }}
> >
<View style={{ flexDirection: 'column' }}> <View style={{ flexDirection: 'column', maxWidth: '70%' }}>
{LocationName ? ( {locationName ? (
<Text <Text
style={{ style={{
color: 'black', color: 'black',
@ -294,38 +300,38 @@ export default function Call() {
fontSize: 16 fontSize: 16
}} }}
> >
{`${LocationName}`} {`${locationName}`}
</Text> </Text>
) : null} ) : null}
<TouchableOpacity <TouchableOpacity
onLongPress={() => { onLongPress={() => {
return openMaps(Latitude, Longitude); return openMaps(latitude, longitude);
}} }}
> >
<Text <Text
style={[{ style={[{
color: 'black', color: 'black',
}, LocationName ? {} : {fontSize: 12, fontWeight: 600}]} }, locationName ? {} : { fontSize: 12, fontWeight: 600 }]}
> >
{`${StreetAddress}`} {`${streetAddress}`}
</Text> </Text>
<Text <Text
style={[{ style={[{
color: 'black', color: 'black',
}, LocationName ? {} : {fontSize: 12, fontWeight: 600}]} }, locationName ? {} : { fontSize: 12, fontWeight: 600 }]}
> >
{`${Town}, ${State}`} {`${town}, ${state}`}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
{AddressApartment ? ( {addressApartment ? (
<View> <View>
<View style={{ margin: 10 }} /> <View style={{ margin: 10 }} />
<Text <Text
style={[{ style={[{
color: 'black', color: 'black',
}, LocationName ? {} : {fontSize: 12, fontWeight: 600}]} }, locationName ? {} : { fontSize: 12, fontWeight: 600 }]}
> >
{`${AddressApartment}`} {`${addressApartment}`}
</Text> </Text>
</View> </View>
) : null} ) : null}
@ -361,7 +367,7 @@ export default function Call() {
justifyContent: 'center' justifyContent: 'center'
}} }}
onPress={() => { onPress={() => {
return openMaps(Latitude, Longitude); return openMaps(latitude, longitude);
}} }}
> >
<Text style={{ fontSize: 10 }}>Nav</Text> <Text style={{ fontSize: 10 }}>Nav</Text>
@ -400,10 +406,10 @@ export default function Call() {
textAlign: 'center' textAlign: 'center'
}} }}
> >
{Intersection1} {intersection1}
</Text> </Text>
</View> </View>
<View style={{ paddingHorizontal: "3%" }}/> <View style={{ paddingHorizontal: "2%" }} />
<View <View
style={{ style={{
borderRadius: 12, borderRadius: 12,
@ -424,7 +430,7 @@ export default function Call() {
textAlign: 'center' textAlign: 'center'
}} }}
> >
{Intersection2} {intersection2}
</Text> </Text>
</View> </View>
</View> </View>
@ -461,23 +467,23 @@ export default function Call() {
fontSize: 16 fontSize: 16
}} }}
> >
{`${Name}`} {`${name}`}
</Text> </Text>
<TouchableOpacity <TouchableOpacity
onLongPress={() => { onLongPress={() => {
return callNumber(CallBackNumber); return callNumber(callBackNumber);
}} }}
> >
<Text <Text
style={{ color: 'black', fontSize: 12 }} style={{ color: 'black', fontSize: 12 }}
> >
{`${CallBackNumber}`} {`${callBackNumber}`}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<TouchableOpacity <TouchableOpacity
onLongPress={() => { onLongPress={() => {
return callNumber(CallBackNumber); return callNumber(callBackNumber);
}} }}
> >
<Phone <Phone
@ -502,20 +508,20 @@ export default function Call() {
<View style={{ alignItems: 'center' }}> <View style={{ alignItems: 'center' }}>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={{ fontSize: 14 }}> <Text style={{ fontSize: 14 }}>
{`${Age} `} {`${age} `}
</Text> </Text>
<Text style={{ fontSize: 14 }}> <Text style={{ fontSize: 14 }}>
{`${Gender} - `} {`${gender} - `}
</Text> </Text>
<Text style={{ fontSize: 14 }}> <Text style={{ fontSize: 14 }}>
{`Concious: ${Conscious} | `} {`Conscious: ${conscious} | `}
</Text> </Text>
<Text style={{ fontSize: 14 }}> <Text style={{ fontSize: 14 }}>
{`Breathing: ${Breathing}`} {`Breathing: ${breathing}`}
</Text> </Text>
</View> </View>
<Text style={{ fontSize: 12 }}> <Text style={{ fontSize: 12 }}>
{`${Statement}`} {`${statement}`}
</Text> </Text>
</View> </View>
</View> </View>
@ -544,7 +550,7 @@ export default function Call() {
}} }}
> >
<View style={{ flexDirection: 'column' }}> <View style={{ flexDirection: 'column' }}>
{Units?.length > 0 ? ( {units?.length > 0 ? (
<View> <View>
{ownDepartmentResponse?.length > 0 ? ( {ownDepartmentResponse?.length > 0 ? (
<View> <View>
@ -577,7 +583,7 @@ export default function Call() {
> >
{ownDepartmentResponse?.map((unit) => { {ownDepartmentResponse?.map((unit) => {
return ( return (
<View key={unit?.Unit} <View key={unit?.unit}
style={{ style={{
flex: 1, flex: 1,
alignSelf: 'stretch', alignSelf: 'stretch',
@ -588,30 +594,31 @@ export default function Call() {
> >
<Text <Text
style={{ style={{
fontSize: 12,
fontWeight: 600, fontWeight: 600,
textAlign: 'center', textAlign: 'center',
flex: 1 flex: 1
}} }}
> >
{unit?.Unit} {unit?.unit}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Dispatched)} {formatResponseTimes(unit?.dispatched)}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Responding)} {formatResponseTimes(unit?.responding)}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.OnScene)} {formatResponseTimes(unit?.onScene)}
</Text> </Text>
{selectedDepartment?.type === 'EMS' || {selectedDepartment?.type === 'EMS' ||
selectedDepartment?.type === 'Rescue' ? ( selectedDepartment?.type === 'Rescue' ? (
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Transporting)} {formatResponseTimes(unit?.transporting)}
</Text> </Text>
) : null} ) : null}
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.InService)} {formatResponseTimes(unit?.inService)}
</Text> </Text>
</View> </View>
) )
@ -661,7 +668,7 @@ export default function Call() {
/> />
{mutualAidDepartmentResponse?.map((unit) => { {mutualAidDepartmentResponse?.map((unit) => {
return ( return (
<View key={unit?.Unit} <View key={unit?.unit}
style={{ style={{
flex: 1, flex: 1,
alignSelf: 'stretch', alignSelf: 'stretch',
@ -672,30 +679,31 @@ export default function Call() {
> >
<Text <Text
style={{ style={{
fontSize: 12,
fontWeight: 600, fontWeight: 600,
textAlign: 'center', textAlign: 'center',
flex: 1 flex: 1
}} }}
> >
{unit?.Unit} {unit?.unit}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Dispatched)} {formatResponseTimes(unit?.dispatched)}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Responding)} {formatResponseTimes(unit?.responding)}
</Text> </Text>
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.OnScene)} {formatResponseTimes(unit?.onScene)}
</Text> </Text>
{selectedDepartment?.type === 'EMS' || {selectedDepartment?.type === 'EMS' ||
selectedDepartment?.type === 'Rescue' ? ( selectedDepartment?.type === 'Rescue' ? (
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.Transporting)} {formatResponseTimes(unit?.transporting)}
</Text> </Text>
) : null} ) : null}
<Text style={{ textAlign: 'center', flex: 1 }}> <Text style={{ textAlign: 'center', flex: 1 }}>
{formatResponseTimes(unit?.InService)} {formatResponseTimes(unit?.inService)}
</Text> </Text>
</View> </View>
) )
@ -736,10 +744,10 @@ export default function Call() {
minHeight: 200 minHeight: 200
}} }}
> >
{Notes?.split('\n').map((note, index) => ( {notes?.split('\n').map((note, index) => (
<View key={index}> <View key={`notes-${index}`}>
<Text>{note}</Text> <Text>{note}</Text>
{index < Notes.split('\n').length - 1 && ( {index < notes.split('\n').length - 1 && (
<View <View
style={{ style={{
height: 1, height: 1,

View file

@ -42,7 +42,7 @@ export default function TabTwoScreen() {
<ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
different screen densities different screen densities
</ThemedText> </ThemedText>
<Image source={require('@/assets/images/tones-logo.png')} style={{ alignSelf: 'center' }} /> <Image source={require('../assets/images/tones-logo.png')} style={{ alignSelf: 'center' }} />
<ExternalLink href="https://reactnative.dev/docs/images"> <ExternalLink href="https://reactnative.dev/docs/images">
<ThemedText type="link">Learn more</ThemedText> <ThemedText type="link">Learn more</ThemedText>
</ExternalLink> </ExternalLink>

View file

@ -1,20 +1,32 @@
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from "react";
import styled from 'styled-components'; import styled from "styled-components";
import { useCallFeed } from '../hooks/useCallFeed'; import { useCallFeed } from "@/hooks";
import { router } from 'expo-router'; import { router } from "expo-router";
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { SafeAreaView } from 'react-native-safe-area-context';
import { import {
PageHeader, Platform,
PageFooter, Linking,
} from '../components/generalHelpers.jsx'; View,
import { Ionicons } from '@expo/vector-icons'; ScrollView,
Text,
TouchableOpacity,
} from "react-native";
import { StatusBar } from "expo-status-bar";
import { SafeAreaView } from "react-native-safe-area-context";
import { PageHeader, PageFooter } from "@/components/generalHelpers.jsx";
import { Ionicons } from "@expo/vector-icons";
import { AccidentAndEmergency } from "healthicons-react-native/dist/outline"; import { AccidentAndEmergency } from "healthicons-react-native/dist/outline";
import ActionSheet from 'react-native-actions-sheet'; import ActionSheet from "react-native-actions-sheet";
const DepartmentActionSheet = styled(ActionSheet)``; const DepartmentActionSheet = styled(ActionSheet)``;
function toBase64Unicode(str) {
return btoa(
new TextEncoder()
.encode(str)
.reduce((data, byte) => data + String.fromCharCode(byte), "")
);
}
export default function Incidents() { export default function Incidents() {
const actionSheetRef = useRef(null); const actionSheetRef = useRef(null);
const callFeed = useCallFeed(); const callFeed = useCallFeed();
@ -25,16 +37,26 @@ export default function Incidents() {
callDetails, callDetails,
callColorSelector, callColorSelector,
formatCallTimePast, formatCallTimePast,
formatCallDateTime formatCallDateTime,
} = callFeed; } = callFeed;
const sortedAndFilteredCalls = callDetails const sortedAndFilteredCalls =
callDetails
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)) .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
.filter((item, index, self) => { .filter((item, index, self) => {
return index === self.findIndex(i => { return (
return `${i?.data?.Incident?.IncID}${i?.data?.Response?.ServiceName}` === `${item?.data?.Incident?.IncID}${item?.data?.Response?.ServiceName}` index ===
}); self.findIndex((i) => {
}); return (
`${i?.incident?.incID}${i?.response?.serviceName}` ===
`${item?.incident?.incID}${item?.response?.serviceName}`
);
})
);
})
?.map((item) => {
return { ...item, timestamp: item?.incident?.incDate };
}) || [];
const { const {
departmentTypeMap, departmentTypeMap,
@ -49,24 +71,17 @@ export default function Incidents() {
return ( return (
<React.Fragment> <React.Fragment>
<PageHeader> <PageHeader
<View centerHeader={
style={{ <View style={{ flex: 1, alignItems: "center" }}>
flexDirection: 'column',
height: 80,
alignItems: 'center',
justifyContent: 'flex-end',
paddingBottom: 7
}}
>
<TouchableOpacity <TouchableOpacity
style={{ style={{
borderRadius: 6, borderRadius: 6,
elevation: 3, elevation: 3,
backgroundColor: '#fff', backgroundColor: "#fff",
shadowOffset: { width: 0, height: 0 }, shadowOffset: { width: 0, height: 0 },
shadowColor: '#333', shadowColor: "#333",
shadowOpacity: .8, shadowOpacity: 0.8,
shadowRadius: 2, shadowRadius: 2,
paddingHorizontal: 10, paddingHorizontal: 10,
paddingVertical: 2, paddingVertical: 2,
@ -77,175 +92,204 @@ export default function Incidents() {
> >
<Text <Text
style={{ style={{
color: selectedDepartmentColorPicker(selectedDepartment?.type), color: selectedDepartmentColorPicker(
selectedDepartment?.type
),
fontWeight: 600, fontWeight: 600,
fontSize: 14 fontSize: 14,
}} }}
> >
{selectedDepartment?.deptAbv} {selectedDepartment?.deptAbv}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</PageHeader> }
/>
<ScrollView> <ScrollView>
<StatusBar style="dark" /> <StatusBar style="dark" />
<SafeAreaView /> <SafeAreaView />
<View style={{ flexDirection: 'column', padding: 20 }}> <View style={{ flexDirection: "column", padding: 20 }}>
{sortedAndFilteredCalls?.length ? ( {sortedAndFilteredCalls?.length ? (
sortedAndFilteredCalls?.map((callItem, index) => { sortedAndFilteredCalls?.map((callItem, index) => {
const { data: call, timestamp } = callItem; const { incident, address, response, timestamp } = callItem;
const { Incident, Address, Response } = call;
const { const {
ServiceNumber, serviceNumber,
IncDate, incDate,
IncNature, incNature,
IncNatureCode, incNatureCode,
IncNatureCodeDesc, incNatureCodeDesc,
Status, status,
} = Incident; } = incident;
const { const {
StreetAddress, streetAddress,
AddressApartment, addressApartment,
Town, town,
State, state,
LocationName, locationName,
} = Address; } = address;
const { const { serviceName } = response;
ServiceName const SelectedIcon =
} = Response; callIconMap[incNature] || AccidentAndEmergency;
const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency;
return ( return (
<TouchableOpacity <TouchableOpacity
key={`callDetails - ${timestamp}`} key={`callDetails - ${timestamp}`}
style={{ padding: 2 }} style={{ paddingBottom: 15 }}
onPress={() => { onPress={() => {
router.push({ router.push({
pathname: '/call', pathname: "/call",
params: { params: {
callDetails: btoa(JSON.stringify(call)) callDetails: toBase64Unicode(JSON.stringify(callItem)),
} },
}) });
}} }}
> >
<View <View
style={{ style={{
borderRadius: 12, borderRadius: 12,
elevation: 3, elevation: 3,
backgroundColor: '#fff', backgroundColor: "#fff",
shadowOffset: { width: 0, height: 0 }, shadowOffset: { width: 0, height: 0 },
shadowColor: callColorSelector( shadowColor: callColorSelector(
IncNatureCode, incNatureCodeDesc,
IncNature, incNature,
Status status
), ),
shadowOpacity: 1, shadowOpacity: 1,
shadowRadius: 5, shadowRadius: 5,
padding: 10, padding: 10,
}} }}
> >
<View style={{ flexDirection: 'column' }}> <View style={{ flexDirection: "column" }}>
<View key="callDateAndTime" <View
key="callDateAndTime"
style={{ style={{
paddingBottom: 6, paddingBottom: 6,
flexDirection: 'row', flexDirection: "row",
justifyContent: 'space-between' justifyContent: "space-between",
}} }}
> >
<Text style={{ fontSize: 12 }}>{formatCallDateTime(IncDate)}</Text> <Text style={{ fontSize: 12 }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}> {formatCallDateTime(incDate)}
<Text style={{ fontSize: 12 }}>{formatCallTimePast(IncDate)}</Text> </Text>
{Status === 'CLOSED' ? ( <View
style={{ flexDirection: "row", alignItems: "center" }}
>
<Text style={{ fontSize: 12 }}>
{formatCallTimePast(incDate)}
</Text>
{status === "CLOSED" ? (
<Ionicons <Ionicons
name="lock-closed-outline" name="lock-closed-outline"
color='red' color="red"
style={{ style={{
shadowColor: 'black', shadowColor: "black",
shadowOffset: 0, shadowOffset: 0,
shadowOpacity: 1, shadowOpacity: 1,
shadowRadius: 10 shadowRadius: 10,
}} }}
/> />
) : null} ) : null}
</View> </View>
</View> </View>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}> <View
style={{ flexDirection: "row", alignItems: "center" }}
>
<SelectedIcon <SelectedIcon
color={callColorSelector( color={callColorSelector(
IncNatureCode, incNatureCodeDesc,
IncNature, incNature,
Status status
)} )}
opacity={0.3} opacity={0.3}
width={56} width={56}
height={56} height={56}
/> />
<View style={{ flexDirection: 'column' }}> <View
{LocationName ? (
<Text
style={{ style={{
color: 'black', flex: 1,
fontWeight: 600, flexDirection: "column",
fontSize: 16 alignItems: "flex-start",
paddingHorizontal: 2,
maxWidth: "80%",
}} }}
> >
{`${LocationName}`} {locationName ? (
<Text
style={{
color: "black",
fontWeight: 600,
fontSize: 16,
}}
>
{`${locationName}`}
</Text> </Text>
) : ( ) : (
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: "row" }}>
<Text <Text
style={[{ style={[
color: 'black', {
color: "black",
fontSize: 12, fontSize: 12,
fontWeight: 600 fontWeight: 600,
}]} },
]}
> >
{`${StreetAddress}`} {`${streetAddress?.split(",")[0]}`}
</Text> </Text>
{AddressApartment ? ( {addressApartment ? (
<Text <Text
style={[{ style={[
color: 'black', {
color: "black",
fontSize: 12, fontSize: 12,
fontWeight: 600 fontWeight: 600,
}]} },
]}
> >
{` - ${AddressApartment}`} {` - ${addressApartment}`}
</Text> </Text>
) : null} ) : null}
<Text <Text
style={[{ style={[
color: 'black', {
color: "black",
fontSize: 12, fontSize: 12,
fontWeight: 600 fontWeight: 600,
}]} },
]}
> >
{` ${Town}, ${State}`} {` ${town}, ${state}`}
</Text> </Text>
</View> </View>
)} )}
<Text <Text
style={{ style={{
color: 'black', color: "black",
fontWeight: 600, fontWeight: 600,
fontSize: 16 fontSize: 16,
}} }}
> >
{`${IncNature}`} {`${incNature}`}
</Text> </Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> <View
style={{
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Text <Text
style={{ style={{
color: 'black', color: "black",
fontSize: 12, fontSize: 12,
textShadowColor: callColorSelector( textShadowColor: callColorSelector(
IncNatureCode, incNatureCode,
IncNature, incNature,
Status status
), ),
textShadowRadius: 1 textShadowRadius: 1,
}} }}
> >
{`${IncNatureCodeDesc}`} {`${incNatureCodeDesc}`}
</Text> </Text>
</View> </View>
</View> </View>
@ -255,48 +299,47 @@ export default function Incidents() {
</View> </View>
</View> </View>
</View> </View>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> <View
style={{
paddingTop: 5,
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Text <Text
style={{ style={{
fontSize: 12, fontSize: 12,
}} }}
> >
Service: {ServiceName} Service: {serviceName}
</Text> </Text>
<Text <Text
style={{ style={{
fontSize: 12, fontSize: 12,
textAlign: 'right' textAlign: "right",
}} }}
> >
{`Incident #: ${ServiceNumber}`} {`Incident #: ${serviceNumber}`}
</Text> </Text>
</View> </View>
</View> </View>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
) );
})) : ( })
<View style={{ ) : (
marginTop: '50%', <Text>There are no Calls</Text>
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-end',
}}>
<Ionicons name="warning-outline" size={100} color='orange' />
<Text style={{ fontSize: 25 }}>There are no Incidents</Text>
</View>
)} )}
</View> </View>
</ScrollView> </ScrollView>
<PageFooter> <PageFooter>
<View <View
style={{ style={{
flexDirection: 'column', flexDirection: "column",
height: 100, height: 100,
alignItems: 'center', alignItems: "center",
justifyContent: 'flex-start', justifyContent: "flex-start",
paddingTop: 7 paddingTop: 7,
}} }}
/> />
</PageFooter> </PageFooter>
@ -306,10 +349,10 @@ export default function Incidents() {
containerStyle={{ containerStyle={{
height: "50%", height: "50%",
width: "100%", width: "100%",
backgroundColor: '#ECEDEE', backgroundColor: "#ECEDEE",
}} }}
> >
<View style={{ flexDirection: 'column', padding: 20 }}> <View style={{ flexDirection: "column", padding: 20 }}>
{deptList?.map((item) => { {deptList?.map((item) => {
return ( return (
<View style={{ padding: 2 }} key={item?.deptId}> <View style={{ padding: 2 }} key={item?.deptId}>
@ -317,44 +360,56 @@ export default function Incidents() {
style={{ style={{
borderRadius: 6, borderRadius: 6,
elevation: 3, elevation: 3,
backgroundColor: item?.selected ? 'grey' : '#fff', backgroundColor: item?.selected ? "grey" : "#fff",
shadowOffset: { width: 1, height: 1 }, shadowOffset: { width: 1, height: 1 },
shadowColor: '#333', shadowColor: "#333",
shadowOpacity: 0.3, shadowOpacity: 0.3,
shadowRadius: 2, shadowRadius: 2,
marginHorizontal: 20, marginHorizontal: 20,
marginVertical: 6, marginVertical: 6,
padding: 10 padding: 10,
}} }}
onPress={() => { onPress={() => {
actionSheetRef.current?.hide(); actionSheetRef.current?.hide();
return updateSelectedDepartment( return updateSelectedDepartment(
selectedDepartment?.deptId, selectedDepartment?.deptId,
item?.deptId item?.deptId
) );
}}
>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
}} }}
> >
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text <Text
style={{ style={{
color: selectedDepartmentColorPicker( color: selectedDepartmentColorPicker(item?.type),
item?.type
),
fontWeight: 600, fontWeight: 600,
fontSize: 16 fontSize: 16,
}} }}
> >
{item?.dept} {item?.dept}
</Text> </Text>
{item?.primary ? <Ionicons name="star" size={16} color="yellow" style={{ {item?.primary ? (
<Ionicons
name="star"
size={16}
color="yellow"
style={{
paddingLeft: 20, paddingLeft: 20,
shadowColor: '#333', shadowColor: "#333",
shadowOffset: 1, shadowOffset: 1,
shadowOpacity: 1, shadowOpacity: 1,
shadowRadius: 6 shadowRadius: 6,
}} /> : null} }}
/>
) : null}
</View> </View>
<Text>{`${item?.deptAbv} - ${departmentTypeMap[item?.type]}`}</Text> <Text>{`${item?.deptAbv} - ${
departmentTypeMap[item?.type]
}`}</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
); );
@ -362,5 +417,5 @@ export default function Incidents() {
</View> </View>
</DepartmentActionSheet> </DepartmentActionSheet>
</React.Fragment> </React.Fragment>
) );
} }

View file

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native'; import { View, Text, ScrollView, KeyboardAvoidingView, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
@ -20,22 +20,35 @@ import {
ExtraText, ExtraText,
TextLinkContent, TextLinkContent,
LoginTextInput LoginTextInput
} from '../components/generalHelpers.jsx'; } from '@/components/generalHelpers.jsx';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from '@/contexts/firebase';
import { useNotifications } from '@/hooks';
export default function Login() { export default function Login() {
const [hidePassword, setHidePassword] = useState(true); const [hidePassword, setHidePassword] = useState(true);
const [loginButtonDisabled, setLoginButtonDisabled] = useState(true); const [loginButtonDisabled, setLoginButtonDisabled] = useState(true);
const [auth, setAuth] = useState(false); const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { expoPushToken } = useNotifications();
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
number: '', email: '',
password: '' password: ''
}, },
onSubmit: (values) => { onSubmit: async (values) => {
values.number = values.number.replace(/[()\-\s]/g, ''); setError('');
console.log(values); setLoading(true);
setAuth(true); try {
await signInWithEmailAndPassword(auth, values.email, values.password);
router.replace('./incidents');
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, },
}); });
@ -43,49 +56,45 @@ export default function Login() {
useEffect(() => { useEffect(() => {
if (formValues) { if (formValues) {
if (formValues.number.length === 14 && formValues.password) { if (formValues.email && formValues.password) {
setLoginButtonDisabled(false); setLoginButtonDisabled(false);
} else { } else {
setLoginButtonDisabled(true); setLoginButtonDisabled(true);
} }
} }
}, [formValues]) }, [formValues]);
useEffect(() => {
// Temp for Testing
// if (!auth) {
// setTimeout(() => {
// router.replace('./incidents');
// }, 1000);
// }
if (auth) {
router.replace('./incidents');
}
}, [auth])
return ( return (
<React.Fragment> <View style={{ flex: 1 }}>
<StatusBar style="dark" />
<PageHeader> <PageHeader>
<View style={{ flexDirection: 'row', height: 80, alignItems: 'center' }} /> <View style={{ flexDirection: 'row', height: 80, alignItems: 'center' }} />
</PageHeader> </PageHeader>
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={0}
>
<ScrollView keyboardShouldPersistTaps="handled" contentContainerStyle={{ flexGrow: 1 }}>
<StyledContainer> <StyledContainer>
<StatusBar style="dark" />
<SafeAreaView /> <SafeAreaView />
<InnerContainer> <InnerContainer>
<PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} /> <PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} />
<Title>Tones</Title> <Title>Tones</Title>
<SubTitle>Account Login</SubTitle> <SubTitle>Account Login</SubTitle>
<StyledFormArea> <StyledFormArea>
{error ? <MessageBox style={{ color: 'red' }}>{error}</MessageBox> : null}
<LoginTextInput <LoginTextInput
label="Phone Number" label="Email Address"
icon="call-outline" icon="mail-outline"
placeholder="123-456-7890" placeholder="test@organization.com"
placeholderTextColor="gray" placeholderTextColor="gray"
onChangeText={formik.handleChange('number')} onChangeText={formik.handleChange('email')}
onBlur={formik.handleBlur('number')} onBlur={formik.handleBlur('email')}
value={formik.values.number.replace(/^(\d{3})(\d{3})(\d+)$/, "($1) $2-$3")} value={formik.values.email}
keyboardType="number-pad" keyboardType="email-address"
maxLength={14} autoComplete='email'
autoCapitalize='none'
/> />
<LoginTextInput <LoginTextInput
label="Password" label="Password"
@ -122,9 +131,12 @@ export default function Login() {
<TextLinkContent>Landing</TextLinkContent> <TextLinkContent>Landing</TextLinkContent>
</Link> </Link>
</View> </View>
<Text>View Token: {expoPushToken}</Text>
<Line /> <Line />
</InnerContainer> </InnerContainer>
</StyledContainer> </StyledContainer>
</React.Fragment> </ScrollView>
</KeyboardAvoidingView>
</View>
); );
} }

View file

@ -1,6 +1,10 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import * as Notifications from 'expo-notifications';
import { router } from 'expo-router'; import { router } from 'expo-router';
import { View, ScrollView, Text, TouchableOpacity } from 'react-native'; import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
import { auth } from '@/contexts/firebase';
import { useAuth } from '@/contexts/AuthContext';
import { View, ScrollView, Text, TouchableOpacity, KeyboardAvoidingView, Platform } from 'react-native';
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
@ -19,14 +23,16 @@ import {
MessageBox, MessageBox,
LoginTextInput, LoginTextInput,
RegisterDropdownInput, RegisterDropdownInput,
} from '../components/generalHelpers.jsx'; formatPhoneNumber
} from '@/components/generalHelpers.jsx';
export default function Register() { export default function Register() {
const [providerDropdownOpen, setProviderDropdownOpen] = useState(false); const [providerDropdownOpen, setProviderDropdownOpen] = useState(false);
const [hidePassword, setHidePassword] = useState(true); const [hidePassword, setHidePassword] = useState(true);
const [registerButtonDisabled, setRegisterButtonDisabled] = useState(true); const [registerButtonDisabled, setRegisterButtonDisabled] = useState(true);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { user } = useAuth();
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
@ -38,9 +44,60 @@ export default function Register() {
password: '', password: '',
passwordConfirmation: '' passwordConfirmation: ''
}, },
onSubmit: (values) => { onSubmit: async (values) => {
values.number = values.number.replace(/[()\-\s]/g, ''); setError('');
console.log(values); setLoading(true);
try {
const userCredential = await createUserWithEmailAndPassword(auth, values.email, values.password);
await updateProfile(userCredential.user, {
displayName: `${values.firstName} ${values.lastName}`
});
// Request permissions and get push token (native FCM if possible, else Expo token)
let token = null;
let tokenType = null;
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus === 'granted') {
try {
// Try to get native FCM token (works in dev/prod builds, not Expo Go)
const deviceToken = await Notifications.getDevicePushTokenAsync({ provider: 'fcm' });
if (deviceToken?.data) {
token = deviceToken.data;
tokenType = 'fcm';
} else {
// Fallback to Expo push token
const expoToken = await Notifications.getExpoPushTokenAsync();
token = expoToken.data;
tokenType = 'expo';
}
} catch (e) {
// Fallback to Expo push token if native fails
const expoToken = await Notifications.getExpoPushTokenAsync();
token = expoToken.data;
tokenType = 'expo';
}
}
await postgresServices.createUser({
firstName: values.firstName,
lastName: values.lastName,
number: values.number,
email: values.email,
provider: values.provider,
departments: [],
token,
uid: userCredential.user.uid
})
router.replace('./incidents');
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
} }
}); });
@ -48,7 +105,8 @@ export default function Register() {
useEffect(() => { useEffect(() => {
if (formValues) { if (formValues) {
if ((formValues.number.length === 14 || (formValues.number.length === 10 && !formValues.number.includes('('))) && formValues.email && formValues.firstName && formValues.lastName) { const regex = /^[^@]+@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z0-9-]+$/;
if ((formValues.number.length === 14 || (formValues.number.length === 10 && !formValues.number.includes('('))) && regex.test(formValues.email) && formValues.firstName && formValues.lastName) {
if (formValues.password.length !== 0 && (formValues.password === formValues.passwordConfirmation)) { if (formValues.password.length !== 0 && (formValues.password === formValues.passwordConfirmation)) {
setRegisterButtonDisabled(false); setRegisterButtonDisabled(false);
} else { } else {
@ -62,22 +120,33 @@ export default function Register() {
} }
}, [formValues]) }, [formValues])
useEffect(() => {
if (user) {
router.replace('./incidents');
}
}, [user]);
return ( return (
<View> <View style={{ flex: 1 }}>
<PageHeader> <StatusBar style="dark" />
<View style={{ flexDirection: 'row', height: 80, alignItems: 'flex-end' }}> <PageHeader
leftHeader={
<TouchableOpacity onPress={router.back} style={{ flexDirection: 'row', alignItems: 'center', paddingBottom: 5 }}> <TouchableOpacity onPress={router.back} style={{ flexDirection: 'row', alignItems: 'center', paddingBottom: 5 }}>
<Ionicons name="chevron-back-outline" size={22} color="red" style={{ paddingLeft: 20 }} /> <Ionicons name="chevron-back-outline" size={22} color="red" style={{ paddingLeft: 20 }} />
<Text style={{ color: 'red', fontWeight: 600 }}>Back to Login</Text> <Text style={{ color: 'red', fontWeight: 600 }}>Back to Login</Text>
</TouchableOpacity> </TouchableOpacity>}
</View> />
</PageHeader> <KeyboardAvoidingView
<ScrollView> style={{ flex: 1 }}
<StyledContainer> behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
<StatusBar style="dark" /> keyboardVerticalOffset={0}
>
<ScrollView keyboardShouldPersistTaps="handled" contentContainerStyle={{ flexGrow: 1 }}>
<SafeAreaView /> <SafeAreaView />
<StyledContainer>
<InnerContainer> <InnerContainer>
<PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} /> <PageImage resizeMode="cover" source={require('./../assets/images/tones-logo.png')} />
{error ? <MessageBox style={{ color: 'red' }}>{error}</MessageBox> : null}
<Title>Tones</Title> <Title>Tones</Title>
<SubTitle>Account Register</SubTitle> <SubTitle>Account Register</SubTitle>
<StyledFormArea> <StyledFormArea>
@ -106,8 +175,9 @@ export default function Register() {
placeholderTextColor="gray" placeholderTextColor="gray"
onChangeText={formik.handleChange('number')} onChangeText={formik.handleChange('number')}
onBlur={formik.handleBlur('number')} onBlur={formik.handleBlur('number')}
value={formik.values.number.replace(/^(\d{3})(\d{3})(\d+)$/, "($1) $2-$3")} value={formatPhoneNumber(formik.values.number)}
keyboardType="number-pad" autoComplete='tel'
keyboardType='phone-pad'
maxLength={14} maxLength={14}
/> />
<RegisterDropdownInput <RegisterDropdownInput
@ -127,6 +197,8 @@ export default function Register() {
onBlur={formik.handleBlur('email')} onBlur={formik.handleBlur('email')}
value={formik.values.email} value={formik.values.email}
keyboardType="email-address" keyboardType="email-address"
autoComplete='email'
autoCapitalize='none'
/> />
<LoginTextInput <LoginTextInput
label="Password" label="Password"
@ -162,6 +234,7 @@ export default function Register() {
</InnerContainer> </InnerContainer>
</StyledContainer> </StyledContainer>
</ScrollView> </ScrollView>
</KeyboardAvoidingView>
</View> </View>
) )
} }

View file

@ -1,91 +0,0 @@
import { Image, StyleSheet, Platform } from 'react-native';
import { HelloWave } from '@/components/HelloWave';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
export default function HomeScreen() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
headerImage={
<Image
source={require('@/assets/images/tones-logo.png')}
style={styles.reactLogo}
/>
}
>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Welcome!</ThemedText>
<HelloWave />
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
<ThemedText>
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
Press{' '}
<ThemedText type="defaultSemiBold">
{Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
</ThemedText>{' '}
to open developer tools.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
<ThemedText>
Tap the Explore tab to learn more about what's included in this starter app.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
<ThemedText>
When you're ready, run{' '}
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
<ThemedText>
When you're ready, run{' '}
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
<ThemedText>
When you're ready, run{' '}
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
</ThemedText>
</ThemedView>
</ParallaxScrollView>
);
}
const styles = StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
});

View file

@ -2,8 +2,8 @@ import Ionicons from '@expo/vector-icons/Ionicons';
import { PropsWithChildren, useState } from 'react'; import { PropsWithChildren, useState } from 'react';
import { StyleSheet, TouchableOpacity, useColorScheme } from 'react-native'; import { StyleSheet, TouchableOpacity, useColorScheme } from 'react-native';
import { ThemedText } from '@/components/ThemedText'; import { ThemedText } from '../components/ThemedText';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '../components/ThemedView';
import { Colors } from '@/constants/Colors'; import { Colors } from '@/constants/Colors';
export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {

View file

@ -7,7 +7,7 @@ import Animated, {
withSequence, withSequence,
} from 'react-native-reanimated'; } from 'react-native-reanimated';
import { ThemedText } from '@/components/ThemedText'; import { ThemedText } from '../components/ThemedText';
export function HelloWave() { export function HelloWave() {
const rotationAnimation = useSharedValue(0); const rotationAnimation = useSharedValue(0);

View file

@ -7,7 +7,7 @@ import Animated, {
useScrollViewOffset, useScrollViewOffset,
} from 'react-native-reanimated'; } from 'react-native-reanimated';
import { ThemedView } from '@/components/ThemedView'; import { ThemedView } from '../components/ThemedView';
const HEADER_HEIGHT = 250; const HEADER_HEIGHT = 250;

View file

@ -1,6 +1,6 @@
import { Text, type TextProps, StyleSheet } from 'react-native'; import { Text, type TextProps, StyleSheet } from 'react-native';
import { useThemeColor } from '@/hooks/useThemeColor'; import { useThemeColor } from '../hooks/useThemeColor';
export type ThemedTextProps = TextProps & { export type ThemedTextProps = TextProps & {
lightColor?: string; lightColor?: string;

View file

@ -1,6 +1,6 @@
import { View, type ViewProps } from 'react-native'; import { View, type ViewProps } from 'react-native';
import { useThemeColor } from '@/hooks/useThemeColor'; import { useThemeColor } from '../hooks/useThemeColor';
export type ThemedViewProps = ViewProps & { export type ThemedViewProps = ViewProps & {
lightColor?: string; lightColor?: string;

View file

@ -1,7 +1,8 @@
import React, { useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { View, Text, LayoutAnimation, Image, TextInput, TouchableOpacity, TouchableNativeFeedback, ScrollView } from 'react-native'; import { View, Text, LayoutAnimation, Image, TextInput, TouchableOpacity, TouchableNativeFeedback, ScrollView, Platform, Modal, Pressable } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import { Row } from './Row';
import { Container } from './Container'; import { Container } from './Container';
export const StyledContainer = styled.View` export const StyledContainer = styled.View`
@ -204,11 +205,33 @@ const providerConversion = {
} }
export const PageHeader = ({ export const PageHeader = ({
children leftHeader = <View style={{ flex: 1 }} />,
centerHeader = <View style={{ flex: 1 }} />,
rightHeader = <View style={{ flex: 1 }} />
}) => { }) => {
return ( return (
<View style={{ position: 'sticky', top: 0, backgroundColor: '#ECEDEE', zIndex: 1, marginBottom: -100 }}> <View style={{ position: 'sticky', top: 0, backgroundColor: '#ECEDEE', zIndex: 1, marginBottom: -100 }}>
{children} <View
style={{
flexDirection: 'column',
height: 80,
alignItems: 'center',
justifyContent: 'flex-end',
paddingBottom: 7
}}
>
<View style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
paddingHorizontal: 0
}}>
{leftHeader}
{centerHeader}
{rightHeader}
</View>
</View>
</View> </View>
) )
} }
@ -249,91 +272,108 @@ export const LoginTextInput = ({
export const RegisterDropdownInput = ({ export const RegisterDropdownInput = ({
label, label,
isOpen, isOpen: _isOpen,
setOpen, setOpen: _setOpen,
selectedValue, selectedValue,
onValueChange, onValueChange,
menu menu
}) => { }) => {
const [modalVisible, setModalVisible] = useState(false);
return ( return (
<Container> <Container>
<StyledInputLabel>{label}</StyledInputLabel> <StyledInputLabel>{label}</StyledInputLabel>
<TouchableOpacity activeOpacity={0.8} key={`${menu.menuName}2`} <TouchableOpacity
activeOpacity={0.8}
style={{ style={{
backgroundColor: '#E5E7EB', backgroundColor: '#E5E7EB',
marginTop: 3, marginTop: 3,
marginBottom: 10, marginBottom: 10,
borderRadius: '5px', borderRadius: 5,
flexDirection: 'row',
alignItems: 'center',
minHeight: 60,
paddingHorizontal: 15,
}} }}
onPress={() => { onPress={() => setModalVisible(true)}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); >
LayoutAnimation.configureNext(LayoutAnimation.create(200, 'easeInEaseOut', 'opacity'));
isOpen ? setOpen(false) : setOpen(true);
}}>
<Row style={{
paddingHorizontal: 16,
paddingVertical: 16 / 1.2,
}}>
<Ionicons <Ionicons
name={menu.iconName} name={menu.iconName}
size={30} size={30}
color={menu.iconColor} color={menu.iconColor}
/> />
<Text style={{ <Text style={{ color: selectedValue ? 'black' : 'grey', fontSize: 16, paddingHorizontal: 16, flex: 1 }}>
fontSize: 16,
paddingHorizontal: 16
}}>
{selectedValue ? providerConversion[selectedValue] : menu.placeholder} {selectedValue ? providerConversion[selectedValue] : menu.placeholder}
</Text> </Text>
<DropdownArrow <DropdownArrow onPress={() => setModalVisible(!modalVisible)}>
onPress={() => { <Ionicons name={modalVisible ? "chevron-up-outline" : "chevron-down-outline"} size={30} color="gray" />
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
LayoutAnimation.configureNext(LayoutAnimation.create(200, 'easeInEaseOut', 'opacity'));
isOpen ? setOpen(false) : setOpen(true);
}}
>
<Ionicons
name={isOpen ? "chevron-up-outline" : "chevron-down-outline"}
size={30}
color="gray"
/>
</DropdownArrow> </DropdownArrow>
</Row> </TouchableOpacity>
{isOpen && <ScrollView style={{ borderRadius: '5px', backgroundColor: '#E5E7EB' }}> <Modal
{menu.dropdownList.map((subMenu, index) => { visible={modalVisible}
return ( animationType="slide"
<TouchableNativeFeedback transparent={true}
key={index} onRequestClose={() => setModalVisible(false)}
onPress={() => { >
onValueChange(subMenu.value); <Pressable
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); style={{ flex: 1 }}
LayoutAnimation.configureNext(LayoutAnimation.create(200, 'easeInEaseOut', 'opacity')); onPress={() => setModalVisible(false)}
setOpen(false); />
<View style={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
backgroundColor: '#fff',
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
paddingBottom: 32,
paddingTop: 16,
}}>
<Pressable
style={{ flex: 1, paddingHorizontal: 15, alignItems: 'flex-end' }}
onPress={() => setModalVisible(false)}
>
<Text style={{ color: 'red', fontWeight: 600 }}>
Close
</Text>
</Pressable>
<Picker
selectedValue={selectedValue}
onValueChange={(value) => {
onValueChange(value);
}} }}
> >
<View style={{ {menu.dropdownList.map((item) => (
paddingHorizontal: 16, <Picker.Item color="black" label={item.label} value={item.value} key={item.value} />
paddingVertical: 16 / 1.5, ))}
borderTopColor: 'gray', </Picker>
borderTopWidth: .5,
marginHorizontal: 10
}}>
<Text>{subMenu.label}</Text>
{selectedValue === subMenu.value &&
<SelectedCheckmark>
<Ionicons
name="checkmark-outline"
size={30}
color="red"
/>
</SelectedCheckmark>
}
</View> </View>
</TouchableNativeFeedback> </Modal>
)
})}
</ScrollView>}
</TouchableOpacity>
</Container> </Container>
) );
} }
export const formatPhoneNumber = (e) => {
let formattedNumber;
const length = e?.length;
const regex = () => e.replace(/[^0-9\.]+/g, "");
const areaCode = () => `(${regex().slice(0, 3)})`;
const firstSix = () => `${areaCode()} ${regex().slice(3, 6)}`;
const trailer = (start) => `${regex().slice(start, regex().length)}`;
if (length <= 3) {
formattedNumber = regex();
} else if (length === 4) {
formattedNumber = `${areaCode()} ${trailer(3)}`;
} else if (length === 5) {
formattedNumber = `${areaCode().replace(")", "")}`;
} else if (length >= 5 && length <= 9) {
formattedNumber = `${areaCode()} ${trailer(3)}`;
} else if (length >= 10) {
formattedNumber = `${firstSix()}-${trailer(6)}`;
}
return formattedNumber;
};

30
contexts/AuthContext.js Normal file
View file

@ -0,0 +1,30 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged, signOut } from 'firebase/auth';
import { auth } from './firebase';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (firebaseUser) => {
setUser(firebaseUser);
setLoading(false);
});
return unsubscribe;
}, []);
const logout = () => signOut(auth);
return (
<AuthContext.Provider value={{ user, loading, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
return useContext(AuthContext);
};

View file

@ -0,0 +1,35 @@
import React, { createContext, useEffect, useState } from 'react';
import { AppState } from 'react-native';
export const GlobalVariablesContext = createContext(null);
export const GlobalVariablesProvider = ({ children }) => {
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
const handleAppStateChange = (nextAppState) => {
if (appState.match(/active/) && nextAppState.match(/inactive|background/)) {
console.log('App is in background or inactive');
} else if (appState.match(/inactive|background/) && nextAppState === 'active') {
console.log('App is in the foreground');
}
setAppState(nextAppState);
};
const subscription = AppState.addEventListener('change', handleAppStateChange);
return () => {
subscription.remove();
};
}, [appState]);
const exportedVariables = {
appState,
setAppState
}
return (
<GlobalVariablesContext.Provider value={exportedVariables}>
{children}
</GlobalVariablesContext.Provider>
)
};

View file

@ -20,7 +20,7 @@ export const WebSocketProvider = ({ children }) => {
} }
console.log(`🔁 Connecting (Attempt ${reconnectAttempts.current + 1}/${maxReconnectAttempts})`); console.log(`🔁 Connecting (Attempt ${reconnectAttempts.current + 1}/${maxReconnectAttempts})`);
ws.current = new WebSocket(process.env.EXPO_PUBLIC_WS_URL); ws.current = new WebSocket(`${process.env.EXPO_PUBLIC_WS_URL}/callfeed?apiKey=${process.env.EXPO_PUBLIC_DATABASE_API_KEY}`);
ws.current.onopen = () => { ws.current.onopen = () => {
console.log('✅ WebSocket connected'); console.log('✅ WebSocket connected');

23
contexts/firebase.js Normal file
View file

@ -0,0 +1,23 @@
import { initializeApp } from 'firebase/app';
import { initializeAuth, getReactNativePersistence } from 'firebase/auth';
import AsyncStorage from '@react-native-async-storage/async-storage';
const firebaseConfig = {
apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.EXPO_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
};
const app = initializeApp(firebaseConfig);
const auth = initializeAuth(app, {
persistence: getReactNativePersistence(AsyncStorage)
});
export { auth };

4
contexts/index.js Normal file
View file

@ -0,0 +1,4 @@
export { AuthProvider } from './AuthContext';
export { GlobalVariablesProvider, GlobalVariablesContext } from './GlobalVariablesContext';
export { postgresServices } from './postgres';
export { WebSocketProvider, WebSocketContext } from './WebSocketContext';

62
contexts/postgres.js Normal file
View file

@ -0,0 +1,62 @@
export const postgresServices = {
getCallsParams: async (args) => {
let response;
try {
const { numCalls, departments, status } = args;
response = await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/getCallsParams`, {
method: "POST",
headers: {
apiKey: process.env.EXPO_PUBLIC_DATABASE_API_KEY,
"Content-Type": 'application/json'
},
body: JSON.stringify({
numCalls,
departments,
status
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (e) {
console.error("Failed to fetch initial calls: ", e);
}
return response?.json() || [];
},
createUser: async (args) => {
try {
const {
firstName,
lastName,
number,
email,
provider,
departments,
token,
uid
} = args;
await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/createUser`, {
method: "POST",
headers: {
apiKey: process.env.EXPO_PUBLIC_DATABASE_API_KEY,
"Content-Type": 'application/json'
},
body: JSON.stringify({
firstName,
lastName,
number,
email,
provider,
departments,
globalRole: 'user',
primaryDept,
token,
firebaseUid: uid
}),
});
} catch (e) {
console.error("Failed to Add User to Database: ", e);
}
return 'User Added to Database';
}
}

21
eas.json Normal file
View file

@ -0,0 +1,21 @@
{
"cli": {
"version": ">= 16.3.2",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {}
}
}

View file

@ -1,2 +1,5 @@
export { useCallFeed } from './useCallFeed'; export { useCallFeed } from './useCallFeed';
export { useDepartments } from './useDepartments'; export { useDepartments } from './useDepartments';
export { useGlobalVariablesContext } from './useGlobalVariablesContext';
export { useNotifications } from './useNotifications';
export { useWebSocketContext } from './useWebSocketContext';

View file

@ -1,13 +1,18 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import { useDepartments } from '../useDepartments'; import { useDepartments } from "../useDepartments";
import { C, Cardiology, Cpr, FourByFour } from "healthicons-react-native/dist/outline"; import {
import { useWebSocketContext } from '../useWebSocketContext'; Cardiology,
Cpr,
FourByFour,
} from "healthicons-react-native/dist/outline";
import { postgresServices } from "@/contexts";
import { useWebSocketContext } from "../useWebSocketContext";
const callIconMap = { const callIconMap = {
"CHEST PAIN|HEART PROBLEMS": Cardiology, "CHEST PAIN|HEART PROBLEMS": Cardiology,
"CARDIAC ARREST|DEATH": Cpr, "CARDIAC ARREST|DEATH": Cpr,
"MOTOR VEHICLE COLLISION (MVC)": FourByFour, "MOTOR VEHICLE COLLISION (MVC)": FourByFour,
} };
// Squares // Squares
@ -37,119 +42,6 @@ const callIconMap = {
// Bacteria - Sick // Bacteria - Sick
// RuralClinic - Medical Facility Response // RuralClinic - Medical Facility Response
const callDetails = {
"Incident": {
"IncID": 75,
"IncNumber": 6873,
"JurisdictionNumber": 3,
"ServiceNumber": 42,
"ServiceID": 45,
"IncDate": "2024-09-25T01:01:01.55",
// "IncNature": "CHEST PAIN|HEART PROBLEMS",
"IncNature": "MOTOR VEHICLE COLLISION (MVC)",
// "IncNature": "CARDIAC ARREST|DEATH",
"IncNatureCode": "ALS",
"IncNatureCodeDesc": "ALS PRIORITY (ALS)",
"Notes": "570, 16:30> 311 Responding\n580, 16:25> Call Dispatched",
"Status": "OPEN",
"Origin": "911"
},
"Address": {
"StreetAddress": "275 E Main St",
"AddressApartment": "IFO",
"Town": "Bridgeport",
"State": "CT",
"ZipCode": "06608",
"Latitude": 41.178435683035445,
"Longitude": -73.18194442701176,
"County": "Fairfield",
"Intersection1": "E MAIN ST",
"Intersection2": "STRATFORD AVE",
"LocationName": "Chipotle Mexican Grill",
"WeatherCondition": "Foggy"
},
"Person": {
"Name": "John Doe",
"Age": 19,
"Gender": "Female",
"Statement": "BLOOD PRESSURE 56/41 - IN AND OUT OF CON",
"Conscious": "No",
"Breathing": "Yes",
"CallBackNumber": "(223) 456-7890"
},
"Response": {
"IncID": 75,
"ResponseID": 75,
"ServiceID": 45,
"ServiceName": "DARIEN EMS",
"Units": [
{
"Unit": 311,
"Department": 'Darien EMS',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:02:02.55",
"OnScene": "2024-09-25T01:10:10.55",
"Transporting": "2024-09-25T01:25:01.55",
"InService": "2024-09-25T02:00:01.55",
},
{
"Unit": 315,
"Department": 'Darien EMS Supv',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:03:03.15",
"OnScene": "2024-09-25T01:11:11.55",
"Transporting": null,
"InService": "2024-09-25T02:10:01.55",
},
{
"Unit": 310,
"Department": 'Darien EMS',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:01:01.55",
"OnScene": "2024-09-25T01:06:06.55",
"Transporting": "2024-09-25T01:25:01.55",
"InService": "2024-09-25T02:15:01.55",
},
{
"Unit": 'NHT20',
"Department": 'Noroton Heights Fire Department',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:08:08.55",
"OnScene": "2024-09-25T01:12:12.55",
"Transporting": null,
"InService": "2024-09-25T01:01:01.55",
},
{
"Unit": 'NFDE31',
"Department": 'Noroton Fire Department',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:07:07.55",
"OnScene": "2024-09-25T01:14:14.55",
"Transporting": null,
"InService": "2024-09-25T01:01:01.55",
},
{
"Unit": 'DFDT43',
"Department": 'Darien Fire Department',
"Dispatched": "2024-09-25T01:01:01.55",
"Responding": "2024-09-25T01:10:10.55",
"OnScene": "2024-09-25T01:18:18.55",
"Transporting": null,
"InService": "2024-09-25T01:01:01.55",
},
{
"Unit": 1514,
"Department": 'Greenwich EMS',
"Dispatched": "2024-09-25T01:15:15.55",
"Responding": "2024-09-25T01:30:30.55",
"OnScene": "2024-09-25T01:45:45.55",
"Transporting": "2024-09-25T02:05:15.55",
"InService": "2024-09-25T02:25:01.55",
},
]
}
}
const formatCallTimePast = (callValue) => { const formatCallTimePast = (callValue) => {
const initDate = new Date(callValue); const initDate = new Date(callValue);
const currentTime = new Date(); const currentTime = new Date();
@ -157,52 +49,69 @@ const formatCallTimePast = (callValue) => {
const timeDifference = currentTime - initDate; const timeDifference = currentTime - initDate;
const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const hours = Math.floor(
(timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
);
const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000); const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
if (days && days !== 0) { if (days && days !== 0) {
return `${days} day${days === 1 ? '' : 's'} ago`; return `${days} day${days === 1 ? "" : "s"} ago`;
} else if (hours && hours !== 0) { } else if (hours && hours !== 0) {
return `${hours} hour${hours === 1 ? '' : 's'} ago`; return `${hours} hour${hours === 1 ? "" : "s"} ago`;
} else if (minutes && minutes !== 0) { } else if (minutes && minutes !== 0) {
return `${minutes} minute${minutes === 1 ? '' : 's'} ago`; return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
} else if (seconds && seconds !== 0) { } else if (seconds && seconds !== 0) {
return `${seconds} second${seconds === 1 ? '' : 's'} ago`; return `${seconds} second${seconds === 1 ? "" : "s"} ago`;
} }
return `Unknown Time Past`; return `Unknown Time Past`;
} };
const formatCallDateTime = (callValue) => { const formatCallDateTime = (callValue) => {
const initDate = new Date(callValue); const initDate = new Date(callValue);
if (initDate) { if (initDate) {
const formattedDate = `${initDate.toLocaleDateString('en-US', { const formattedDate = `${initDate.toLocaleDateString("en-US", {
month: 'short', month: "short",
day: 'numeric', day: "numeric",
year: 'numeric', year: "numeric",
})}`; })}`;
const hours = initDate.getHours().toString().padStart(2, '0'); const hours = initDate.getHours().toString().padStart(2, "0");
const minutes = initDate.getMinutes().toString().padStart(2, '0'); const minutes = initDate.getMinutes().toString().padStart(2, "0");
const formattedTime = `${hours}:${minutes}`; const formattedTime = `${hours}:${minutes}`;
return `${formattedDate} - ${formattedTime}`; return `${formattedDate} - ${formattedTime}`;
} }
return 'Date Unavailable'; return "Date Unavailable";
} };
export const useCallFeed = () => { const getIncidents = async (departments, incidentStatus) => {
return postgresServices.getCallsParams({
numCalls: 25,
departments,
status: incidentStatus
});
};
export const useCallFeed = (callPage = false) => {
const departments = useDepartments(); const departments = useDepartments();
const { lastMessage } = useWebSocketContext(); const { lastMessage } = useWebSocketContext();
const [allCalls, setAllCalls] = useState([]); const [allCalls, setAllCalls] = useState([]);
const { CallThemes } = departments?.accountDetails; const [init, setInit] = useState(true);
const { const { CallThemes, InitList } = departments?.accountDetails;
CriticalCallList, const { CriticalCallList, HighCallList, MediumCallList, LowCallList } =
HighCallList, CallThemes;
MediumCallList, const [selectedStatus, setSelectedStatus] = useState({id: 'all', value: 'All Incidents'});
LowCallList,
} = CallThemes;
useEffect(() => { useEffect(() => {
if (lastMessage) { async function fetchData() {
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.deptId }), selectedStatus?.id);
setAllCalls(incidents);
setInit(false);
}
if (!callPage) fetchData();
}, []);
useEffect(() => {
if (lastMessage && !init) {
const parsedMessage = JSON?.parse(lastMessage); const parsedMessage = JSON?.parse(lastMessage);
if (parsedMessage?.data) { if (parsedMessage?.data) {
setAllCalls([...allCalls, parsedMessage]); setAllCalls([...allCalls, parsedMessage]);
@ -210,19 +119,29 @@ export const useCallFeed = () => {
} }
}, [lastMessage]); }, [lastMessage]);
useEffect(() => {
async function fetchData() {
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.deptId }), selectedStatus?.id);
setAllCalls(incidents);
}
if (!init) {
if (!callPage) fetchData();
}
}, [selectedStatus]);
const callColorSelector = (callAcuity, cardiacArrestCall, status) => { const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
if (status === 'CLOSED') { if (status?.toLowerCase() === "closed") {
return '#0000CD'; return "#0000CD";
} else if (CriticalCallList.includes(cardiacArrestCall)) { } else if (CriticalCallList.some(critical => cardiacArrestCall.includes(critical))) {
return '#8B0000'; return "#8B0000";
} else if (HighCallList.includes(callAcuity)) { } else if (HighCallList.some(high => callAcuity.includes(high))) {
return "#FF0000"; return "#FF0000";
} else if (MediumCallList.includes(callAcuity)) { } else if (MediumCallList.some(medium => callAcuity.includes(medium))) {
return "#FF8C00"; return "#FF8C00";
} else if (LowCallList.includes(callAcuity)) { } else if (LowCallList.some(low => callAcuity.includes(low))) {
return "#228B22"; return "#228B22";
} }
return 'grey'; return "grey";
}; };
return { return {
@ -231,6 +150,8 @@ export const useCallFeed = () => {
callDetails: allCalls, callDetails: allCalls,
callColorSelector, callColorSelector,
formatCallTimePast, formatCallTimePast,
formatCallDateTime formatCallDateTime,
} selectedStatus,
} setSelectedStatus
};
};

View file

@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const departmentTypeMap = { const departmentTypeMap = {
EMS: 'Medical Services', EMS: 'Medical Services',
@ -10,27 +9,47 @@ const departmentTypeMap = {
const accountDetails = { const accountDetails = {
"CallThemes" : { "CallThemes" : {
"CriticalCallList": [ "CriticalCallList": [
"CARDIAC ARREST|DEATH", "CARDIAC ARREST"
], ],
"HighCallList": [ "HighCallList": [
"ALS" "EMS ALS PRIORITY (ALS)",
"EMS Advanced Life Support life threatening response (ALS)",
"EMS ALS Intercept Required",
"EMS ALS Response Cardiac Related",
"EMS ALS Response Respiratory Distress",
"EMS ALS Response Stroke Alert",
"EMS Basic Life Support with Paramedic Assist (BLS)",
"EMS ALS Tiered Response with Fire",
"EMS Response Behavioral Emergency (ALS)",
"EMS Response Obstetric Emergency (ALS)",
"EMS ALS Response Overdose / Poisoning",
"EMS ALS Priority Interfacility Transfer",
"EMS Response Unresponsive / Unconscious Patient (ALS)"
], ],
"MediumCallList": [ "MediumCallList": [
"ALS-STANDARD", "ALS-STANDARD",
"BLS-PRIORITY" "BLS-PRIORITY",
"EMS BLS Priority Response",
"EMS BLS Response Fall Injury"
], ],
"LowCallList": [ "LowCallList": [
"BLS-STANDARD" "EMS Standard Basic Life Support Response (BLS)",
"EMS BLS Non-Emergency Transport",
"EMS BLS Standby Event Coverage",
"EMS Public Assist Lift Only (BLS)",
"EMS BLS Scheduled Interfacility Transport"
] ]
}, },
"InitList": [ "InitList": [
{ {
deptId: 0, deptId: 1,
dept: 'Darien EMS', dept: 'Darien EMS',
addDepts: [ addDepts: [
'Darien EMS Supv' 'Darien EMS Supv'
], ],
deptAbv: 'DEMS', deptAbv: 'DEMS',
rank: 'Assistant Director',
rankAbv: 'Asst. Director',
type: 'EMS', type: 'EMS',
primary: true, primary: true,
selected: true, selected: true,
@ -39,9 +58,11 @@ const accountDetails = {
hasVolunteer: true, hasVolunteer: true,
}, },
{ {
deptId: 1, deptId: 2,
dept: 'Noroton Fire Department', dept: 'Noroton Fire Department',
deptAbv: 'NFD', deptAbv: 'NFD',
rank: 'Lieutenant',
rankAbv: 'Lt.',
type: 'Fire', type: 'Fire',
primary: false, primary: false,
selected: false, selected: false,
@ -50,9 +71,11 @@ const accountDetails = {
hasVolunteer: true, hasVolunteer: true,
}, },
{ {
deptId: 2, deptId: 3,
dept: 'Stamford Fire Department', dept: 'Stamford Fire Rescue',
deptAbv: 'SFD', deptAbv: 'SFD',
rank: 'Paramedic',
rankAbv: 'EMT-P',
type: 'Rescue', type: 'Rescue',
primary: false, primary: false,
selected: false, selected: false,

View file

@ -0,0 +1 @@
export { useGlobalVariablesContext } from './useGlobalVariablesContext';

View file

@ -0,0 +1,4 @@
import { useContext } from 'react';
import { GlobalVariablesContext } from '../../contexts';
export const useGlobalVariablesContext = () => useContext(GlobalVariablesContext);

View file

@ -0,0 +1 @@
export { useNotifications } from './useNotifications';

View file

@ -0,0 +1,112 @@
import { useState, useEffect, useRef } from 'react';
import { Platform } from 'react-native';
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
const schedulePushNotification = async (title, body, dataObj) => {
await Notifications.scheduleNotificationAsync({
content: {
title,
body,
data: { data: dataObj },
},
trigger: {
type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL,
seconds: 2,
},
});
}
const registerForPushNotificationsAsync = async () => {
let token;
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('myNotificationChannel', {
name: 'A channel is needed for the permissions prompt to appear',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
// if (Device.isDevice) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
return;
}
// Learn more about projectId:
// https://docs.expo.dev/push-notifications/push-notifications-setup/#configure-projectid
// EAS projectId is used here.
try {
const projectId =
Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
if (!projectId) {
throw new Error('Project ID not found');
}
token = (
await Notifications.getExpoPushTokenAsync({
projectId,
})
).data;
} catch (e) {
token = `${e}`;
}
// } else {
// alert('Must use physical device for Push Notifications');
// }
return token;
}
export const useNotifications = () => {
const [expoPushToken, setExpoPushToken] = useState('');
const [channels, setChannels] = useState([]);
const [notification, setNotification] = useState(undefined);
const notificationListener = useRef();
const responseListener = useRef();
useEffect(() => {
registerForPushNotificationsAsync().then(token => token && setExpoPushToken(token));
if (Platform.OS === 'android') {
Notifications.getNotificationChannelsAsync().then(value => setChannels(value ?? []));
}
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
});
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
console.log(response);
});
return () => {
notificationListener.current?.remove();
responseListener.current?.remove();
};
}, []);
return ({
schedulePushNotification: async (title, body, dataObj) => {
await schedulePushNotification(title, body, dataObj);
},
expoPushToken,
expoNotificationChannels: channels,
expoNotification: notification,
});
}

View file

@ -1,4 +1,4 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { WebSocketContext } from '../../contexts/WebSocketContext'; import { WebSocketContext } from '../../contexts';
export const useWebSocketContext = () => useContext(WebSocketContext); export const useWebSocketContext = () => useContext(WebSocketContext);

View file

@ -7,15 +7,31 @@ podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0' ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
platform :ios, podfile_properties['ios.deploymentTarget'] || '13.4' platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
install! 'cocoapods', install! 'cocoapods',
:deterministic_uuids => false :deterministic_uuids => false
prepare_react_native_project! prepare_react_native_project!
target 'testapplication' do target 'Tones' do
use_expo_modules! use_expo_modules!
config = use_native_modules!
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
else
config_command = [
'node',
'--no-warnings',
'--eval',
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
'react-native-config',
'--json',
'--platform',
'ios'
]
end
config = use_native_modules!(config_command)
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
@ -47,12 +63,4 @@ target 'testapplication' do
end end
end end
end end
post_integrate do |installer|
begin
expo_patch_react_imports!(installer)
rescue => e
Pod::UI.warn e
end
end
end end

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
{ {
"expo.jsEngine": "hermes", "expo.jsEngine": "hermes",
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true" "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
"newArchEnabled": "false"
} }

View file

@ -10,31 +10,31 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
3BB8D1083F3D4AAFA506B09F /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1350D069573E4AEBBF8BA6A3 /* noop-file.swift */; };
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
640C5CE36A784C1E86D867C7 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2358EABEB0CA4428951E7149 /* noop-file.swift */; }; 93A35CBBC1C2DF84FE39E633 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EA8B81AA605F084BFB23750B /* PrivacyInfo.xcprivacy */; };
96905EF65AED1B983A6B3ABC /* libPods-testapplication.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-testapplication.a */; }; 96905EF65AED1B983A6B3ABC /* libPods-Tones.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Tones.a */; };
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; }; B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
FF358844A8FA907CDEC7216D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A9DA6C7B26A64A23DFDE186E /* PrivacyInfo.xcprivacy */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
13B07F961A680F5B00A75B9A /* testapplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testapplication.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1350D069573E4AEBBF8BA6A3 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "Tones/noop-file.swift"; sourceTree = "<group>"; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = testapplication/AppDelegate.h; sourceTree = "<group>"; }; 13B07F961A680F5B00A75B9A /* Tones.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tones.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = testapplication/AppDelegate.mm; sourceTree = "<group>"; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Tones/AppDelegate.h; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = testapplication/Images.xcassets; sourceTree = "<group>"; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = Tones/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = testapplication/Info.plist; sourceTree = "<group>"; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Tones/Images.xcassets; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = testapplication/main.m; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tones/Info.plist; sourceTree = "<group>"; };
2358EABEB0CA4428951E7149 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "testapplication/noop-file.swift"; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Tones/main.m; sourceTree = "<group>"; };
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-testapplication.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-testapplication.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Tones.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tones.a"; sourceTree = BUILT_PRODUCTS_DIR; };
6C2E3173556A471DD304B334 /* Pods-testapplication.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testapplication.debug.xcconfig"; path = "Target Support Files/Pods-testapplication/Pods-testapplication.debug.xcconfig"; sourceTree = "<group>"; }; 6C2E3173556A471DD304B334 /* Pods-Tones.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tones.debug.xcconfig"; path = "Target Support Files/Pods-Tones/Pods-Tones.debug.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-testapplication.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-testapplication.release.xcconfig"; path = "Target Support Files/Pods-testapplication/Pods-testapplication.release.xcconfig"; sourceTree = "<group>"; }; 7A4D352CD337FB3A3BF06240 /* Pods-Tones.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tones.release.xcconfig"; path = "Target Support Files/Pods-Tones/Pods-Tones.release.xcconfig"; sourceTree = "<group>"; };
96FAC8CF002144E68DCEBFD0 /* testapplication-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "testapplication-Bridging-Header.h"; path = "testapplication/testapplication-Bridging-Header.h"; sourceTree = "<group>"; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Tones/SplashScreen.storyboard; sourceTree = "<group>"; };
A9DA6C7B26A64A23DFDE186E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = testapplication/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = testapplication/SplashScreen.storyboard; sourceTree = "<group>"; };
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
EA8B81AA605F084BFB23750B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = Tones/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-testapplication/ExpoModulesProvider.swift"; sourceTree = "<group>"; }; F8CAF977DAD74AAA91FDDD99 /* Tones-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "Tones-Bridging-Header.h"; path = "Tones/Tones-Bridging-Header.h"; sourceTree = "<group>"; };
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Tones/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -42,14 +42,14 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
96905EF65AED1B983A6B3ABC /* libPods-testapplication.a in Frameworks */, 96905EF65AED1B983A6B3ABC /* libPods-Tones.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
13B07FAE1A68108700A75B9A /* testapplication */ = { 13B07FAE1A68108700A75B9A /* Tones */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BB2F792B24A3F905000567C9 /* Supporting */, BB2F792B24A3F905000567C9 /* Supporting */,
@ -59,18 +59,18 @@
13B07FB61A68108700A75B9A /* Info.plist */, 13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB71A68108700A75B9A /* main.m */, 13B07FB71A68108700A75B9A /* main.m */,
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */, AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
2358EABEB0CA4428951E7149 /* noop-file.swift */, 1350D069573E4AEBBF8BA6A3 /* noop-file.swift */,
96FAC8CF002144E68DCEBFD0 /* testapplication-Bridging-Header.h */, F8CAF977DAD74AAA91FDDD99 /* Tones-Bridging-Header.h */,
A9DA6C7B26A64A23DFDE186E /* PrivacyInfo.xcprivacy */, EA8B81AA605F084BFB23750B /* PrivacyInfo.xcprivacy */,
); );
name = testapplication; name = Tones;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
2D16E6871FA4F8E400B85C8A /* Frameworks */ = { 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-testapplication.a */, 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Tones.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -85,7 +85,7 @@
83CBB9F61A601CBA00E9B192 = { 83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07FAE1A68108700A75B9A /* testapplication */, 13B07FAE1A68108700A75B9A /* Tones */,
832341AE1AAA6A7D00B99B32 /* Libraries */, 832341AE1AAA6A7D00B99B32 /* Libraries */,
83CBBA001A601CBA00E9B192 /* Products */, 83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */, 2D16E6871FA4F8E400B85C8A /* Frameworks */,
@ -100,17 +100,17 @@
83CBBA001A601CBA00E9B192 /* Products */ = { 83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07F961A680F5B00A75B9A /* testapplication.app */, 13B07F961A680F5B00A75B9A /* Tones.app */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
92DBD88DE9BF7D494EA9DA96 /* testapplication */ = { 92DBD88DE9BF7D494EA9DA96 /* Tones */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */, FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */,
); );
name = testapplication; name = Tones;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
BB2F792B24A3F905000567C9 /* Supporting */ = { BB2F792B24A3F905000567C9 /* Supporting */ = {
@ -119,14 +119,14 @@
BB2F792C24A3F905000567C9 /* Expo.plist */, BB2F792C24A3F905000567C9 /* Expo.plist */,
); );
name = Supporting; name = Supporting;
path = testapplication/Supporting; path = Tones/Supporting;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D65327D7A22EEC0BE12398D9 /* Pods */ = { D65327D7A22EEC0BE12398D9 /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6C2E3173556A471DD304B334 /* Pods-testapplication.debug.xcconfig */, 6C2E3173556A471DD304B334 /* Pods-Tones.debug.xcconfig */,
7A4D352CD337FB3A3BF06240 /* Pods-testapplication.release.xcconfig */, 7A4D352CD337FB3A3BF06240 /* Pods-Tones.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@ -134,7 +134,7 @@
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = { D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
92DBD88DE9BF7D494EA9DA96 /* testapplication */, 92DBD88DE9BF7D494EA9DA96 /* Tones */,
); );
name = ExpoModulesProviders; name = ExpoModulesProviders;
sourceTree = "<group>"; sourceTree = "<group>";
@ -142,26 +142,26 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
13B07F861A680F5B00A75B9A /* testapplication */ = { 13B07F861A680F5B00A75B9A /* Tones */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "testapplication" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Tones" */;
buildPhases = ( buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
7E5AAFC44944C4D49F90AE74 /* [Expo] Configure project */, BBDF11722E0998CCEE7FC139 /* [Expo] Configure project */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
6CD366C487D1C4076EEFC1E9 /* [CP] Embed Pods Frameworks */, 5F318AA4CE51F8E175CC6D0A /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
); );
name = testapplication; name = Tones;
productName = testapplication; productName = Tones;
productReference = 13B07F961A680F5B00A75B9A /* testapplication.app */; productReference = 13B07F961A680F5B00A75B9A /* Tones.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@ -177,7 +177,7 @@
}; };
}; };
}; };
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testapplication" */; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Tones" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@ -190,7 +190,7 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
13B07F861A680F5B00A75B9A /* testapplication */, 13B07F861A680F5B00A75B9A /* Tones */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -203,7 +203,7 @@
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */, BB2F792D24A3F905000567C9 /* Expo.plist in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,
FF358844A8FA907CDEC7216D /* PrivacyInfo.xcprivacy in Resources */, 93A35CBBC1C2DF84FE39E633 /* PrivacyInfo.xcprivacy in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -240,20 +240,20 @@
outputFileListPaths = ( outputFileListPaths = (
); );
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-testapplication-checkManifestLockResult.txt", "$(DERIVED_FILE_DIR)/Pods-Tones-checkManifestLockResult.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; 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"; 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; showEnvVarsInLog = 0;
}; };
6CD366C487D1C4076EEFC1E9 /* [CP] Embed Pods Frameworks */ = { 5F318AA4CE51F8E175CC6D0A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testapplication/Pods-testapplication-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-Tones/Pods-Tones-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
@ -262,10 +262,50 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-testapplication/Pods-testapplication-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tones/Pods-Tones-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
7E5AAFC44944C4D49F90AE74 /* [Expo] Configure project */ = { 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tones/Pods-Tones-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication/ExpoApplication_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXNotifications/ExpoNotifications_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoDevice/ExpoDevice_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoApplication_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoNotifications_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoDevice_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tones/Pods-Tones-resources.sh\"\n";
showEnvVarsInLog = 0;
};
BBDF11722E0998CCEE7FC139 /* [Expo] Configure project */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -282,33 +322,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-testapplication/expo-configure-project.sh\"\n"; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-Tones/expo-configure-project.sh\"\n";
};
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-testapplication/Pods-testapplication-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-testapplication/Pods-testapplication-resources.sh\"\n";
showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -320,7 +334,7 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */,
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */, B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,
640C5CE36A784C1E86D867C7 /* noop-file.swift in Sources */, 3BB8D1083F3D4AAFA506B09F /* noop-file.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -329,19 +343,19 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-testapplication.debug.xcconfig */; baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-Tones.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = testapplication/testapplication.entitlements; CODE_SIGN_ENTITLEMENTS = Tones/Tones.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
"FB_SONARKIT_ENABLED=1", "FB_SONARKIT_ENABLED=1",
); );
INFOPLIST_FILE = testapplication/Info.plist; INFOPLIST_FILE = Tones/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@ -350,9 +364,9 @@
"-lc++", "-lc++",
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.anonymous.testapplication; PRODUCT_BUNDLE_IDENTIFIER = com.mattdimegs.tones;
PRODUCT_NAME = testapplication; PRODUCT_NAME = Tones;
SWIFT_OBJC_BRIDGING_HEADER = "testapplication/testapplication-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Tones/Tones-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -362,14 +376,14 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-testapplication.release.xcconfig */; baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-Tones.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = testapplication/testapplication.entitlements; CODE_SIGN_ENTITLEMENTS = Tones/Tones.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = testapplication/Info.plist; INFOPLIST_FILE = Tones/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@ -378,9 +392,9 @@
"-lc++", "-lc++",
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.anonymous.testapplication; PRODUCT_BUNDLE_IDENTIFIER = com.mattdimegs.tones;
PRODUCT_NAME = testapplication; PRODUCT_NAME = Tones;
SWIFT_OBJC_BRIDGING_HEADER = "testapplication/testapplication-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Tones/Tones-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@ -391,7 +405,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CC = "";
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
@ -418,7 +431,6 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CXX = "";
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
@ -436,9 +448,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD = "";
LDPLUSPLUS = "";
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
@ -449,6 +459,7 @@
); );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
USE_HERMES = true; USE_HERMES = true;
}; };
name = Debug; name = Debug;
@ -457,7 +468,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CC = "";
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
@ -484,7 +494,6 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
CXX = "";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
@ -495,9 +504,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD = "";
LDPLUSPLUS = "";
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
@ -515,7 +522,7 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "testapplication" */ = { 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Tones" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */, 13B07F941A680F5B00A75B9A /* Debug */,
@ -524,7 +531,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "testapplication" */ = { 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Tones" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA201A601CBA00E9B192 /* Debug */,

View file

@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testapplication.app" BuildableName = "Tones.app"
BlueprintName = "testapplication" BlueprintName = "Tones"
ReferencedContainer = "container:testapplication.xcodeproj"> ReferencedContainer = "container:Tones.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@ -33,9 +33,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E" BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "testapplicationTests.xctest" BuildableName = "TonesTests.xctest"
BlueprintName = "testapplicationTests" BlueprintName = "TonesTests"
ReferencedContainer = "container:testapplication.xcodeproj"> ReferencedContainer = "container:Tones.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@ -55,9 +55,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testapplication.app" BuildableName = "Tones.app"
BlueprintName = "testapplication" BlueprintName = "Tones"
ReferencedContainer = "container:testapplication.xcodeproj"> ReferencedContainer = "container:Tones.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
@ -72,9 +72,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testapplication.app" BuildableName = "Tones.app"
BlueprintName = "testapplication" BlueprintName = "Tones"
ReferencedContainer = "container:testapplication.xcodeproj"> ReferencedContainer = "container:Tones.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>

View file

@ -2,7 +2,7 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:testapplication.xcodeproj"> location = "group:Tones.xcodeproj">
</FileRef> </FileRef>
<FileRef <FileRef
location = "group:Pods/Pods.xcodeproj"> location = "group:Pods/Pods.xcodeproj">

View file

@ -0,0 +1,32 @@
<?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>API_KEY</key>
<string>AIzaSyClZkx4PFWhfIG3JDb6GD3g6Bl7-pWLNrU</string>
<key>GCM_SENDER_ID</key>
<string>917296693147</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.mattdimegs.tones</string>
<key>PROJECT_ID</key>
<string>tones-9f1d4</string>
<key>STORAGE_BUCKET</key>
<string>tones-9f1d4.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:917296693147:ios:73d6d426aa60e52b35ab3e</string>
<key>DATABASE_URL</key>
<string>https://tones-9f1d4-default-rtdb.firebaseio.com</string>
</dict>
</plist>

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View file

@ -0,0 +1,20 @@
{
"colors": [
{
"color": {
"components": {
"alpha": "1.000",
"blue": "1.00000000000000",
"green": "1.00000000000000",
"red": "1.00000000000000"
},
"color-space": "srgb"
},
"idiom": "universal"
}
],
"info": {
"version": 1,
"author": "expo"
}
}

View file

@ -7,10 +7,12 @@
}, },
{ {
"idiom": "universal", "idiom": "universal",
"filename": "image@2x.png",
"scale": "2x" "scale": "2x"
}, },
{ {
"idiom": "universal", "idiom": "universal",
"filename": "image@3x.png",
"scale": "3x" "scale": "3x"
} }
], ],

View file

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>test-application</string> <string>Tones</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -19,7 +19,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.0</string> <string>1.0.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@ -28,12 +28,14 @@
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>myapp</string> <string>myapp</string>
<string>com.anonymous.testapplication</string> <string>com.mattdimegs.tones</string>
</array> </array>
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>

View file

@ -4,6 +4,16 @@
<dict> <dict>
<key>NSPrivacyAccessedAPITypes</key> <key>NSPrivacyAccessedAPITypes</key>
<array> <array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
<string>0A2A.1</string>
<string>3B52.1</string>
</array>
</dict>
<dict> <dict>
<key>NSPrivacyAccessedAPIType</key> <key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string> <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
@ -14,12 +24,10 @@
</dict> </dict>
<dict> <dict>
<key>NSPrivacyAccessedAPIType</key> <key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string> <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key> <key>NSPrivacyAccessedAPITypeReasons</key>
<array> <array>
<string>0A2A.1</string> <string>35F9.1</string>
<string>3B52.1</string>
<string>C617.1</string>
</array> </array>
</dict> </dict>
<dict> <dict>
@ -31,14 +39,6 @@
<string>85F4.1</string> <string>85F4.1</string>
</array> </array>
</dict> </dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array> </array>
<key>NSPrivacyCollectedDataTypes</key> <key>NSPrivacyCollectedDataTypes</key>
<array/> <array/>

Some files were not shown because too many files have changed in this diff Show more