Apparence-io / CamerAwesome

📸 Embedding a camera experience within your own app shouldn't be that hard. A flutter plugin to integrate awesome Android / iOS camera experience.
https://ApparenceKit.dev
MIT License
906 stars 199 forks source link

Even with enablePhysicalButton set to true, pressing the volume button does not capture the photo. #444

Open danieljiwonkang98 opened 4 months ago

danieljiwonkang98 commented 4 months ago

Issue: Even with enablePhysicalButton set to true, pressing the volume button does not capture the photo.

Steps to Reproduce:

Open the camera screen. Ensure that enablePhysicalButton is set to true. Press the volume button while on the camera screen. Expected Behavior:

Pressing the volume button should trigger photo capture when enablePhysicalButton is set to true.

Actual Behavior:

Pressing the volume button does not capture the photo, regardless of the enablePhysicalButton setting.

Additional Information:

No error messages or logs are displayed when pressing the volume button. Other camera functionalities, such as tapping the capture button, work as expected.

Code for below:

import 'package:app/constants/app_theme.dart';
import 'package:app/constants/images.dart';
import 'package:app/logger.dart';
import 'package:app/screens/home/album_screen.dart';
import 'package:app/services/image_service.dart';
import 'package:app/widgets/circular_capture_button.dart';
import 'package:app/widgets/custom_bottom_navigation_widget.dart';
import 'package:app/widgets/custom_capture_button.dart';
import 'package:app/widgets/flash_animation_widget.dart';
import 'package:app/widgets/media_preview_widget.dart';
import 'package:camerawesome/camerawesome_plugin.dart';
import 'package:camerawesome/pigeon.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';

class CameraScreen extends StatefulWidget {
  const CameraScreen({super.key});

  @override
  CameraScreenState createState() => CameraScreenState();
}

class CameraScreenState extends State<CameraScreen> {
  final imageService = Get.find<ImageService>();
  bool _isButtonActive = true;
  final _isFlashVisible = false.obs;

  void _simulateScreenshotFlash() {
    if (_isFlashVisible.value) return;
    _isFlashVisible.value = true;
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(children: [
      Scaffold(
        extendBodyBehindAppBar: true,
        backgroundColor: Colors.red,
        appBar: PreferredSize(
          preferredSize: const Size.fromHeight(10.0), // here the desired height
          child: AppBar(
            backgroundColor: Colors.black.withOpacity(0.2),
            elevation: 0,
          ),
        ),
        body: Container(
          color: Colors.white,
          child: CameraAwesomeBuilder.awesome(
            enablePhysicalButton: true,
            defaultFilter: AwesomeFilter.Sierra,
            saveConfig: SaveConfig.photoAndVideo(
              // 1.
              initialCaptureMode: CaptureMode.photo,
              // 2.
              // photoPathBuilder: (sensors) async {
              //   // 1.
              //   final Directory extDir = await getTemporaryDirectory();
              //   final testDir =
              //       await Directory('${extDir.path}/camerawesome/photo')
              //           .create(recursive: true);

              //   // 2.
              //   if (sensors.length == 1) {
              //     final String filePath =
              //         '${testDir.path}/photo/${DateTime.now().millisecondsSinceEpoch}.jpg';
              //     // 3.
              //     return SingleCaptureRequest(filePath, sensors.first);
              //   } else {
              //     // 4.
              //     return MultipleCaptureRequest(
              //       {
              //         for (final sensor in sensors)
              //           sensor:
              //               '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg',
              //       },
              //     );
              //   }
              // },
              // // 3.
              // videoPathBuilder: (sensors) async {
              //   // 1.
              //   final Directory extDir = await getTemporaryDirectory();
              //   final testDir =
              //       await Directory('${extDir.path}/camerawesome/video')
              //           .create(recursive: true);

              //   // 2.
              //   if (sensors.length == 1) {
              //     final String filePath =
              //         '${testDir.path}/video/${DateTime.now().millisecondsSinceEpoch}.mp4';
              //     // 3.
              //     return SingleCaptureRequest(filePath, sensors.first);
              //   } else {
              //     // 4.
              //     return MultipleCaptureRequest(
              //       {
              //         for (final sensor in sensors)
              //           sensor:
              //               '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.mp4',
              //       },
              //     );
              //   }
              // },
              // 4.
              // videoOptions: VideoOptions(
              //   enableAudio: true,
              //   ios: CupertinoVideoOptions(
              //     fps: 10,
              //     // TODODOC Add other possble params
              //   ),
              //   android: AndroidVideoOptions(
              //     bitrate: 6000000,
              //     fallbackStrategy: QualityFallbackStrategy.lower,
              //   ),
              // ),
              // 5.
              exifPreferences: ExifPreferences(saveGPSLocation: true),
              // 6.
              mirrorFrontCamera: false,
            ),
            sensorConfig: SensorConfig.single(
                aspectRatio: CameraAspectRatios.ratio_16_9,
                // flashMode: FlashMode.on, Flashmode Not Working ** BUG **
                sensor: Sensor.position(SensorPosition.back),
                zoom: 0),
            previewFit: CameraPreviewFit.fitWidth,
            previewPadding: const EdgeInsets.only(left: 150, top: 100),
            previewAlignment: Alignment.topRight,
            theme: AwesomeTheme(
              bottomActionsBackgroundColor: Colors.black.withOpacity(0.9),
              buttonTheme: AwesomeButtonTheme(
                rotateWithCamera: false,
                backgroundColor: AppColors.primaryBackground.withOpacity(0.5),
                iconSize: 40,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.all(16),
                buttonBuilder: (child, onTap) {
                  return ClipOval(
                    child: Material(
                      color: Colors.transparent,
                      shape: const CircleBorder(),
                      child: InkWell(
                        splashColor: Colors.cyan,
                        highlightColor: Colors.cyan.withOpacity(0.5),
                        onTap: onTap,
                        child: child,
                      ),
                    ),
                  );
                },
              ),
            ),
            topActionsBuilder: (state) {
              return Container(
                color: Colors.black.withOpacity(0.2),
                child: Row(
                  children: [
                    const SizedBox(width: 20),
                    GestureDetector(
                      onTap: () {
                        //TODO
                        throw UnimplementedError();
                      },
                      child: const CircleAvatar(
                        backgroundColor: Colors.black,
                        child: Icon(
                          Icons.person_add,
                          color: Colors.white,
                        ),
                      ),
                    ),
                    const Spacer(),
                    GestureDetector(
                      onTap: () {
                        //TODO
                        throw UnimplementedError();
                      },
                      child: Container(
                        height: 40,
                        decoration: BoxDecoration(
                          color: Colors.black,
                          borderRadius: BorderRadius.circular(50),
                        ),
                        child: const Padding(
                          padding: EdgeInsets.symmetric(horizontal: 12),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              Icon(
                                Icons.search,
                                color: Colors.white,
                              ),
                              SizedBox(width: 4),
                              Text(
                                'Search',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 16,
                                ),
                              ),
                              SizedBox(width: 6),
                            ],
                          ),
                        ),
                      ),
                    ),
                    const Spacer(),
                    GestureDetector(
                      onTap: () {
                        //TODO
                        throw UnimplementedError();
                      },
                      child: const CircleAvatar(
                        backgroundColor: Colors.black,
                        child: Icon(
                          Icons.inbox,
                          color: Colors.white,
                        ),
                      ),
                    ),
                    const SizedBox(width: 20),
                  ],
                ),
              );
            },
            middleContentBuilder: (state) {
              return GestureDetector(
                onTap: () {},
                onDoubleTap: () {
                  AppLogger.logInfo("Double tap");
                  HapticFeedback.lightImpact();
                  state.switchCameraSensor();
                },
                child: Column(
                  children: [
                    Builder(builder: (context) {
                      return Expanded(
                        // This Expanded is fine as it's within a Column
                        child: Stack(
                          children: [
                            Align(
                              alignment: Alignment.center,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Opacity(
                                    opacity: 0.7,
                                    child: Image.asset(
                                      cameraFocusbox,
                                      height: 80,
                                      width: 80,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            Align(
                              alignment: Alignment.center,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Expanded(
                                    child: Container(
                                      color: Colors.black.withOpacity(0.2),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            // This is the section that was previously incorrectly wrapped in an Expanded
                          ],
                        ),
                      );
                    }),
                  ],
                ),
              );
            },
            bottomActionsBuilder: (state) => Column(
              children: [
                Stack(
                  alignment: Alignment.bottomCenter,
                  clipBehavior: Clip.none,
                  children: [
                    const SizedBox(
                      child: CustomBottomNavigationWidget(
                        selectedItem: NavigationItem.camera,
                      ),
                    ),
                    Align(
                      child: IgnorePointer(
                        ignoring: !_isButtonActive,
                        child: CustomCaptureButton(
                          onTapPhoto: () {
                            AppLogger.logInfo("Tap Capture Button");
                            _simulateScreenshotFlash();
                          },
                          onLongPress: () {},
                          onLongPressUp: () {},
                          state: state,
                          photoButtonWidget: const CircularPhotoButton(),
                          videoButtonWidget: const CircularVideoButton(),
                          videoRecordingButtonWidget:
                              const CircularVideoButton(),
                        ),
                      ),
                    ),
                    Column(
                      children: [
                        Row(
                          children: [
                            const SizedBox(width: 40),
                            Padding(
                              padding: const EdgeInsets.only(top: 12),
                              child: SizedBox(
                                child: StreamBuilder<MediaCapture?>(
                                  stream: state.captureState$,
                                  builder: (_, snapshot) {
                                    if (snapshot.data == null) {
                                      return const SizedBox(
                                        height: 70,
                                        width: 70,
                                      );
                                    }
                                    if (snapshot.data!.status ==
                                        MediaCaptureStatus.success) {
                                      AppLogger.logInfo(
                                          "MediaCaptureStatus.success");

                                      imageService
                                          .saveImageToDocumentsDirectory(
                                              snapshot.data!);
                                    }
                                    return SizedBox(
                                      height: 70,
                                      width: 70,
                                      child: MediaPreviewWidget(
                                        mediaCapture: snapshot.data!,
                                        onMediaTap:
                                            (MediaCapture mediaCapture) {
                                          AppLogger.logInfo(
                                              "Moved to albumScreen");
                                          Get.to(
                                            () => const AlbumScreen(),
                                          );
                                        },
                                      ),
                                    );
                                  },
                                ),
                              ),
                            ),
                            const Spacer(),
                            Padding(
                              padding: const EdgeInsets.only(top: 12),
                              child: SizedBox(
                                height: 70,
                                width: 70,
                                child: AwesomeFlashButton(
                                  state: state,
                                  onFlashTap: (p0, p1) {
                                    AppLogger.logInfo("Flash Tap");
                                    p0.switchCameraFlash();
                                  },
                                ),
                              ),
                            ),
                            const SizedBox(width: 40),
                          ],
                        ),
                        const SizedBox(
                          height: 70,
                        )
                      ],
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
      IgnorePointer(
        child: Obx(() => FlashAnimation(
              isVisible: _isFlashVisible.value,
              onAnimationEnd: () => _isFlashVisible.value = false,
            )),
      ),
    ]);
  }
}
danieljiwonkang98 commented 4 months ago

@g-apparence Can you please look over this issue?

eduardo-pellenz commented 3 months ago

Same bug here