add some ui improvements
This commit is contained in:
parent
9690161207
commit
003e982ff8
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_blue_plus_windows/flutter_blue_plus_windows.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
@ -46,6 +47,12 @@ class _AppState extends State<AppView> {
|
||||
// adapterState: _adapterState,
|
||||
// );
|
||||
|
||||
// only allow portrait orientations
|
||||
SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'Xiao Pet Tracker',
|
||||
localizationsDelegates: const [
|
||||
|
@ -69,7 +69,7 @@
|
||||
},
|
||||
{
|
||||
"id": "2:1642885530071590702",
|
||||
"lastPropertyId": "3:4134744801341910087",
|
||||
"lastPropertyId": "4:5477306218303066701",
|
||||
"name": "CaptureBox",
|
||||
"properties": [
|
||||
{
|
||||
@ -87,6 +87,11 @@
|
||||
"id": "3:4134744801341910087",
|
||||
"name": "uuid",
|
||||
"type": 9
|
||||
},
|
||||
{
|
||||
"id": "4:5477306218303066701",
|
||||
"name": "startTime",
|
||||
"type": 10
|
||||
}
|
||||
],
|
||||
"relations": []
|
||||
|
@ -87,7 +87,7 @@ final _entities = <obx_int.ModelEntity>[
|
||||
obx_int.ModelEntity(
|
||||
id: const obx_int.IdUid(2, 1642885530071590702),
|
||||
name: 'CaptureBox',
|
||||
lastPropertyId: const obx_int.IdUid(3, 4134744801341910087),
|
||||
lastPropertyId: const obx_int.IdUid(4, 5477306218303066701),
|
||||
flags: 0,
|
||||
properties: <obx_int.ModelProperty>[
|
||||
obx_int.ModelProperty(
|
||||
@ -104,6 +104,11 @@ final _entities = <obx_int.ModelEntity>[
|
||||
id: const obx_int.IdUid(3, 4134744801341910087),
|
||||
name: 'uuid',
|
||||
type: 9,
|
||||
flags: 0),
|
||||
obx_int.ModelProperty(
|
||||
id: const obx_int.IdUid(4, 5477306218303066701),
|
||||
name: 'startTime',
|
||||
type: 10,
|
||||
flags: 0)
|
||||
],
|
||||
relations: <obx_int.ModelRelation>[],
|
||||
@ -252,10 +257,11 @@ obx_int.ModelDefinition getObjectBoxModel() {
|
||||
objectToFB: (CaptureBox object, fb.Builder fbb) {
|
||||
final typeOffset = fbb.writeString(object.type);
|
||||
final uuidOffset = fbb.writeString(object.uuid);
|
||||
fbb.startTable(4);
|
||||
fbb.startTable(5);
|
||||
fbb.addInt64(0, object.id);
|
||||
fbb.addOffset(1, typeOffset);
|
||||
fbb.addOffset(2, uuidOffset);
|
||||
fbb.addInt64(3, object.startTime.millisecondsSinceEpoch);
|
||||
fbb.finish(fbb.endTable());
|
||||
return object.id;
|
||||
},
|
||||
@ -266,7 +272,10 @@ obx_int.ModelDefinition getObjectBoxModel() {
|
||||
.vTableGet(buffer, rootOffset, 6, '');
|
||||
final uuidParam = const fb.StringReader(asciiOptimization: true)
|
||||
.vTableGet(buffer, rootOffset, 8, '');
|
||||
final object = CaptureBox(type: typeParam, uuid: uuidParam)
|
||||
final startTimeParam = DateTime.fromMillisecondsSinceEpoch(
|
||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0));
|
||||
final object = CaptureBox(
|
||||
type: typeParam, uuid: uuidParam, startTime: startTimeParam)
|
||||
..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0);
|
||||
|
||||
return object;
|
||||
@ -336,4 +345,8 @@ class CaptureBox_ {
|
||||
/// See [CaptureBox.uuid].
|
||||
static final uuid =
|
||||
obx.QueryStringProperty<CaptureBox>(_entities[1].properties[2]);
|
||||
|
||||
/// See [CaptureBox.startTime].
|
||||
static final startTime =
|
||||
obx.QueryDateProperty<CaptureBox>(_entities[1].properties[3]);
|
||||
}
|
||||
|
@ -5,10 +5,9 @@ import 'package:csv/csv.dart';
|
||||
import 'package:ditredi/ditredi.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:ditredi/ditredi.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'package:xiao_pet_tracker/xiao_connector/cubit/xiao_connector_cubit.dart';
|
||||
import 'package:xiao_pet_tracker/xiao_connector/models/capture_point.dart';
|
||||
@ -31,8 +30,11 @@ class RecordingsDetailsPage extends StatefulWidget {
|
||||
class _RecordingsDetailsPageState extends State<RecordingsDetailsPage> {
|
||||
final _controllerRotation = DiTreDiController();
|
||||
final _controllerAcceleration = DiTreDiController();
|
||||
final f = DateFormat('hh:mm:ss.SSS');
|
||||
List<CapturePoint> _capturePoints = [];
|
||||
|
||||
bool isStoringCSV = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_capturePoints =
|
||||
@ -54,10 +56,10 @@ class _RecordingsDetailsPageState extends State<RecordingsDetailsPage> {
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
'Capture Start Time: ${DateTime.fromMillisecondsSinceEpoch(_capturePoints.first.millisecondsSinceEpochSend)}',
|
||||
'Start Time: ${f.format(DateTime.fromMillisecondsSinceEpoch(_capturePoints.first.millisecondsSinceEpochSend))}',
|
||||
),
|
||||
Text(
|
||||
'Capture End Time: ${DateTime.fromMillisecondsSinceEpoch(_capturePoints.first.millisecondsSinceEpochSend)}',
|
||||
'End Time: ${f.format(DateTime.fromMillisecondsSinceEpoch(_capturePoints.last.millisecondsSinceEpochSend))}',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
@ -66,50 +68,68 @@ class _RecordingsDetailsPageState extends State<RecordingsDetailsPage> {
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
// await Permission.storage.request();
|
||||
if (isStoringCSV)
|
||||
const CircularProgressIndicator()
|
||||
else
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
isStoringCSV = true;
|
||||
});
|
||||
// await Permission.storage.request();
|
||||
|
||||
final Directory? downloadsDir = (Platform.isIOS)
|
||||
? await getApplicationDocumentsDirectory()
|
||||
: await getDownloadsDirectory();
|
||||
final Directory? downloadsDir = (Platform.isIOS)
|
||||
? await getApplicationDocumentsDirectory()
|
||||
: await getDownloadsDirectory();
|
||||
|
||||
File f = File(
|
||||
downloadsDir!.path + "/${widget.type}_${widget.uuid}.csv");
|
||||
File f = File(downloadsDir!.path +
|
||||
"/${widget.type}_${widget.uuid}.csv");
|
||||
|
||||
List<List<dynamic>> rows = [];
|
||||
List<List<dynamic>> rows = [];
|
||||
|
||||
List<dynamic> row = [];
|
||||
row.add('sendTimeStamp');
|
||||
row.add('receivedTimeStamp');
|
||||
row.add('accelerationX');
|
||||
row.add('accelerationY');
|
||||
row.add('accelerationZ');
|
||||
row.add('rotationX');
|
||||
row.add('rotationY');
|
||||
row.add('rotationZ');
|
||||
|
||||
rows.add(row);
|
||||
|
||||
for (var i = 0; i < _capturePoints.length; i++) {
|
||||
List<dynamic> row = [];
|
||||
row.add(_capturePoints[i].millisecondsSinceEpochSend);
|
||||
row.add(_capturePoints[i].millisecondsSinceEpochReceived);
|
||||
row.add(_capturePoints[i].accelerationX);
|
||||
row.add(_capturePoints[i].accelerationY);
|
||||
row.add(_capturePoints[i].accelerationZ);
|
||||
row.add(_capturePoints[i].rotationX);
|
||||
row.add(_capturePoints[i].rotationY);
|
||||
row.add(_capturePoints[i].rotationZ);
|
||||
row.add('sendTimeStamp');
|
||||
row.add('receivedTimeStamp');
|
||||
row.add('accelerationX');
|
||||
row.add('accelerationY');
|
||||
row.add('accelerationZ');
|
||||
row.add('rotationX');
|
||||
row.add('rotationY');
|
||||
row.add('rotationZ');
|
||||
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
String csv = const ListToCsvConverter().convert(rows);
|
||||
for (var i = 0; i < _capturePoints.length; i++) {
|
||||
List<dynamic> row = [];
|
||||
row.add(_capturePoints[i].millisecondsSinceEpochSend);
|
||||
row.add(_capturePoints[i].millisecondsSinceEpochReceived);
|
||||
row.add(_capturePoints[i].accelerationX);
|
||||
row.add(_capturePoints[i].accelerationY);
|
||||
row.add(_capturePoints[i].accelerationZ);
|
||||
row.add(_capturePoints[i].rotationX);
|
||||
row.add(_capturePoints[i].rotationY);
|
||||
row.add(_capturePoints[i].rotationZ);
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
f.writeAsString(csv);
|
||||
},
|
||||
child: const Text('Export to CSV'),
|
||||
),
|
||||
String csv = const ListToCsvConverter().convert(rows);
|
||||
|
||||
f.writeAsString(csv);
|
||||
setState(
|
||||
() {
|
||||
isStoringCSV = false;
|
||||
},
|
||||
);
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Succesfully exported the CSV!'),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Text('Export to CSV'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
@ -2,10 +2,10 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:xiao_pet_tracker/app_router/app_router.gr.dart';
|
||||
import 'package:xiao_pet_tracker/xiao_connector/cubit/xiao_connector_cubit.dart';
|
||||
import 'package:xiao_pet_tracker/xiao_connector/models/capture_box.dart';
|
||||
import 'package:xiao_pet_tracker/xiao_connector/view/xiao_connector_page.dart';
|
||||
|
||||
@RoutePage()
|
||||
class RecordingsPage extends StatelessWidget {
|
||||
@ -26,6 +26,7 @@ class RecordingsView extends StatefulWidget {
|
||||
|
||||
class _SettingsViewState extends State<RecordingsView> {
|
||||
List<CaptureBox> _captureBoxes = [];
|
||||
final f = DateFormat('hh:mm - dd.MM.yyyy ');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -47,7 +48,7 @@ class _SettingsViewState extends State<RecordingsView> {
|
||||
return ListTile(
|
||||
leading: FIcon(FAssets.icons.pawPrint),
|
||||
title: Text('Collection Type: ${_captureBoxes[i].type}'),
|
||||
subtitle: Text('Uuid: ${_captureBoxes[i].uuid}'),
|
||||
subtitle: Text(f.format(_captureBoxes[i].startTime)),
|
||||
onTap: () {
|
||||
AutoRouter.of(context).push(
|
||||
RecordingsDetailsRoute(
|
||||
@ -56,6 +57,38 @@ class _SettingsViewState extends State<RecordingsView> {
|
||||
),
|
||||
);
|
||||
},
|
||||
onLongPress: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Delete this recording?'),
|
||||
content: const Text(
|
||||
"Are you sure you want to delete this recording with all of it's data? This cannot be undone.",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context
|
||||
.read<XiaoConnectorCubit>()
|
||||
.deleteRecording(_captureBoxes[i].uuid);
|
||||
_pullRefresh();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -228,6 +228,12 @@ class XiaoConnectorCubit extends Cubit<XiaoConnectorState> {
|
||||
emit(state.copyWith(status: XiaoConnectorStatus.connected));
|
||||
}
|
||||
|
||||
Future<void> disconnectDevice() async {
|
||||
await device.disconnect();
|
||||
_services = [];
|
||||
emit(state.copyWith(status: XiaoConnectorStatus.initial));
|
||||
}
|
||||
|
||||
void toggleRecording({required String captureType}) {
|
||||
isRecording = !isRecording;
|
||||
if (isRecording) {
|
||||
@ -237,6 +243,7 @@ class XiaoConnectorCubit extends Cubit<XiaoConnectorState> {
|
||||
CaptureBox(
|
||||
type: _captureType,
|
||||
uuid: _uuid,
|
||||
startTime: DateTime.now(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -256,6 +263,18 @@ class XiaoConnectorCubit extends Cubit<XiaoConnectorState> {
|
||||
return points;
|
||||
}
|
||||
|
||||
List<CaptureBox> getAllCaptureBoxes() => _captureBoxes.getAll();
|
||||
void deleteRecording(String uuid) {
|
||||
_capturePointsBox.query(CapturePoint_.uuid.equals(uuid)).build().remove();
|
||||
_captureBoxes.query(CaptureBox_.uuid.equals(uuid)).build().remove();
|
||||
}
|
||||
|
||||
List<CaptureBox> getAllCaptureBoxes() {
|
||||
final query = (_captureBoxes.query()
|
||||
..order(CaptureBox_.startTime, flags: Order.descending))
|
||||
.build();
|
||||
final boxes = query.find();
|
||||
return boxes;
|
||||
}
|
||||
|
||||
List<CapturePoint> getAllCapturePoints() => _capturePointsBox.getAll();
|
||||
}
|
||||
|
@ -5,10 +5,14 @@ class CaptureBox {
|
||||
CaptureBox({
|
||||
required this.type,
|
||||
required this.uuid,
|
||||
required this.startTime,
|
||||
});
|
||||
@Id()
|
||||
int id = 0;
|
||||
|
||||
String type;
|
||||
String uuid;
|
||||
|
||||
@Property(type: PropertyType.date)
|
||||
DateTime startTime;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ class CapturePoint {
|
||||
int accelerationY;
|
||||
int accelerationZ;
|
||||
|
||||
// @Property(type: PropertyType.date)
|
||||
int millisecondsSinceEpochReceived;
|
||||
int millisecondsSinceEpochSend;
|
||||
}
|
||||
|
@ -14,26 +14,36 @@ class ConnectedView extends StatelessWidget {
|
||||
title: const Text('Xiao Connector'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'''
|
||||
You are connected to the Xiao Sense.
|
||||
Now you can open the live feed.''',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.read<XiaoConnectorCubit>().startCapturing();
|
||||
// context.read<XiaoConnectorCubit>().setCapturingOn();
|
||||
},
|
||||
child: const Text('Open Live Feed'),
|
||||
),
|
||||
],
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'''
|
||||
You are connected to the Xiao Sense.
|
||||
Now you can open the live feed.''',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.read<XiaoConnectorCubit>().startCapturing();
|
||||
},
|
||||
child: const Text('Open Live Feed'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.read<XiaoConnectorCubit>().disconnectDevice();
|
||||
},
|
||||
child: const Text('Disconnect'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -5,6 +5,6 @@ class FailureView extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Text('Failure');
|
||||
return const Text('Oops. Something bad happened! :(');
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user