Initial commit: monorepo Match Live TV.

Rails API, app Flutter, infrastruttura Docker/MediaMTX, sito marketing e documentazione di deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-26 17:45:37 +02:00
commit bba6df52c0
381 changed files with 20599 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
import '../models/match.dart';
/// Lato che ha vinto set o partita.
enum ScoringSide { home, away }
/// Regole punteggio (pallavolo di default, campi sovrascrivibili per tornei).
class MatchScoringRules {
const MatchScoringRules({
required this.setsToWin,
this.pointsPerSet = 25,
this.pointsDecidingSet = 15,
this.minPointLead = 2,
});
final int setsToWin;
final int pointsPerSet;
final int pointsDecidingSet;
final int minPointLead;
int get maxSets => (setsToWin * 2) - 1;
factory MatchScoringRules.fromMatch(MatchModel match) {
final overrides = match.scoringRules;
return MatchScoringRules(
setsToWin: match.setsToWin,
pointsPerSet: overrides?['points_per_set'] as int? ?? 25,
pointsDecidingSet: overrides?['points_deciding_set'] as int? ?? 15,
minPointLead: overrides?['min_point_lead'] as int? ?? 2,
);
}
Map<String, dynamic> toJson() => {
'points_per_set': pointsPerSet,
'points_deciding_set': pointsDecidingSet,
'min_point_lead': minPointLead,
};
/// Punti necessari per chiudere il set corrente.
int pointsTarget(int currentSet) {
if (currentSet >= maxSets) return pointsDecidingSet;
return pointsPerSet;
}
/// Chi ha vinto il set in corso in base ai punti (null se ancora aperto).
ScoringSide? setWinnerFromPoints({
required int homePoints,
required int awayPoints,
required int currentSet,
}) {
final target = pointsTarget(currentSet);
final lead = minPointLead;
if (homePoints >= target && homePoints - awayPoints >= lead) {
return ScoringSide.home;
}
if (awayPoints >= target && awayPoints - homePoints >= lead) {
return ScoringSide.away;
}
return null;
}
bool isMatchOver({required int homeSets, required int awaySets}) {
return homeSets >= setsToWin || awaySets >= setsToWin;
}
ScoringSide? matchWinner({required int homeSets, required int awaySets}) {
if (homeSets >= setsToWin) return ScoringSide.home;
if (awaySets >= setsToWin) return ScoringSide.away;
return null;
}
}