Link between front-end and back-end

This commit is contained in:
2025-07-09 12:41:00 +02:00
parent 6735ddb5fd
commit 1b261c08bb
31 changed files with 5507 additions and 40 deletions

View File

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:rtime/models/battery.dart';
import 'package:rtime/images_manager.dart';
class BatteryCard extends StatelessWidget {
final Battery battery;
final VoidCallback? onTap;
const BatteryCard({
super.key,
required this.battery,
this.onTap,
});
@override
Widget build(BuildContext context) {
final BorderRadius cardBorderRadius =
Theme.of(context).cardTheme.shape is RoundedRectangleBorder
? (Theme.of(context).cardTheme.shape as RoundedRectangleBorder).borderRadius as BorderRadius
: BorderRadius.circular(12);
return Card(
margin: const EdgeInsets.only(right: 16),
child: InkWell(
onTap: onTap,
borderRadius: cardBorderRadius,
child: ClipRRect(
borderRadius: cardBorderRadius,
child: SizedBox(
width: 140,
height: 170,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Colors.blueGrey[700]
: Colors.grey[200],
borderRadius: BorderRadius.circular(12),
),
child: battery.imageUuid != null && battery.imageUuid!.isNotEmpty
? FutureBuilder<Image?>(
future: ImagesManager.instance.loadImage(battery.imageUuid!),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator(color: Colors.tealAccent));
} else if (snapshot.hasError || !snapshot.hasData || snapshot.data == null) {
return Icon(Icons.broken_image, size: 50, color: Colors.blueGrey[400]);
} else {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: snapshot.data!,
);
}
},
)
: Icon(Icons.battery_charging_full, size: 50, color: Theme.of(context).brightness == Brightness.dark ? Colors.tealAccent : Colors.green.shade400),
),
const SizedBox(height: 10),
Text(
battery.name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
'${battery.voltage}V - ${battery.type}',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).brightness == Brightness.dark ? Colors.white70 : Colors.black54),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,82 @@
import 'package:flutter/material.dart';
import 'package:rtime/models/drone.dart';
import 'package:rtime/images_manager.dart';
class DroneCard extends StatelessWidget {
final Drone drone;
final VoidCallback? onTap;
const DroneCard({
super.key,
required this.drone,
this.onTap,
});
@override
Widget build(BuildContext context) {
final BorderRadius cardBorderRadius =
Theme.of(context).cardTheme.shape is RoundedRectangleBorder
? (Theme.of(context).cardTheme.shape as RoundedRectangleBorder).borderRadius as BorderRadius
: BorderRadius.circular(12);
return Card(
margin: const EdgeInsets.only(right: 16),
child: InkWell(
onTap: onTap,
borderRadius: cardBorderRadius,
child: ClipRRect(
borderRadius: cardBorderRadius,
child: SizedBox(
width: 140,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Colors.blueGrey[700]
: Colors.grey[200],
borderRadius: BorderRadius.circular(12),
),
child: drone.imageUuid != null && drone.imageUuid!.isNotEmpty
? FutureBuilder<Image?>(
future: ImagesManager.instance.loadImage(drone.imageUuid!),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator(color: Colors.lightBlueAccent));
} else if (snapshot.hasError || !snapshot.hasData || snapshot.data == null) {
return Icon(Icons.broken_image, size: 50, color: Colors.blueGrey[400]);
} else {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: snapshot.data!,
);
}
},
)
: Icon(Icons.airplanemode_active, size: 50, color: Theme.of(context).brightness == Brightness.dark ? Colors.lightBlueAccent : Colors.blue.shade400),
),
const SizedBox(height: 10),
Text(
drone.name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
class FadePageRoute extends PageRouteBuilder {
final Widget page;
FadePageRoute({required this.page})
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
page,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
FadeTransition(
opacity: animation,
child: child,
),
);
}
class SlideRightPageRoute extends PageRouteBuilder {
final Widget page;
SlideRightPageRoute({required this.page})
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
page,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}
class SlideUpPageRoute extends PageRouteBuilder {
final Widget page;
SlideUpPageRoute({required this.page})
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
page,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.easeOut;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}