diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 749fe70..8fa1f0e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,3 +1,6 @@ +import java.util.Properties +import java.io.FileInputStream + plugins { id("com.android.application") id("kotlin-android") @@ -5,6 +8,12 @@ plugins { id("dev.flutter.flutter-gradle-plugin") } +val keystoreProperties = Properties() +val keystorePropertiesFile = rootProject.file("key.properties") +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} + android { namespace = "com.example.marscar_controller" compileSdk = flutter.compileSdkVersion @@ -21,7 +30,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.marscar_controller" + applicationId = "cn.meowdream.marscar_controller" // 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 @@ -30,6 +39,14 @@ android { versionName = flutter.versionName } + signingConfigs { + create("release") { + keyAlias = keystoreProperties["keyAlias"] as String + keyPassword = keystoreProperties["keyPassword"] as String + storeFile = keystoreProperties["storeFile"]?.let { file(it) } + storePassword = keystoreProperties["storePassword"] as String + } + } buildTypes { release { // TODO: Add your own signing config for the release build. diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 71d2a1d..6a928d0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html index f888738..023a344 100644 --- a/android/build/reports/problems/problems-report.html +++ b/android/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..bba8451 Binary files /dev/null and b/assets/images/logo.png differ diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index d6d370a..6bfed04 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -34,8 +34,8 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { - carIpController.text = '192.168.137.122'; - cameraIpController.text = '192.168.137.138'; + carIpController.text = '192.168.137.34'; + cameraIpController.text = '192.168.137.121'; GlobalSettingState globalSettingState = context.watch(); return Scaffold( body: globalSettingState.cameraIP != '' && globalSettingState.carIP != '' ? diff --git a/lib/pages/player_page.dart b/lib/pages/player_page.dart index ca92d64..f785e03 100644 --- a/lib/pages/player_page.dart +++ b/lib/pages/player_page.dart @@ -10,6 +10,7 @@ import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:provider/provider.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:marscar_controller/pages/square_joystick.dart'; class PlayerPage extends StatefulWidget { const PlayerPage({super.key}); @@ -26,7 +27,7 @@ class _PlayerPageState extends State { Timer? _reconnectionTimer; - final int callBackPeriod = 20; + final int callBackPeriod = 10; RawDatagramSocket? _udpSocket; @@ -52,12 +53,11 @@ class _PlayerPageState extends State { Timer? _connectionHealthTimer; DateTime? _lastMessageReceivedTime; - String _fpsInfo = 'FPS: N/A'; String _bitrateInfo = '速率: N/A'; Timer? _infoTimer; - double maxPawRateScale = 1.0; - Set _pawScaleSelection = {1.0}; + double maxPawRateScale = 0.35; + Set _pawScaleSelection = {0.35}; @override void initState() { @@ -196,16 +196,10 @@ class _PlayerPageState extends State { final nativePlayer = player.platform as NativePlayer; try { final bitrate = await nativePlayer.getProperty('video-bitrate'); - final fps = await nativePlayer.getProperty('video-fps'); - if (mounted) { setState(() { final bitrateInKbps = (double.tryParse(bitrate) ?? 0) / 1024; _bitrateInfo = '速率: ${bitrateInKbps.toStringAsFixed(0)} Kbps'; - final double? fpsValue = double.tryParse(fps); - if (fpsValue != null) { - _fpsInfo = 'FPS: ${fpsValue.toStringAsFixed(1)}'; - } }); } } catch (e) { @@ -317,7 +311,7 @@ class _PlayerPageState extends State { final avgLatency = _latencyReadings.reduce((a, b) => a + b) / _latencyReadings.length; if (mounted) { setState(() { - _pingResult = '图传延迟: ${avgLatency.toStringAsFixed(0)} ms'; + _pingResult = '图传信号延迟: ${avgLatency.toStringAsFixed(0)} ms'; _videoLatencyHistory.add(FlSpot(DateTime.now().millisecondsSinceEpoch.toDouble(), avgLatency)); if (_videoLatencyHistory.length > _maxHistoryCount) { @@ -412,7 +406,7 @@ class _PlayerPageState extends State { left: 0, child: Center( child: Container( - width: 300, + width: 400, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), @@ -422,7 +416,7 @@ class _PlayerPageState extends State { collapsedIconColor: Colors.white, iconColor: Colors.white, title: Text( - '$_pingResult $_bitrateInfo $_fpsInfo\n$_controlLatencyResult', + '$_pingResult $_bitrateInfo\n$_controlLatencyResult', style: const TextStyle(color: Colors.white, fontSize: 12), textAlign: TextAlign.center, ), @@ -438,7 +432,7 @@ class _PlayerPageState extends State { ), const SizedBox(height: 8), SizedBox( - height: 120, + height: 80, child: LineChart( LineChartData( lineBarsData: [ @@ -505,7 +499,7 @@ class _PlayerPageState extends State { ), const SizedBox(height: 8), SizedBox( - height: 120, + height: 80, child: LineChart( LineChartData( lineBarsData: [ @@ -569,160 +563,86 @@ class _PlayerPageState extends State { Positioned( left: 64, bottom: 32, - child: Joystick( - includeInitialAnimation: false, - period: Duration(milliseconds: callBackPeriod), - stick: CircleAvatar( - radius: 20, - backgroundColor: Color.fromARGB(200, 255, 255, 255), + child: SizedBox( + width: 160, + height: 160, + child: SquareJoystick( + onChanged: (Offset position) { + setState(() { + lx = position.dx * 127 + 127.5; + ly = position.dy * 127 + 127.5; + }); + }, ), - base: JoystickSquareBase( - size: 160, - decoration: JoystickBaseDecoration( - color: Color.fromARGB(60, 200, 200, 200), - ) - ), - stickOffsetCalculator: const RectangleStickOffsetCalculator(), - listener: (details) { - setState(() { - lx = details.x * 127 + 127.5; - ly = details.y * 127 + 127.5; - }); - }, ), ), Positioned( right: 128, bottom: 180, - child: Joystick( - includeInitialAnimation: false, - period: Duration(milliseconds: callBackPeriod), - stick: CircleAvatar( - radius: 20, - backgroundColor: Color.fromARGB(200, 255, 255, 255), + child: SizedBox( + width: 160, + height: 160, + child: Joystick2D( + onChanged: (Offset position) { + if(position.dx == 0 && position.dy == 0) { + left = right = forward = backward = 0; + } else { + var angle = -atan2(position.dy, position.dx), pi_18 = pi / 18.0; + setState(() { + left = angle < - pi_18 * 12 || angle > pi_18 * 12 ? position.dx * maxPawRateScale : 0; + right = angle > - pi_18 * 6 && angle < pi_18 * 6 ? position.dx * maxPawRateScale : 0; + forward = angle > pi_18 * 3 && angle < pi_18 * 15 ? -position.dy * maxPawRateScale : 0; + backward = angle > - pi_18 * 15 && angle < - pi_18 * 3 ? -position.dy * maxPawRateScale : 0; + }); + } + }, ), - base: Container( - width: 160, - height: 160, - decoration: BoxDecoration( - color: Color.fromARGB(60, 200, 200, 200), - shape: BoxShape.circle, - border: BoxBorder.all( - color: Theme.of(context).colorScheme.outline, - width: 1 - ) - ), - ), - listener: (details) { - if(details.x == 0 && details.y == 0) { - left = right = forward = backward = 0; - } else { - var angle = -atan2(details.y, details.x), pi_18 = pi / 18.0; - setState(() { - left = angle < - pi_18 * 12 || angle > pi_18 * 12 ? details.x * maxPawRateScale : 0; - right = angle > - pi_18 * 6 && angle < pi_18 * 6 ? details.x * maxPawRateScale : 0; - forward = angle > pi_18 * 3 && angle < pi_18 * 15 ? -details.y * maxPawRateScale : 0; - backward = angle > - pi_18 * 15 && angle < - pi_18 * 3 ? -details.y * maxPawRateScale : 0; - }); - } - }, ), ), Positioned( bottom: 180, - right: 64, - child: Joystick( - includeInitialAnimation: false, - period: Duration(milliseconds: callBackPeriod), - mode: JoystickMode.vertical, - stick: CircleAvatar( - radius: 20, - backgroundColor: Color.fromARGB(200, 255, 255, 255), + right: 54, + child: SizedBox( + width: 60, + height: 160, + child: VerticalJoystick( + onChanged: (double y) { + setState(() { + up = y < 0 ? -y * maxPawRateScale * 0.6 : 0; + down = y > 0 ? -y * maxPawRateScale * 0.6 : 0; + }); + }, ), - base: Container( - width: 32, - height: 160, - decoration: BoxDecoration( - color: Color.fromARGB(60, 255, 255, 255), - borderRadius: const BorderRadius.all( - Radius.circular(20) - ), - border: BoxBorder.all( - color: Theme.of(context).colorScheme.outline, - width: 1 - ) - ) - ), - listener: (details) { - setState(() { - up = details.y < 0 ? -details.y * maxPawRateScale * 0.6 : 0; - down = details.y > 0 ? -details.y * maxPawRateScale * 0.6 : 0; - }); - }, ), ), Positioned( - bottom: 100, + bottom: 90, right: 64, - child: Joystick( - includeInitialAnimation: false, - period: Duration(milliseconds: callBackPeriod), - mode: JoystickMode.horizontal, - stick: CircleAvatar( - radius: 20, - backgroundColor: Color.fromARGB(200, 255, 255, 255), + child: SizedBox( + width: 160, + height: 60, + child: HorizontalJoystick( + onChanged: (double x) { + setState(() { + ry = x * 127 + 127.5; + }); + }, ), - base: Container( - width: 160, - height: 32, - decoration: BoxDecoration( - color: Color.fromARGB(60, 255, 255, 255), - borderRadius: const BorderRadius.all( - Radius.circular(20) - ), - border: BoxBorder.all( - color: Theme.of(context).colorScheme.outline, - width: 1 - ) - ) - ), - listener: (details) { - setState(() { - ry = details.x * 127 + 127.5; - }); - }, ), ), Positioned( - bottom: 40, + bottom: 30, right: 64, - child: Joystick( - includeInitialAnimation: false, - period: Duration(milliseconds: callBackPeriod), - mode: JoystickMode.horizontal, - stick: CircleAvatar( - radius: 20, - backgroundColor: Color.fromARGB(200, 255, 255, 255), + child: SizedBox( + width: 160, + height: 60, + child: HorizontalJoystick( + onChanged: (double x) { + setState(() { + rx = x * 127 / 2 + 127.5; + }); + }, ), - base: Container( - width: 160, - height: 32, - decoration: BoxDecoration( - color: Color.fromARGB(60, 255, 255, 255), - borderRadius: const BorderRadius.all( - Radius.circular(20) - ), - border: BoxBorder.all( - color: Theme.of(context).colorScheme.outline, - width: 1 - ) - ) - ), - listener: (details) { - setState(() { - rx = details.x * 127 / 2 + 127.5; - }); - }, ), ), Positioned( @@ -799,9 +719,9 @@ class _PlayerPageState extends State { child: SegmentedButton( segments: const >[ ButtonSegment(value: 0.05, label: Text('精确')), - ButtonSegment(value: 0.2, label: Text('缓慢')), - ButtonSegment(value: 0.5, label: Text('默认')), - ButtonSegment(value: 1.0, label: Text('狂暴')), + ButtonSegment(value: 0.10, label: Text('缓慢')), + ButtonSegment(value: 0.35, label: Text('默认')), + ButtonSegment(value: 0.5, label: Text('狂暴')), ], selected: _pawScaleSelection, onSelectionChanged: (Set newSelection) { diff --git a/lib/pages/square_joystick.dart b/lib/pages/square_joystick.dart new file mode 100644 index 0000000..f8eb3d5 --- /dev/null +++ b/lib/pages/square_joystick.dart @@ -0,0 +1,478 @@ +import 'package:flutter/material.dart'; + +class Joystick2D extends StatefulWidget { + final ValueChanged onChanged; + + const Joystick2D({ + super.key, + required this.onChanged, + }); + + @override + State createState() => _Joystick2DState(); +} + +class _Joystick2DState extends State { + Offset _stickPosition = Offset.zero; + bool _active = false; + + void _onPanUpdate(Offset localPosition, Size size) { + final center = size.center(Offset.zero); + final delta = localPosition - center; + final distance = delta.distance; + final maxDistance = size.width / 2; + + final constrainedDelta = distance > maxDistance + ? Offset( + delta.dx * maxDistance / distance, + delta.dy * maxDistance / distance, + ) + : delta; + + setState(() { + _stickPosition = constrainedDelta; + _active = true; + }); + + final normalized = Offset( + constrainedDelta.dx / maxDistance, + constrainedDelta.dy / maxDistance, + ); + + widget.onChanged(normalized); + } + + void _resetJoystick() { + setState(() { + _stickPosition = Offset.zero; + _active = false; + }); + widget.onChanged(Offset.zero); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanStart: (details) { + final box = context.findRenderObject() as RenderBox; + final localPosition = box.globalToLocal(details.globalPosition); + _onPanUpdate(localPosition, box.size); + }, + onPanUpdate: (details) { + final box = context.findRenderObject() as RenderBox; + final localPosition = box.globalToLocal(details.globalPosition); + _onPanUpdate(localPosition, box.size); + }, + onPanEnd: (_) => _resetJoystick(), + onPanCancel: _resetJoystick, + child: CustomPaint( + painter: JoystickPainter( + stickPosition: _stickPosition, + active: _active, + ), + ), + ); + } +} + +class JoystickPainter extends CustomPainter { + final Offset stickPosition; + final bool active; + + JoystickPainter({required this.stickPosition, required this.active}); + + @override + void paint(Canvas canvas, Size size) { + final center = size.center(Offset.zero); + final radius = size.width / 2; + const stickRadius = 20.0; + + canvas.drawCircle( + center, + radius, + Paint() + ..color = active ? Colors.white.withValues(alpha: 0.3) : Colors.white.withValues(alpha: 0.1) + ..style = PaintingStyle.fill, + ); + + canvas.drawCircle( + center, + radius, + Paint() + ..color = Colors.grey + ..style = PaintingStyle.stroke + ..strokeWidth = 2.0, + ); + + canvas.drawCircle( + center + stickPosition, + stickRadius, + Paint() + ..color = active ? Colors.white : Colors.grey + ..style = PaintingStyle.fill, + ); + } + + @override + bool shouldRepaint(JoystickPainter oldDelegate) { + return stickPosition != oldDelegate.stickPosition || active != oldDelegate.active; + } +} + +class SquareJoystick extends StatefulWidget { + final ValueChanged onChanged; + + const SquareJoystick({ + super.key, + required this.onChanged, + }); + + @override + State createState() => _SquareJoystickState(); +} + +class _SquareJoystickState extends State { + Offset _stickPosition = Offset.zero; + bool _active = false; + + void _onPanUpdate(Offset localPosition, Size size) { + final center = size.center(Offset.zero); + var dx = localPosition.dx - center.dx; + var dy = localPosition.dy - center.dy; + + final maxDistance = size.width / 2; + dx = dx.clamp(-maxDistance, maxDistance); + dy = dy.clamp(-maxDistance, maxDistance); + + setState(() { + _stickPosition = Offset(dx, dy); + _active = true; + }); + + final normalized = Offset( + dx / maxDistance, + dy / maxDistance, + ); + + widget.onChanged(normalized); + } + + void _resetJoystick() { + setState(() { + _stickPosition = Offset.zero; + _active = false; + }); + widget.onChanged(Offset.zero); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanStart: (details) { + final box = context.findRenderObject() as RenderBox; + final localPosition = box.globalToLocal(details.globalPosition); + _onPanUpdate(localPosition, box.size); + }, + onPanUpdate: (details) { + final box = context.findRenderObject() as RenderBox; + final localPosition = box.globalToLocal(details.globalPosition); + _onPanUpdate(localPosition, box.size); + }, + onPanEnd: (_) => _resetJoystick(), + onPanCancel: _resetJoystick, + child: CustomPaint( + painter: SquareJoystickPainter( + stickPosition: _stickPosition, + active: _active, + ), + ), + ); + } +} + +class SquareJoystickPainter extends CustomPainter { + final Offset stickPosition; + final bool active; + + SquareJoystickPainter({required this.stickPosition, required this.active}); + + @override + @override + void paint(Canvas canvas, Size size) { + final center = size.center(Offset.zero); + const stickRadius = 20.0; + final squareRect = Rect.fromCenter( + center: center, + width: size.width, + height: size.height, + ); + + final roundedRect = RRect.fromRectAndRadius( + squareRect, + Radius.circular(size.width / 8), + ); + + canvas.drawRRect( + roundedRect, + Paint() + ..color = + active ? Colors.white.withValues(alpha: 0.3) : Colors.white.withValues(alpha: 0.1) + ..style = PaintingStyle.fill, + ); + + canvas.drawRRect( + roundedRect, + Paint() + ..color = Colors.grey + ..style = PaintingStyle.stroke + ..strokeWidth = 2.0, + ); + + canvas.drawCircle( + center + stickPosition, + stickRadius, + Paint() + ..color = active ? Colors.white : Colors.grey + ..style = PaintingStyle.fill, + ); + } + + @override + bool shouldRepaint(SquareJoystickPainter oldDelegate) { + return stickPosition != oldDelegate.stickPosition || active != oldDelegate.active; + } +} + +class HorizontalJoystick extends StatefulWidget { + final ValueChanged onChanged; + + const HorizontalJoystick({ + super.key, + required this.onChanged, + }); + + @override + State createState() => _HorizontalJoystickState(); +} + +class _HorizontalJoystickState extends State { + double _stickPosition = 0.0; + bool _active = false; + + void _onPanUpdate(Offset localPosition, Size size) { + final centerX = size.width / 2; + final dx = (localPosition.dx - centerX).clamp(-centerX, centerX); + + setState(() { + _stickPosition = dx; + _active = true; + }); + + final normalized = dx / centerX; + widget.onChanged(normalized); + } + + void _resetJoystick() { + setState(() { + _stickPosition = 0.0; + _active = false; + }); + widget.onChanged(0.0); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanStart: (details) { + final box = context.findRenderObject() as RenderBox; + _onPanUpdate(box.globalToLocal(details.globalPosition), box.size); + }, + onPanUpdate: (details) { + final box = context.findRenderObject() as RenderBox; + _onPanUpdate(box.globalToLocal(details.globalPosition), box.size); + }, + onPanEnd: (_) => _resetJoystick(), + onPanCancel: _resetJoystick, + child: CustomPaint( + painter: HorizontalJoystickPainter( + stickPosition: _stickPosition, + active: _active, + ), + ), + ); + } +} + +class HorizontalJoystickPainter extends CustomPainter { + final double stickPosition; + final bool active; + + HorizontalJoystickPainter({required this.stickPosition, required this.active}); + + @override + void paint(Canvas canvas, Size size) { + final center = size.center(Offset.zero); + const stickRadius = 15.0; + final trackHeight = size.height / 2; + + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: center, + width: size.width, + height: trackHeight, + ), + Radius.circular(trackHeight / 2), + ), + Paint() + ..color = active ? Colors.white.withValues(alpha: 0.3) : Colors.white.withValues(alpha: 0.1), + ); + + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: center, + width: size.width, + height: trackHeight, + ), + Radius.circular(trackHeight / 2), + ), + Paint() + ..color = Colors.grey + ..style = PaintingStyle.stroke + ..strokeWidth = 2.0, + ); + + canvas.drawCircle( + Offset(center.dx + stickPosition, center.dy), + stickRadius * 1.333, + Paint() + ..color = active ? Colors.white : Colors.grey + ..style = PaintingStyle.fill, + ); + } + + @override + bool shouldRepaint(HorizontalJoystickPainter oldDelegate) { + return stickPosition != oldDelegate.stickPosition || active != oldDelegate.active; + } +} + +class VerticalJoystick extends StatefulWidget { + final ValueChanged onChanged; + + const VerticalJoystick({ + super.key, + required this.onChanged, + }); + + @override + State createState() => _VerticalJoystickState(); +} + +class _VerticalJoystickState extends State { + double _stickPosition = 0.0; + bool _active = false; + + void _onPanUpdate(Offset localPosition, Size size) { + final centerY = size.height / 2; + final dy = (localPosition.dy - centerY).clamp(-centerY, centerY); + + setState(() { + _stickPosition = dy; + _active = true; + }); + + final normalized = dy / centerY; + widget.onChanged(normalized); + } + + void _resetJoystick() { + setState(() { + _stickPosition = 0.0; + _active = false; + }); + widget.onChanged(0.0); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanStart: (details) { + final box = context.findRenderObject() as RenderBox; + _onPanUpdate(box.globalToLocal(details.globalPosition), box.size); + }, + onPanUpdate: (details) { + final box = context.findRenderObject() as RenderBox; + _onPanUpdate(box.globalToLocal(details.globalPosition), box.size); + }, + onPanEnd: (_) => _resetJoystick(), + onPanCancel: _resetJoystick, + child: CustomPaint( + painter: VerticalJoystickPainter( + stickPosition: _stickPosition, + active: _active, + ), + ), + ); + } +} + +class VerticalJoystickPainter extends CustomPainter { + final double stickPosition; + final bool active; + + VerticalJoystickPainter({required this.stickPosition, required this.active}); + + @override + void paint(Canvas canvas, Size size) { + final center = size.center(Offset.zero); + const stickRadius = 15.0; + final trackWidth = size.width / 2; + + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: center, + width: trackWidth, + height: size.height, + ), + Radius.circular(trackWidth / 2), + ), + Paint() + ..color = active ? Colors.white.withValues(alpha: 0.3) : Colors.white.withValues(alpha: 0.1), + ); + + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: center, + width: trackWidth, + height: size.height, + ), + Radius.circular(trackWidth / 2), + ), + Paint() + ..color = Colors.grey + ..style = PaintingStyle.stroke + ..strokeWidth = 2.0, + ); + + canvas.drawCircle( + Offset(center.dx, center.dy + stickPosition), + stickRadius * 1.333, + Paint() + ..color = active ? Colors.white : Colors.grey + ..style = PaintingStyle.fill, + ); + } + + @override + bool shouldRepaint(VerticalJoystickPainter oldDelegate) { + return stickPosition != oldDelegate.stickPosition || active != oldDelegate.active; + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index fc37608..eb86177 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,22 @@ 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" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -142,6 +158,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.2" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" + source: hosted + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -184,6 +208,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -565,6 +597,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.4" diff --git a/pubspec.yaml b/pubspec.yaml index e2ade93..a95d9fe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,7 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 + flutter_launcher_icons: "^0.14.4" # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -67,9 +68,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/images/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 467e587..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:marscar_controller/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}