Adds flight,battery models and image file managment
This commit is contained in:
@ -3,10 +3,13 @@ import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:rtime/models/battery.dart';
|
||||
import 'package:rtime/models/flight.dart';
|
||||
import '../models/drone.dart';
|
||||
|
||||
|
||||
import 'package:path_provider/path_provider.dart';import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class DbHelper
|
||||
{
|
||||
@ -47,15 +50,42 @@ class DbHelper
|
||||
CREATE TABLE drones(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
image TEXT
|
||||
image_uuid TEXT
|
||||
)
|
||||
''');
|
||||
|
||||
await db.execute('''
|
||||
CREATE TABLE batteries(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
volatege REAL NOT NULL,
|
||||
image_uuid TEXT
|
||||
)
|
||||
''');
|
||||
|
||||
await db.execute('''
|
||||
CREATE TABLE flights(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
start_timestamp INTEGER NOT NULL,
|
||||
end_timestamp INTEGER NOT NULL,
|
||||
drone_id INTEGER NOT NULL,
|
||||
battery_id INTEGER NOT NULL,
|
||||
location_lat REAL,
|
||||
location_long REAL,
|
||||
FOREIGN KEY(drone_id) REFERENCES drones(id),
|
||||
FOREIGN KEY(battery_id) REFERENCES batteries(id)
|
||||
)
|
||||
''');
|
||||
}
|
||||
|
||||
Future<int> insertDrone(Drone drone) async
|
||||
// Drone related helpers
|
||||
Future<Drone> insertDrone(Drone drone) async
|
||||
{
|
||||
final db = await database;
|
||||
return await db.insert("drones", drone.toMap());
|
||||
drone.id = await db.insert("drones", drone.toMap());
|
||||
return drone;
|
||||
}
|
||||
|
||||
Future<List<Drone>> getDrones() async
|
||||
@ -65,10 +95,54 @@ class DbHelper
|
||||
return maps.map((e) => Drone.fromMap(e)).toList();
|
||||
}
|
||||
|
||||
Future<int> deleteItem(int drone_id) async
|
||||
Future<int> deleteDrone(int droneId) async
|
||||
{
|
||||
// TODO: Delete image
|
||||
final db = await database;
|
||||
return await db.delete("drones", where: "id = ?", whereArgs: [droneId]);
|
||||
}
|
||||
|
||||
// Battery related helpers
|
||||
Future<Battery> insertBattery(Battery battery) async
|
||||
{
|
||||
final db = await database;
|
||||
return await db.delete("drones", where: "id = ?", whereArgs: [drone_id]);
|
||||
battery.id = await db.insert("batteries", battery.toMap());
|
||||
return battery;
|
||||
}
|
||||
|
||||
Future<List<Battery>> getBatteries() async
|
||||
{
|
||||
final db = await database;
|
||||
final maps = await db.query("batteries");
|
||||
return maps.map((e) => Battery.fromMap(e)).toList();
|
||||
}
|
||||
|
||||
Future<int> deleteBattery(int batteryId) async
|
||||
{
|
||||
// TODO: Delete image
|
||||
final db = await database;
|
||||
return await db.delete("batteries", where: "id = ?", whereArgs: [batteryId]);
|
||||
}
|
||||
|
||||
// Flight related helpers
|
||||
Future<Flight> insertFlight(Flight flight) async
|
||||
{
|
||||
final db = await database;
|
||||
flight.id = await db.insert("flights", flight.toMap());
|
||||
return flight;
|
||||
}
|
||||
|
||||
Future<List<Flight>> getFlights() async
|
||||
{
|
||||
final db = await database;
|
||||
final maps = await db.query("flights");
|
||||
return maps.map((e) => Flight.fromMap(e)).toList();
|
||||
}
|
||||
|
||||
Future<int> deleteFlight(int flightId) async
|
||||
{
|
||||
final db = await database;
|
||||
return await db.delete("flights", where: "id = ?", whereArgs: [flightId]);
|
||||
}
|
||||
|
||||
Future closeDb() async
|
||||
|
||||
79
lib/images_manager.dart
Normal file
79
lib/images_manager.dart
Normal file
@ -0,0 +1,79 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:uuid/v5.dart';
|
||||
|
||||
class ImagesManager
|
||||
{
|
||||
static final ImagesManager instance = ImagesManager._internal();
|
||||
ImagesManager._internal();
|
||||
|
||||
static final Logger log = Logger("ImagesManager");
|
||||
|
||||
static Uri? _imagesDirectory;
|
||||
|
||||
Future<Uri> get imageDirectory async
|
||||
{
|
||||
if(_imagesDirectory != null) return _imagesDirectory!;
|
||||
await _initImagesDirectory();
|
||||
return _imagesDirectory!;
|
||||
}
|
||||
|
||||
Future _initImagesDirectory() async
|
||||
{
|
||||
final directoryLoc = await getApplicationDocumentsDirectory();
|
||||
final directoryName = "images";
|
||||
final directoryPath = path.join(directoryLoc.path, directoryName);
|
||||
final directoryUri = Uri.directory(directoryPath);
|
||||
final directory = Directory.fromUri(directoryUri);
|
||||
|
||||
if(!await directory.exists())
|
||||
{
|
||||
log.info("Image directory does not yet extists. Creating it.");
|
||||
}
|
||||
|
||||
directory.create(recursive: false);
|
||||
|
||||
log.info("Image directory set up at '$directory'");
|
||||
|
||||
_imagesDirectory = directoryUri;
|
||||
}
|
||||
|
||||
Future<String?> createImage(ImageSource source) async
|
||||
{
|
||||
// Get image from camera or not
|
||||
final XFile? ximage = await ImagePicker().pickImage(source: source);
|
||||
if(ximage == null) return null;
|
||||
|
||||
final uuid = Uuid().v6();
|
||||
final imageDir = await imageDirectory;
|
||||
ximage.saveTo(path.join(imageDir.path, uuid + path.extension(ximage.name)));
|
||||
return uuid;
|
||||
}
|
||||
|
||||
Future<Image?> loadImage(String imageUuid) async
|
||||
{
|
||||
final imageDir = await imageDirectory;
|
||||
if(!Uuid.isValidUUID(fromString: imageUuid))
|
||||
{
|
||||
log.warning("Tried to load an image with an invalid UUID : '$imageUuid'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
final imagePath = path.join(imageDir.path, "$imageUuid.jpg");
|
||||
final file = File(imagePath);
|
||||
if(!await file.exists())
|
||||
{
|
||||
log.warning("Tried to load an image that does not extist: '$imagePath'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return Image.file(file);
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,14 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:rtime/db/db_helper.dart';
|
||||
import 'package:rtime/images_manager.dart';
|
||||
import 'package:rtime/models/drone.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
||||
|
||||
void main() {
|
||||
if(Platform.isWindows || Platform.isLinux)
|
||||
@ -74,7 +78,16 @@ class MyHomePage extends StatefulWidget {
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
Future _incrementCounter() async {
|
||||
|
||||
DbHelper.instance.insertDrone(Drone
|
||||
(
|
||||
name: "Image test",
|
||||
imageUuid: await ImagesManager.instance.createImage(ImageSource.camera)
|
||||
));
|
||||
|
||||
|
||||
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
@ -82,7 +95,6 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
DbHelper.instance.insertDrone(Drone(name: "skibidi drone"));
|
||||
});
|
||||
}
|
||||
|
||||
@ -94,6 +106,43 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
var children =
|
||||
<Widget>[
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: Future<Widget>(() async
|
||||
{
|
||||
final drones = await DbHelper.instance.getDrones();
|
||||
|
||||
if(drones.isEmpty)
|
||||
{
|
||||
return Icon(Icons.question_mark);
|
||||
}
|
||||
|
||||
final image = await ImagesManager.instance.loadImage(drones.first.imageUuid!);
|
||||
if(image == null)
|
||||
{
|
||||
return Icon(Icons.error);
|
||||
}
|
||||
|
||||
return image;
|
||||
}),
|
||||
builder: (BuildContext ctx, AsyncSnapshot<Widget> img)
|
||||
{
|
||||
if(!img.hasData)
|
||||
{
|
||||
return Center(child: CircularProgressIndicator(),);
|
||||
}
|
||||
|
||||
return img.data!;
|
||||
}
|
||||
),
|
||||
Icon(Icons.build)];
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
@ -122,14 +171,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
@ -139,3 +182,4 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
lib/models/battery.dart
Normal file
33
lib/models/battery.dart
Normal file
@ -0,0 +1,33 @@
|
||||
class Battery {
|
||||
int? id;
|
||||
String name;
|
||||
String type;
|
||||
double voltage;
|
||||
String? imageUuid;
|
||||
|
||||
Battery({
|
||||
this.id,
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.voltage,
|
||||
this.imageUuid,
|
||||
});
|
||||
|
||||
factory Battery.fromMap(Map<String, dynamic> map) => Battery(
|
||||
id: map["id"],
|
||||
name: map["name"],
|
||||
type: map["type"],
|
||||
voltage: map["voltage"],
|
||||
imageUuid: map["image_uuid"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"type": type,
|
||||
"voltage": voltage,
|
||||
"image_uuid": imageUuid,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,24 +1,14 @@
|
||||
import 'package:image/image.dart' as img;
|
||||
class Drone {
|
||||
int? id;
|
||||
String name;
|
||||
String? imageUuid;
|
||||
|
||||
class Drone
|
||||
{
|
||||
final int? id;
|
||||
final String name;
|
||||
//final img.Image image;
|
||||
Drone({this.id, required this.name, this.imageUuid});
|
||||
|
||||
Drone ({this.id, required this.name}); //required this.image});
|
||||
factory Drone.fromMap(Map<String, dynamic> map) =>
|
||||
Drone(id: map["id"], name: map["name"], imageUuid: map["image_uuid"]);
|
||||
|
||||
factory Drone.fromMap(Map<String, dynamic> map) => Drone
|
||||
(
|
||||
id: map["id"],
|
||||
name: map["name"],
|
||||
//image: img.decodeJpg(map["image"])!,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() =>
|
||||
{
|
||||
"id": id,
|
||||
"name": name,
|
||||
//"image": img.encodeJpg(image),
|
||||
};
|
||||
Map<String, dynamic> toMap() {
|
||||
return {"id": id, "name": name, "image_uuid": imageUuid};
|
||||
}
|
||||
}
|
||||
|
||||
51
lib/models/flight.dart
Normal file
51
lib/models/flight.dart
Normal file
@ -0,0 +1,51 @@
|
||||
class Flight {
|
||||
int? id;
|
||||
String name;
|
||||
|
||||
// Timestamp in seconds since epoch
|
||||
int startTimestamp;
|
||||
int endTimestamp;
|
||||
|
||||
// Foreign keys
|
||||
int droneId;
|
||||
int batteryId;
|
||||
|
||||
// Location
|
||||
double? locationLat;
|
||||
double? locationLong;
|
||||
|
||||
Flight({
|
||||
this.id,
|
||||
required this.name,
|
||||
required this.startTimestamp,
|
||||
required this.endTimestamp,
|
||||
required this.droneId,
|
||||
required this.batteryId,
|
||||
this.locationLat,
|
||||
this.locationLong,
|
||||
});
|
||||
|
||||
factory Flight.fromMap(Map<String, dynamic> map) => Flight(
|
||||
id: map["id"],
|
||||
name: map["name"],
|
||||
startTimestamp: map["start_timestamp"],
|
||||
endTimestamp: map["end_timestamp"],
|
||||
droneId: map["drone_id"],
|
||||
batteryId: map["batteryId"],
|
||||
locationLat: map["location_lat"],
|
||||
locationLong: map["location_long"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"start_timestamp": startTimestamp,
|
||||
"end_timestamp": endTimestamp,
|
||||
"drone_id": droneId,
|
||||
"battery_id": batteryId,
|
||||
"location_lat": locationLat,
|
||||
"location_long": locationLong,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user