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,174 @@
|
||||
import 'player.dart';
|
||||
|
||||
class TeamStatus {
|
||||
TeamStatus._();
|
||||
static const String pending = 'pending';
|
||||
static const String approved = 'approved';
|
||||
static const String rejected = 'rejected';
|
||||
|
||||
static String normalize(String? raw) {
|
||||
switch (raw) {
|
||||
case pending:
|
||||
case approved:
|
||||
case rejected:
|
||||
return raw!;
|
||||
default:
|
||||
return approved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Team {
|
||||
const Team({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.logoUrl,
|
||||
this.description,
|
||||
this.wins = 0,
|
||||
this.losses = 0,
|
||||
this.draws = 0,
|
||||
this.players = const <Player>[],
|
||||
this.primaryColor,
|
||||
this.managerId,
|
||||
this.managerEmail = '',
|
||||
this.managerPhone,
|
||||
this.status = TeamStatus.approved,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final String? logoUrl;
|
||||
final String? description;
|
||||
final int wins;
|
||||
final int losses;
|
||||
final int draws;
|
||||
final List<Player> players;
|
||||
final String? primaryColor;
|
||||
final String? managerId;
|
||||
final String managerEmail;
|
||||
final String? managerPhone;
|
||||
final String status;
|
||||
|
||||
bool get isApproved => status == TeamStatus.approved;
|
||||
bool get isPending => status == TeamStatus.pending;
|
||||
bool get isRejected => status == TeamStatus.rejected;
|
||||
|
||||
int get totalGames => wins + losses + draws;
|
||||
String get record => '$wins-$losses-$draws';
|
||||
double get winPercentage => totalGames == 0 ? 0 : wins / totalGames;
|
||||
|
||||
Player? get topScorer {
|
||||
if (players.isEmpty) return null;
|
||||
Player best = players.first;
|
||||
for (final p in players) {
|
||||
if (p.goalsScored > best.goalsScored) best = p;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
Team copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
String? logoUrl,
|
||||
String? description,
|
||||
int? wins,
|
||||
int? losses,
|
||||
int? draws,
|
||||
List<Player>? players,
|
||||
String? primaryColor,
|
||||
String? managerId,
|
||||
String? managerEmail,
|
||||
String? managerPhone,
|
||||
String? status,
|
||||
}) {
|
||||
return Team(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
logoUrl: logoUrl ?? this.logoUrl,
|
||||
description: description ?? this.description,
|
||||
wins: wins ?? this.wins,
|
||||
losses: losses ?? this.losses,
|
||||
draws: draws ?? this.draws,
|
||||
players: players ?? this.players,
|
||||
primaryColor: primaryColor ?? this.primaryColor,
|
||||
managerId: managerId ?? this.managerId,
|
||||
managerEmail: managerEmail ?? this.managerEmail,
|
||||
managerPhone: managerPhone ?? this.managerPhone,
|
||||
status: status ?? this.status,
|
||||
);
|
||||
}
|
||||
|
||||
factory Team.fromJson(Map<String, dynamic> data) {
|
||||
final rawPlayers = (data['players'] as List?) ?? const [];
|
||||
return Team(
|
||||
id: (data['id'] as String?) ?? '',
|
||||
name: (data['name'] as String?) ?? '',
|
||||
logoUrl: data['logo_url'] as String?,
|
||||
description: data['description'] as String?,
|
||||
wins: (data['wins'] as num?)?.toInt() ?? 0,
|
||||
losses: (data['losses'] as num?)?.toInt() ?? 0,
|
||||
draws: (data['draws'] as num?)?.toInt() ?? 0,
|
||||
players: rawPlayers
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(Player.fromMap)
|
||||
.toList(growable: false),
|
||||
primaryColor: data['primary_color'] as String?,
|
||||
managerId: data['manager_id'] as String?,
|
||||
managerEmail: (data['manager_email'] as String?) ?? '',
|
||||
managerPhone: data['manager_phone'] as String?,
|
||||
status: TeamStatus.normalize(data['status'] as String?),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, Object?> toJson() {
|
||||
return <String, Object?>{
|
||||
'name': name,
|
||||
'logo_url': logoUrl,
|
||||
'description': description,
|
||||
'wins': wins,
|
||||
'losses': losses,
|
||||
'draws': draws,
|
||||
'primary_color': primaryColor,
|
||||
'manager_id': managerId,
|
||||
'manager_email': managerEmail,
|
||||
'manager_phone': managerPhone,
|
||||
'status': status,
|
||||
'players': players.map((p) => p.toMap()).toList(growable: false),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! Team) return false;
|
||||
if (other.id != id) return false;
|
||||
if (other.name != name) return false;
|
||||
if (other.logoUrl != logoUrl) return false;
|
||||
if (other.description != description) return false;
|
||||
if (other.wins != wins) return false;
|
||||
if (other.losses != losses) return false;
|
||||
if (other.draws != draws) return false;
|
||||
if (other.primaryColor != primaryColor) return false;
|
||||
if (other.managerId != managerId) return false;
|
||||
if (other.managerEmail != managerEmail) return false;
|
||||
if (other.managerPhone != managerPhone) return false;
|
||||
if (other.status != status) return false;
|
||||
if (other.players.length != players.length) return false;
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
if (other.players[i] != players[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
id, name, logoUrl, description, wins, losses, draws,
|
||||
primaryColor, managerId, managerEmail, managerPhone,
|
||||
status, Object.hashAll(players),
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Team(id: $id, name: $name, status: $status, record: $record, '
|
||||
'players: ${players.length})';
|
||||
}
|
||||
Reference in New Issue
Block a user