Billing Stripe, link regia mobile e staff solo trasmissione.

Aggiunge fatturazione club, pagina regia condivisibile senza account, roster squadre e rimuove la modalità controller dall'app (v1.1.0).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 07:23:13 +02:00
parent 4083bc5dee
commit f4b7be0f80
156 changed files with 5033 additions and 2033 deletions

View File

@@ -1,10 +1,8 @@
import 'package:flutter/material.dart';
import '../../app/theme.dart';
import '../../features/controller_mode/controller_screen.dart';
import 'score_overlay_bar.dart';
/// Controlli punteggio per overlay camera (portrait e landscape).
/// Punteggio in sola lettura sulla camera (la regia avviene via link web).
class CameraScoreControls extends StatelessWidget {
const CameraScoreControls({
super.key,
@@ -15,11 +13,6 @@ class CameraScoreControls extends StatelessWidget {
required this.currentSet,
required this.homeSets,
required this.awaySets,
required this.onHomePoint,
required this.onAwayPoint,
required this.onHomeMinus,
required this.onAwayMinus,
required this.onCloseSet,
this.lastDelta,
this.compact = false,
this.pointsTarget,
@@ -32,85 +25,10 @@ class CameraScoreControls extends StatelessWidget {
final int currentSet;
final int homeSets;
final int awaySets;
final VoidCallback onHomePoint;
final VoidCallback onAwayPoint;
final VoidCallback onHomeMinus;
final VoidCallback onAwayMinus;
final VoidCallback onCloseSet;
final int? lastDelta;
final bool compact;
final int? pointsTarget;
@override
Widget build(BuildContext context) {
if (compact) {
return _LandscapeControls(
homeName: homeName,
awayName: awayName,
homePoints: homePoints,
awayPoints: awayPoints,
currentSet: currentSet,
homeSets: homeSets,
awaySets: awaySets,
lastDelta: lastDelta,
pointsTarget: pointsTarget,
onHomePoint: onHomePoint,
onAwayPoint: onAwayPoint,
onHomeMinus: onHomeMinus,
onAwayMinus: onAwayMinus,
onCloseSet: onCloseSet,
);
}
return _PortraitControls(
homeName: homeName,
awayName: awayName,
homePoints: homePoints,
awayPoints: awayPoints,
currentSet: currentSet,
homeSets: homeSets,
awaySets: awaySets,
pointsTarget: pointsTarget,
onHomePoint: onHomePoint,
onAwayPoint: onAwayPoint,
onHomeMinus: onHomeMinus,
onAwayMinus: onAwayMinus,
onCloseSet: onCloseSet,
);
}
}
class _PortraitControls extends StatelessWidget {
const _PortraitControls({
required this.homeName,
required this.awayName,
required this.homePoints,
required this.awayPoints,
required this.currentSet,
required this.homeSets,
required this.awaySets,
required this.onHomePoint,
required this.onAwayPoint,
required this.onHomeMinus,
required this.onAwayMinus,
required this.onCloseSet,
this.pointsTarget,
});
final String homeName;
final String awayName;
final int homePoints;
final int awayPoints;
final int currentSet;
final int homeSets;
final int awaySets;
final VoidCallback onHomePoint;
final VoidCallback onAwayPoint;
final VoidCallback onHomeMinus;
final VoidCallback onAwayMinus;
final VoidCallback onCloseSet;
final int? pointsTarget;
@override
Widget build(BuildContext context) {
return Column(
@@ -125,179 +43,19 @@ class _PortraitControls extends StatelessWidget {
currentSet: currentSet,
homeSets: homeSets,
awaySets: awaySets,
pointsTarget: pointsTarget,
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
child: ScoreTapButton(label: '+1 $homeName', onTap: onHomePoint, large: true),
),
const SizedBox(width: 8),
Expanded(
child: ScoreTapButton(label: '+1 $awayName', onTap: onAwayPoint, large: true),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: homePoints > 0 ? onHomeMinus : null,
child: Text('-1 $homeName', style: const TextStyle(fontSize: 12)),
),
),
const SizedBox(width: 8),
Expanded(
child: OutlinedButton(
onPressed: awayPoints > 0 ? onAwayMinus : null,
child: Text('-1 $awayName', style: const TextStyle(fontSize: 12)),
),
),
],
),
const SizedBox(height: 8),
YellowActionButton(label: 'Chiudi set', onPressed: onCloseSet),
],
);
}
}
class _LandscapeControls extends StatelessWidget {
const _LandscapeControls({
required this.homeName,
required this.awayName,
required this.homePoints,
required this.awayPoints,
required this.currentSet,
required this.homeSets,
required this.awaySets,
required this.onHomePoint,
required this.onAwayPoint,
required this.onHomeMinus,
required this.onAwayMinus,
required this.onCloseSet,
this.lastDelta,
this.pointsTarget,
});
final String homeName;
final String awayName;
final int homePoints;
final int awayPoints;
final int currentSet;
final int homeSets;
final int awaySets;
final VoidCallback onHomePoint;
final VoidCallback onAwayPoint;
final VoidCallback onHomeMinus;
final VoidCallback onAwayMinus;
final VoidCallback onCloseSet;
final int? lastDelta;
final int? pointsTarget;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
ScoreOverlayBar(
homeName: homeName,
awayName: awayName,
homePoints: homePoints,
awayPoints: awayPoints,
currentSet: currentSet,
homeSets: homeSets,
awaySets: awaySets,
compact: true,
compact: compact,
lastDelta: lastDelta,
pointsTarget: pointsTarget,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(child: _CompactScoreBtn(label: '+1', sub: homeName, onTap: onHomePoint)),
const SizedBox(width: 6),
Expanded(child: _CompactScoreBtn(label: '+1', sub: awayName, onTap: onAwayPoint)),
const SizedBox(width: 6),
Expanded(
child: _CompactScoreBtn(
label: '-1',
sub: homeName,
onTap: homePoints > 0 ? onHomeMinus : null,
muted: true,
),
),
const SizedBox(width: 6),
Expanded(
child: _CompactScoreBtn(
label: '-1',
sub: awayName,
onTap: awayPoints > 0 ? onAwayMinus : null,
muted: true,
),
),
],
),
const SizedBox(height: 6),
YellowActionButton(label: 'Chiudi set', onPressed: onCloseSet),
if (!compact) ...[
const SizedBox(height: 8),
Text(
'Punteggio: condividi il link regia con chi gestisce il tabellone.',
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.white54),
textAlign: TextAlign.center,
),
],
],
);
}
}
class _CompactScoreBtn extends StatelessWidget {
const _CompactScoreBtn({
required this.label,
required this.sub,
required this.onTap,
this.muted = false,
});
final String label;
final String sub;
final VoidCallback? onTap;
final bool muted;
@override
Widget build(BuildContext context) {
final enabled = onTap != null;
return Material(
color: muted
? Colors.black.withValues(alpha: enabled ? 0.65 : 0.35)
: AppTheme.primaryRed.withValues(alpha: enabled ? 0.92 : 0.45),
borderRadius: BorderRadius.circular(10),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(10),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
label,
style: TextStyle(
color: enabled ? Colors.white : Colors.white38,
fontWeight: FontWeight.w900,
fontSize: 18,
),
),
Text(
sub,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: enabled ? Colors.white70 : Colors.white30,
fontSize: 9,
),
),
],
),
),
),
);
}
}