Skip to content
This repository has been archived by the owner on Jan 6, 2025. It is now read-only.

Commit

Permalink
feat: init sequence capture, #4
Browse files Browse the repository at this point in the history
  • Loading branch information
luifr10 committed Mar 3, 2024
1 parent 2930cad commit 99dba2f
Show file tree
Hide file tree
Showing 20 changed files with 697 additions and 51 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ samples, guidance on mobile development, and a full API reference.
```shell
docker-compose up -d
```

### Generating translation
```shell
dart run build_runner build
```
5 changes: 5 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:label="panoramax_mobile"
android:name="${applicationName}"
Expand Down
8 changes: 8 additions & 0 deletions lib/component/app_bar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
part of panoramax;

PreferredSizeWidget PanoramaxAppBar({context, title = "Panoramax"}) {
return AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
);
}
6 changes: 5 additions & 1 deletion lib/component/collection_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ class CollectionPreview extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
DATE_FORMATTER.format(DateTime.parse(collection.updated)),
DATE_FORMATTER.format(DateTime.parse(
collection.updated != null ?
collection.updated! :
collection.created
)),
style: GoogleFonts.nunito(
fontSize: 14,
color: Colors.grey[500],
Expand Down
7 changes: 5 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"yourCollection": "Your collections",
"newSequenceNameField": "Name",
"newSequenceNameField_placeholder": "Enter the new sequence name",
"newSequenceSendButton": "Send",
"yourSequence": "Your sequences",
"element": "element(s)",
"createCollection_tooltip": "Create a new collection"
"createSequence_tooltip": "Create a new sequence"
}
9 changes: 6 additions & 3 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"yourCollection": "Vos Collections",
"element": "element(s)",
"createCollection_tooltip": "Créer une nouvelle collection"
"newSequenceNameField": "Nom",
"newSequenceNameField_placeholder": "Saisissez le nom de la nouvelle séquence",
"newSequenceSendButton": "Envoyer",
"yourSequence": "Vos séquences",
"element": "élément(s)",
"createSequence_tooltip": "Créer une nouvelle séquence"
}
35 changes: 17 additions & 18 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
library panoramax;

import 'dart:io';
import 'package:flutter/material.dart';
import '../service/api/api.dart';
import 'package:camera/camera.dart';
import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_exif_plugin/flutter_exif_plugin.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:panoramax_mobile/service/api/model/geo_visio.dart';
import 'package:intl/intl.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'dart:ui';
import 'package:badges/badges.dart' as badges;
import 'package:permission_handler/permission_handler.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:loading_btn/loading_btn.dart';

import '../service/api/api.dart';

part 'component/app_bar.dart';
part 'component/collection_preview.dart';
part 'page/homepage.dart';
part 'page/capture_page.dart';
part 'page/collection_creation_page.dart';


final DateFormat DATE_FORMATTER = DateFormat.yMd();
Expand All @@ -21,27 +36,11 @@ void main() {
class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Panoramax',
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "flutter run". You'll see
// the application has a purple toolbar. Then, without quitting the app,
// try changing the seedColor in the colorScheme below to Colors.green
// and then invoke "hot reload" (save your changes or press the "hot
// reload" button in a Flutter-supported IDE, or press "r" if you used
// the command line to start the app).
//
// Notice that the counter didn't reset back to zero; the application
// state is not lost during the reload. To reset the state, use hot
// restart instead.
//
// This works for code too, not just values: Most code changes can be
// tested with just a hot reload.
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
Expand All @@ -55,7 +54,7 @@ class MyApp extends StatelessWidget {
Locale('en'),
Locale('fr'),
],
home: const HomePage(title: 'Panoramax'),
home: const HomePage(),
);
}
}
Expand Down
184 changes: 184 additions & 0 deletions lib/page/capture_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
part of panoramax;

class CapturePage extends StatefulWidget {
const CapturePage({Key? key, required this.cameras}) : super(key: key);

final List<CameraDescription>? cameras;

@override
State<CapturePage> createState() => _CapturePageState();
}

class _CapturePageState extends State<CapturePage> {
late CameraController _cameraController;
bool _isRearCameraSelected = true;
List<File> _imgListCaptured = [];

@override
void dispose() {
_cameraController.dispose();
super.dispose();
}

@override
void initState() {
super.initState();
initCamera(widget.cameras![0]);
}

Future goToCollectionCreationPage(){
return Navigator.push(context,
MaterialPageRoute(builder: (_) => CollectionCreationPage(imgList: _imgListCaptured))
);
}

Future takePicture() async {
if (!_cameraController.value.isInitialized) {
return null;
}
if (_cameraController.value.isTakingPicture) {
return null;
}
try {
await _cameraController.setFlashMode(FlashMode.off);
final XFile rawImage = await _cameraController.takePicture();
debugPrint(rawImage.path);
File imageFile = File(rawImage.path);

int currentUnix = DateTime.now().millisecondsSinceEpoch;
String fileFormat = imageFile.path.split('.').last;

bool storagePermission = await Permission.storage.isGranted;
bool mediaPermission = await Permission.accessMediaLocation.isGranted;
bool manageExternalStoragePermission = await Permission.manageExternalStorage.isGranted;
bool locationPermission = await Permission.location.isGranted;

if (!storagePermission) {
storagePermission = await Permission.storage.request().isGranted;
}

if (!mediaPermission) {
mediaPermission =
await Permission.accessMediaLocation.request().isGranted;
}

if (!manageExternalStoragePermission) {
manageExternalStoragePermission = (await Permission.manageExternalStorage.request()).isGranted;
}

if (!locationPermission) {
locationPermission = (await Permission.location.request()).isGranted;
}

bool isPermissionGranted = storagePermission && mediaPermission && manageExternalStoragePermission;

if (isPermissionGranted) {
final exif = FlutterExif.fromPath(rawImage.path);
final currentLocation = await Geolocator.getCurrentPosition();
await exif.setLatLong(currentLocation.latitude, currentLocation.longitude);
await exif.setAltitude(currentLocation.altitude);
await exif.saveAttributes();
setState(() {
_imgListCaptured.add(new File(rawImage.path));
});
} else {
throw Exception("No permission to move file");
}
} on CameraException catch (e) {
debugPrint('Error occured while taking picture: $e');
return null;
}
}

Future initCamera(CameraDescription cameraDescription) async {
_cameraController =
CameraController(cameraDescription, ResolutionPreset.high);
try {
await _cameraController.initialize().then((_) {
if (!mounted) return;
setState(() {});
});
} on CameraException catch (e) {
debugPrint("camera error $e");
}
}

@override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height * 0.12;
var cartIcon = IconButton(
onPressed: () {
},
iconSize: 30,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
icon: const Icon(Icons.add_shopping_cart_outlined, color: Colors.white),
);
return Stack(
children: [
(_cameraController.value.isInitialized)
? CameraPreview(_cameraController)
: Container(
color: Colors.transparent,
child: const Center(child: CircularProgressIndicator())),
new Positioned(
bottom: height,
left: 0,
child: new Container(
width: MediaQuery.of(context).size.width,
height: height,
decoration: new BoxDecoration(color: Colors.transparent),
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Expanded(
child: IconButton(
onPressed: takePicture,
iconSize: 100,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
icon: const Icon(Icons.circle_outlined, color: Colors.white),
)),
]),
)
),
new Positioned(
bottom: 0,
left: 0,
child: new Container(
width: MediaQuery.of(context).size.width,
height: height,
decoration: new BoxDecoration(color: Colors.black),
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Expanded(
child: IconButton(
padding: EdgeInsets.zero,
iconSize: 30,
icon: Icon(
_isRearCameraSelected
? CupertinoIcons.switch_camera
: CupertinoIcons.switch_camera_solid,
color: Colors.white),
onPressed: () {
setState(
() => _isRearCameraSelected = !_isRearCameraSelected);
initCamera(widget.cameras![_isRearCameraSelected ? 0 : 1]);
},
)),
_imgListCaptured.length > 0 ? badges.Badge(
badgeContent: Text('${_imgListCaptured.length}'),
child: cartIcon,
): cartIcon,
Expanded(
child: IconButton(
padding: EdgeInsets.zero,
iconSize: 30,
icon: Icon(Icons.send_outlined,
color: Colors.white),
onPressed: goToCollectionCreationPage,
)),
]),
)
)
]
);
}
}
Loading

0 comments on commit 99dba2f

Please sign in to comment.