Initial commit: Flutter app + PHP/MySQL backend on Hostinger
Replaces Firebase with a self-hosted PHP/MySQL API served from winded.prymsolutions.com. Includes full backend (schema, auth, events, teams, brackets, suggestions, stats, media, file upload) and updated Flutter repositories and domain models. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../teams/domain/player.dart';
|
||||
import '../../teams/domain/team.dart';
|
||||
import '../../teams/infrastructure/teams_repository.dart';
|
||||
|
||||
part 'stats_notifier.g.dart';
|
||||
|
||||
/// A player paired with the team they belong to. Records are emitted by the
|
||||
/// stats providers so leaderboard rows can show "Player — Team" without doing
|
||||
/// a second lookup.
|
||||
typedef PlayerWithTeam = ({Player player, Team team});
|
||||
|
||||
/// Top scorers across every team, sorted by goals scored (descending). Ties
|
||||
/// are broken by assists, then by player name so the order is deterministic.
|
||||
@riverpod
|
||||
Future<List<PlayerWithTeam>> topScorers(TopScorersRef ref) async {
|
||||
final teams = await ref.watch(teamsStreamProvider.future);
|
||||
final entries = <PlayerWithTeam>[
|
||||
for (final team in teams)
|
||||
for (final player in team.players) (player: player, team: team),
|
||||
];
|
||||
entries.sort((a, b) {
|
||||
final byGoals = b.player.goalsScored.compareTo(a.player.goalsScored);
|
||||
if (byGoals != 0) return byGoals;
|
||||
final byAssists = b.player.assists.compareTo(a.player.assists);
|
||||
if (byAssists != 0) return byAssists;
|
||||
return a.player.name.compareTo(b.player.name);
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
/// Top assisters across every team, sorted by assists (descending). Ties are
|
||||
/// broken by goals, then by player name.
|
||||
@riverpod
|
||||
Future<List<PlayerWithTeam>> topAssisters(TopAssistersRef ref) async {
|
||||
final teams = await ref.watch(teamsStreamProvider.future);
|
||||
final entries = <PlayerWithTeam>[
|
||||
for (final team in teams)
|
||||
for (final player in team.players) (player: player, team: team),
|
||||
];
|
||||
entries.sort((a, b) {
|
||||
final byAssists = b.player.assists.compareTo(a.player.assists);
|
||||
if (byAssists != 0) return byAssists;
|
||||
final byGoals = b.player.goalsScored.compareTo(a.player.goalsScored);
|
||||
if (byGoals != 0) return byGoals;
|
||||
return a.player.name.compareTo(b.player.name);
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
/// League standings: teams sorted by wins (desc), then draws (desc), then by
|
||||
/// fewer losses, then name. The points column shown in the UI is computed as
|
||||
/// `wins * 3 + draws`.
|
||||
@riverpod
|
||||
Future<List<Team>> teamStandings(TeamStandingsRef ref) async {
|
||||
final teams = await ref.watch(teamsStreamProvider.future);
|
||||
final sorted = [...teams];
|
||||
sorted.sort((a, b) {
|
||||
final byWins = b.wins.compareTo(a.wins);
|
||||
if (byWins != 0) return byWins;
|
||||
final byDraws = b.draws.compareTo(a.draws);
|
||||
if (byDraws != 0) return byDraws;
|
||||
final byLosses = a.losses.compareTo(b.losses);
|
||||
if (byLosses != 0) return byLosses;
|
||||
return a.name.compareTo(b.name);
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
Reference in New Issue
Block a user