I am creating an app like snapchat where the app start with camera page and before this it ask user for camera and microphone permission if the user grant both permission then the camera widget will be displayed other wise instead of camera widget center text button is being displayed that open the app settings
Now the issue is if the user grant the permission and i navigate to other tabs or close and re-open the app i saw the text button instead of camera for like very short interval of micro-seconds I don't want this behavior if the permission is granted just show camera page at once if not granted then show the center text button
Anyone can tell me how to solve this:
Here is my CameraPreview class code:
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
class CameraaPreview extends StatefulWidget {
final List<CameraDescription> cameras;
const CameraaPreview(
{super.key, required this.cameras, required this.permissionStatus});
final bool permissionStatus;
@override
State<CameraaPreview> createState() => _CameraaPreviewState();
}
class _CameraaPreviewState extends State<CameraaPreview> {
late CameraController _cameraController;
Future<void>? _intializeFutureController;
XFile? image;
bool havePic = false;
bool haveVide = false;
bool _isRecording = false;
late Timer _timer;
bool isBackCameraOpen = true;
int _recordedSeconds = 0;
bool _permissionsGranted = false;
@override
void initState() {
super.initState();
requestCameraAndMicrophonePermissions().then((granted) {
if (granted) {
setState(() {
_permissionsGranted = true;
_cameraController = CameraController(
widget.cameras[0], ResolutionPreset.max,
imageFormatGroup: ImageFormatGroup.bgra8888);
_intializeFutureController = _cameraController.initialize();
});
}
});
}
@override
void dispose() {
_cameraController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final Size height = MediaQuery.of(context).size;
const double navBarHeight = kBottomNavigationBarHeight;
final avatarSize = height.width * 0.0999;
final avataPostion = (navBarHeight - avatarSize) / 0.35;
if (!_permissionsGranted) {
return Center(
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.transparent),
onPressed: () {
openAppSettings();
},
child: const Text(
'Grant Permissions for Camera and Microphone to continue',
style: TextStyle(
color: Colors.black,
),
),
),
);
}
if (_permissionsGranted) {
_permissionsGranted = true;
_cameraController = CameraController(
widget.cameras[0], ResolutionPreset.max,
imageFormatGroup: ImageFormatGroup.bgra8888);
_intializeFutureController = _cameraController.initialize();
}
return havePic
? _showImage(image)
: RepaintBoundary(
child: FutureBuilder(
future: _intializeFutureController,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(
color: Colors.yellow,
),
);
} else if (snapshot.hasError) {
return Center(
child: Text('Error: ${snapshot.error}'),
);
} else {
return Stack(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: AspectRatio(
aspectRatio: _cameraController.value.aspectRatio,
child: CameraPreview(
_cameraController,
),
),
),
Positioned(
bottom: avataPostion,
left: height.width / 2.25 - avatarSize / 2,
child: GestureDetector(
onLongPressStart: (_) => _startRecording(),
onLongPressEnd: (_) => _stopRecording(),
onTap: () => _clickPrecture(),
child: CircleAvatar(
radius: avatarSize,
backgroundColor: Colors.transparent,
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.white, width: 4),
borderRadius:
BorderRadius.circular(avatarSize)),
),
),
),
),
Positioned(
top: 40,
left: height.width / 1.18,
child: GestureDetector(
onLongPressStart: (_) {
_startRecording();
},
onLongPressEnd: (_) {
_stopRecording();
},
child: IconButton(
onPressed: () {
setState(() {
isBackCameraOpen
? _openFrontCam()
: _openBackCam();
});
},
icon: const Icon(
Icons.crop_rotate,
color: Colors.white,
),
),
),
),
if (_isRecording)
Positioned(
top: 20,
left: height.width / 2.25,
child: Text(
'$_recordedSeconds s',
style: const TextStyle(
color: Colors.red,
fontSize: 24,
),
),
),
],
);
}
},
),
);
}
Future<bool> requestCameraAndMicrophonePermissions() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.camera,
Permission.microphone,
].request();
return (statuses[Permission.camera] == PermissionStatus.granted &&
statuses[Permission.microphone] == PermissionStatus.granted);
}
void _clickPrecture() async {
if (_cameraController.value.isInitialized) {
image = await _cameraController.takePicture();
setState(() {
havePic = !havePic;
});
}
}
void _startRecording() async {
if (_cameraController.value.isInitialized) {
_cameraController.startVideoRecording();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
_recordedSeconds += 1;
});
});
setState(() {
_isRecording = true;
});
}
}
void _stopRecording() async {
if (_cameraController.value.isRecordingVideo) {
_timer.cancel();
_recordedSeconds = 0;
XFile videoFile = await _cameraController.stopVideoRecording();
setState(() {
_isRecording = false;
});
}
}
void _openFrontCam() {
_cameraController = CameraController(
widget.cameras[1], ResolutionPreset.max,
imageFormatGroup: ImageFormatGroup.bgra8888);
_intializeFutureController = _cameraController.initialize();
isBackCameraOpen = !isBackCameraOpen;
}
void _openBackCam() {
_cameraController = CameraController(
widget.cameras[0], ResolutionPreset.max,
imageFormatGroup: ImageFormatGroup.bgra8888);
_intializeFutureController = _cameraController.initialize();
isBackCameraOpen = !isBackCameraOpen;
}
_showImage(XFile? image) {
return Stack(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Image.file(
File(image!.path),
fit: BoxFit.cover,
),
),
],
);
}
}
here is my homePage class Code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:ssnnaappcchhaatt/ios_screens/camera_preview.dart';
import 'package:ssnnaappcchhaatt/ios_screens/chat_page.dart';
import 'package:ssnnaappcchhaatt/ios_screens/map_page.dart';
import 'package:ssnnaappcchhaatt/ios_screens/play_page.dart';
import 'package:ssnnaappcchhaatt/ios_screens/search_page.dart';
import 'package:ssnnaappcchhaatt/ios_screens/stories_page.dart';
class HomePage extends StatefulWidget {
final List<CameraDescription> cameras;
final bool permissionStatus;
static const homePage = 'homePage/';
const HomePage(
{super.key, required this.cameras, required this.permissionStatus});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int currentIndex = 2;
bool cameraShow = true;
@override
Widget build(BuildContext context) {
final screens = [
const MapPage(),
const ChatPage(),
!cameraShow
? const SearchPage()
: CameraaPreview(
cameras: widget.cameras,
permissionStatus: widget.permissionStatus,
),
const StoriesPage(),
const PlayPage()
];
return Scaffold(
backgroundColor: const Color.fromARGB(255, 169, 154, 154),
body: screens[currentIndex],
bottomNavigationBar: BottomNavigationBar(
items: [
const BottomNavigationBarItem(
label: "Map",
icon: Icon(
CupertinoIcons.map_pin,
size: 24,
),
),
const BottomNavigationBarItem(
label: "Chat",
icon: Icon(
CupertinoIcons.chat_bubble,
size: 24,
),
),
BottomNavigationBarItem(
label: !cameraShow ? "Camera" : "Search",
icon: !cameraShow
? GestureDetector(
onTap: () => {
Navigator.of(context)
.pushReplacementNamed(HomePage.homePage)
},
child: const Icon(
CupertinoIcons.camera,
size: 24,
),
)
: const Icon(
CupertinoIcons.search,
size: 24,
),
),
const BottomNavigationBarItem(
label: "Stories",
icon: Icon(
CupertinoIcons.group,
size: 30,
),
),
const BottomNavigationBarItem(
label: "play",
icon: Icon(
CupertinoIcons.play,
size: 24,
),
)
],
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
backgroundColor: Colors.transparent,
unselectedItemColor: Colors.black,
selectedItemColor: Colors.blue,
currentIndex: currentIndex,
onTap: (value) {
if (value == 2 || currentIndex == 2) {
setState(() {
currentIndex = value;
cameraShow = !cameraShow;
});
} else {
setState(() {
currentIndex = value;
});
}
}),
);
}
}
here is my main class code:
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:ssnnaappcchhaatt/ios_screens/home_page.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final cameras = await availableCameras();
runApp(MyApp(
cameras: cameras,
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key, required this.cameras});
final List<CameraDescription> cameras;
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Snap Chat',
debugShowCheckedModeBanner: false,
home: HomePage(
cameras: cameras,
permissionStatus: false,
),
routes: {
HomePage.homePage: (context) => HomePage(
cameras: cameras,
permissionStatus: false,
),
},
);
}
}