Skip to content

Commit 9dce064

Browse files
authored
Log file client development (#472)
* Rewrote tank_list into log_list * Modified log list reader to only show csv files * Made CsvReader class * CsvReader now can output nested list of formatted data types * Fixed empty-line bug * Added basic csv file preview functionality * Added async loading to CsvView * Implemented local file retrieval to bypass CORS issues * Wrote tests for UI and removed unused files * Changed scrollable DataTable to Listview to cut down on load time * Implemented use of csv package * Added shared parseHTML method * Minor changes as requested * Fixed formatting issues * Fixed csv_reader_test formatting issue * Fixed formatting issues * Added test for CsvView displaying table * Fixed csv package implementation issue * Fixed formatting issues
1 parent d393fa5 commit 9dce064

18 files changed

Lines changed: 27312 additions & 163 deletions
228 KB
Loading
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:log_file_client/utils/log_list.dart';
3+
4+
class AppDrawer extends StatelessWidget {
5+
const AppDrawer({
6+
required this.logList,
7+
required this.openLogFile,
8+
super.key,
9+
});
10+
final List<Log> logList;
11+
final void Function(Log) openLogFile;
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Drawer(
16+
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
17+
child: Column(
18+
children: [
19+
// Header
20+
DrawerHeader(
21+
child: Image.asset('lib/assets/oap.png'),
22+
),
23+
24+
// CSV files that can be opened
25+
Expanded(
26+
child: ListView.builder(
27+
itemCount: logList.length,
28+
itemBuilder: (context, index) {
29+
final log = logList[index];
30+
return ListTile(
31+
title: Text(log.name),
32+
onTap: () {
33+
openLogFile(log);
34+
},
35+
);
36+
},
37+
),
38+
),
39+
],
40+
),
41+
);
42+
}
43+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:log_file_client/utils/csv_reader.dart';
5+
6+
class CsvView extends StatelessWidget {
7+
CsvView({required this.csvPath, super.key});
8+
final String csvPath;
9+
late final Future<List<List<dynamic>>> csvTable = getCsvTable();
10+
11+
Future<List<List<dynamic>>> getCsvTable() async {
12+
// final reader = CsvReaderForApp(csvPath);
13+
final reader = CsvReaderLocal('sample_short.csv');
14+
final table = await reader.csvTable();
15+
return table;
16+
}
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
return FutureBuilder<List>(
21+
future: csvTable,
22+
builder: (context, snapshot) {
23+
if (snapshot.connectionState == ConnectionState.waiting) {
24+
return const Center(child: CircularProgressIndicator());
25+
} else if (snapshot.hasError) {
26+
return Center(child: Text('Error: ${snapshot.error}'));
27+
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
28+
return const Center(child: Text('No data found'));
29+
} else {
30+
final csvTable = snapshot.data!;
31+
return Column(
32+
children: [
33+
// Headers
34+
Container(
35+
padding: EdgeInsets.all(5),
36+
decoration: const BoxDecoration(
37+
border: Border(bottom: BorderSide(color: Colors.grey)),
38+
),
39+
child: Row(
40+
children: csvTable[0].asMap().entries.map<Widget>((entry) {
41+
final int idx = entry.key;
42+
final header = entry.value;
43+
return Expanded(
44+
flex: idx == 0
45+
? 2
46+
: 1, // Allow more space for the first column for the datetimes
47+
child: Text(
48+
header.toString(),
49+
style: const TextStyle(fontStyle: FontStyle.italic),
50+
),
51+
);
52+
}).toList(),
53+
),
54+
),
55+
56+
// Data
57+
Expanded(
58+
child: ListView.builder(
59+
// Cutoff at 5000 lines to avoid long wait times
60+
itemCount: csvTable.length > 5000
61+
? csvTable.sublist(1, 5000).length
62+
: csvTable.length - 1,
63+
itemBuilder: (context, index) {
64+
return Container(
65+
padding: EdgeInsets.all(5),
66+
decoration: BoxDecoration(
67+
border: Border(
68+
bottom: BorderSide(color: Colors.grey.shade400),
69+
),
70+
),
71+
child: Row(
72+
children: csvTable[index + 1]
73+
.asMap()
74+
.entries
75+
.map<Widget>((entry) {
76+
final int idx = entry.key;
77+
final cell = entry.value;
78+
return Expanded(
79+
flex: idx == 0
80+
? 2
81+
: 1, // Allow more space for the first column
82+
child: Text(
83+
cell is num
84+
? (idx >= 2 && idx <= 5
85+
? cell.toStringAsFixed(3)
86+
: cell.toStringAsFixed(0))
87+
: cell.toString(),
88+
),
89+
);
90+
}).toList(),
91+
),
92+
);
93+
},
94+
),
95+
),
96+
],
97+
);
98+
}
99+
},
100+
);
101+
}
102+
}

extras/log_file_client/lib/main.dart

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:flutter/material.dart';
2-
import 'package:log_file_client/tank_grid_view.dart';
2+
import 'package:log_file_client/pages/home_page.dart';
33

44
void main() {
55
runApp(const MyApp());
@@ -19,14 +19,7 @@ class MyApp extends StatelessWidget {
1919
),
2020
useMaterial3: true,
2121
),
22-
home: const MyHomePage(),
22+
home: const HomePage(),
2323
);
2424
}
2525
}
26-
27-
class MyHomePage extends StatefulWidget {
28-
const MyHomePage({super.key});
29-
30-
@override
31-
State<MyHomePage> createState() => TankGridView();
32-
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:log_file_client/components/app_drawer.dart';
5+
import 'package:log_file_client/components/csv_view.dart';
6+
import 'package:log_file_client/utils/log_list.dart';
7+
8+
class HomePage extends StatefulWidget {
9+
const HomePage({super.key, this.logListReader});
10+
11+
final LogListReader? logListReader;
12+
13+
@override
14+
State<HomePage> createState() => _HomePageState();
15+
}
16+
17+
class _HomePageState extends State<HomePage> {
18+
late final LogListReader logListReader;
19+
List<Log>? _logList;
20+
bool _isLoading = true;
21+
int _openedLogIndex = -1;
22+
23+
@override
24+
void initState() {
25+
super.initState();
26+
logListReader = widget.logListReader ?? LogListReaderForAppLocal();
27+
unawaited(_getLogList());
28+
}
29+
30+
// Fetches the list of csv files available
31+
Future<void> _getLogList() async {
32+
final result = await logListReader.fetchList();
33+
setState(() {
34+
_logList = result;
35+
_isLoading = false;
36+
});
37+
}
38+
39+
void openLogFile(Log log) {
40+
setState(() {
41+
_openedLogIndex = _logList!.indexOf(log); // Open the selected log file
42+
Navigator.of(context).pop(); // Close the drawer
43+
});
44+
}
45+
46+
@override
47+
Widget build(BuildContext context) {
48+
return Scaffold(
49+
appBar: AppBar(
50+
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
51+
title: const Text('Tank Monitor'),
52+
),
53+
drawer: _isLoading
54+
? Drawer() // null drawer
55+
: AppDrawer(
56+
logList: _logList!,
57+
openLogFile: openLogFile,
58+
),
59+
body: Center(
60+
child: _isLoading
61+
? const CircularProgressIndicator()
62+
: _openedLogIndex >= 0
63+
? CsvView(csvPath: _logList![_openedLogIndex].uri)
64+
: null,
65+
),
66+
);
67+
}
68+
}

extras/log_file_client/lib/tank_grid_view.dart

Lines changed: 0 additions & 55 deletions
This file was deleted.

extras/log_file_client/lib/tank_list.dart

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)