add some ui improvements
Some checks failed
xiao_pet_tracker / semantic-pull-request (push) Failing after 2s
xiao_pet_tracker / build (push) Failing after 2s
xiao_pet_tracker / spell-check (push) Failing after 1s

This commit is contained in:
baldeau 2024-11-14 10:36:22 +01:00
parent 9690161207
commit 003e982ff8
11 changed files with 180 additions and 69 deletions

View File

@ -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 [

View File

@ -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": []

View File

@ -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]);
}

View File

@ -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,16 +68,22 @@ class _RecordingsDetailsPageState extends State<RecordingsDetailsPage> {
const SizedBox(
height: 16,
),
if (isStoringCSV)
const CircularProgressIndicator()
else
ElevatedButton(
onPressed: () async {
setState(() {
isStoringCSV = true;
});
// await Permission.storage.request();
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 = [];
@ -107,6 +115,18 @@ class _RecordingsDetailsPageState extends State<RecordingsDetailsPage> {
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'),
),

View File

@ -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'),
),
],
);
},
);
},
);
},
),

View File

@ -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();
}

View File

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

View File

@ -27,7 +27,6 @@ class CapturePoint {
int accelerationY;
int accelerationZ;
// @Property(type: PropertyType.date)
int millisecondsSinceEpochReceived;
int millisecondsSinceEpochSend;
}

View File

@ -14,6 +14,7 @@ class ConnectedView extends StatelessWidget {
title: const Text('Xiao Connector'),
),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -24,18 +25,27 @@ Now you can open the live feed.''',
textAlign: TextAlign.center,
),
const SizedBox(
height: 8,
height: 48,
),
ElevatedButton(
onPressed: () {
context.read<XiaoConnectorCubit>().startCapturing();
// context.read<XiaoConnectorCubit>().setCapturingOn();
},
child: const Text('Open Live Feed'),
),
const SizedBox(
height: 48,
),
ElevatedButton(
onPressed: () {
context.read<XiaoConnectorCubit>().disconnectDevice();
},
child: const Text('Disconnect'),
),
],
),
),
),
);
}
}

View File

@ -5,6 +5,6 @@ class FailureView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Text('Failure');
return const Text('Oops. Something bad happened! :(');
}
}

View File

@ -2,6 +2,7 @@ package main
import (
"encoding/binary"
"fmt"
"machine"
"time"