Compare commits
15 commits
Author | SHA1 | Date | |
---|---|---|---|
e6f23b83be | |||
f11f9d8371 | |||
4aff7380ce | |||
7501c04bbd | |||
3aebd4cd1c | |||
aea3a26096 | |||
b635f29f45 | |||
fd081d46a6 | |||
c1b220f007 | |||
754e14946c | |||
48b663799d | |||
894d26dad1 | |||
7f30ef9abf | |||
65b86bbb13 | |||
23ecee5061 |
41 changed files with 987 additions and 846 deletions
28
CHANGELOG.md
28
CHANGELOG.md
|
@ -2,6 +2,34 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.11.1](https://github.com/alerte-secours/as-app/compare/v1.11.0...v1.11.1) (2025-07-18)
|
||||||
|
|
||||||
|
## [1.11.0](https://github.com/alerte-secours/as-app/compare/v1.10.9...v1.11.0) (2025-07-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **anchor:** bglost notification scroll to permissions + wip ([fd081d4](https://github.com/alerte-secours/as-app/commit/fd081d46a657059353bfb1e6022b68eedaee4e1a))
|
||||||
|
* optout sentry reporting ([c1b220f](https://github.com/alerte-secours/as-app/commit/c1b220f0078db8d07b3d58a7ac146d8af159a17d))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* force location sync storage effect on interval ([7f30ef9](https://github.com/alerte-secours/as-app/commit/7f30ef9abf11bbdade5c3db3bfd7269dc212b39c))
|
||||||
|
* menu paramètres ([754e149](https://github.com/alerte-secours/as-app/commit/754e14946c0fa397558e5983a39c082c9072fe5c))
|
||||||
|
* message_permission_required ([894d26d](https://github.com/alerte-secours/as-app/commit/894d26dad12c4736cde827232764ed5c8d77df4e))
|
||||||
|
* **notification:** android background-geolocation-lost ([aea3a26](https://github.com/alerte-secours/as-app/commit/aea3a2609639f01b1d7aa414c67e3bdb99a1a47c))
|
||||||
|
* title_permission_required ([48b6637](https://github.com/alerte-secours/as-app/commit/48b663799d4bb4ef69671f0291a77a65418e2544))
|
||||||
|
* wip ([b635f29](https://github.com/alerte-secours/as-app/commit/b635f29f45928210bc9a9a8c5d201d91a6b48a07))
|
||||||
|
|
||||||
|
## [1.10.9](https://github.com/alerte-secours/as-app/compare/v1.10.7...v1.10.9) (2025-07-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bg location force sync all 12 hours ([732dc3d](https://github.com/alerte-secours/as-app/commit/732dc3df7b6ab635c70d02d657d066e6c72a49c4))
|
||||||
|
* **ios:** upgrade bundling ([23ecee5](https://github.com/alerte-secours/as-app/commit/23ecee5061e5e7324407223e7c1ce9a815f96521))
|
||||||
|
|
||||||
## [1.10.8](https://github.com/alerte-secours/as-app/compare/v1.10.7...v1.10.8) (2025-07-04)
|
## [1.10.8](https://github.com/alerte-secours/as-app/compare/v1.10.7...v1.10.8) (2025-07-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,8 @@ android {
|
||||||
applicationId 'com.alertesecours'
|
applicationId 'com.alertesecours'
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 188
|
versionCode 191
|
||||||
versionName "1.10.8"
|
versionName "1.11.1"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testBuildType System.getProperty('testBuildType', 'debug')
|
testBuildType System.getProperty('testBuildType', 'debug')
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
|
|
|
@ -64,6 +64,10 @@
|
||||||
<action android:name="com.alertesecours.OPEN_RELATIVES"/>
|
<action android:name="com.alertesecours.OPEN_RELATIVES"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.alertesecours.OPEN_BACKGROUND_GEOLOCATION_SETTINGS"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
<intent-filter android:autoVerify="true" data-generated="true">
|
<intent-filter android:autoVerify="true" data-generated="true">
|
||||||
<action android:name="android.intent.action.VIEW"/>
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
<data android:scheme="https" android:host="app.alertesecours.fr" android:pathPrefix="/"/>
|
<data android:scheme="https" android:host="app.alertesecours.fr" android:pathPrefix="/"/>
|
||||||
|
|
7
android/app/src/main/res/values-fr/strings.xml
Normal file
7
android/app/src/main/res/values-fr/strings.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Alerte Secours</string>
|
||||||
|
|
||||||
|
<!-- French permission message for background geolocation -->
|
||||||
|
<string name="message_permission_required">Alerte Secours nécessite la localisation en arrière-plan pour les alertes de proximité.</string>
|
||||||
|
<string name="title_permission_required">Autorisation requise</string>
|
||||||
|
</resources>
|
|
@ -4,4 +4,6 @@
|
||||||
<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>
|
||||||
<string name="expo_runtime_version">1.0.0</string>
|
<string name="expo_runtime_version">1.0.0</string>
|
||||||
|
<string name="message_permission_required">Alerte Secours nécessite la localisation en arrière-plan pour les alertes de proximité.</string>
|
||||||
|
<string name="title_permission_required">Autorisation requise</string>
|
||||||
</resources>
|
</resources>
|
|
@ -131,12 +131,12 @@ let config = {
|
||||||
"tel",
|
"tel",
|
||||||
"telprompt",
|
"telprompt",
|
||||||
],
|
],
|
||||||
|
BGTaskSchedulerPermittedIdentifiers: [
|
||||||
|
"com.transistorsoft.fetch",
|
||||||
|
"com.transistorsoft.customtask",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
UIBackgroundModes: ["location", "fetch", "processing"],
|
UIBackgroundModes: ["location", "fetch", "processing"],
|
||||||
BGTaskSchedulerPermittedIdentifiers: [
|
|
||||||
"com.transistorsoft.fetch",
|
|
||||||
"com.transistorsoft.customtask",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
[
|
||||||
|
|
|
@ -97,3 +97,72 @@ You can run this script directly:
|
||||||
export DEVICE=emulator-5554
|
export DEVICE=emulator-5554
|
||||||
./install-android.sh
|
./install-android.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# enable USB debug mode
|
||||||
|
|
||||||
|
Add udev rules for your device
|
||||||
|
|
||||||
|
1. First, find your device's vendor ID:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lsusb
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for your phone manufacturer (e.g., Google, Samsung, OnePlus). Note the ID like 18d1:4ee7
|
||||||
|
|
||||||
|
2. Create/edit the udev rules file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo micro /etc/udev/rules.d/51-android.rules
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add a line for your device. Here are common manufacturers:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Google
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev"
|
||||||
|
# Samsung
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="plugdev"
|
||||||
|
# OnePlus
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2a70", MODE="0666", GROUP="plugdev"
|
||||||
|
# Xiaomi
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2717", MODE="0666", GROUP="plugdev"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Set proper permissions and reload rules:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo chmod a+r /etc/udev/rules.d/51-android.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo service udev restart
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Add yourself to the plugdev group:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo usermod -aG plugdev $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
Force the authorization prompt
|
||||||
|
|
||||||
|
1. Kill adb server:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
adb kill-server
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Unplug your device
|
||||||
|
3. On your phone:
|
||||||
|
- Go to Developer options
|
||||||
|
- Revoke USB debugging authorizations
|
||||||
|
- Toggle USB debugging OFF then ON
|
||||||
|
|
||||||
|
4. Plug the device back in
|
||||||
|
5. Start adb with proper permissions:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
adb start-server
|
||||||
|
adb devices
|
||||||
|
```
|
||||||
|
|
||||||
|
6. The authorization prompt should now appear on your phone
|
8
index.js
8
index.js
|
@ -19,7 +19,7 @@ import onMessageReceived from "~/notifications/onMessageReceived";
|
||||||
|
|
||||||
import { createLogger } from "~/lib/logger";
|
import { createLogger } from "~/lib/logger";
|
||||||
import * as Sentry from "@sentry/react-native";
|
import * as Sentry from "@sentry/react-native";
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
import { memoryAsyncStorage } from "~/storage/memoryAsyncStorage";
|
||||||
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
||||||
|
|
||||||
// setup notification, this have to stay in index.js
|
// setup notification, this have to stay in index.js
|
||||||
|
@ -38,7 +38,7 @@ const FORCE_SYNC_INTERVAL = 12 * 60 * 60 * 1000;
|
||||||
// Helper functions for persisting sync time
|
// Helper functions for persisting sync time
|
||||||
const getLastSyncTime = async () => {
|
const getLastSyncTime = async () => {
|
||||||
try {
|
try {
|
||||||
const value = await AsyncStorage.getItem(
|
const value = await memoryAsyncStorage.getItem(
|
||||||
STORAGE_KEYS.GEOLOCATION_LAST_SYNC_TIME,
|
STORAGE_KEYS.GEOLOCATION_LAST_SYNC_TIME,
|
||||||
);
|
);
|
||||||
return value ? parseInt(value, 10) : Date.now();
|
return value ? parseInt(value, 10) : Date.now();
|
||||||
|
@ -52,7 +52,7 @@ const getLastSyncTime = async () => {
|
||||||
|
|
||||||
const setLastSyncTime = async (time) => {
|
const setLastSyncTime = async (time) => {
|
||||||
try {
|
try {
|
||||||
await AsyncStorage.setItem(
|
await memoryAsyncStorage.setItem(
|
||||||
STORAGE_KEYS.GEOLOCATION_LAST_SYNC_TIME,
|
STORAGE_KEYS.GEOLOCATION_LAST_SYNC_TIME,
|
||||||
time.toString(),
|
time.toString(),
|
||||||
);
|
);
|
||||||
|
@ -139,7 +139,7 @@ const HeadlessTask = async (event) => {
|
||||||
geolocBgLogger.debug("getCurrentPosition result", { location });
|
geolocBgLogger.debug("getCurrentPosition result", { location });
|
||||||
|
|
||||||
if (timeSinceLastSync >= FORCE_SYNC_INTERVAL) {
|
if (timeSinceLastSync >= FORCE_SYNC_INTERVAL) {
|
||||||
geolocBgLogger.info("Forcing location sync after 24h");
|
geolocBgLogger.info("Forcing location sync");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Change pace to ensure location updates with timeout
|
// Change pace to ensure location updates with timeout
|
||||||
|
|
249
install-ios.sh
Executable file
249
install-ios.sh
Executable file
|
@ -0,0 +1,249 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}Error: $1${NC}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}$1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}Warning: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_plain() {
|
||||||
|
echo -e "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Xcode command line tools are available
|
||||||
|
if ! command -v xcrun &> /dev/null; then
|
||||||
|
print_error "Xcode command line tools are not installed."
|
||||||
|
print_info "Please install them by running: xcode-select --install"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Define IPA path
|
||||||
|
IPA_PATH="ios/build/AlerteSecours.ipa"
|
||||||
|
|
||||||
|
# Check if IPA file exists
|
||||||
|
if [ ! -f "$IPA_PATH" ]; then
|
||||||
|
print_error "IPA file not found at: $IPA_PATH"
|
||||||
|
print_info "Please build the iOS bundle first by running:"
|
||||||
|
print_info " yarn bundle:ios"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Found IPA file: $IPA_PATH"
|
||||||
|
|
||||||
|
# Function to get connected physical iOS devices
|
||||||
|
get_physical_devices() {
|
||||||
|
xcrun devicectl list devices 2>/dev/null | awk 'NR>2 && $4=="available" {print $3}' || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get available simulators (booted ones)
|
||||||
|
get_booted_simulators() {
|
||||||
|
xcrun simctl list devices | grep -E "\(Booted\)" | sed -E 's/.*\(([A-F0-9-]{36})\) \(Booted\)/\1/' || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get simulator name by UDID
|
||||||
|
get_simulator_name() {
|
||||||
|
local udid="$1"
|
||||||
|
xcrun simctl list devices | grep "$udid" | sed -E 's/^[[:space:]]*([^(]+).*/\1/' | xargs
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get device name by UDID (for physical devices)
|
||||||
|
get_device_name() {
|
||||||
|
local udid="$1"
|
||||||
|
xcrun devicectl list devices 2>/dev/null | awk -v target_udid="$udid" 'NR>2 && $3==target_udid {print $1}' || echo "Unknown Device"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate physical device UDID
|
||||||
|
validate_physical_device() {
|
||||||
|
local device_id="$1"
|
||||||
|
local devices=$(get_physical_devices)
|
||||||
|
|
||||||
|
if [ -z "$devices" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$devices" | grep -q "^$device_id$"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate simulator UDID
|
||||||
|
validate_simulator() {
|
||||||
|
local simulator_id="$1"
|
||||||
|
local simulators=$(get_booted_simulators)
|
||||||
|
|
||||||
|
if [ -z "$simulators" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$simulators" | grep -q "^$simulator_id$"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install on physical device
|
||||||
|
install_on_device() {
|
||||||
|
local device_id="$1"
|
||||||
|
local device_name=$(get_device_name "$device_id")
|
||||||
|
|
||||||
|
print_info "Installing on physical device: $device_name ($device_id)"
|
||||||
|
|
||||||
|
if xcrun devicectl device install app --device "$device_id" "$IPA_PATH"; then
|
||||||
|
print_success "Installation completed successfully on $device_name!"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "Installation failed on $device_name"
|
||||||
|
print_info "Common solutions:"
|
||||||
|
print_info " 1. Make sure the device is unlocked and trusted"
|
||||||
|
print_info " 2. Check that the provisioning profile matches the device"
|
||||||
|
print_info " 3. Verify the device has enough storage space"
|
||||||
|
print_info " 4. Try disconnecting and reconnecting the device"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install on simulator
|
||||||
|
install_on_simulator() {
|
||||||
|
local simulator_id="$1"
|
||||||
|
local simulator_name=$(get_simulator_name "$simulator_id")
|
||||||
|
|
||||||
|
print_info "Installing on simulator: $simulator_name ($simulator_id)"
|
||||||
|
|
||||||
|
if xcrun simctl install "$simulator_id" "$IPA_PATH"; then
|
||||||
|
print_success "Installation completed successfully on $simulator_name!"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "Installation failed on $simulator_name"
|
||||||
|
print_info "Make sure the simulator is booted and try again"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main installation logic
|
||||||
|
if [ -n "$IOS_DEVICE" ]; then
|
||||||
|
# Specific physical device requested
|
||||||
|
print_info "Using specified physical device: $IOS_DEVICE"
|
||||||
|
|
||||||
|
if ! validate_physical_device "$IOS_DEVICE"; then
|
||||||
|
print_error "Physical device $IOS_DEVICE is not connected or not found."
|
||||||
|
print_info "Connected physical devices:"
|
||||||
|
physical_devices=$(get_physical_devices)
|
||||||
|
if [ -n "$physical_devices" ]; then
|
||||||
|
echo "$physical_devices" | while read -r device; do
|
||||||
|
device_name=$(get_device_name "$device")
|
||||||
|
print_info " - $device ($device_name)"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
print_info " No physical devices found"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
install_on_device "$IOS_DEVICE"
|
||||||
|
|
||||||
|
elif [ -n "$IOS_SIMULATOR" ]; then
|
||||||
|
# Specific simulator requested
|
||||||
|
print_info "Using specified simulator: $IOS_SIMULATOR"
|
||||||
|
|
||||||
|
if ! validate_simulator "$IOS_SIMULATOR"; then
|
||||||
|
print_error "Simulator $IOS_SIMULATOR is not booted or not found."
|
||||||
|
print_info "Booted simulators:"
|
||||||
|
booted_simulators=$(get_booted_simulators)
|
||||||
|
if [ -n "$booted_simulators" ]; then
|
||||||
|
echo "$booted_simulators" | while read -r sim; do
|
||||||
|
sim_name=$(get_simulator_name "$sim")
|
||||||
|
print_info " - $sim ($sim_name)"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
print_info " No booted simulators found"
|
||||||
|
print_info " Start a simulator from Xcode or run: xcrun simctl boot <simulator-udid>"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
install_on_simulator "$IOS_SIMULATOR"
|
||||||
|
|
||||||
|
else
|
||||||
|
# Auto-detect: prefer physical devices, fallback to simulators
|
||||||
|
print_info "Auto-detecting iOS targets..."
|
||||||
|
|
||||||
|
# Try physical devices first
|
||||||
|
physical_devices=$(get_physical_devices)
|
||||||
|
if [ -n "$physical_devices" ]; then
|
||||||
|
target_device=$(echo "$physical_devices" | head -n 1)
|
||||||
|
device_count=$(echo "$physical_devices" | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$device_count" -gt 1 ]; then
|
||||||
|
print_warning "Multiple physical devices found. Using first device: $target_device"
|
||||||
|
print_info "Available physical devices:"
|
||||||
|
echo "$physical_devices" | while read -r device; do
|
||||||
|
device_name=$(get_device_name "$device")
|
||||||
|
if [ "$device" = "$target_device" ]; then
|
||||||
|
print_info " - $device ($device_name) [selected]"
|
||||||
|
else
|
||||||
|
print_info " - $device ($device_name)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
print_info "To use a specific device, run: IOS_DEVICE=<device-udid> yarn install:ios"
|
||||||
|
else
|
||||||
|
device_name=$(get_device_name "$target_device")
|
||||||
|
print_info "Using physical device: $device_name ($target_device)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install_on_device "$target_device"
|
||||||
|
else
|
||||||
|
# No physical devices, try simulators
|
||||||
|
print_info "No physical devices found. Looking for booted simulators..."
|
||||||
|
|
||||||
|
booted_simulators=$(get_booted_simulators)
|
||||||
|
if [ -n "$booted_simulators" ]; then
|
||||||
|
target_simulator=$(echo "$booted_simulators" | head -n 1)
|
||||||
|
simulator_count=$(echo "$booted_simulators" | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$simulator_count" -gt 1 ]; then
|
||||||
|
print_warning "Multiple booted simulators found. Using first simulator: $target_simulator"
|
||||||
|
print_info "Available booted simulators:"
|
||||||
|
echo "$booted_simulators" | while read -r sim; do
|
||||||
|
sim_name=$(get_simulator_name "$sim")
|
||||||
|
if [ "$sim" = "$target_simulator" ]; then
|
||||||
|
print_info " - $sim ($sim_name) [selected]"
|
||||||
|
else
|
||||||
|
print_info " - $sim ($sim_name)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
print_info "To use a specific simulator, run: IOS_SIMULATOR=<simulator-udid> yarn install:ios"
|
||||||
|
else
|
||||||
|
simulator_name=$(get_simulator_name "$target_simulator")
|
||||||
|
print_info "Using simulator: $simulator_name ($target_simulator)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install_on_simulator "$target_simulator"
|
||||||
|
else
|
||||||
|
print_error "No iOS devices or booted simulators found."
|
||||||
|
print_info "Please either:"
|
||||||
|
print_info " 1. Connect and trust an iOS device, or"
|
||||||
|
print_info " 2. Boot a simulator from Xcode"
|
||||||
|
print_info ""
|
||||||
|
print_info "Usage examples:"
|
||||||
|
print_info " Auto-detect: yarn install:ios"
|
||||||
|
print_info " Specific device: IOS_DEVICE=<device-udid> yarn install:ios"
|
||||||
|
print_info " Specific simulator: IOS_SIMULATOR=<simulator-udid> yarn install:ios"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
|
@ -1,16 +1,11 @@
|
||||||
# This is used by the React Native CLI to control various options
|
# This `.xcode.env` file is versioned and is used to source the environment
|
||||||
# Configuration name to load
|
# used when running script phases inside Xcode.
|
||||||
CONFIGURATION_NAME=Debug
|
# To customize your local environment, you can create an `.xcode.env.local`
|
||||||
# Path to the Xcode project
|
# file that is not versioned.
|
||||||
PROJECT_PATH="AlerteSecours.xcodeproj"
|
|
||||||
# Whether to enable the New Architecture
|
|
||||||
RCT_NEW_ARCH_ENABLED=0
|
|
||||||
# Whether to enable Hermes
|
|
||||||
USE_HERMES=1
|
|
||||||
|
|
||||||
# Sentry Configuration
|
# NODE_BINARY variable contains the PATH to the node executable.
|
||||||
export SENTRY_PROPERTIES="ios/sentry.properties"
|
#
|
||||||
export AUTO_RELEASE=true
|
# Customize the NODE_BINARY variable here.
|
||||||
export SENTRY_CLI_EXTRA_ARGS="--log-level debug"
|
# For example, to use nvm with brew, add the following line
|
||||||
export SENTRY_CLI_RN_XCODE_EXTRA_ARGS="--allow-fetch"
|
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||||
export SENTRY_INCLUDE_NATIVE_SOURCES=true
|
export NODE_BINARY=$(command -v node)
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,24 +1,21 @@
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import <Firebase/Firebase.h>
|
|
||||||
// @generated begin react-native-background-fetch-import - expo prebuild (DO NOT MODIFY) sync-fb890e6efd6cc6e67ebbda1087e0a6d7e0bcc527
|
// @generated begin react-native-background-fetch-import - expo prebuild (DO NOT MODIFY) sync-fb890e6efd6cc6e67ebbda1087e0a6d7e0bcc527
|
||||||
#import <TSBackgroundFetch/TSBackgroundFetch.h>
|
#import <TSBackgroundFetch/TSBackgroundFetch.h>
|
||||||
// @generated end react-native-background-fetch-import
|
// @generated end react-native-background-fetch-import
|
||||||
|
#import <Firebase/Firebase.h>
|
||||||
|
|
||||||
#import <React/RCTBundleURLProvider.h>
|
#import <React/RCTBundleURLProvider.h>
|
||||||
#import <React/RCTLinkingManager.h>
|
#import <React/RCTLinkingManager.h>
|
||||||
|
|
||||||
#import <Firebase.h>
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
|
// @generated begin @react-native-firebase/app-didFinishLaunchingWithOptions - expo prebuild (DO NOT MODIFY) sync-ecd111c37e49fdd1ed6354203cd6b1e2a38cccda
|
||||||
|
[FIRApp configure];
|
||||||
|
// @generated end @react-native-firebase/app-didFinishLaunchingWithOptions
|
||||||
self.moduleName = @"main";
|
self.moduleName = @"main";
|
||||||
|
|
||||||
// see https://github.com/invertase/react-native-firebase/issues/7788#issuecomment-2211820768
|
|
||||||
// and https://rnfirebase.io/#configure-react-native-firebase-modules
|
|
||||||
[FIRApp configure];
|
|
||||||
|
|
||||||
// You can add your custom initial props in the dictionary below.
|
// You can add your custom initial props in the dictionary below.
|
||||||
// They will be passed down to the ViewController used by React Native.
|
// They will be passed down to the ViewController used by React Native.
|
||||||
self.initialProps = @{};
|
self.initialProps = @{};
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>API_KEY</key>
|
|
||||||
<string>YOUR_API_KEY_HERE</string>
|
|
||||||
<key>GCM_SENDER_ID</key>
|
|
||||||
<string>YOUR_GCM_SENDER_ID_HERE</string>
|
|
||||||
<key>PLIST_VERSION</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>BUNDLE_ID</key>
|
|
||||||
<string>com.alertesecours.alertesecours</string>
|
|
||||||
<key>PROJECT_ID</key>
|
|
||||||
<string>YOUR_PROJECT_ID_HERE</string>
|
|
||||||
<key>STORAGE_BUCKET</key>
|
|
||||||
<string>YOUR_STORAGE_BUCKET_HERE</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>YOUR_GOOGLE_APP_ID_HERE</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
Binary file not shown.
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 62 KiB |
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"filename": "image.png",
|
|
||||||
"scale": "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": {
|
|
||||||
"version": 1,
|
|
||||||
"author": "expo"
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 160 KiB |
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"filename": "image.png",
|
|
||||||
"scale": "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "universal",
|
|
||||||
"scale": "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": {
|
|
||||||
"version": 1,
|
|
||||||
"author": "expo"
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 70 B |
|
@ -2,6 +2,11 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||||
|
<array>
|
||||||
|
<string>com.transistorsoft.fetch</string>
|
||||||
|
<string>com.transistorsoft.customtask</string>
|
||||||
|
</array>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
@ -19,7 +24,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.10.8</string>
|
<string>1.11.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
@ -42,7 +47,7 @@
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>188</string>
|
<string>191</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EXPO-VIEWCONTROLLER-1">
|
||||||
<device id="retina5_5" orientation="portrait" appearance="light"/>
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||||
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -12,34 +13,29 @@
|
||||||
<objects>
|
<objects>
|
||||||
<viewController storyboardIdentifier="SplashScreenViewController" id="EXPO-VIEWCONTROLLER-1" sceneMemberID="viewController">
|
<viewController storyboardIdentifier="SplashScreenViewController" id="EXPO-VIEWCONTROLLER-1" sceneMemberID="viewController">
|
||||||
<view key="view" userInteractionEnabled="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="EXPO-ContainerView" userLabel="ContainerView">
|
<view key="view" userInteractionEnabled="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="EXPO-ContainerView" userLabel="ContainerView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" image="SplashScreenBackground" translatesAutoresizingMaskIntoConstraints="NO" id="EXPO-SplashScreenBackground" userLabel="SplashScreenBackground">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
|
||||||
</imageView>
|
|
||||||
<imageView id="EXPO-SplashScreen" userLabel="SplashScreenLogo" image="SplashScreenLogo" contentMode="scaleAspectFit" clipsSubviews="true" userInteractionEnabled="false" translatesAutoresizingMaskIntoConstraints="false">
|
<imageView id="EXPO-SplashScreen" userLabel="SplashScreenLogo" image="SplashScreenLogo" contentMode="scaleAspectFit" clipsSubviews="true" userInteractionEnabled="false" translatesAutoresizingMaskIntoConstraints="false">
|
||||||
<rect key="frame" x="0" y="0" width="414" height="736"/>
|
<rect key="frame" x="0" y="0" width="414" height="736"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<viewLayoutGuide key="safeArea" id="Rmq-lb-GrQ"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="top" secondItem="EXPO-ContainerView" secondAttribute="top" id="83fcb9b545b870ba44c24f0feeb116490c499c52"/>
|
<constraint firstItem="EXPO-SplashScreen" firstAttribute="top" secondItem="EXPO-ContainerView" secondAttribute="top" id="83fcb9b545b870ba44c24f0feeb116490c499c52"/>
|
||||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="leading" secondItem="EXPO-ContainerView" secondAttribute="leading" id="61d16215e44b98e39d0a2c74fdbfaaa22601b12c"/>
|
<constraint firstItem="EXPO-SplashScreen" firstAttribute="leading" secondItem="EXPO-ContainerView" secondAttribute="leading" id="61d16215e44b98e39d0a2c74fdbfaaa22601b12c"/>
|
||||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="trailing" secondItem="EXPO-ContainerView" secondAttribute="trailing" id="f934da460e9ab5acae3ad9987d5b676a108796c1"/>
|
<constraint firstItem="EXPO-SplashScreen" firstAttribute="trailing" secondItem="EXPO-ContainerView" secondAttribute="trailing" id="f934da460e9ab5acae3ad9987d5b676a108796c1"/>
|
||||||
<constraint firstItem="EXPO-SplashScreen" firstAttribute="bottom" secondItem="EXPO-ContainerView" secondAttribute="bottom" id="d6a0be88096b36fb132659aa90203d39139deda9"/>
|
<constraint firstItem="EXPO-SplashScreen" firstAttribute="bottom" secondItem="EXPO-ContainerView" secondAttribute="bottom" id="d6a0be88096b36fb132659aa90203d39139deda9"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<viewLayoutGuide key="safeArea" id="Rmq-lb-GrQ"/>
|
|
||||||
<color key="backgroundColor" name="SplashScreenBackground"/>
|
<color key="backgroundColor" name="SplashScreenBackground"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EXPO-PLACEHOLDER-1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="EXPO-PLACEHOLDER-1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="140.625" y="129.4921875"/>
|
<point key="canvasLocation" x="0.0" y="0.0"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="SplashScreenBackground" width="1" height="1"/>
|
|
||||||
<image name="SplashScreen" width="414" height="736"/>
|
|
||||||
<image name="SplashScreenLogo" width="414" height="736"/>
|
<image name="SplashScreenLogo" width="414" height="736"/>
|
||||||
<namedColor name="SplashScreenBackground">
|
<namedColor name="SplashScreenBackground">
|
||||||
<color alpha="1.000" blue="0.780392156862745" green="0.309803921568627" red="0.211764705882353" customColorSpace="sRGB" colorSpace="custom"/>
|
<color alpha="1.000" blue="0.780392156862745" green="0.309803921568627" red="0.211764705882353" customColorSpace="sRGB" colorSpace="custom"/>
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>EXUpdatesCheckOnLaunch</key>
|
|
||||||
<string>ERROR_RECOVERY_ONLY</string>
|
|
||||||
<key>EXUpdatesCodeSigningCertificate</key>
|
|
||||||
<string>YOUR_CODE_SIGNING_CERTIFICATE_HERE</string>
|
|
||||||
<key>EXUpdatesCodeSigningMetadata</key>
|
|
||||||
<dict>
|
|
||||||
<key>keyid</key>
|
|
||||||
<string>main</string>
|
|
||||||
<key>alg</key>
|
|
||||||
<string>rsa-v1_5-sha256</string>
|
|
||||||
</dict>
|
|
||||||
<key>EXUpdatesEnabled</key>
|
|
||||||
<true/>
|
|
||||||
<key>EXUpdatesLaunchWaitMs</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
<key>EXUpdatesRuntimeVersion</key>
|
|
||||||
<string>1.0.0</string>
|
|
||||||
<key>EXUpdatesURL</key>
|
|
||||||
<string>https://expo-updates.alertesecours.fr/api/manifest?project=alerte-secours&channel=release</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>API_KEY</key>
|
|
||||||
<string>YOUR_API_KEY_HERE</string>
|
|
||||||
<key>GCM_SENDER_ID</key>
|
|
||||||
<string>YOUR_GCM_SENDER_ID_HERE</string>
|
|
||||||
<key>PLIST_VERSION</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>BUNDLE_ID</key>
|
|
||||||
<string>com.alertesecours.alertesecours</string>
|
|
||||||
<key>PROJECT_ID</key>
|
|
||||||
<string>YOUR_PROJECT_ID_HERE</string>
|
|
||||||
<key>STORAGE_BUCKET</key>
|
|
||||||
<string>YOUR_STORAGE_BUCKET_HERE</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>YOUR_GOOGLE_APP_ID_HERE</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
100
ios/Podfile
100
ios/Podfile
|
@ -1,19 +1,5 @@
|
||||||
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
|
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
|
||||||
|
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
||||||
|
|
||||||
# see https://github.com/zoontek/react-native-permissions?tab=readme-ov-file#ios
|
|
||||||
# require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
|
||||||
def node_require(script)
|
|
||||||
# Resolve script with node to allow for hoisting
|
|
||||||
require Pod::Executable.execute_command('node', ['-p',
|
|
||||||
"require.resolve(
|
|
||||||
'#{script}',
|
|
||||||
{paths: [process.argv[1]]},
|
|
||||||
)", __dir__]).strip
|
|
||||||
end
|
|
||||||
# Use it to require both react-native's and this package's scripts:
|
|
||||||
node_require('react-native/scripts/react_native_pods.rb')
|
|
||||||
node_require('react-native-permissions/scripts/setup.rb')
|
|
||||||
|
|
||||||
require 'json'
|
require 'json'
|
||||||
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
||||||
|
@ -21,11 +7,18 @@ 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']
|
||||||
|
|
||||||
use_autolinking_method_symbol = ('use' + '_native' + '_modules!').to_sym
|
platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
|
||||||
origin_autolinking_method = self.method(use_autolinking_method_symbol)
|
install! 'cocoapods',
|
||||||
self.define_singleton_method(use_autolinking_method_symbol) do |*args|
|
:deterministic_uuids => false
|
||||||
if ENV['EXPO_UNSTABLE_CORE_AUTOLINKING'] == '1'
|
|
||||||
Pod::UI.puts('Using expo-modules-autolinking as core autolinking source'.green)
|
prepare_react_native_project!
|
||||||
|
|
||||||
|
target 'AlerteSecours' do
|
||||||
|
use_expo_modules!
|
||||||
|
|
||||||
|
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
|
||||||
|
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
|
||||||
|
else
|
||||||
config_command = [
|
config_command = [
|
||||||
'node',
|
'node',
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
|
@ -36,53 +29,13 @@ self.define_singleton_method(use_autolinking_method_symbol) do |*args|
|
||||||
'--platform',
|
'--platform',
|
||||||
'ios'
|
'ios'
|
||||||
]
|
]
|
||||||
origin_autolinking_method.call(config_command)
|
|
||||||
else
|
|
||||||
origin_autolinking_method.call()
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
platform :ios, '16.0'
|
config = use_native_modules!(config_command)
|
||||||
install! 'cocoapods',
|
|
||||||
:deterministic_uuids => false
|
|
||||||
|
|
||||||
prepare_react_native_project!
|
|
||||||
|
|
||||||
# ⬇️ uncomment the permissions you need
|
|
||||||
setup_permissions([
|
|
||||||
# 'AppTrackingTransparency',
|
|
||||||
# 'Bluetooth',
|
|
||||||
# 'Calendars',
|
|
||||||
# 'CalendarsWriteOnly',
|
|
||||||
'Camera',
|
|
||||||
'Contacts',
|
|
||||||
# 'FaceID',
|
|
||||||
'LocationAccuracy',
|
|
||||||
'LocationAlways',
|
|
||||||
'LocationWhenInUse',
|
|
||||||
# 'MediaLibrary',
|
|
||||||
'Microphone',
|
|
||||||
# 'Motion',
|
|
||||||
'Notifications',
|
|
||||||
'PhotoLibrary',
|
|
||||||
# 'PhotoLibraryAddOnly',
|
|
||||||
# 'Reminders',
|
|
||||||
# 'Siri',
|
|
||||||
# 'SpeechRecognition',
|
|
||||||
# 'StoreKit',
|
|
||||||
])
|
|
||||||
|
|
||||||
target 'AlerteSecours' do
|
|
||||||
use_expo_modules!
|
|
||||||
config = use_native_modules!
|
|
||||||
|
|
||||||
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']
|
||||||
|
|
||||||
# see https://rnfirebase.io/#configure-react-native-firebase-modules
|
|
||||||
use_frameworks! :linkage => :static
|
|
||||||
$RNFirebaseAsStaticFramework = true
|
|
||||||
|
|
||||||
use_react_native!(
|
use_react_native!(
|
||||||
:path => config[:reactNativePath],
|
:path => config[:reactNativePath],
|
||||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
||||||
|
@ -112,30 +65,5 @@ target 'AlerteSecours' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set deployment target for all pods
|
|
||||||
installer.pods_project.targets.each do |target|
|
|
||||||
target.build_configurations.each do |config|
|
|
||||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
installer.pods_project.build_configurations.each do |config|
|
|
||||||
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
post_integrate do |installer|
|
|
||||||
begin
|
|
||||||
expo_patch_react_imports!(installer)
|
|
||||||
rescue => e
|
|
||||||
Pod::UI.warn e
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# pod 'Firebase', :modular_headers => true
|
|
||||||
# pod 'FirebaseCoreInternal', :modular_headers => true
|
|
||||||
# pod 'GoogleUtilities', :modular_headers => true
|
|
||||||
# pod 'FirebaseCore', :modular_headers => true
|
|
||||||
# pod 'FirebaseMessaging', :modular_headers => true
|
|
||||||
|
|
|
@ -2724,8 +2724,8 @@ SPEC CHECKSUMS:
|
||||||
RNBackgroundGeolocation: bd7bf842870d57e283d07c1753ccc0d3d8231f1c
|
RNBackgroundGeolocation: bd7bf842870d57e283d07c1753ccc0d3d8231f1c
|
||||||
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
|
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
|
||||||
RNCMaskedView: 090213d32d8b3bb83a4dcb7d12c18f0152591906
|
RNCMaskedView: 090213d32d8b3bb83a4dcb7d12c18f0152591906
|
||||||
RNFBApp: 017499cd7ea340963bfac43b4fcb28d2b0b21a09
|
RNFBApp: 5f87753a8d8b37d229adf85cd0ff37709ffdf008
|
||||||
RNFBMessaging: 81f9447a3790df25c72753b446247ebeba95b182
|
RNFBMessaging: 3fa1114c0868dd21f20dfe186adf42297ea316b1
|
||||||
RNGestureHandler: 82c5ab302616348584b7563e06753b288a03fa7e
|
RNGestureHandler: 82c5ab302616348584b7563e06753b288a03fa7e
|
||||||
RNImageCropPicker: e7ab6fb43d2fc3e84651e786ef4a080d63b0ed3d
|
RNImageCropPicker: e7ab6fb43d2fc3e84651e786ef4a080d63b0ed3d
|
||||||
RNNotifee: 4a6ee5c7deaf00e005050052d73ee6315dff7ec9
|
RNNotifee: 4a6ee5c7deaf00e005050052d73ee6315dff7ec9
|
||||||
|
@ -2740,6 +2740,6 @@ SPEC CHECKSUMS:
|
||||||
UMAppLoader: 7e7e0eaa7854ffd652c00a68c443afb28c3bedba
|
UMAppLoader: 7e7e0eaa7854ffd652c00a68c443afb28c3bedba
|
||||||
Yoga: 1259c7a8cbaccf7b4c3ddf8ee36ca11be9dee407
|
Yoga: 1259c7a8cbaccf7b4c3ddf8ee36ca11be9dee407
|
||||||
|
|
||||||
PODFILE CHECKSUM: 813a2af6b17217607ed41610bc263ce233bc3cef
|
PODFILE CHECKSUM: 31e0fc7a4ffceea736dbc4c9b93cc887c8b9d808
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"expo.jsEngine": "hermes",
|
"expo.jsEngine": "hermes",
|
||||||
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
|
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
|
||||||
|
"newArchEnabled": "false",
|
||||||
"ios.useFrameworks": "static",
|
"ios.useFrameworks": "static",
|
||||||
"apple.extraPods": "[]",
|
"apple.extraPods": "[]",
|
||||||
"apple.ccacheEnabled": "false",
|
"apple.ccacheEnabled": "false",
|
||||||
"apple.privacyManifestAggregationEnabled": "true",
|
"apple.privacyManifestAggregationEnabled": "true"
|
||||||
"newArchEnabled": "false"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "alerte-secours",
|
"name": "alerte-secours",
|
||||||
"version": "1.10.8",
|
"version": "1.11.1",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start --dev-client --private-key-path ./keys/private-key.pem",
|
"start": "expo start --dev-client --private-key-path ./keys/private-key.pem",
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
"e2e:test": "detox test --configuration android.emu.debug",
|
"e2e:test": "detox test --configuration android.emu.debug",
|
||||||
"e2e:run": "yarn start & yarn e2e:build && yarn e2e:deploy && yarn e2e:test",
|
"e2e:run": "yarn start & yarn e2e:build && yarn e2e:deploy && yarn e2e:test",
|
||||||
"install:android": "./install-android.sh",
|
"install:android": "./install-android.sh",
|
||||||
|
"install:ios": "./install-ios.sh",
|
||||||
"log:android": "adb -s $DEVICE logcat | grep -E 'ReactNativeJS: '",
|
"log:android": "adb -s $DEVICE logcat | grep -E 'ReactNativeJS: '",
|
||||||
"log:ios:simulator": "xcrun simctl spawn booted log stream --level debug --predicate 'subsystem contains \"com.facebook.react.log\" and processImagePath contains \"AlerteSecours\"'",
|
"log:ios:simulator": "xcrun simctl spawn booted log stream --level debug --predicate 'subsystem contains \"com.facebook.react.log\" and processImagePath contains \"AlerteSecours\"'",
|
||||||
"log:ios": "idevicesyslog | grep -i 'AlerteSecours\\|ReactNative'",
|
"log:ios": "idevicesyslog | grep -i 'AlerteSecours\\|ReactNative'",
|
||||||
|
@ -49,8 +50,8 @@
|
||||||
"screenshot:android": "scripts/screenshot-android.sh"
|
"screenshot:android": "scripts/screenshot-android.sh"
|
||||||
},
|
},
|
||||||
"customExpoVersioning": {
|
"customExpoVersioning": {
|
||||||
"versionCode": 188,
|
"versionCode": 191,
|
||||||
"buildNumber": 188
|
"buildNumber": 191
|
||||||
},
|
},
|
||||||
"commit-and-tag-version": {
|
"commit-and-tag-version": {
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { ErrorUtils } from "react-native";
|
||||||
import { createLogger } from "~/lib/logger";
|
import { createLogger } from "~/lib/logger";
|
||||||
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
import { authActions, permissionWizardActions } from "~/stores";
|
import { authActions, permissionWizardActions, paramsActions } from "~/stores";
|
||||||
import { secureStore } from "~/storage/memorySecureStore";
|
import { secureStore } from "~/storage/memorySecureStore";
|
||||||
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ const initializeStores = () => {
|
||||||
// Then initialize other stores sequentially
|
// Then initialize other stores sequentially
|
||||||
initializeStore("authActions", authActions.init);
|
initializeStore("authActions", authActions.init);
|
||||||
initializeStore("permissionWizard", permissionWizardActions.init);
|
initializeStore("permissionWizard", permissionWizardActions.init);
|
||||||
|
initializeStore("paramsActions", paramsActions.init);
|
||||||
initializeStore("storeSubscriptions", storeSubscriptions.init);
|
initializeStore("storeSubscriptions", storeSubscriptions.init);
|
||||||
|
|
||||||
appLogger.info("Core initialization complete");
|
appLogger.info("Core initialization complete");
|
||||||
|
|
|
@ -18,8 +18,8 @@ export default function DrawerItemList(props) {
|
||||||
const { routes } = state;
|
const { routes } = state;
|
||||||
|
|
||||||
const section1 = routes.slice(0, 5);
|
const section1 = routes.slice(0, 5);
|
||||||
const section2 = routes.slice(5, 8);
|
const section2 = routes.slice(5, 9);
|
||||||
const section3 = routes.slice(8, routes.length);
|
const section3 = routes.slice(9, routes.length);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { navActions } from "~/stores";
|
||||||
|
import { createLogger } from "~/lib/logger";
|
||||||
|
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
|
const backgroundGeolocationLogger = createLogger({
|
||||||
|
module: BACKGROUND_SCOPES.NOTIFICATIONS,
|
||||||
|
feature: "action-open-background-geolocation-settings",
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function actionOpenBackgroundGeolocationSettings({ data }) {
|
||||||
|
backgroundGeolocationLogger.debug(
|
||||||
|
"actionOpenBackgroundGeolocationSettings called",
|
||||||
|
);
|
||||||
|
|
||||||
|
navActions.setNextNavigation([
|
||||||
|
{
|
||||||
|
name: "Params",
|
||||||
|
params: {
|
||||||
|
anchor: "permissions",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
|
@ -1,9 +1,26 @@
|
||||||
import { navActions } from "~/stores";
|
import { navActions } from "~/stores";
|
||||||
|
import { createLogger } from "~/lib/logger";
|
||||||
|
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
|
const settingsLogger = createLogger({
|
||||||
|
module: BACKGROUND_SCOPES.NOTIFICATIONS,
|
||||||
|
feature: "action-open-settings",
|
||||||
|
});
|
||||||
|
|
||||||
export default function actionOpenSettings({ data }) {
|
export default function actionOpenSettings({ data }) {
|
||||||
|
settingsLogger.debug("actionOpenSettings called", {
|
||||||
|
data,
|
||||||
|
hasData: !!data,
|
||||||
|
dataKeys: data ? Object.keys(data) : [],
|
||||||
|
});
|
||||||
|
|
||||||
navActions.setNextNavigation([
|
navActions.setNextNavigation([
|
||||||
{
|
{
|
||||||
name: "Params",
|
name: "Params",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
settingsLogger.debug("Navigation set to Params screen", {
|
||||||
|
navigationTarget: "Params",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,18 @@ export default async function notifBackgroundGeolocationLost(data) {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// DEBUG: Log notification configuration for diagnosis
|
||||||
|
backgroundGeolocationLogger.info(
|
||||||
|
"DEBUG: Background geolocation notification config",
|
||||||
|
{
|
||||||
|
channelId,
|
||||||
|
pressActionId: "open-settings",
|
||||||
|
launchActivity: "default",
|
||||||
|
hasData: !!data,
|
||||||
|
dataKeys: data ? Object.keys(data) : [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Generate notification content
|
// Generate notification content
|
||||||
const { title, body, bigText } =
|
const { title, body, bigText } =
|
||||||
generateBackgroundGeolocationLostContent(data);
|
generateBackgroundGeolocationLostContent(data);
|
||||||
|
@ -34,14 +46,14 @@ export default async function notifBackgroundGeolocationLost(data) {
|
||||||
bigText,
|
bigText,
|
||||||
android: {
|
android: {
|
||||||
pressAction: {
|
pressAction: {
|
||||||
id: "open-settings",
|
id: "open-background-geolocation-settings",
|
||||||
launchActivity: "default",
|
launchActivity: "default",
|
||||||
},
|
},
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: "Paramètres",
|
title: "Paramètres",
|
||||||
pressAction: {
|
pressAction: {
|
||||||
id: "open-settings",
|
id: "open-background-geolocation-settings",
|
||||||
launchActivity: "default",
|
launchActivity: "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,6 +5,6 @@ const channelId = "system";
|
||||||
export async function createNotificationChannel() {
|
export async function createNotificationChannel() {
|
||||||
await createChannel({
|
await createChannel({
|
||||||
id: channelId,
|
id: channelId,
|
||||||
name: "System",
|
name: "Paramètres",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,10 +84,13 @@ export const createNotificationHandlers = (handlers) => {
|
||||||
suggest_keep_open: async (data) => await openAlert({ data }),
|
suggest_keep_open: async (data) => await openAlert({ data }),
|
||||||
relative_invitation: async (data) => await openRelatives({ data }),
|
relative_invitation: async (data) => await openRelatives({ data }),
|
||||||
relative_allow_ask: async (data) => await openRelatives({ data }),
|
relative_allow_ask: async (data) => await openRelatives({ data }),
|
||||||
background_geolocation_lost: async (data) => {
|
background_geolocation_lost: async (_data) => {
|
||||||
navActions.setNextNavigation([
|
navActions.setNextNavigation([
|
||||||
{
|
{
|
||||||
name: "Params",
|
name: "Params",
|
||||||
|
params: {
|
||||||
|
anchor: "permissions",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import actionRelativeAllowReject from "./actions/actionRelativeAllowReject";
|
||||||
import actionRelativeInvitationAccept from "./actions/actionRelativeInvitationAccept";
|
import actionRelativeInvitationAccept from "./actions/actionRelativeInvitationAccept";
|
||||||
import actionRelativeInvitationReject from "./actions/actionRelativeInvitationReject";
|
import actionRelativeInvitationReject from "./actions/actionRelativeInvitationReject";
|
||||||
import actionOpenSettings from "./actions/actionOpenSettings";
|
import actionOpenSettings from "./actions/actionOpenSettings";
|
||||||
|
import actionOpenBackgroundGeolocationSettings from "./actions/actionOpenBackgroundGeolocationSettings";
|
||||||
|
|
||||||
import { navActions } from "~/stores";
|
import { navActions } from "~/stores";
|
||||||
|
|
||||||
|
@ -97,11 +98,12 @@ export const onNotificationOpenedAppEvent = async (remoteMessage) => {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
try {
|
try {
|
||||||
eventLogger.info("Processing background notification tap", {
|
eventLogger.debug("Processing background notification tap", {
|
||||||
messageId: remoteMessage?.messageId,
|
messageId: remoteMessage?.messageId,
|
||||||
data: remoteMessage?.data,
|
data: remoteMessage?.data,
|
||||||
notification: remoteMessage?.notification,
|
notification: remoteMessage?.notification,
|
||||||
clickAction: remoteMessage?.notification?.android?.clickAction,
|
clickAction: remoteMessage?.notification?.android?.clickAction,
|
||||||
|
notificationType: remoteMessage?.data?.type || "unknown",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!remoteMessage?.notification) {
|
if (!remoteMessage?.notification) {
|
||||||
|
@ -275,8 +277,27 @@ export const onEvent = async ({ type, notification, pressAction }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "open-settings": {
|
case "open-settings": {
|
||||||
|
eventLogger.debug("Processing open-settings action", {
|
||||||
|
data,
|
||||||
|
actionId,
|
||||||
|
notificationId: notification?.id,
|
||||||
|
launchActivity: pressAction?.launchActivity,
|
||||||
|
});
|
||||||
await actionOpenSettings({ data });
|
await actionOpenSettings({ data });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "open-background-geolocation-settings": {
|
||||||
|
eventLogger.debug(
|
||||||
|
"Processing open-background-geolocation-settings action",
|
||||||
|
{
|
||||||
|
data,
|
||||||
|
actionId,
|
||||||
|
notificationId: notification?.id,
|
||||||
|
launchActivity: pressAction?.launchActivity,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await actionOpenBackgroundGeolocationSettings({ data });
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,6 +123,11 @@ export default async function setActionCategories() {
|
||||||
title: "Paramètres",
|
title: "Paramètres",
|
||||||
foreground: true,
|
foreground: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "open-background-geolocation-settings",
|
||||||
|
title: "Paramètres",
|
||||||
|
foreground: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
78
src/scenes/Params/SentryOptOut.js
Normal file
78
src/scenes/Params/SentryOptOut.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import React, { useCallback } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { Title, Switch } from "react-native-paper";
|
||||||
|
import { createStyles } from "~/theme";
|
||||||
|
import { useParamsState, paramsActions } from "~/stores";
|
||||||
|
import Text from "~/components/Text";
|
||||||
|
import { setSentryEnabled } from "~/sentry";
|
||||||
|
|
||||||
|
function SentryOptOut() {
|
||||||
|
const styles = useStyles();
|
||||||
|
const { sentryEnabled } = useParamsState(["sentryEnabled"]);
|
||||||
|
|
||||||
|
const handleToggle = useCallback(async () => {
|
||||||
|
const newValue = !sentryEnabled;
|
||||||
|
await paramsActions.setSentryEnabled(newValue);
|
||||||
|
|
||||||
|
// Dynamically enable/disable Sentry
|
||||||
|
setSentryEnabled(newValue);
|
||||||
|
}, [sentryEnabled]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Title style={styles.title}>Rapport d'erreurs</Title>
|
||||||
|
<View style={styles.content}>
|
||||||
|
<View style={styles.switchContainer}>
|
||||||
|
<Text style={styles.label}>Envoyer les rapports d'erreurs</Text>
|
||||||
|
<Switch
|
||||||
|
value={sentryEnabled}
|
||||||
|
onValueChange={handleToggle}
|
||||||
|
style={styles.switch}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.description}>
|
||||||
|
Les rapports d'erreurs nous aident à améliorer l'application en nous
|
||||||
|
permettant de mieux identifier et corriger les problèmes techniques.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ theme: { colors } }) => ({
|
||||||
|
container: {
|
||||||
|
width: "100%",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginVertical: 15,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
switchContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: 5,
|
||||||
|
paddingVertical: 5,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 16,
|
||||||
|
flex: 1,
|
||||||
|
marginRight: 15,
|
||||||
|
},
|
||||||
|
switch: {
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: colors.onSurfaceVariant,
|
||||||
|
textAlign: "left",
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default SentryOptOut;
|
|
@ -1,17 +1,40 @@
|
||||||
import React from "react";
|
import React, { useCallback, useRef } from "react";
|
||||||
import { View, ScrollView } from "react-native";
|
import { View, ScrollView, InteractionManager } from "react-native";
|
||||||
import { createStyles } from "~/theme";
|
import { createStyles } from "~/theme";
|
||||||
import ParamsNotifications from "./Notifications";
|
import ParamsNotifications from "./Notifications";
|
||||||
import ParamsRadius from "./Radius";
|
import ParamsRadius from "./Radius";
|
||||||
import ParamsEmergencyCall from "./EmergencyCall";
|
import ParamsEmergencyCall from "./EmergencyCall";
|
||||||
import ThemeSwitcher from "./ThemeSwitcher";
|
import ThemeSwitcher from "./ThemeSwitcher";
|
||||||
import Permissions from "./Permissions";
|
import Permissions from "./Permissions";
|
||||||
|
import SentryOptOut from "./SentryOptOut";
|
||||||
|
import { useRoute, useFocusEffect } from "@react-navigation/native";
|
||||||
|
|
||||||
export default function ParamsView({ data }) {
|
export default function ParamsView({ data }) {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
|
||||||
|
const scrollRef = useRef(null);
|
||||||
|
const { params } = useRoute();
|
||||||
|
const didScroll = useRef(false);
|
||||||
|
|
||||||
|
const recordLayout = useCallback(
|
||||||
|
(key) =>
|
||||||
|
({
|
||||||
|
nativeEvent: {
|
||||||
|
layout: { y },
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
if (didScroll.current || params?.anchor !== key) return;
|
||||||
|
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
scrollRef.current?.scrollTo({ y, animated: true });
|
||||||
|
didScroll.current = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[params?.anchor],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.scrollView}>
|
<ScrollView ref={scrollRef} style={styles.scrollView}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
|
@ -26,6 +49,9 @@ export default function ParamsView({ data }) {
|
||||||
<ParamsRadius data={data} />
|
<ParamsRadius data={data} />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
|
<SentryOptOut />
|
||||||
|
</View>
|
||||||
|
<View onLayout={recordLayout("permissions")} style={styles.section}>
|
||||||
<Permissions />
|
<Permissions />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -3,6 +3,15 @@ import { Platform } from "react-native";
|
||||||
|
|
||||||
import env from "~/env";
|
import env from "~/env";
|
||||||
import packageJson from "../../package.json";
|
import packageJson from "../../package.json";
|
||||||
|
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||||
|
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
||||||
|
import { createLogger } from "~/lib/logger";
|
||||||
|
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
|
const sentryLogger = createLogger({
|
||||||
|
module: SYSTEM_SCOPES.APP,
|
||||||
|
feature: "sentry",
|
||||||
|
});
|
||||||
|
|
||||||
// Get the build number from native code
|
// Get the build number from native code
|
||||||
const getBuildNumber = () => {
|
const getBuildNumber = () => {
|
||||||
|
@ -23,60 +32,139 @@ const getReleaseVersion = () => {
|
||||||
return `com.alertesecours@${version}+${buildNumber}`;
|
return `com.alertesecours@${version}+${buildNumber}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
Sentry.init({
|
// Check if Sentry is enabled by user preference
|
||||||
dsn: env.SENTRY_DSN,
|
const checkSentryEnabled = async () => {
|
||||||
tracesSampleRate: 0.1,
|
try {
|
||||||
debug: __DEV__,
|
// Wait for memory storage to be initialized
|
||||||
// Configure release to match ios-archive.sh format
|
let retries = 0;
|
||||||
release: getReleaseVersion(),
|
const maxRetries = 10;
|
||||||
// Use BUILD_TIME from env to match the value used in sourcemap upload
|
|
||||||
dist: env.BUILD_TIME,
|
|
||||||
enableNative: true,
|
|
||||||
attachStacktrace: true,
|
|
||||||
environment: __DEV__ ? "development" : "production",
|
|
||||||
normalizeDepth: 10,
|
|
||||||
maxBreadcrumbs: 100,
|
|
||||||
// Enable debug ID tracking
|
|
||||||
_experiments: {
|
|
||||||
debugIds: true,
|
|
||||||
},
|
|
||||||
beforeSend(event) {
|
|
||||||
event.extra = {
|
|
||||||
...event.extra,
|
|
||||||
jsEngine: global.HermesInternal ? "hermes" : "jsc",
|
|
||||||
hermesEnabled: !!global.HermesInternal,
|
|
||||||
version: packageJson.version,
|
|
||||||
buildNumber: getBuildNumber(),
|
|
||||||
buildTime: env.BUILD_TIME,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (event.exception) {
|
while (retries < maxRetries) {
|
||||||
event.exception.values = event.exception.values?.map((value) => ({
|
try {
|
||||||
...value,
|
const stored = await memoryAsyncStorage.getItem(
|
||||||
mechanism: {
|
STORAGE_KEYS.SENTRY_ENABLED,
|
||||||
...value.mechanism,
|
);
|
||||||
handled: true,
|
if (stored !== null) {
|
||||||
synthetic: false,
|
return JSON.parse(stored);
|
||||||
type: "hermes",
|
}
|
||||||
},
|
break; // Storage is ready, no preference stored
|
||||||
}));
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error.message?.includes("not initialized") &&
|
||||||
|
retries < maxRetries - 1
|
||||||
|
) {
|
||||||
|
// Wait a bit and retry if storage not initialized
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
|
retries++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sentryLogger.warn("Failed to check Sentry preference", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
sentryLogger.warn("Failed to check Sentry preference", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Default to enabled if no preference stored or error occurred
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return event;
|
// Initialize Sentry with user preference check
|
||||||
},
|
const initializeSentry = async () => {
|
||||||
beforeBreadcrumb(breadcrumb) {
|
const isEnabled = await checkSentryEnabled();
|
||||||
if (breadcrumb.category === "console") {
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: env.SENTRY_DSN,
|
||||||
|
enabled: isEnabled,
|
||||||
|
tracesSampleRate: 0.1,
|
||||||
|
debug: __DEV__,
|
||||||
|
// Configure release to match ios-archive.sh format
|
||||||
|
release: getReleaseVersion(),
|
||||||
|
// Use BUILD_TIME from env to match the value used in sourcemap upload
|
||||||
|
dist: env.BUILD_TIME,
|
||||||
|
enableNative: true,
|
||||||
|
attachStacktrace: true,
|
||||||
|
environment: __DEV__ ? "development" : "production",
|
||||||
|
normalizeDepth: 10,
|
||||||
|
maxBreadcrumbs: 100,
|
||||||
|
// Enable debug ID tracking
|
||||||
|
_experiments: {
|
||||||
|
debugIds: true,
|
||||||
|
},
|
||||||
|
beforeSend(event) {
|
||||||
|
event.extra = {
|
||||||
|
...event.extra,
|
||||||
|
jsEngine: global.HermesInternal ? "hermes" : "jsc",
|
||||||
|
hermesEnabled: !!global.HermesInternal,
|
||||||
|
version: packageJson.version,
|
||||||
|
buildNumber: getBuildNumber(),
|
||||||
|
buildTime: env.BUILD_TIME,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (event.exception) {
|
||||||
|
event.exception.values = event.exception.values?.map((value) => ({
|
||||||
|
...value,
|
||||||
|
mechanism: {
|
||||||
|
...value.mechanism,
|
||||||
|
handled: true,
|
||||||
|
synthetic: false,
|
||||||
|
type: "hermes",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
|
},
|
||||||
|
beforeBreadcrumb(breadcrumb) {
|
||||||
|
if (breadcrumb.category === "console") {
|
||||||
|
return breadcrumb;
|
||||||
|
}
|
||||||
return breadcrumb;
|
return breadcrumb;
|
||||||
}
|
},
|
||||||
return breadcrumb;
|
replaysSessionSampleRate: 0.1,
|
||||||
},
|
replaysOnErrorSampleRate: 1.0,
|
||||||
replaysSessionSampleRate: 0.1,
|
integrations: [
|
||||||
replaysOnErrorSampleRate: 1.0,
|
// Sentry.mobileReplayIntegration({
|
||||||
integrations: [
|
// maskAllText: false,
|
||||||
// Sentry.mobileReplayIntegration({
|
// maskAllImages: false,
|
||||||
// maskAllText: false,
|
// maskAllVectors: false,
|
||||||
// maskAllImages: false,
|
// }),
|
||||||
// maskAllVectors: false,
|
],
|
||||||
// }),
|
});
|
||||||
],
|
};
|
||||||
|
|
||||||
|
// Initialize Sentry asynchronously
|
||||||
|
initializeSentry().catch((error) => {
|
||||||
|
sentryLogger.warn("Failed to initialize Sentry", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Export function to dynamically control Sentry
|
||||||
|
export const setSentryEnabled = (enabled) => {
|
||||||
|
try {
|
||||||
|
// Use the newer Sentry API
|
||||||
|
const client = Sentry.getClient();
|
||||||
|
if (client) {
|
||||||
|
const options = client.getOptions();
|
||||||
|
options.enabled = enabled;
|
||||||
|
if (!enabled) {
|
||||||
|
// Clear any pending events when disabling
|
||||||
|
Sentry.withScope((scope) => {
|
||||||
|
scope.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sentryLogger.info("Sentry state toggled", { enabled });
|
||||||
|
} else {
|
||||||
|
sentryLogger.warn("Sentry client not available for toggling");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
sentryLogger.warn("Failed to toggle Sentry state", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -80,4 +80,5 @@ export const STORAGE_KEYS = {
|
||||||
LAST_KNOWN_LOCATION: registerAsyncStorageKey("@last_known_location"),
|
LAST_KNOWN_LOCATION: registerAsyncStorageKey("@last_known_location"),
|
||||||
EULA_ACCEPTED_SIMPLE: registerAsyncStorageKey("eula_accepted"),
|
EULA_ACCEPTED_SIMPLE: registerAsyncStorageKey("eula_accepted"),
|
||||||
EMULATOR_MODE_ENABLED: registerAsyncStorageKey("emulator_mode_enabled"),
|
EMULATOR_MODE_ENABLED: registerAsyncStorageKey("emulator_mode_enabled"),
|
||||||
|
SENTRY_ENABLED: registerAsyncStorageKey("@sentry_enabled"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
import { createAtom } from "~/lib/atomic-zustand";
|
import { createAtom } from "~/lib/atomic-zustand";
|
||||||
|
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||||
|
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
||||||
|
import { createLogger } from "~/lib/logger";
|
||||||
|
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
|
const paramsLogger = createLogger({
|
||||||
|
module: SYSTEM_SCOPES.APP,
|
||||||
|
feature: "params",
|
||||||
|
});
|
||||||
|
|
||||||
export default createAtom(({ merge, reset }) => {
|
export default createAtom(({ merge, reset }) => {
|
||||||
const setDevModeEnabled = (b) => {
|
const setDevModeEnabled = (b) => {
|
||||||
|
@ -37,6 +46,45 @@ export default createAtom(({ merge, reset }) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setSentryEnabled = async (sentryEnabled) => {
|
||||||
|
merge({
|
||||||
|
sentryEnabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Persist to storage
|
||||||
|
try {
|
||||||
|
await memoryAsyncStorage.setItem(
|
||||||
|
STORAGE_KEYS.SENTRY_ENABLED,
|
||||||
|
JSON.stringify(sentryEnabled),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
paramsLogger.warn("Failed to persist Sentry preference", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const initSentryEnabled = async () => {
|
||||||
|
try {
|
||||||
|
const stored = await memoryAsyncStorage.getItem(
|
||||||
|
STORAGE_KEYS.SENTRY_ENABLED,
|
||||||
|
);
|
||||||
|
if (stored !== null) {
|
||||||
|
const sentryEnabled = JSON.parse(stored);
|
||||||
|
merge({ sentryEnabled });
|
||||||
|
return sentryEnabled;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
paramsLogger.warn("Failed to load Sentry preference", {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = async () => {
|
||||||
|
await initSentryEnabled();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
default: {
|
default: {
|
||||||
// devModeEnabled: false,
|
// devModeEnabled: false,
|
||||||
|
@ -46,6 +94,7 @@ export default createAtom(({ merge, reset }) => {
|
||||||
mapColorScheme: "auto",
|
mapColorScheme: "auto",
|
||||||
hasRegisteredRelatives: null,
|
hasRegisteredRelatives: null,
|
||||||
alertListSortBy: "location",
|
alertListSortBy: "location",
|
||||||
|
sentryEnabled: true,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
reset,
|
reset,
|
||||||
|
@ -55,6 +104,8 @@ export default createAtom(({ merge, reset }) => {
|
||||||
setMapColorScheme,
|
setMapColorScheme,
|
||||||
setHasRegisteredRelatives,
|
setHasRegisteredRelatives,
|
||||||
setAlertListSortBy,
|
setAlertListSortBy,
|
||||||
|
setSentryEnabled,
|
||||||
|
init,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue