Rails API, app Flutter, infrastruttura Docker/MediaMTX, sito marketing e documentazione di deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
159 lines
5.2 KiB
Dart
159 lines
5.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../app/theme.dart';
|
|
import '../../shared/models/score_state.dart';
|
|
import '../../shared/widgets/destructive_cta.dart';
|
|
import '../../shared/widgets/live_badge.dart';
|
|
import '../../shared/widgets/metric_card.dart';
|
|
import '../../shared/widgets/score_overlay_bar.dart';
|
|
import '../../platform/streaming_preview.dart';
|
|
|
|
class CameraScreenPortrait extends StatelessWidget {
|
|
const CameraScreenPortrait({
|
|
super.key,
|
|
required this.elapsed,
|
|
required this.batteryLevel,
|
|
required this.homeName,
|
|
required this.awayName,
|
|
required this.score,
|
|
required this.networkType,
|
|
required this.bitrateMbps,
|
|
required this.fps,
|
|
required this.viewerCount,
|
|
required this.sessionId,
|
|
this.platformLabel = 'LIVE',
|
|
required this.onStop,
|
|
});
|
|
|
|
final Duration elapsed;
|
|
final int batteryLevel;
|
|
final String homeName;
|
|
final String awayName;
|
|
final ScoreState score;
|
|
final String networkType;
|
|
final double bitrateMbps;
|
|
final int fps;
|
|
final int viewerCount;
|
|
final String sessionId;
|
|
final String platformLabel;
|
|
final VoidCallback onStop;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
|
|
return Scaffold(
|
|
backgroundColor: AppTheme.background,
|
|
body: SafeArea(
|
|
child: Column(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
child: Row(
|
|
children: [
|
|
LiveBadge(elapsed: elapsed),
|
|
const Spacer(),
|
|
const Icon(Icons.battery_std, size: 18, color: AppTheme.textSecondary),
|
|
const SizedBox(width: 4),
|
|
Text('$batteryLevel%', style: theme.textTheme.labelLarge),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 3,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: NativeStreamingPreview(
|
|
showGrid: true,
|
|
platformLabel: platformLabel,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: ScoreOverlayBar(
|
|
homeName: homeName,
|
|
awayName: awayName,
|
|
homePoints: score.homePoints,
|
|
awayPoints: score.awayPoints,
|
|
currentSet: score.currentSet,
|
|
homeSets: score.homeSets,
|
|
awaySets: score.awaySets,
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: Row(
|
|
children: [
|
|
MetricCard(
|
|
label: 'Segnale',
|
|
value: networkType,
|
|
icon: Icons.signal_cellular_alt,
|
|
),
|
|
const SizedBox(width: 8),
|
|
MetricCard(
|
|
label: 'Mbps',
|
|
value: bitrateMbps.toStringAsFixed(1),
|
|
icon: Icons.speed,
|
|
),
|
|
const SizedBox(width: 8),
|
|
MetricCard(label: 'fps', value: '$fps', icon: Icons.movie),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.surface,
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.play_circle, color: AppTheme.primaryRed),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(platformLabel, style: theme.textTheme.titleMedium),
|
|
Text(
|
|
viewerCount > 0
|
|
? '$viewerCount spettatori'
|
|
: 'IN DIRETTA',
|
|
style: theme.textTheme.bodyMedium,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
|
child: Text(
|
|
'Registrazione locale attiva: /sd/match_$sessionId',
|
|
style: theme.textTheme.bodyMedium?.copyWith(fontSize: 11),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: DestructiveCta(label: 'INTERROMPI', onPressed: onStop),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|