Skip to content

Commit

Permalink
#14, #15, misc bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rotenaple committed Jan 10, 2024
1 parent 4303e6a commit 0047205
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 104 deletions.
128 changes: 128 additions & 0 deletions lib/csv.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';

class ParseCSV {
String _pathName = "Unnamed Path";

Future<(List<List<dynamic>>, String)> readCSV(String path, String source) async {
String csvData = await _loadCSVData(path, source);
final lines = csvData.split('\n');
if (kDebugMode) {
print(lines);
}

return (_processLines(lines), _pathName);
}

Future<String> _loadCSVData(String path, String source) async {
if (source == "asset") {
return await rootBundle.loadString(path);
} else {
final file = File(path);
return await file.readAsString();
}
}

List<List<dynamic>> _processLines(List<String> lines) {
List<List<dynamic>> data = [];
for (var line in lines) {
if (_isPathNameLine(line)) {
_pathName = line.substring(2).trim();
continue;
}

if (_isCommentOrEmpty(line)) {
continue;
}

var row = _processRow(line);
if (row != null) {
data.add(row);
}
}
return data;
}

bool _isPathNameLine(String line) => line.trim().startsWith('##');

bool _isCommentOrEmpty(String line) => line.trim().isEmpty || line.trim().startsWith('#');

List<dynamic>? _processRow(String line) {
List<dynamic> row = line.split(',');
if (row.length >= 4) {
return [
row[0],
double.tryParse(row[1]) ?? 0.0,
double.tryParse(row[2]) ?? 0.0,
double.tryParse(row[3]) ?? 0.0
];
}
return null;
}

Future<void> importCSV() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['csv'],
);

if (result != null) {
File file = File(result.files.single.path!);
if (await _validateCSV(file)) {
await _saveFileToAppDirectory(file);
}
}
}

Future<bool> _validateCSV(File file) async {
final input = await file.readAsString();
final lines = input.split('\n');

for (var line in lines) {
if (_isCommentOrEmpty(line)) {
continue;
}

if (!_isValidCSVRow(line)) {
return false;
}
}
return true;
}

bool _isValidCSVRow(String line) {
List<dynamic> row = line.split(',');
return row.length == 4 &&
_isValidDouble(row[1], -90, 90) &&
_isValidDouble(row[2], -180, 180) &&
_isValidDouble(row[3], 0, double.infinity);
}

bool _isValidDouble(String value, double min, double max) {
double? val = double.tryParse(value);
return val != null && val >= min && val <= max;
}

Future<void> _saveFileToAppDirectory(File file) async {
Directory appDocDir = await getApplicationDocumentsDirectory();
String baseFilePath = '${appDocDir.path}/${file.uri.pathSegments.last}';
String newFilePath = baseFilePath;

int counter = 2;
while (File(newFilePath).existsSync()) {
newFilePath = _appendNumberSuffix(baseFilePath, counter);
counter++;
}

await file.copy(newFilePath);
}

String _appendNumberSuffix(String filePath, int counter) {
String extension = filePath.substring(filePath.lastIndexOf('.'));
String pathWithoutExtension = filePath.substring(0, filePath.lastIndexOf('.'));
return '${pathWithoutExtension}_$counter$extension';
}
}
62 changes: 9 additions & 53 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:gps_path_tracker/location_service.dart';
import 'package:gps_path_tracker/pick_path.dart';
import 'package:file_picker/file_picker.dart';
import 'package:gps_path_tracker/pick_path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:gps_path_tracker/time_provider.dart';
import 'package:gps_path_tracker/csv.dart';

import 'package:latlong2/latlong.dart';

void main() => runApp(const MyApp());
Expand Down Expand Up @@ -52,52 +50,12 @@ class _MyAppState extends State<MyApp> {
}

Future<void> importData() async {
var returnValue = await ReadCSV().readCSV('assets/pathdata.csv', "asset");
var returnValue = await ParseCSV().readCSV('assets/pathdata.csv', "asset");
nameLatLngSet = returnValue.$1;
_pathName = returnValue.$2;
}

Future<void> importCSV() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['csv'],
);

if (result != null) {
File file = File(result.files.single.path!);

final input = await file.readAsString();
final lines = input.split('\n');
bool csvNoErrors = true;

for (var line in lines) {
if (line.trim().isEmpty || line.trim().startsWith('#')) {
continue;
}

List<dynamic> row = line.split(',');
if (row.length != 4 ||
double.tryParse(row[1]) == null ||
double.tryParse(row[1])! < -90 ||
double.tryParse(row[1])! > 90 ||
double.tryParse(row[2]) == null ||
double.tryParse(row[2])! < -180 ||
double.tryParse(row[2])! > 180 ||
double.tryParse(row[3]) == null ||
double.tryParse(row[3])! < 0) {
csvNoErrors = false;
break;
}
}

if (csvNoErrors) {
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
final String newFilePath = '$appDocPath/${file.uri.pathSegments.last}';
await file.copy(newFilePath);
}
}
}

void _initLocationStream() {
_locationService.initLocationStream((latitude, longitude, speed) {
Expand Down Expand Up @@ -127,7 +85,7 @@ class _MyAppState extends State<MyApp> {
LatLng(nameLatLngSet[_targetIndex][1], nameLatLngSet[_targetIndex][2]);
_targetStr =
'${nameLatLngSet[_targetIndex][1].toStringAsFixed(7)}, ${nameLatLngSet[_targetIndex][2].toStringAsFixed(7)}';
_targetName = nameLatLngSet[_targetIndex][0];
_targetName = "$_targetIndex " + nameLatLngSet[_targetIndex][0];
}

void _updateDisplayInfo() {
Expand Down Expand Up @@ -178,7 +136,7 @@ class _MyAppState extends State<MyApp> {
String _calculateEtaDisplay() {
if (_currentSpeed > 0.0) {
return GetFutureTime()
.getFutureTime((_linearDistance / _currentSpeed * 3.6).toInt());
.getFutureTime((_estDistance / _currentSpeed * 3.6).toInt());
} else {
return "N/A";
}
Expand Down Expand Up @@ -271,10 +229,8 @@ class _MyAppState extends State<MyApp> {
}

void processSelectedPath(String path) async {
// Process the file at the given path
// For example, read the CSV, update the state, etc.

var returnValue = await ReadCSV().readCSV('assets/pathdata.csv', "path");
var returnValue = await ParseCSV().readCSV(path, "path");
print(returnValue);
var newData = returnValue.$1;
_pathName = returnValue.$2;
setState(() {
Expand Down Expand Up @@ -343,7 +299,7 @@ class _MyAppState extends State<MyApp> {
Visibility(
visible: !isHorizontal,
child: const SizedBox(
height: 80,
height: 100,
width: 200,
),
),
Expand Down Expand Up @@ -410,7 +366,7 @@ class _MyAppState extends State<MyApp> {
leading: const Icon(Icons.file_copy),
title: const Text('Import Custom Path File'),
onTap: () {
importCSV();
ParseCSV().importCSV();
Navigator.pop(context);
},
),
Expand Down
60 changes: 9 additions & 51 deletions lib/pick_path.dart
Original file line number Diff line number Diff line change
@@ -1,56 +1,8 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';

class ReadCSV {
String _pathName = "Unnamed Path";
late (Future<List<List<dynamic>>>, int) record;


Future<(List<List<dynamic>>, String)> readCSV(String path, String source) async {
String csvData;
if (source == "asset") {
csvData = await rootBundle.loadString(path);
} else {
final file = File(path);
csvData = await file.readAsString();
}

final lines = csvData.split('\n');
if (kDebugMode) {
print(lines);
}

List<List<dynamic>> data = [];
for (var line in lines) {

if (line.trim().startsWith('##')) {
_pathName = line.substring(2).trim();
continue;
}

if (line.trim().isEmpty || line.trim().startsWith('#')) {
continue;
}

List<dynamic> row = line.split(',');
if (row.isNotEmpty && row.length >= 4) {
row = [
row[0], // Assuming the first column is a String
double.tryParse(row[1]) ?? 0.0, // Latitude
double.tryParse(row[2]) ?? 0.0, // Longitude
double.tryParse(row[3]) ?? 0.0 // Some other numeric value
];
data.add(row);
}
}
return (data,_pathName);
}
}

class FileDetails {
final File file;
final DateTime addedDate;
Expand All @@ -75,7 +27,9 @@ class PickPath extends StatelessWidget {
return fileDetails;
}


@override

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
Expand Down Expand Up @@ -108,7 +62,8 @@ class PickPath extends StatelessWidget {
);
}

Widget buildFileCard(FileDetails fileDetail, String fileName, BuildContext context) {
Widget buildFileCard(
FileDetails fileDetail, String fileName, BuildContext context) {
return InkWell(
onTap: () {
Navigator.pop(context, fileDetail.file.path);
Expand All @@ -119,8 +74,10 @@ class PickPath extends StatelessWidget {
);
}

ListTile buildListTile(FileDetails fileDetail, String fileName, BuildContext context) {
final addedDate = DateFormat('dd MMM yyyy kk:mm').format(fileDetail.addedDate);
ListTile buildListTile(
FileDetails fileDetail, String fileName, BuildContext context) {
final addedDate =
DateFormat('dd MMM yyyy kk:mm').format(fileDetail.addedDate);
return ListTile(
leading: const Icon(Icons.map),
title: Text(fileName),
Expand Down Expand Up @@ -156,6 +113,7 @@ class PickPath extends StatelessWidget {
onPressed: () async {
await fileDetail.file.delete();
Navigator.pop(context);
Navigator.pop(context);
},
child: const Text('Delete'),
),
Expand Down

0 comments on commit 0047205

Please sign in to comment.