From 1edb26eb8e4f964527ec4a805a36dd1b854e1732 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:10:54 +0200 Subject: [PATCH] Fix firebase problem (#15) * Add print statements * Solve bug of too frequent firebase fetches * Fix small bug * Fix null update problem in presentation screen --- .../presentation_screen.dart | 4 + .../screens/presentation_screen_knockout.dart | 116 +------------ .../presentation_screen_qualification.dart | 97 +---------- .../widgets/timer_view.dart | 156 ++++++++++++++++-- .../integrals_service/integrals_service.dart | 2 +- 5 files changed, 159 insertions(+), 216 deletions(-) diff --git a/lib/screens/presentation_screen/presentation_screen.dart b/lib/screens/presentation_screen/presentation_screen.dart index 116f17a..ac79fff 100644 --- a/lib/screens/presentation_screen/presentation_screen.dart +++ b/lib/screens/presentation_screen/presentation_screen.dart @@ -50,6 +50,10 @@ class _PresentationScreenState extends State { }); } activeAgendaItemId = widget.activeAgendaItem?.id; + } else { + setState(() { + activeAgendaItem = null; + }); } final settings = Provider.of(context); diff --git a/lib/screens/presentation_screen/screens/presentation_screen_knockout.dart b/lib/screens/presentation_screen/screens/presentation_screen_knockout.dart index d98ffe0..7449a04 100644 --- a/lib/screens/presentation_screen/screens/presentation_screen_knockout.dart +++ b/lib/screens/presentation_screen/screens/presentation_screen_knockout.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; import 'package:integration_bee_helper/models/agenda_item_model/agenda_item_knockout.dart'; @@ -13,7 +11,6 @@ import 'package:integration_bee_helper/screens/presentation_screen/widgets/timer import 'package:integration_bee_helper/screens/presentation_screen/widgets/title_view.dart'; import 'package:integration_bee_helper/services/basic_services/intl_service.dart'; import 'package:integration_bee_helper/widgets/current_integral_stream.dart'; -import 'package:just_audio/just_audio.dart'; class PresentationScreenKnockout extends StatefulWidget { final AgendaItemModelKnockout activeAgendaItem; @@ -36,12 +33,6 @@ class _PresentationScreenKnockoutState extends State { String agendaItemId = ''; - late Timer timer; - Duration timeLeft = Duration.zero; - bool timerRed = false; - - late final AudioPlayer player; - late final ConfettiController competitor1ConfettiController; late final ConfettiController competitor2ConfettiController; @@ -78,11 +69,6 @@ class _PresentationScreenKnockoutState } } - DateTime? get timerStopsAt => widget.activeAgendaItem.timer.timerStopsAt; - - Duration? get pausedTimerDuration => - widget.activeAgendaItem.timer.pausedTimerDuration; - void initialize() async { agendaItemId = widget.activeAgendaItem.id; @@ -93,111 +79,16 @@ class _PresentationScreenKnockoutState void initState() { initialize(); - player = AudioPlayer(); - competitor1ConfettiController = ConfettiController(duration: const Duration(seconds: 10)); competitor2ConfettiController = ConfettiController(duration: const Duration(seconds: 10)); - const timerInterval = Duration(milliseconds: 250); - const timeWarningDuration = Duration(seconds: 30); - - timer = Timer.periodic(timerInterval, (timer) { - switch (problemPhase) { - case ProblemPhase.idle: - competitor1ConfettiController.stop(); - competitor2ConfettiController.stop(); - - if (widget.activeAgendaItem.currentIntegralType == - IntegralType.regular) { - setState(() { - timeLeft = widget.activeAgendaItem.timeLimitPerIntegral; - timerRed = false; - }); - } else { - setState(() { - timeLeft = widget.activeAgendaItem.timeLimitPerSpareIntegral; - timerRed = false; - }); - } - break; - case ProblemPhase.showProblem: - competitor1ConfettiController.stop(); - competitor2ConfettiController.stop(); - - if (pausedTimerDuration != null) { - setState(() { - timeLeft = pausedTimerDuration!; - timerRed = pausedTimerDuration! < - timeWarningDuration + const Duration(seconds: 1); - }); - } else if (timerStopsAt == null) { - setState(() { - timeLeft = Duration.zero; - timerRed = false; - }); - } else { - final difference = timerStopsAt!.difference(DateTime.now()); - - setState(() { - timeLeft = difference.isNegative ? Duration.zero : difference; - timerRed = - difference < timeWarningDuration + const Duration(seconds: 1); - }); - - if (difference < timeWarningDuration + const Duration(seconds: 1) && - difference + timerInterval > - timeWarningDuration + const Duration(seconds: 1)) { - playWarningSound(); - } - if (difference < Duration.zero && - difference + timerInterval > Duration.zero) { - playTimeUpSound(); - } - } - break; - case ProblemPhase.showSolution: - case ProblemPhase.showSolutionAndWinner: - if (widget.activeAgendaItem.currentWinner == Score.competitor1) { - if (competitor1ConfettiController.state != - ConfettiControllerState.playing) { - competitor1ConfettiController.play(); - } - } else if (widget.activeAgendaItem.currentWinner == - Score.competitor2) { - if (competitor2ConfettiController.state != - ConfettiControllerState.playing) { - competitor2ConfettiController.play(); - } - } - - setState(() { - timeLeft = Duration.zero; - timerRed = false; - }); - - break; - } - }); - super.initState(); } - void playWarningSound() { - if (widget.isPreview) return; - player.setAsset('sound/time_warning.mp3').then((_) => player.play()); - } - - void playTimeUpSound() { - if (widget.isPreview) return; - player.setAsset('sound/time_up.mp3').then((_) => player.play()); - } - @override void dispose() { - timer.cancel(); - player.dispose(); competitor1ConfettiController.dispose(); competitor2ConfettiController.dispose(); super.dispose(); @@ -218,10 +109,11 @@ class _PresentationScreenKnockoutState alignment: Alignment.center, children: [ TimerView( - timeLeft: timeLeft, - timerRed: timerRed, - paused: pausedTimerDuration != null, + activeAgendaItem: widget.activeAgendaItem, size: widget.size, + isPreview: widget.isPreview, + competitor1ConfettiController: competitor1ConfettiController, + competitor2ConfettiController: competitor2ConfettiController, ), ScoreView( competitor1Name: widget.activeAgendaItem.competitor1Name, diff --git a/lib/screens/presentation_screen/screens/presentation_screen_qualification.dart b/lib/screens/presentation_screen/screens/presentation_screen_qualification.dart index 0122965..a2bd770 100644 --- a/lib/screens/presentation_screen/screens/presentation_screen_qualification.dart +++ b/lib/screens/presentation_screen/screens/presentation_screen_qualification.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:integration_bee_helper/models/agenda_item_model/agenda_item_qualification.dart'; import 'package:integration_bee_helper/models/integral_model/current_integral_wrapper.dart'; @@ -12,7 +10,6 @@ import 'package:integration_bee_helper/screens/presentation_screen/widgets/timer import 'package:integration_bee_helper/screens/presentation_screen/widgets/title_view.dart'; import 'package:integration_bee_helper/services/basic_services/intl_service.dart'; import 'package:integration_bee_helper/services/integrals_service/integrals_service.dart'; -import 'package:just_audio/just_audio.dart'; import 'package:provider/provider.dart'; class PresentationScreenQualification extends StatefulWidget { @@ -36,12 +33,6 @@ class _PresentationScreenQualificationState extends State { String agendaItemId = ''; - late Timer timer; - Duration timeLeft = Duration.zero; - bool timerRed = false; - - late final AudioPlayer player; - String get uid => widget.activeAgendaItem.uid; ProblemPhase get problemPhase => widget.activeAgendaItem.problemPhase; List get integralsCodes => widget.activeAgendaItem.integralsCodes; @@ -76,89 +67,9 @@ class _PresentationScreenQualificationState void initState() { initialize(); - player = AudioPlayer(); - - const timerInterval = Duration(milliseconds: 250); - const timeWarningDuration = Duration(seconds: 30); - - timer = Timer.periodic(timerInterval, (timer) { - switch (problemPhase) { - case ProblemPhase.idle: - if (widget.activeAgendaItem.currentIntegralType == - IntegralType.regular) { - setState(() { - timeLeft = widget.activeAgendaItem.timeLimitPerIntegral; - timerRed = false; - }); - } else { - setState(() { - timeLeft = widget.activeAgendaItem.timeLimitPerSpareIntegral; - timerRed = false; - }); - } - break; - case ProblemPhase.showProblem: - if (pausedTimerDuration != null) { - setState(() { - timeLeft = pausedTimerDuration!; - timerRed = pausedTimerDuration! < - timeWarningDuration + const Duration(seconds: 1); - }); - } else if (timerStopsAt == null) { - setState(() { - timeLeft = Duration.zero; - timerRed = false; - }); - } else { - final difference = timerStopsAt!.difference(DateTime.now()); - - setState(() { - timeLeft = difference.isNegative ? Duration.zero : difference; - timerRed = - difference < timeWarningDuration + const Duration(seconds: 1); - }); - - if (difference < timeWarningDuration + const Duration(seconds: 1) && - difference + timerInterval > - timeWarningDuration + const Duration(seconds: 1)) { - playWarningSound(); - } - if (difference < Duration.zero && - difference + timerInterval > Duration.zero) { - playTimeUpSound(); - } - } - break; - case ProblemPhase.showSolution: - case ProblemPhase.showSolutionAndWinner: - setState(() { - timeLeft = Duration.zero; - timerRed = false; - }); - break; - } - }); - super.initState(); } - void playWarningSound() { - if (widget.isPreview) return; - player.setAsset('time_warning.mp3').then((_) => player.play()); - } - - void playTimeUpSound() { - if (widget.isPreview) return; - player.setAsset('time_up.mp3').then((_) => player.play()); - } - - @override - void dispose() { - timer.cancel(); - player.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { if (agendaItemId != widget.activeAgendaItem.id) { @@ -180,10 +91,9 @@ class _PresentationScreenQualificationState alignment: Alignment.center, children: [ TimerView( - timeLeft: timeLeft, - timerRed: timerRed, - paused: pausedTimerDuration != null, + activeAgendaItem: widget.activeAgendaItem, size: widget.size, + isPreview: widget.isPreview, ), IntegralView( currentIntegral: currentIntegral, @@ -201,7 +111,8 @@ class _PresentationScreenQualificationState ), NamesView( competitorNames: widget.activeAgendaItem.competitorNames, - problemName: problemName ?? MyIntl.of(context).exerciseNumber(1), + problemName: + problemName ?? MyIntl.of(context).exerciseNumber(1), size: widget.size, ), ], diff --git a/lib/screens/presentation_screen/widgets/timer_view.dart b/lib/screens/presentation_screen/widgets/timer_view.dart index 9170b76..68370da 100644 --- a/lib/screens/presentation_screen/widgets/timer_view.dart +++ b/lib/screens/presentation_screen/widgets/timer_view.dart @@ -1,29 +1,165 @@ +import 'dart:async'; + +import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; import 'package:integration_bee_helper/extensions/duration_extension.dart'; +import 'package:integration_bee_helper/models/agenda_item_model/agenda_item_knockout.dart'; +import 'package:integration_bee_helper/models/agenda_item_model/agenda_item_live_competition.dart'; +import 'package:integration_bee_helper/models/agenda_item_model/problem_phase.dart'; +import 'package:integration_bee_helper/models/agenda_item_model/score.dart'; +import 'package:integration_bee_helper/models/integral_model/integral_type.dart'; import 'package:integration_bee_helper/theme/theme_colors.dart'; import 'package:integration_bee_helper/widgets/triangle_painter.dart'; +import 'package:just_audio/just_audio.dart'; -class TimerView extends StatelessWidget { - final Duration timeLeft; - final bool timerRed; - final bool paused; +class TimerView extends StatefulWidget { + final AgendaItemModelLiveCompetition activeAgendaItem; final Size size; + final bool isPreview; + + final ConfettiController? competitor1ConfettiController; + final ConfettiController? competitor2ConfettiController; const TimerView({ super.key, - required this.timeLeft, - required this.timerRed, - required this.paused, + required this.activeAgendaItem, required this.size, + required this.isPreview, + this.competitor1ConfettiController, + this.competitor2ConfettiController, }); + @override + State createState() => _TimerViewState(); +} + +class _TimerViewState extends State { + late Timer timer; + Duration timeLeft = Duration.zero; + bool timerRed = false; + + late final AudioPlayer player; + + DateTime? get timerStopsAt => widget.activeAgendaItem.timer.timerStopsAt; + Duration? get pausedTimerDuration => + widget.activeAgendaItem.timer.pausedTimerDuration; + bool get paused => pausedTimerDuration != null; + + @override + void initState() { + player = AudioPlayer(); + + const timerInterval = Duration(milliseconds: 250); + const timeWarningDuration = Duration(seconds: 30); + + timer = Timer.periodic(timerInterval, (timer) { + switch (widget.activeAgendaItem.problemPhase) { + case ProblemPhase.idle: + widget.competitor1ConfettiController?.stop(); + widget.competitor2ConfettiController?.stop(); + + if (widget.activeAgendaItem.currentIntegralType == + IntegralType.regular) { + setState(() { + timeLeft = widget.activeAgendaItem.timeLimitPerIntegral; + timerRed = false; + }); + } else { + setState(() { + timeLeft = widget.activeAgendaItem.timeLimitPerSpareIntegral; + timerRed = false; + }); + } + break; + case ProblemPhase.showProblem: + widget.competitor1ConfettiController?.stop(); + widget.competitor2ConfettiController?.stop(); + + if (pausedTimerDuration != null) { + setState(() { + timeLeft = pausedTimerDuration!; + timerRed = pausedTimerDuration! < + timeWarningDuration + const Duration(seconds: 1); + }); + } else if (timerStopsAt == null) { + setState(() { + timeLeft = Duration.zero; + timerRed = false; + }); + } else { + final difference = timerStopsAt!.difference(DateTime.now()); + + setState(() { + timeLeft = difference.isNegative ? Duration.zero : difference; + timerRed = + difference < timeWarningDuration + const Duration(seconds: 1); + }); + + if (difference < timeWarningDuration + const Duration(seconds: 1) && + difference + timerInterval > + timeWarningDuration + const Duration(seconds: 1)) { + playWarningSound(); + } + if (difference < Duration.zero && + difference + timerInterval > Duration.zero) { + playTimeUpSound(); + } + } + break; + case ProblemPhase.showSolution: + case ProblemPhase.showSolutionAndWinner: + if (widget.activeAgendaItem is AgendaItemModelKnockout) { + final knockout = widget.activeAgendaItem as AgendaItemModelKnockout; + + if (knockout.currentWinner == Score.competitor1) { + if (widget.competitor1ConfettiController?.state != + ConfettiControllerState.playing) { + widget.competitor1ConfettiController?.play(); + } + } else if (knockout.currentWinner == Score.competitor2) { + if (widget.competitor2ConfettiController?.state != + ConfettiControllerState.playing) { + widget.competitor2ConfettiController?.play(); + } + } + } + + setState(() { + timeLeft = Duration.zero; + timerRed = false; + }); + + break; + } + }); + + super.initState(); + } + + @override + void dispose() { + timer.cancel(); + player.dispose(); + super.dispose(); + } + + void playWarningSound() { + if (widget.isPreview) return; + player.setAsset('sound/time_warning.mp3').then((_) => player.play()); + } + + void playTimeUpSound() { + if (widget.isPreview) return; + player.setAsset('sound/time_up.mp3').then((_) => player.play()); + } + @override Widget build(BuildContext context) { - final p = size.width / 1920.0; + final p = widget.size.width / 1920.0; return Container( - width: size.width, - height: size.height, + width: widget.size.width, + height: widget.size.height, alignment: Alignment.topLeft, child: Padding( padding: EdgeInsets.symmetric(vertical: 50 * p), diff --git a/lib/services/integrals_service/integrals_service.dart b/lib/services/integrals_service/integrals_service.dart index de11cde..89f1b37 100644 --- a/lib/services/integrals_service/integrals_service.dart +++ b/lib/services/integrals_service/integrals_service.dart @@ -60,7 +60,7 @@ class IntegralsService { .collection('integrals') .where('uid', isEqualTo: _uid) .where('code', isEqualTo: integralCode) - .limit(1) + .orderBy('createdAt') .snapshots() .map( (res) =>