fix: запрос разрешение на фотку в фото пикере

This commit is contained in:
Jganenokk
2026-08-15 16:23:42 +07:00
parent 70bf0a20c8
commit 27b81af3fc
6 changed files with 61 additions and 8 deletions
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:komet/backend/modules/contacts.dart'; import 'package:komet/backend/modules/contacts.dart';
import 'package:komet/core/config/app_frost.dart'; import 'package:komet/core/config/app_frost.dart';
@@ -882,6 +883,8 @@ class _KeepAlivePageState extends State<_KeepAlivePage>
} }
} }
enum _CameraAccess { unknown, granted, denied }
class _CameraTile extends StatefulWidget { class _CameraTile extends StatefulWidget {
final VoidCallback onTap; final VoidCallback onTap;
final ColorScheme cs; final ColorScheme cs;
@@ -893,30 +896,59 @@ class _CameraTile extends StatefulWidget {
} }
class _CameraTileState extends State<_CameraTile> with WidgetsBindingObserver { class _CameraTileState extends State<_CameraTile> with WidgetsBindingObserver {
static const String _askedKey = 'komet_camera_permission_asked';
CameraController? _controller; CameraController? _controller;
bool _starting = false; bool _starting = false;
_CameraAccess _access = _CameraAccess.unknown;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_maybeStartPreview(); _resolveAccess();
} }
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) { if (state == AppLifecycleState.resumed) {
_maybeStartPreview(); _resolveAccess();
} else if (state == AppLifecycleState.inactive || } else if (state == AppLifecycleState.inactive ||
state == AppLifecycleState.paused) { state == AppLifecycleState.paused) {
_stopPreview(); _stopPreview();
} }
} }
Future<void> _maybeStartPreview() async { Future<void> _resolveAccess() async {
if (_starting || _controller != null) return;
if (!(Platform.isAndroid || Platform.isIOS)) return; if (!(Platform.isAndroid || Platform.isIOS)) return;
if (!await Permission.camera.status.isGranted) return;
var status = await Permission.camera.status;
if (status.isDenied) {
final prefs = await SharedPreferences.getInstance();
if (!(prefs.getBool(_askedKey) ?? false)) {
await prefs.setBool(_askedKey, true);
status = await Permission.camera.request();
}
}
if (!mounted) return;
final granted = status.isGranted;
setState(
() => _access = granted ? _CameraAccess.granted : _CameraAccess.denied,
);
if (granted) _startPreview();
}
void _onTap() {
if (_access == _CameraAccess.denied) {
openAppSettings();
return;
}
widget.onTap();
}
Future<void> _startPreview() async {
if (_starting || _controller != null) return;
_starting = true; _starting = true;
try { try {
final cameras = await availableCameras(); final cameras = await availableCameras();
@@ -962,9 +994,11 @@ class _CameraTileState extends State<_CameraTile> with WidgetsBindingObserver {
final cs = widget.cs; final cs = widget.cs;
final controller = _controller; final controller = _controller;
final hasPreview = controller != null && controller.value.isInitialized; final hasPreview = controller != null && controller.value.isInitialized;
final denied = _access == _CameraAccess.denied;
final l10n = AppLocalizations.of(context)!;
return GestureDetector( return GestureDetector(
onTap: widget.onTap, onTap: _onTap,
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
@@ -997,14 +1031,19 @@ class _CameraTileState extends State<_CameraTile> with WidgetsBindingObserver {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( Icon(
Symbols.photo_camera, denied
? Symbols.no_photography
: Symbols.photo_camera,
size: 34, size: 34,
color: cs.onSurface, color: cs.onSurface,
weight: 400, weight: 400,
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
Text( Text(
AppLocalizations.of(context)!.attachSheetCamera, denied
? l10n.attachSheetCameraAllow
: l10n.attachSheetCamera,
textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: cs.onSurfaceVariant, color: cs.onSurfaceVariant,
fontSize: 12, fontSize: 12,
+1
View File
@@ -977,6 +977,7 @@
"attachSheetSettings": "Settings", "attachSheetSettings": "Settings",
"attachSheetAddCaptionHint": "Add a caption...", "attachSheetAddCaptionHint": "Add a caption...",
"attachSheetCamera": "Camera", "attachSheetCamera": "Camera",
"attachSheetCameraAllow": "Allow camera",
"photoEditorApplyFailed": "Couldn't apply", "photoEditorApplyFailed": "Couldn't apply",
"photoEditorFlipTooltip": "Flip", "photoEditorFlipTooltip": "Flip",
"photoEditorRotateTooltip": "Rotate", "photoEditorRotateTooltip": "Rotate",
+6
View File
@@ -4400,6 +4400,12 @@ abstract class AppLocalizations {
/// **'Camera'** /// **'Camera'**
String get attachSheetCamera; String get attachSheetCamera;
/// No description provided for @attachSheetCameraAllow.
///
/// In en, this message translates to:
/// **'Allow camera'**
String get attachSheetCameraAllow;
/// No description provided for @photoEditorApplyFailed. /// No description provided for @photoEditorApplyFailed.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
+3
View File
@@ -2287,6 +2287,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get attachSheetCamera => 'Camera'; String get attachSheetCamera => 'Camera';
@override
String get attachSheetCameraAllow => 'Allow camera';
@override @override
String get photoEditorApplyFailed => 'Couldn\'t apply'; String get photoEditorApplyFailed => 'Couldn\'t apply';
+3
View File
@@ -2301,6 +2301,9 @@ class AppLocalizationsRu extends AppLocalizations {
@override @override
String get attachSheetCamera => 'Камера'; String get attachSheetCamera => 'Камера';
@override
String get attachSheetCameraAllow => 'Разрешите камеру';
@override @override
String get photoEditorApplyFailed => 'Не удалось применить'; String get photoEditorApplyFailed => 'Не удалось применить';
+1
View File
@@ -742,6 +742,7 @@
"attachSheetSettings": "Настройки", "attachSheetSettings": "Настройки",
"attachSheetAddCaptionHint": "Добавить подпись...", "attachSheetAddCaptionHint": "Добавить подпись...",
"attachSheetCamera": "Камера", "attachSheetCamera": "Камера",
"attachSheetCameraAllow": "Разрешите камеру",
"photoEditorApplyFailed": "Не удалось применить", "photoEditorApplyFailed": "Не удалось применить",
"photoEditorFlipTooltip": "Отразить", "photoEditorFlipTooltip": "Отразить",
"photoEditorRotateTooltip": "Повернуть", "photoEditorRotateTooltip": "Повернуть",