Skip to content
Snippets Groups Projects
Commit e83d272b authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Merge branch '51-add-take-and-save-pictures-feature' into 'master'

Resolve "Add "take and save pictures" feature"

Closes #51

See merge request !50
parents 2c5ab76e bb9826e8
No related branches found
No related tags found
1 merge request!50Resolve "Add "take and save pictures" feature"
Pipeline #4946 passed
......@@ -44,7 +44,7 @@ android {
defaultConfig {
applicationId "org.benoitharrault.random"
minSdkVersion 19
minSdkVersion 21
targetSdkVersion 30
versionCode appVersionCode.toInteger()
versionName appVersionName
......
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
app.versionName=1.0.43
app.versionCode=44
app.versionName=1.0.44
app.versionCode=45
......@@ -2,6 +2,7 @@
"app_name": "Sandbox App",
"bottom_nav_sample": "Sample",
"bottom_nav_camera": "Camera",
"bottom_nav_api": "API",
"bottom_nav_chart": "Graph",
"bottom_nav_game": "Game",
......
......@@ -2,6 +2,7 @@
"app_name": "App de test",
"bottom_nav_sample": "Démo",
"bottom_nav_camera": "Caméra",
"bottom_nav_api": "API",
"bottom_nav_chart": "Graph",
"bottom_nav_game": "Jeu",
......
......@@ -3,7 +3,7 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
class BottomNavCubit extends HydratedCubit<int> {
BottomNavCubit() : super(0);
int pagesCount = 5;
int pagesCount = 6;
void updateIndex(int index) {
if (isIndexAllowed(index)) {
......
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:random/ui/widgets/take_picture_widget.dart';
class CameraPage extends StatelessWidget {
const CameraPage({super.key});
static Icon navBarIcon = const Icon(UniconsLine.camera);
static String navBarText = 'bottom_nav_camera';
@override
Widget build(BuildContext context) {
return Material(
color: Theme.of(context).colorScheme.background,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const SizedBox(height: 8),
const TakePictureWidget(),
],
),
);
}
}
......@@ -5,6 +5,7 @@ import 'package:flutter_swipe/flutter_swipe.dart';
import 'package:random/cubit/bottom_nav_cubit.dart';
import 'package:random/ui/screens/about_page.dart';
import 'package:random/ui/screens/api_page.dart';
import 'package:random/ui/screens/camera_page.dart';
import 'package:random/ui/screens/demo_page.dart';
import 'package:random/ui/screens/game_page.dart';
import 'package:random/ui/screens/graph_page.dart';
......@@ -25,6 +26,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
const List<Widget> pageNavigation = <Widget>[
DemoPage(),
ApiPage(),
CameraPage(),
GraphPage(),
GamePage(),
SettingsPage(),
......
......@@ -50,6 +50,10 @@ class BottomNavBar extends StatelessWidget {
icon: const Icon(UniconsLine.globe),
label: tr('bottom_nav_api'),
),
BottomNavigationBarItem(
icon: const Icon(UniconsLine.camera),
label: tr('bottom_nav_camera'),
),
BottomNavigationBarItem(
icon: const Icon(UniconsLine.pen),
label: tr('bottom_nav_chart'),
......
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:random/utils/picture_storage.dart';
class TakePictureWidget extends StatefulWidget {
const TakePictureWidget({super.key});
@override
TakePictureWidgetState createState() => TakePictureWidgetState();
}
class TakePictureWidgetState extends State<TakePictureWidget> {
CameraController? controller;
PictureStorage? storage;
List<String> previousImages = [];
List<String> debug = [];
@override
void initState() {
loadCamera();
storage = PictureStorage();
super.initState();
}
loadCamera() async {
final List<CameraDescription>? cameras = await availableCameras();
if (cameras != null) {
controller = CameraController(
cameras.first,
ResolutionPreset.max,
enableAudio: false,
);
controller!.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
} else {
print("No camera found.");
}
}
@override
void dispose() {
controller!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 400,
child: controller == null
? Center(child: Text("Loading camera..."))
: !controller!.value.isInitialized
? Center(child: CircularProgressIndicator())
: CameraPreview(controller!),
),
ElevatedButton.icon(
label: Text("Take picture"),
icon: Icon(UniconsLine.camera),
onPressed: () async {
try {
if ((controller != null) && (controller!.value.isInitialized)) {
final XFile image = await controller!.takePicture();
print('image.path: ' + image.path);
debug.add('image.path: ' + image.path);
File savedFile = await storage!.writeCounter(File(image.path));
debug.add('image.path: ' + image.path);
String imagePath = savedFile.path;
print('imagePath: ' + imagePath);
debug.add('imagePath: ' + imagePath);
previousImages.add(imagePath);
setState(() {});
}
} catch (e) {
debug.add('error: ' + e.toString());
setState(() {});
print(e);
}
},
),
Text('debug: '),
Column(
children: debug.map((String line) {
return Text(line);
}).toList(),
),
previousImages.length == 0
? Text('no previous images')
: Column(
children: previousImages.map((String imagePath) {
return Row(
children: [
// Image.file(File(imagePath)),
Text(imagePath),
],
);
}).toList(),
),
],
),
);
}
}
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
class PictureStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<String> _localFilePath(String name) async {
final path = await _localPath;
return path + '/' + name;
}
Future<File> moveFile(File sourceFile, String newPath) async {
try {
return await sourceFile.rename(newPath);
} on FileSystemException catch (e) {
print('Found exception while moving file: ' + e.toString());
final newFile = await sourceFile.copy(newPath);
await sourceFile.delete();
return newFile;
}
}
Future<File> writeCounter(File sourceFile) async {
final targetFile = await _localFilePath(basename(sourceFile.path));
return moveFile(sourceFile, targetFile);
}
}
......@@ -25,6 +25,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.2"
camera:
dependency: "direct main"
description:
name: camera
sha256: "9499cbc2e51d8eb0beadc158b288380037618ce4e30c9acbc4fae1ac3ecb5797"
url: "https://pub.dev"
source: hosted
version: "0.10.5+9"
camera_android:
dependency: transitive
description:
name: camera_android
sha256: "351429510121d179b9aac5a2e8cb525c3cd6c39f4d709c5f72dfb21726e52371"
url: "https://pub.dev"
source: hosted
version: "0.10.8+16"
camera_avfoundation:
dependency: transitive
description:
name: camera_avfoundation
sha256: "7d0763dfcbf060f56aa254a68c103210280bee9e97bbe4fdef23e257a4f70ab9"
url: "https://pub.dev"
source: hosted
version: "0.9.14"
camera_platform_interface:
dependency: transitive
description:
name: camera_platform_interface
sha256: e971ebca970f7cfee396f76ef02070b5e441b4aa04942da9c108d725f57bbd32
url: "https://pub.dev"
source: hosted
version: "2.7.2"
camera_web:
dependency: transitive
description:
name: camera_web
sha256: f18ccfb33b2a7c49a52ad5aa3f07330b7422faaecbdfd9b9fe8e51182f6ad67d
url: "https://pub.dev"
source: hosted
version: "0.3.2+4"
characters:
dependency: transitive
description:
......@@ -49,6 +89,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
url: "https://pub.dev"
source: hosted
version: "0.3.3+8"
crypto:
dependency: transitive
description:
......@@ -123,6 +171,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
url: "https://pub.dev"
source: hosted
version: "2.0.17"
flutter_swipe:
dependency: "direct main"
description:
......@@ -365,6 +421,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
......@@ -438,5 +502,5 @@ packages:
source: hosted
version: "1.0.4"
sdks:
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"
dart: ">=3.2.3 <4.0.0"
flutter: ">=3.16.6"
......@@ -3,7 +3,7 @@ description: A random application, for testing purpose only.
publish_to: 'none'
version: 1.0.43+44
version: 1.0.44+45
environment:
sdk: '^3.0.0'
......@@ -12,6 +12,7 @@ dependencies:
flutter:
sdk: flutter
camera: ^0.10.5+8
easy_localization: ^3.0.1
equatable: ^2.0.5
flutter_bloc: ^8.1.1
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment