Compare commits
No commits in common. "main" and "v1.12.1" have entirely different histories.
11 changed files with 67 additions and 215 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -84,9 +84,6 @@ DerivedData
|
||||||
# aidigest
|
# aidigest
|
||||||
codebase.md
|
codebase.md
|
||||||
|
|
||||||
# Build logs
|
|
||||||
logs/
|
|
||||||
|
|
||||||
# Sensitive configuration files
|
# Sensitive configuration files
|
||||||
ios/GoogleService-Info.plist
|
ios/GoogleService-Info.plist
|
||||||
ios/AlerteSecours/GoogleService-Info.plist
|
ios/AlerteSecours/GoogleService-Info.plist
|
||||||
|
|
|
@ -2,15 +2,6 @@
|
||||||
|
|
||||||
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.12.3](https://github.com/alerte-secours/as-app/compare/v1.12.2...v1.12.3) (2025-09-05)
|
|
||||||
|
|
||||||
## [1.12.2](https://github.com/alerte-secours/as-app/compare/v1.12.1...v1.12.2) (2025-08-24)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* 112 ([8487573](https://github.com/alerte-secours/as-app/commit/8487573c0f8eb6656cd5825ff217efe046d65407))
|
|
||||||
|
|
||||||
## [1.12.1](https://github.com/alerte-secours/as-app/compare/v1.12.0...v1.12.1) (2025-08-10)
|
## [1.12.1](https://github.com/alerte-secours/as-app/compare/v1.12.0...v1.12.1) (2025-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 211
|
versionCode 209
|
||||||
versionName "1.12.3"
|
versionName "1.12.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'
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
|
|
||||||
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||||
|
@ -11,7 +10,6 @@
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
|
|
@ -25,7 +25,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.12.3</string>
|
<string>1.12.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>211</string>
|
<string>209</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "alerte-secours",
|
"name": "alerte-secours",
|
||||||
"version": "1.12.3",
|
"version": "1.12.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",
|
||||||
|
@ -50,8 +50,8 @@
|
||||||
"screenshot:android": "scripts/screenshot-android.sh"
|
"screenshot:android": "scripts/screenshot-android.sh"
|
||||||
},
|
},
|
||||||
"customExpoVersioning": {
|
"customExpoVersioning": {
|
||||||
"versionCode": 211,
|
"versionCode": 209,
|
||||||
"buildNumber": 211
|
"buildNumber": 209
|
||||||
},
|
},
|
||||||
"commit-and-tag-version": {
|
"commit-and-tag-version": {
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -86,9 +86,6 @@ mv ios/main.jsbundle.hbc ios/main.jsbundle
|
||||||
|
|
||||||
cd ios
|
cd ios
|
||||||
|
|
||||||
# Create logs directory if it doesn't exist
|
|
||||||
mkdir -p ../logs
|
|
||||||
|
|
||||||
# Create archive using xcodebuild
|
# Create archive using xcodebuild
|
||||||
echo "Creating archive..."
|
echo "Creating archive..."
|
||||||
xcodebuild \
|
xcodebuild \
|
||||||
|
@ -96,6 +93,6 @@ xcodebuild \
|
||||||
-scheme AlerteSecours \
|
-scheme AlerteSecours \
|
||||||
-configuration Release \
|
-configuration Release \
|
||||||
-archivePath AlerteSecours.xcarchive \
|
-archivePath AlerteSecours.xcarchive \
|
||||||
archive 2>&1 | tee "../logs/ios-archive-$(date +%Y%m%d-%H%M%S).log"
|
archive
|
||||||
|
|
||||||
echo "Archive completed successfully at AlerteSecours.xcarchive"
|
echo "Archive completed successfully at AlerteSecours.xcarchive"
|
||||||
|
|
|
@ -17,13 +17,11 @@ import {
|
||||||
import { createStyles, useTheme } from "~/theme";
|
import { createStyles, useTheme } from "~/theme";
|
||||||
import openSettings from "~/lib/native/openSettings";
|
import openSettings from "~/lib/native/openSettings";
|
||||||
import {
|
import {
|
||||||
requestBatteryOptimizationExemption,
|
RequestDisableOptimization,
|
||||||
isBatteryOptimizationEnabled,
|
BatteryOptEnabled,
|
||||||
openBatteryOptimizationFallbacks,
|
} from "react-native-battery-optimization-check";
|
||||||
} from "~/lib/native/batteryOptimization";
|
|
||||||
|
|
||||||
import requestPermissionLocationBackground from "~/permissions/requestPermissionLocationBackground";
|
import requestPermissionLocationBackground from "~/permissions/requestPermissionLocationBackground";
|
||||||
import requestPermissionLocationForeground from "~/permissions/requestPermissionLocationForeground";
|
|
||||||
import requestPermissionMotion from "~/permissions/requestPermissionMotion";
|
import requestPermissionMotion from "~/permissions/requestPermissionMotion";
|
||||||
import CustomButton from "~/components/CustomButton";
|
import CustomButton from "~/components/CustomButton";
|
||||||
import Text from "~/components/Text";
|
import Text from "~/components/Text";
|
||||||
|
@ -47,8 +45,6 @@ const HeroMode = () => {
|
||||||
useState(null);
|
useState(null);
|
||||||
const [batteryOptAttempted, setBatteryOptAttempted] = useState(false);
|
const [batteryOptAttempted, setBatteryOptAttempted] = useState(false);
|
||||||
const [batteryOptInProgress, setBatteryOptInProgress] = useState(false);
|
const [batteryOptInProgress, setBatteryOptInProgress] = useState(false);
|
||||||
const [batteryOptFallbackOpened, setBatteryOptFallbackOpened] =
|
|
||||||
useState(false);
|
|
||||||
const permissions = usePermissionsState([
|
const permissions = usePermissionsState([
|
||||||
"locationBackground",
|
"locationBackground",
|
||||||
"motion",
|
"motion",
|
||||||
|
@ -79,14 +75,16 @@ const HeroMode = () => {
|
||||||
setBatteryOptInProgress(true);
|
setBatteryOptInProgress(true);
|
||||||
|
|
||||||
// Check if battery optimization is enabled
|
// Check if battery optimization is enabled
|
||||||
const isEnabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
setBatteryOptimizationEnabled(isEnabled);
|
setBatteryOptimizationEnabled(isEnabled);
|
||||||
|
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
console.log("Battery optimization is enabled, requesting exemption...");
|
console.log(
|
||||||
|
"Battery optimization is enabled, requesting to disable...",
|
||||||
|
);
|
||||||
|
|
||||||
// Request to disable battery optimization (opens Android Settings)
|
// Request to disable battery optimization (opens Android Settings)
|
||||||
await requestBatteryOptimizationExemption();
|
RequestDisableOptimization();
|
||||||
setBatteryOptAttempted(true);
|
setBatteryOptAttempted(true);
|
||||||
|
|
||||||
// Return false to indicate user needs to complete action in Settings
|
// Return false to indicate user needs to complete action in Settings
|
||||||
|
@ -108,45 +106,31 @@ const HeroMode = () => {
|
||||||
const handleRequestPermissions = useCallback(async () => {
|
const handleRequestPermissions = useCallback(async () => {
|
||||||
setRequesting(true);
|
setRequesting(true);
|
||||||
try {
|
try {
|
||||||
|
// Don't change step immediately to avoid race conditions
|
||||||
console.log("Starting permission requests...");
|
console.log("Starting permission requests...");
|
||||||
|
|
||||||
// 1) Battery optimization (opens Settings)
|
// Request battery optimization FIRST (opens Android Settings)
|
||||||
|
// This prevents the bubbling issue by handling Settings-based permissions before in-app dialogs
|
||||||
const batteryOptDisabled = await handleBatteryOptimization();
|
const batteryOptDisabled = await handleBatteryOptimization();
|
||||||
console.log("Battery optimization disabled:", batteryOptDisabled);
|
console.log("Battery optimization disabled:", batteryOptDisabled);
|
||||||
if (!batteryOptDisabled) {
|
|
||||||
// Settings flow opened; wait for user to return before requesting in-app permissions
|
|
||||||
setRequesting(false);
|
|
||||||
setHasAttempted(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Foreground location
|
// Request motion permission second
|
||||||
let fgGranted = await requestPermissionLocationForeground();
|
|
||||||
permissionsActions.setLocationForeground(fgGranted);
|
|
||||||
console.log("Location foreground permission:", fgGranted);
|
|
||||||
|
|
||||||
// 3) Background location (only after FG granted)
|
|
||||||
let bgGranted = false;
|
|
||||||
if (fgGranted) {
|
|
||||||
bgGranted = await requestPermissionLocationBackground();
|
|
||||||
permissionsActions.setLocationBackground(bgGranted);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
"Skipping background location since foreground not granted",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
console.log("Location background permission:", bgGranted);
|
|
||||||
|
|
||||||
// 4) Motion
|
|
||||||
const motionGranted = await requestPermissionMotion.requestPermission();
|
const motionGranted = await requestPermissionMotion.requestPermission();
|
||||||
permissionsActions.setMotion(motionGranted);
|
permissionsActions.setMotion(motionGranted);
|
||||||
console.log("Motion permission:", motionGranted);
|
console.log("Motion permission:", motionGranted);
|
||||||
|
|
||||||
// Step after all requests
|
// Request background location last (after user returns from Settings if needed)
|
||||||
|
const locationGranted = await requestPermissionLocationBackground();
|
||||||
|
permissionsActions.setLocationBackground(locationGranted);
|
||||||
|
console.log("Location background permission:", locationGranted);
|
||||||
|
|
||||||
|
// Only set step to tracking after all permission requests are complete
|
||||||
permissionWizardActions.setCurrentStep("tracking");
|
permissionWizardActions.setCurrentStep("tracking");
|
||||||
|
|
||||||
if (fgGranted && bgGranted && motionGranted && batteryOptDisabled) {
|
// Check if we should proceed to success immediately
|
||||||
|
if (locationGranted && motionGranted && batteryOptDisabled) {
|
||||||
permissionWizardActions.setHeroPermissionsGranted(true);
|
permissionWizardActions.setHeroPermissionsGranted(true);
|
||||||
|
// Don't navigate immediately, let the useEffect handle it
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error requesting permissions:", error);
|
console.error("Error requesting permissions:", error);
|
||||||
|
@ -159,7 +143,7 @@ const HeroMode = () => {
|
||||||
// Re-check battery optimization status before retrying
|
// Re-check battery optimization status before retrying
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
try {
|
try {
|
||||||
const isEnabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
setBatteryOptimizationEnabled(isEnabled);
|
setBatteryOptimizationEnabled(isEnabled);
|
||||||
|
|
||||||
// If battery optimization is now disabled, update the store
|
// If battery optimization is now disabled, update the store
|
||||||
|
@ -195,7 +179,7 @@ const HeroMode = () => {
|
||||||
const checkInitialBatteryOptimization = async () => {
|
const checkInitialBatteryOptimization = async () => {
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
try {
|
try {
|
||||||
const isEnabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
setBatteryOptimizationEnabled(isEnabled);
|
setBatteryOptimizationEnabled(isEnabled);
|
||||||
|
|
||||||
// If already disabled, update the store
|
// If already disabled, update the store
|
||||||
|
@ -224,7 +208,7 @@ const HeroMode = () => {
|
||||||
) {
|
) {
|
||||||
console.log("App became active, re-checking battery optimization...");
|
console.log("App became active, re-checking battery optimization...");
|
||||||
try {
|
try {
|
||||||
const isEnabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
setBatteryOptimizationEnabled(isEnabled);
|
setBatteryOptimizationEnabled(isEnabled);
|
||||||
|
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
|
@ -232,19 +216,6 @@ const HeroMode = () => {
|
||||||
"Battery optimization disabled after returning from settings",
|
"Battery optimization disabled after returning from settings",
|
||||||
);
|
);
|
||||||
permissionsActions.setBatteryOptimizationDisabled(true);
|
permissionsActions.setBatteryOptimizationDisabled(true);
|
||||||
} else if (!batteryOptFallbackOpened) {
|
|
||||||
try {
|
|
||||||
console.log(
|
|
||||||
"Battery optimization still enabled; opening fallback settings...",
|
|
||||||
);
|
|
||||||
await openBatteryOptimizationFallbacks();
|
|
||||||
setBatteryOptFallbackOpened(true);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(
|
|
||||||
"Error opening battery optimization fallback settings:",
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
|
@ -263,7 +234,7 @@ const HeroMode = () => {
|
||||||
return () => {
|
return () => {
|
||||||
subscription?.remove();
|
subscription?.remove();
|
||||||
};
|
};
|
||||||
}, [batteryOptAttempted, batteryOptFallbackOpened]);
|
}, [batteryOptAttempted]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasAttempted && allGranted) {
|
if (hasAttempted && allGranted) {
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
import { Platform } from "react-native";
|
|
||||||
import SendIntentAndroid from "react-native-send-intent";
|
|
||||||
import {
|
|
||||||
RequestDisableOptimization,
|
|
||||||
BatteryOptEnabled,
|
|
||||||
} from "react-native-battery-optimization-check";
|
|
||||||
import { createLogger } from "~/lib/logger";
|
|
||||||
import { FEATURE_SCOPES } from "~/lib/logger/scopes";
|
|
||||||
|
|
||||||
const log = createLogger({
|
|
||||||
module: FEATURE_SCOPES.PERMISSIONS,
|
|
||||||
feature: "battery-optimization",
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if battery optimization is currently ENABLED for this app on Android.
|
|
||||||
* On iOS, returns false (no battery optimization concept).
|
|
||||||
*/
|
|
||||||
export async function isBatteryOptimizationEnabled() {
|
|
||||||
if (Platform.OS !== "android") return false;
|
|
||||||
try {
|
|
||||||
const enabled = await BatteryOptEnabled();
|
|
||||||
log.info("Battery optimization status", { enabled });
|
|
||||||
return enabled;
|
|
||||||
} catch (e) {
|
|
||||||
log.error("Failed to read battery optimization status", {
|
|
||||||
error: e?.message,
|
|
||||||
stack: e?.stack,
|
|
||||||
});
|
|
||||||
// Conservative: assume enabled if unknown
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launches the primary system flow to request ignoring battery optimizations.
|
|
||||||
* This opens a Settings screen; it does not yield a synchronous result.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* - false on Android to indicate the user must complete an action in Settings
|
|
||||||
* - true on iOS (no-op)
|
|
||||||
*/
|
|
||||||
export async function requestBatteryOptimizationExemption() {
|
|
||||||
if (Platform.OS !== "android") return true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
log.info("Requesting to disable battery optimization (primary intent)");
|
|
||||||
// This opens the OS dialog/settings. No result is provided, handle via AppState return.
|
|
||||||
RequestDisableOptimization();
|
|
||||||
return false;
|
|
||||||
} catch (e) {
|
|
||||||
log.error("Primary request to disable battery optimization failed", {
|
|
||||||
error: e?.message,
|
|
||||||
stack: e?.stack,
|
|
||||||
});
|
|
||||||
// Even if it throws, we'll guide users via fallbacks.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens best-effort fallback screens to let users disable battery optimization.
|
|
||||||
* Call this AFTER the user returns and status is still enabled.
|
|
||||||
*
|
|
||||||
* Strategy:
|
|
||||||
* - Try the list of battery optimization exceptions
|
|
||||||
* - Fallback to app settings
|
|
||||||
*/
|
|
||||||
export async function openBatteryOptimizationFallbacks() {
|
|
||||||
if (Platform.OS !== "android") return true;
|
|
||||||
|
|
||||||
// Try the generic battery optimization settings list
|
|
||||||
try {
|
|
||||||
log.info("Opening fallback: IGNORE_BATTERY_OPTIMIZATION_SETTINGS");
|
|
||||||
await SendIntentAndroid.openSettings(
|
|
||||||
"android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS",
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
log.warn("Failed to open IGNORE_BATTERY_OPTIMIZATION_SETTINGS", {
|
|
||||||
error: e?.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final fallback: app details settings
|
|
||||||
try {
|
|
||||||
log.info("Opening fallback: APPLICATION_DETAILS_SETTINGS (app details)");
|
|
||||||
await SendIntentAndroid.openAppSettings();
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
log.error("Failed to open APPLICATION_DETAILS_SETTINGS", {
|
|
||||||
error: e?.message,
|
|
||||||
stack: e?.stack,
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@ import { Platform, Linking } from "react-native";
|
||||||
import RNImmediatePhoneCall from "react-native-immediate-phone-call";
|
import RNImmediatePhoneCall from "react-native-immediate-phone-call";
|
||||||
|
|
||||||
export function phoneCallEmergency() {
|
export function phoneCallEmergency() {
|
||||||
const emergencyNumber = "112";
|
const emergencyNumber = "+112";
|
||||||
|
|
||||||
if (Platform.OS === "ios") {
|
if (Platform.OS === "ios") {
|
||||||
// Use telprompt URL scheme on iOS
|
// Use telprompt URL scheme on iOS
|
||||||
|
|
|
@ -10,9 +10,9 @@ import { Button, Title } from "react-native-paper";
|
||||||
import { usePermissionsState, permissionsActions } from "~/stores";
|
import { usePermissionsState, permissionsActions } from "~/stores";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import {
|
import {
|
||||||
requestBatteryOptimizationExemption,
|
RequestDisableOptimization,
|
||||||
isBatteryOptimizationEnabled,
|
BatteryOptEnabled,
|
||||||
} from "~/lib/native/batteryOptimization";
|
} from "react-native-battery-optimization-check";
|
||||||
import openSettings from "~/lib/native/openSettings";
|
import openSettings from "~/lib/native/openSettings";
|
||||||
|
|
||||||
import requestPermissionFcm from "~/permissions/requestPermissionFcm";
|
import requestPermissionFcm from "~/permissions/requestPermissionFcm";
|
||||||
|
@ -26,19 +26,23 @@ import * as Location from "expo-location";
|
||||||
import * as Notifications from "expo-notifications";
|
import * as Notifications from "expo-notifications";
|
||||||
import * as Contacts from "expo-contacts";
|
import * as Contacts from "expo-contacts";
|
||||||
|
|
||||||
|
// Battery optimization request handler
|
||||||
const requestBatteryOptimizationDisable = async () => {
|
const requestBatteryOptimizationDisable = async () => {
|
||||||
if (Platform.OS !== "android") return true;
|
if (Platform.OS !== "android") {
|
||||||
|
return true; // iOS doesn't have battery optimization
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const enabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
if (enabled) {
|
if (isEnabled) {
|
||||||
console.log("Battery optimization enabled, requesting exemption...");
|
console.log("Battery optimization enabled, requesting to disable...");
|
||||||
await requestBatteryOptimizationExemption();
|
RequestDisableOptimization();
|
||||||
// User must interact in Settings; will re-check on AppState 'active'
|
// Return false as the user needs to interact with the system dialog
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
console.log("Battery optimization already disabled");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
console.log("Battery optimization already disabled");
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error handling battery optimization:", error);
|
console.error("Error handling battery optimization:", error);
|
||||||
return false;
|
return false;
|
||||||
|
@ -106,8 +110,8 @@ const checkPermissionStatus = async (permission) => {
|
||||||
return true; // iOS doesn't have battery optimization
|
return true; // iOS doesn't have battery optimization
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const enabled = await isBatteryOptimizationEnabled();
|
const isEnabled = await BatteryOptEnabled();
|
||||||
return !enabled; // true if optimization is disabled
|
return !isEnabled; // Return true if optimization is disabled
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error checking battery optimization:", error);
|
console.error("Error checking battery optimization:", error);
|
||||||
return false;
|
return false;
|
||||||
|
@ -196,33 +200,24 @@ export default function Permissions() {
|
||||||
|
|
||||||
const handleRequestPermission = async (permission) => {
|
const handleRequestPermission = async (permission) => {
|
||||||
try {
|
try {
|
||||||
let granted = false;
|
const granted = await requestPermissions[permission]();
|
||||||
|
setPermissions[permission](granted);
|
||||||
|
|
||||||
if (permission === "locationBackground") {
|
// For battery optimization, we need to handle the async nature differently
|
||||||
// Ensure foreground location is granted first
|
if (
|
||||||
const fgGranted = await checkPermissionStatus("locationForeground");
|
permission === "batteryOptimizationDisabled" &&
|
||||||
if (!fgGranted) {
|
Platform.OS === "android"
|
||||||
const fgReq = await requestPermissionLocationForeground();
|
) {
|
||||||
setPermissions.locationForeground(fgReq);
|
// Give a short delay for the system dialog to potentially complete
|
||||||
if (!fgReq) {
|
setTimeout(async () => {
|
||||||
granted = false;
|
const actualStatus = await checkPermissionStatus(permission);
|
||||||
} else {
|
setPermissions[permission](actualStatus);
|
||||||
granted = await requestPermissionLocationBackground();
|
}, 1000);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
granted = await requestPermissionLocationBackground();
|
|
||||||
}
|
|
||||||
setPermissions.locationBackground(granted);
|
|
||||||
} else {
|
} else {
|
||||||
granted = await requestPermissions[permission]();
|
// Double-check the status to ensure UI is in sync
|
||||||
setPermissions[permission](granted);
|
const actualStatus = await checkPermissionStatus(permission);
|
||||||
|
setPermissions[permission](actualStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double-check the status to ensure UI is in sync.
|
|
||||||
// For battery optimization, this immediate check may still be 'enabled';
|
|
||||||
// we'll re-check again on AppState 'active' after returning from Settings.
|
|
||||||
const actualStatus = await checkPermissionStatus(permission);
|
|
||||||
setPermissions[permission](actualStatus);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error requesting ${permission} permission:`, error);
|
console.error(`Error requesting ${permission} permission:`, error);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue