Compare commits

...

9 Commits

24 changed files with 979 additions and 206 deletions

View File

@ -6,7 +6,7 @@ plugins {
}
android {
namespace = "com.example.rtime"
namespace = "fr.chaboissier.rtime"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.rtime"
applicationId = "fr.chaboissier.rtime"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion

View File

@ -3,6 +3,10 @@
android:label="rtime"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Ucrop.CropTheme"/>
<activity
android:name=".MainActivity"
android:exported="true"
@ -42,4 +46,7 @@
<data android:mimeType="text/plain"/>
</intent>
</queries>
<!-- GPS Location permission to be able to locate flights. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
</manifest>

View File

@ -1,4 +1,4 @@
package com.example.rtime
package fr.chaboissier.rtime
import io.flutter.embedding.android.FlutterActivity

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Ucrop.CropTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
</resources>

View File

@ -15,4 +15,5 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<style name="Ucrop.CropTheme" parent="Theme.AppCompat.Light.NoActionBar"/> <!--add this line-->
</resources>

View File

@ -1,3 +1,5 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.useAndroidX=true
android.enableJetifier=true

7
build.yaml Normal file
View File

@ -0,0 +1,7 @@
targets:
$default:
builders:
source_gen|combining_builder:
options:
build_extensions:
'^lib/{{}}.dart': 'lib/generated/{{}}.g.dart'

View File

@ -45,5 +45,7 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<string>To locate the flights.</string>
</dict>
</plist>

39
lib/config.dart Normal file
View File

@ -0,0 +1,39 @@
// This file holds a class to represent the configuration/settings of the app
import 'dart:io';
import 'package:json_annotation/json_annotation.dart';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
part 'generated/config.g.dart';
@JsonSerializable()
class RTimeConfig {
final String language;
RTimeConfig({required this.language});
factory RTimeConfig.fromJson(Map<String, dynamic> json) =>
_$RTimeConfigFromJson(json);
Map<String, dynamic> toJson() => _$RTimeConfigToJson(this);
static Future<RTimeConfig?> readFromConfig() async {
final directory = await getApplicationDocumentsDirectory();
final configName = "rtime_config.json";
final configPath = path.join(directory.path, configName);
final string = jsonDecode(await File(configPath).readAsString());
return RTimeConfig.fromJson(string);
}
void writeConfig() async {
final directory = await getApplicationDocumentsDirectory();
final configName = "rtime_config.json";
final configPath = path.join(directory.path, configName);
await File(configPath).writeAsString(jsonEncode(toJson()));
}
}

View File

@ -3,79 +3,195 @@ 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 {
static final DbHelper instance = DbHelper._internal();
static final log = Logger("DbHelper");
static Database? _database;
class DbHelper
{
static final DbHelper instance = DbHelper._internal();
static final log = Logger("DbHelper");
static Database? _database;
DbHelper._internal();
DbHelper._internal();
Future<Database> get database async {
if (_database != null) return _database!;
await _initDb();
return _database!;
}
Future<Database> get database async
{
if (_database != null) return _database!;
await _initDb();
return _database!;
}
Future _initDb() async {
final directory = await getApplicationDocumentsDirectory();
final db_name = "rtime.db";
final path = join(directory.path, db_name);
log.info("Opeing database file at $path");
Future _initDb() async
{
final directory = await getApplicationDocumentsDirectory();
final db_name = "rtime.db";
final path = join(directory.path, db_name);
log.info("Opeing database file at $path");
_database = await openDatabase(path, version: 1, onCreate: _onCreate);
_database = await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
log.info("Database opened successfully !");
log.info("${(await getDrones()).length} drones in DB.");
}
log.info("Database opened successfully !");
log.info("${(await getDrones()).length} drones in DB.");
}
Future _onCreate(Database db, int version) async
{
log.info("Database does not exist, creating a new one.");
await db.execute('''
Future _onCreate(Database db, int version) async {
log.info("Database does not exist, creating a new one.");
await db.execute('''
CREATE TABLE drones(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
image TEXT
image_uuid TEXT
)
''');
}
Future<int> insertDrone(Drone drone) async
{
final db = await database;
return await db.insert("drones", drone.toMap());
}
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
)
''');
Future<List<Drone>> getDrones() async
{
final db = await database;
final maps = await db.query("drones");
return maps.map((e) => Drone.fromMap(e)).toList();
}
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> deleteItem(int drone_id) async
{
final db = await database;
return await db.delete("drones", where: "id = ?", whereArgs: [drone_id]);
}
// Drone related helpers
Future<Drone> insertDrone(Drone drone) async {
final db = await database;
drone.id = await db.insert("drones", drone.toMap());
return drone;
}
Future closeDb() async
{
final db = await database;
log.info("Closing database.");
db.close();
_database = null;
Future<List<Drone>> getDrones() async {
final db = await database;
final maps = await db.query("drones");
return maps.map((e) => Drone.fromMap(e)).toList();
}
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;
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],
);
}
Future<List<Battery>> getBatteriesByType(String type) async {
final db = await database;
final maps = await db.query(
"batteries",
where: "type = ?",
whereArgs: [type],
);
return maps.map((e) => Battery.fromMap(e)).toList();
}
// 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]);
}
// Complex requests
Future<List<Flight>> getDroneFlights(int droneId) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT * FROM flights AS F
JOIN drones AS D ON F.drone_id = D.id
''');
return maps.map((e) => Flight.fromMap(e)).toList();
}
Future<List<Flight>> getBatteryFlights(int batteryId) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT * FROM flights AS F
JOIN batteries AS B ON F.battery_id = B.id
''');
return maps.map((e) => Flight.fromMap(e)).toList();
}
Future<List<Flight>> getFlightsBetween(
int startTimestamp,
int endTimestamp,
) async {
final db = await database;
final maps = await db.rawQuery('''
SELECT * FROM flights AS F
WHERE F.start_timestamp >= $startTimestamp AND F.end_timestamp <= $endTimestamp
''');
return maps.map((e) => Flight.fromMap(e)).toList();
}
Future<int?> getTotalFlightTime() async {
final db = await database;
final ft = await db.rawQuery('''
SELECT SUM(F.end_timestamp - F.startTimestamp) FROM flights AS F
''');
final mapping = ft.firstOrNull;
if (mapping == null) {
return null;
}
final val = mapping["SUM(F.end_timestamp - F.startTimestamp)"];
if (val is! int) {
return null;
}
return val;
}
Future closeDb() async {
final db = await database;
log.info("Closing database.");
db.close();
_database = null;
}
}

View File

@ -1,3 +0,0 @@
import 'package:sqflite/sqflite.dart';

View File

@ -0,0 +1,13 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../config.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
RTimeConfig _$RTimeConfigFromJson(Map<String, dynamic> json) =>
RTimeConfig(language: json['language'] as String);
Map<String, dynamic> _$RTimeConfigToJson(RTimeConfig instance) =>
<String, dynamic>{'language': instance.language};

103
lib/images_manager.dart Normal file
View File

@ -0,0 +1,103 @@
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:image_cropper/image_cropper.dart' as img_cropper;
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;
// Crop image
final uuid = Uuid().v6();
final imageDir = await imageDirectory;
final finalPath = path.join(
imageDir.path,
uuid + path.extension(ximage.name),
);
final tempPath = path.join(
imageDir.path,
"${uuid}_tocrop${path.extension(ximage.name)}",
);
await ximage.saveTo(tempPath);
img_cropper.CroppedFile? cropped = await img_cropper.ImageCropper()
.cropImage(
sourcePath: tempPath,
aspectRatio: img_cropper.CropAspectRatio(ratioX: 1.0, ratioY: 1.0),
uiSettings: [
img_cropper.AndroidUiSettings(
toolbarTitle: "Crop image",
toolbarColor: Colors.black,
toolbarWidgetColor: Colors.white,
),
img_cropper.IOSUiSettings(title: "Crop image"),
],
);
if (cropped == null) return null;
await File(finalPath).writeAsBytes(await cropped.readAsBytes());
await File(tempPath).delete();
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);
}
}

View File

@ -1,141 +1,38 @@
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:rtime/pages/home_page.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)
{
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
}
if (Platform.isWindows || Platform.isLinux) {
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
}
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) =>
print('${record.level.name}: ${record.time}: ${record.message}')
);
runApp(const MyApp());
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen(
(record) =>
print('${record.level.name}: ${record.time}: ${record.message}'),
);
runApp(const RTimeApp());
//DbHelper.instance.closeDb();
//DbHelper.instance.closeDb();
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
class RTimeApp extends StatelessWidget {
const RTimeApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
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),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
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
// so that the display can reflect the updated values. If we changed
// _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"));
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// 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.
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a specific color (to
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
// change color while the other colors stay the same.
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
//
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
// 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,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
return Text("RtimeAPP");
}
}

33
lib/models/battery.dart Normal file
View 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,
};
}
}

View File

@ -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
View 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,
};
}
}

View File

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
sqlite3_flutter_libs
)

View File

@ -5,11 +5,13 @@
import FlutterMacOS
import Foundation
import file_selector_macos
import path_provider_foundation
import sqflite_darwin
import sqlite3_flutter_libs
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))

View File

@ -1,6 +1,22 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
url: "https://pub.dev"
source: hosted
version: "85.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "01949bf52ad33f0e0f74f881fbaac4f348c556531951d92c8d16f1262aa19ff8"
url: "https://pub.dev"
source: hosted
version: "7.5.4"
archive:
dependency: transitive
description:
@ -9,6 +25,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.7"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
@ -25,6 +49,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
build:
dependency: transitive
description:
name: build
sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
build_config:
dependency: transitive
description:
name: build_config
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.4"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62
url: "https://pub.dev"
source: hosted
version: "2.5.4"
build_runner:
dependency: transitive
description:
name: build_runner
sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792"
url: "https://pub.dev"
source: hosted
version: "9.1.2"
built_collection:
dependency: transitive
description:
name: built_collection
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
url: "https://pub.dev"
source: hosted
version: "8.10.1"
characters:
dependency: transitive
description:
@ -33,6 +121,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
url: "https://pub.dev"
source: hosted
version: "2.0.4"
clock:
dependency: transitive
description:
@ -41,6 +137,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.2"
code_builder:
dependency: transitive
description:
name: code_builder
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.1"
collection:
dependency: transitive
description:
@ -49,6 +153,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev"
source: hosted
version: "0.3.4+2"
crypto:
dependency: transitive
description:
@ -65,6 +185,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dart_style:
dependency: transitive
description:
name: dart_style
sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
fake_async:
dependency: transitive
description:
@ -81,6 +209,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
url: "https://pub.dev"
source: hosted
version: "0.9.3+2"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711"
url: "https://pub.dev"
source: hosted
version: "0.9.4+3"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.dev"
source: hosted
version: "2.6.2"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.dev"
source: hosted
version: "0.9.3+4"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter:
dependency: "direct main"
description: flutter
@ -94,11 +270,72 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
url: "https://pub.dev"
source: hosted
version: "2.0.28"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
graphs:
dependency: transitive
description:
name: graphs
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
http:
dependency: transitive
description:
name: http
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
image:
dependency: "direct main"
description:
@ -107,6 +344,126 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.5.4"
image_cropper:
dependency: "direct main"
description:
name: image_cropper
sha256: "4e9c96c029eb5a23798da1b6af39787f964da6ffc78fd8447c140542a9f7c6fc"
url: "https://pub.dev"
source: hosted
version: "9.1.0"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
sha256: fd81ebe36f636576094377aab32673c4e5d1609b32dec16fad98d2b71f1250a9
url: "https://pub.dev"
source: hosted
version: "6.1.0"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
sha256: "6ca6b81769abff9a4dcc3bbd3d75f5dfa9de6b870ae9613c8cd237333a4283af"
url: "https://pub.dev"
source: hosted
version: "7.1.0"
image_picker:
dependency: "direct main"
description:
name: image_picker
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb"
url: "https://pub.dev"
source: hosted
version: "0.8.12+23"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
url: "https://pub.dev"
source: hosted
version: "0.8.12+2"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9"
url: "https://pub.dev"
source: hosted
version: "0.2.1+2"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1"
url: "https://pub.dev"
source: hosted
version: "0.2.1+2"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
url: "https://pub.dev"
source: hosted
version: "2.10.1"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev"
source: hosted
version: "4.9.0"
json_serializable:
dependency: "direct main"
description:
name: json_serializable
sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c
url: "https://pub.dev"
source: hosted
version: "6.9.5"
leak_tracker:
dependency: transitive
description:
@ -171,6 +528,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
dependency: "direct main"
description:
@ -251,6 +624,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
posix:
dependency: transitive
description:
@ -259,11 +640,59 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.3"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_gen:
dependency: transitive
description:
name: source_gen
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
source_helper:
dependency: transitive
description:
name: source_helper
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev"
source: hosted
version: "1.3.5"
source_span:
dependency: transitive
description:
@ -272,6 +701,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.1"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
sqflite:
dependency: "direct main"
description:
@ -352,6 +789,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.1"
string_scanner:
dependency: transitive
description:
@ -384,6 +829,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.4"
timing:
dependency: transitive
description:
name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
typed_data:
dependency: transitive
description:
@ -392,6 +845,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
uuid:
dependency: "direct main"
description:
name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_math:
dependency: transitive
description:
@ -408,6 +869,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "15.0.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
web:
dependency: transitive
description:
@ -416,6 +885,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
xdg_directories:
dependency: transitive
description:
@ -432,6 +917,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.8.1 <4.0.0"
flutter: ">=3.27.0"

View File

@ -1,5 +1,5 @@
name: rtime
description: "A new Flutter project."
description: "An app to track your fpv flight time batteries and drones."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
@ -41,6 +41,10 @@ dependencies:
sqlite3_flutter_libs: ^0.5.34
sqflite_common_ffi: ^2.3.6
image: ^4.5.4
image_picker: ^1.1.2
uuid: ^4.5.1
json_serializable: ^6.9.5
image_cropper: ^9.1.0
dev_dependencies:
flutter_test:

View File

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
}

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
sqlite3_flutter_libs
)