Files
MatchLiveTv/mobile/lib/features/matches/schedule_match_sheet.dart
Emiliano Frascaro f4b7be0f80 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>
2026-05-29 07:23:13 +02:00

177 lines
5.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../app/theme.dart';
import '../../shared/widgets/primary_cta.dart';
class ScheduleMatchResult {
ScheduleMatchResult({
required this.opponentName,
required this.scheduledAt,
this.location,
});
final String opponentName;
final DateTime scheduledAt;
final String? location;
}
Future<ScheduleMatchResult?> showScheduleMatchSheet(
BuildContext context, {
String? teamName,
}) {
return showModalBottomSheet<ScheduleMatchResult>(
context: context,
isScrollControlled: true,
backgroundColor: AppTheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (ctx) => _ScheduleMatchSheet(teamName: teamName),
);
}
class _ScheduleMatchSheet extends StatefulWidget {
const _ScheduleMatchSheet({this.teamName});
final String? teamName;
@override
State<_ScheduleMatchSheet> createState() => _ScheduleMatchSheetState();
}
class _ScheduleMatchSheetState extends State<_ScheduleMatchSheet> {
final _opponentController = TextEditingController();
final _locationController = TextEditingController();
late DateTime _scheduledAt;
@override
void initState() {
super.initState();
final now = DateTime.now();
_scheduledAt = DateTime(now.year, now.month, now.day, now.hour + 2, 0);
if (_scheduledAt.isBefore(now)) {
_scheduledAt = now.add(const Duration(hours: 2));
}
}
@override
void dispose() {
_opponentController.dispose();
_locationController.dispose();
super.dispose();
}
Future<void> _pickDateTime() async {
final date = await showDatePicker(
context: context,
initialDate: _scheduledAt,
firstDate: DateTime.now().subtract(const Duration(days: 1)),
lastDate: DateTime.now().add(const Duration(days: 365)),
);
if (date == null || !mounted) return;
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_scheduledAt),
);
if (time == null) return;
setState(() {
_scheduledAt = DateTime(date.year, date.month, date.day, time.hour, time.minute);
});
}
void _submit() {
final opponent = _opponentController.text.trim();
if (opponent.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Inserisci il nome dellavversario')),
);
return;
}
Navigator.pop(
context,
ScheduleMatchResult(
opponentName: opponent,
scheduledAt: _scheduledAt,
location: _locationController.text.trim().isEmpty
? null
: _locationController.text.trim(),
),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final dateLabel = DateFormat('EEE d MMM yyyy · HH:mm', 'it_IT')
.format(_scheduledAt.toLocal());
final bottom = MediaQuery.paddingOf(context).bottom;
return Padding(
padding: EdgeInsets.fromLTRB(20, 12, 20, 20 + bottom),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: AppTheme.textSecondary.withValues(alpha: 0.4),
borderRadius: BorderRadius.circular(2),
),
),
),
const SizedBox(height: 16),
Text('Programma partita', style: theme.textTheme.titleLarge),
if (widget.teamName != null && widget.teamName!.isNotEmpty) ...[
const SizedBox(height: 4),
Text(
widget.teamName!,
style: theme.textTheme.titleSmall?.copyWith(
color: AppTheme.primaryRed,
fontWeight: FontWeight.w600,
),
),
],
const SizedBox(height: 6),
Text(
'La diretta non parte ora: comparirà sul sito con data e ora. '
'Avvierai lo streaming dallapp quando sei in palestra.',
style: theme.textTheme.bodySmall,
),
const SizedBox(height: 20),
TextField(
controller: _opponentController,
decoration: const InputDecoration(labelText: 'Avversario'),
textCapitalization: TextCapitalization.words,
),
const SizedBox(height: 12),
TextField(
controller: _locationController,
decoration: const InputDecoration(labelText: 'Luogo (opzionale)'),
),
const SizedBox(height: 12),
ListTile(
contentPadding: EdgeInsets.zero,
title: Text('Data e ora', style: theme.textTheme.bodyMedium),
subtitle: Text(dateLabel, style: theme.textTheme.titleMedium),
trailing: const Icon(Icons.calendar_today, color: AppTheme.primaryRed),
onTap: _pickDateTime,
),
const SizedBox(height: 20),
PrimaryCta(
label: 'SALVA IN PROGRAMMA',
icon: Icons.event_available,
onPressed: _submit,
),
],
),
);
}
}