Fix camera permission flow on iOS - 17 Apr 2026
This commit is contained in:
parent
d1b4fb344e
commit
ece167ea75
@ -45,14 +45,19 @@ class ImagePickerHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var status = await permission.status;
|
var status = await permission.status;
|
||||||
if (status.isGranted || status.isLimited) return true;
|
|
||||||
|
|
||||||
// On iOS, if already denied, request() won't show anything.
|
// ⭐ Match Live Chat behavior: On iOS, don't force a manual request if already denied
|
||||||
// On Android, permanently denied also won't show anything.
|
// Let ImagePicker handle it, or only show settings dialog if permanently denied.
|
||||||
if (status.isPermanentlyDenied || (Platform.isIOS && status.isDenied)) {
|
if (Platform.isIOS) {
|
||||||
|
if (status.isPermanentlyDenied) {
|
||||||
await _showSettingsDialog(context, name);
|
await _showSettingsDialog(context, name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true; // Return true to let ImagePicker try to open and trigger system prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android behavior
|
||||||
|
if (status.isGranted || status.isLimited) return true;
|
||||||
|
|
||||||
// Now request permission
|
// Now request permission
|
||||||
status = await permission.request();
|
status = await permission.request();
|
||||||
@ -60,8 +65,10 @@ class ImagePickerHelper {
|
|||||||
if (status.isGranted || status.isLimited) {
|
if (status.isGranted || status.isLimited) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// If user denied it just now, or it was already denied (iOS)
|
// Only show settings dialog if permanently denied on Android
|
||||||
|
if (status.isPermanentlyDenied) {
|
||||||
await _showSettingsDialog(context, name);
|
await _showSettingsDialog(context, name);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -72,7 +72,10 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
msg,
|
msg,
|
||||||
style: AppTextStyles.regular.copyWith(color: Colors.white, fontSize: 12),
|
style: AppTextStyles.regular.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
@ -251,18 +254,31 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
|
|||||||
|
|
||||||
var status = await permission.status;
|
var status = await permission.status;
|
||||||
|
|
||||||
print("status $status");
|
// ⭐ Match Live Chat behavior: On iOS, don't force a manual request if already denied
|
||||||
|
// Let ImagePicker handle it, or only show settings dialog if permanently denied.
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
if (status.isPermanentlyDenied) {
|
||||||
|
await _showSettingsDialog(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // Return true to let ImagePicker try to open and trigger system prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android behavior
|
||||||
|
if (status.isGranted || status.isLimited) return true;
|
||||||
|
|
||||||
status = await permission.request();
|
status = await permission.request();
|
||||||
if (status.isGranted || status.isLimited) return true;
|
if (status.isGranted || status.isLimited) return true;
|
||||||
if (status.isPermanentlyDenied || (Platform.isIOS && status.isDenied)) {
|
|
||||||
|
if (status.isPermanentlyDenied) {
|
||||||
await _showSettingsDialog(name);
|
await _showSettingsDialog(name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _showSettingsDialog(name);
|
|
||||||
return false;
|
return false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("Permission error: $e");
|
debugPrint("❌ Permission error: $e");
|
||||||
|
// Fallback to let the picker try on iOS, or return false on Android
|
||||||
return Platform.isIOS;
|
return Platform.isIOS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,10 +627,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
border: Border.all(
|
border: Border.all(color: const Color(0xFFDFDFDF), width: 1),
|
||||||
color: const Color(0xFFDFDFDF),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 21),
|
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 21),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
36
pubspec.lock
36
pubspec.lock
@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
|
sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "85.0.0"
|
version: "93.0.0"
|
||||||
_flutterfire_internals:
|
_flutterfire_internals:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -21,10 +21,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d"
|
sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.7.1"
|
version: "10.0.1"
|
||||||
animated_notch_bottom_bar:
|
animated_notch_bottom_bar:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -101,10 +101,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.1"
|
||||||
checked_yaml:
|
checked_yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -716,26 +716,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.17"
|
version: "0.12.18"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.1"
|
version: "0.13.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.17.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1121,26 +1121,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb"
|
sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.26.2"
|
version: "1.29.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.6"
|
version: "0.7.9"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a"
|
sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.11"
|
version: "0.6.15"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user