From 5f80c00e50e71e5ffd31e64f0a194b453ae4f889 Mon Sep 17 00:00:00 2001 From: Aline Bonnet Date: Sun, 28 Apr 2024 14:06:33 +0200 Subject: [PATCH 1/5] WIP --- lib/main.dart | 1 + lib/page/capture_page.dart | 112 +++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c8e613d..6961d98 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ library panoramax; +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:camera/camera.dart'; diff --git a/lib/page/capture_page.dart b/lib/page/capture_page.dart index c08e9ce..1979dfa 100644 --- a/lib/page/capture_page.dart +++ b/lib/page/capture_page.dart @@ -15,6 +15,10 @@ class _CapturePageState extends State { bool _isRearCameraSelected = true; final List _imgListCaptured = []; + int _burstDuration = 3; //in seconds + bool _isBurstMode = false; + Timer? _timerBurst; + @override void dispose() { _cameraController.dispose(); @@ -67,6 +71,27 @@ class _CapturePageState extends State { } } + void takeBurstPictures() { + if (_timerBurst != null) { + stopBurstPictures(); + } else { + startBurstPictures(); + } + } + + void stopBurstPictures() { + if (_timerBurst != null) { + _timerBurst!.cancel(); + _timerBurst = null; + } + } + + Future startBurstPictures() async { + _timerBurst = Timer.periodic(Duration(seconds: _burstDuration), (timer) { + takePicture(); + }); + } + void addImageToList(XFile rawImage) { setState(() { _imgListCaptured.add(File(rawImage.path)); @@ -110,7 +135,7 @@ class _CapturePageState extends State { if (widget.cameras?.isEmpty ?? true) { return Scaffold( appBar: AppBar(), - body: Center( + body: Center( child: Text(AppLocalizations.of(context)!.noCameraFoundError), ), ); @@ -127,6 +152,7 @@ class _CapturePageState extends State { children: [ cameraPreview(), captureButton(height, context), + createBurstButtons(), Positioned( bottom: 0, left: 0, @@ -149,12 +175,89 @@ class _CapturePageState extends State { ); } + Widget createBurstButtons() { + return Container( + padding: EdgeInsets.all(100), + height: MediaQuery.of(context).size.height, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + TextButton( + onPressed: () => switchMode(false), + child: Text("Photo".toUpperCase()), + style: _isBurstMode ? notSelectedButton() : selectedButton()), + TextButton( + onPressed: () => switchMode(true), + child: Text("Rafale".toUpperCase()), + style: _isBurstMode ? selectedButton() : notSelectedButton()), + timeButton() + ], + )); + } + + void switchMode(bool isBurstMode) { + if (!isBurstMode) { + stopBurstPictures(); + } + setState(() { + _isBurstMode = isBurstMode; + }); + } + + TextButton timeButton() { + return TextButton( + onPressed: () => (), + child: RichText( + text: TextSpan(children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon(Icons.photo_camera)), + TextSpan(text: "3/s", style: TextStyle(color: Colors.blue)), + ]), + ), + style: selectedTimeButton(),); + } + +ButtonStyle selectedTimeButton() { + return TextButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + foregroundColor: Colors.blue, + backgroundColor: Colors.white); + } + + ButtonStyle selectedButton() { + return TextButton.styleFrom( + //minimumSize: Size(80, 0), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + foregroundColor: Colors.white, + backgroundColor: Colors.blue); + } + + ButtonStyle notSelectedButton() { + return TextButton.styleFrom( + minimumSize: Size(80, 0), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + foregroundColor: Colors.blueGrey, + //backgroundColor: Colors.white, + side: BorderSide(width: 3, color: Colors.blueGrey)); + } + Expanded switchCameraButton(BuildContext context) { return Expanded( child: IconButton( padding: EdgeInsets.zero, iconSize: 30, - icon: Icon(_isRearCameraSelected ? CupertinoIcons.switch_camera : CupertinoIcons.switch_camera_solid, + icon: Icon( + _isRearCameraSelected + ? CupertinoIcons.switch_camera + : CupertinoIcons.switch_camera_solid, color: Colors.white), onPressed: () { setState(() => _isRearCameraSelected = !_isRearCameraSelected); @@ -171,7 +274,8 @@ class _CapturePageState extends State { iconSize: 30, icon: const Icon(Icons.send_outlined, color: Colors.white), onPressed: goToCollectionCreationPage, - tooltip: AppLocalizations.of(context)!.createSequenceWithPicture_tooltip)); + tooltip: AppLocalizations.of(context)! + .createSequenceWithPicture_tooltip)); } Widget imageCart(IconButton cartIcon) { @@ -194,7 +298,7 @@ class _CapturePageState extends State { child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: IconButton( - onPressed: takePicture, + onPressed: _isBurstMode ? takeBurstPictures : takePicture, iconSize: 100, padding: EdgeInsets.zero, constraints: const BoxConstraints(), From 9bdeb468a1f9f7f62e3917d577610750ccd952b7 Mon Sep 17 00:00:00 2001 From: Aline Bonnet Date: Mon, 29 Apr 2024 16:44:51 +0200 Subject: [PATCH 2/5] feat: implement burst mode --- lib/page/capture_page.dart | 71 +++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/lib/page/capture_page.dart b/lib/page/capture_page.dart index 1979dfa..cd2e6f9 100644 --- a/lib/page/capture_page.dart +++ b/lib/page/capture_page.dart @@ -87,6 +87,7 @@ class _CapturePageState extends State { } Future startBurstPictures() async { + takePicture(); _timerBurst = Timer.periodic(Duration(seconds: _burstDuration), (timer) { takePicture(); }); @@ -183,15 +184,26 @@ class _CapturePageState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ - TextButton( - onPressed: () => switchMode(false), - child: Text("Photo".toUpperCase()), - style: _isBurstMode ? notSelectedButton() : selectedButton()), - TextButton( - onPressed: () => switchMode(true), - child: Text("Rafale".toUpperCase()), - style: _isBurstMode ? selectedButton() : notSelectedButton()), - timeButton() + Expanded( + child: + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + TextButton( + onPressed: () => switchMode(false), + child: Text("Photo".toUpperCase()), + style: _isBurstMode ? notSelectedButton() : selectedButton()), + SizedBox(width: 10), + TextButton( + onPressed: () => switchMode(true), + child: Text("Rafale".toUpperCase()), + style: _isBurstMode ? selectedButton() : notSelectedButton()), + ])), + Expanded( + child: + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + timeButton(3), + SizedBox(width: 10), + timeButton(10), + ])) ], )); } @@ -205,21 +217,35 @@ class _CapturePageState extends State { }); } - TextButton timeButton() { + void setDurationBurst(int duration) { + if (_burstDuration != duration) { + stopBurstPictures(); + } + setState(() { + _burstDuration = duration; + }); + } + + TextButton timeButton(int timeInSeconds) { + bool isSelected = timeInSeconds == _burstDuration; + return TextButton( - onPressed: () => (), - child: RichText( - text: TextSpan(children: [ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon(Icons.photo_camera)), - TextSpan(text: "3/s", style: TextStyle(color: Colors.blue)), - ]), + onPressed: () => setDurationBurst(timeInSeconds), + child: Row( + children: [ + Icon(Icons.photo_camera), + SizedBox( + width: 5), // Espacement de 8 points entre l'icône et le texte + Text( + "$timeInSeconds/s", + style: TextStyle(color: isSelected ? Colors.blue : Colors.white), + ), + ], ), - style: selectedTimeButton(),); + style: isSelected ? selectedTimeButton() : notSelectedTimeButton()); } -ButtonStyle selectedTimeButton() { + ButtonStyle selectedTimeButton() { return TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10)), @@ -228,6 +254,11 @@ ButtonStyle selectedTimeButton() { backgroundColor: Colors.white); } + ButtonStyle notSelectedTimeButton() { + return TextButton.styleFrom( + foregroundColor: Colors.white, backgroundColor: Colors.transparent); + } + ButtonStyle selectedButton() { return TextButton.styleFrom( //minimumSize: Size(80, 0), From d63f661bd60d2acb7bf079ba1e6c22a376cd608d Mon Sep 17 00:00:00 2001 From: Aline Bonnet Date: Mon, 13 May 2024 18:24:50 +0200 Subject: [PATCH 3/5] refacto: remove text on capture loader --- lib/page/capture_page.dart | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/lib/page/capture_page.dart b/lib/page/capture_page.dart index 09ef916..56549e9 100644 --- a/lib/page/capture_page.dart +++ b/lib/page/capture_page.dart @@ -432,28 +432,6 @@ class _CapturePageState extends State { ); } - /*Positioned captureButton(double height, BuildContext context) { - return Positioned( - bottom: height, - left: 0, - child: Container( - width: MediaQuery.of(context).size.width, - height: height, - decoration: const BoxDecoration(color: Colors.transparent), - child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded( - child: IconButton( - onPressed: _isBurstMode ? takeBurstPictures : takePicture, - iconSize: 100, - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - icon: const Icon(Icons.circle_outlined, color: Colors.white), - tooltip: AppLocalizations.of(context)!.capture), - ), - ]), - )); - }*/ - Widget galleryButton(BuildContext context) { return Container( height: 60, @@ -488,12 +466,7 @@ class _CapturePageState extends State { child: Loader( message: DefaultTextStyle( style: Theme.of(context).textTheme.bodyLarge!, - child: Text( - AppLocalizations.of(context)!.waitDuringProcessing, - style: const TextStyle( - color: Colors.white, - ), - ), + child: Container(), ), shadowBackground: true, ), From 35e5cbb934ea14fb881e1a28c271c4d142e781ae Mon Sep 17 00:00:00 2001 From: Aline Bonnet Date: Mon, 13 May 2024 18:48:49 +0200 Subject: [PATCH 4/5] refacto: change wording on capture screen --- lib/l10n/app_en.arb | 4 ++-- lib/l10n/app_fr.arb | 4 ++-- lib/page/capture_page.dart | 44 +++++--------------------------------- 3 files changed, 9 insertions(+), 43 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 93a677b..90ab58b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -7,11 +7,11 @@ "loading": "Loading...", "capture": "Take a picture", - "switchCamera": "Switch camera", "createSequenceWithPicture_tooltip": "Create a new sequence with captured pictures", - "waitDuringProcessing": "Processing, please wait...", "noCameraFoundError": "No camera found for this device", "switchCameraRequired": "Turn your phone to start capturing images", + "photo": "Photo", + "sequence": "Sequence", "newSequenceNameField": "Name", "newSequenceNameField_placeholder": "Enter the new sequence name", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index ab828e1..e509a53 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -7,11 +7,11 @@ "loading": "Chargement...", "capture": "Prendre la une photo", - "switchCamera": "Changer de camera", "createSequenceWithPicture_tooltip": "Créer une nouvelle séquence avec les photos prises", - "waitDuringProcessing": "Traitement en cours, veuillez patienter...", "noCameraFoundError": "Pas de caméra trouvée pour cet appareil", "switchCameraRequired": "Tournez votre téléphone pour commencer la capture d'images", + "photo": "Photo", + "sequence": "Sequence", "newSequenceNameField": "Nom", "newSequenceNameField_placeholder": "Saisissez le nom de la nouvelle séquence", diff --git a/lib/page/capture_page.dart b/lib/page/capture_page.dart index 56549e9..d02cc32 100644 --- a/lib/page/capture_page.dart +++ b/lib/page/capture_page.dart @@ -227,21 +227,15 @@ class _CapturePageState extends State { Row(mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () => switchMode(false), - child: Text("Photo".toUpperCase()), + child: Text(AppLocalizations.of(context)!.photo.toUpperCase()), style: _isBurstMode ? notSelectedButton() : selectedButton()), SizedBox(width: 10), TextButton( onPressed: () => switchMode(true), - child: Text("Rafale".toUpperCase()), + child: Text( + AppLocalizations.of(context)!.sequence.toUpperCase()), style: _isBurstMode ? selectedButton() : notSelectedButton()), ])), - Expanded( - child: - Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - timeButton(3), - SizedBox(width: 10), - timeButton(10), - ])) ], )); } @@ -255,34 +249,6 @@ class _CapturePageState extends State { }); } - void setDurationBurst(int duration) { - if (_burstDuration != duration) { - stopBurstPictures(); - } - setState(() { - _burstDuration = duration; - }); - } - - TextButton timeButton(int timeInSeconds) { - bool isSelected = timeInSeconds == _burstDuration; - - return TextButton( - onPressed: () => setDurationBurst(timeInSeconds), - child: Row( - children: [ - Icon(Icons.photo_camera), - SizedBox( - width: 5), // Espacement de 8 points entre l'icône et le texte - Text( - "$timeInSeconds/s", - style: TextStyle(color: isSelected ? Colors.blue : Colors.white), - ), - ], - ), - style: isSelected ? selectedTimeButton() : notSelectedTimeButton()); - } - ButtonStyle selectedTimeButton() { return TextButton.styleFrom( shape: const RoundedRectangleBorder( @@ -313,9 +279,9 @@ class _CapturePageState extends State { shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10)), ), - foregroundColor: Colors.blueGrey, + foregroundColor: Colors.white, //backgroundColor: Colors.white, - side: BorderSide(width: 3, color: Colors.blueGrey)); + side: BorderSide(width: 3, color: Colors.white)); } Widget portraitLayout(BuildContext context) { From 9af9f369e5c8492308683bf17275b43cede84195 Mon Sep 17 00:00:00 2001 From: Aline Bonnet Date: Tue, 14 May 2024 17:01:48 +0200 Subject: [PATCH 5/5] fix: fix color of capture button --- lib/page/capture_page.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/page/capture_page.dart b/lib/page/capture_page.dart index d02cc32..0e7881a 100644 --- a/lib/page/capture_page.dart +++ b/lib/page/capture_page.dart @@ -17,6 +17,7 @@ class _CapturePageState extends State { int _burstDuration = 3; //in seconds bool _isBurstMode = false; + bool _isBurstPlay = false; Timer? _timerBurst; Stream? _positionStream; @@ -100,6 +101,9 @@ class _CapturePageState extends State { } else { startBurstPictures(); } + setState(() { + _isBurstPlay = !_isBurstPlay; + }); } void stopBurstPictures() { @@ -392,7 +396,7 @@ class _CapturePageState extends State { width: 60, decoration: BoxDecoration( shape: BoxShape.circle, - color: (_timerBurst == null) ? Colors.white : Colors.red), + color: _isBurstPlay ? Colors.red : Colors.white), ), tooltip: AppLocalizations.of(context)!.capture), );