Skip to content

Commit

Permalink
fix(raffle): Extra logging & error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
vanlooverenkoen committed Nov 24, 2023
1 parent 40e08ab commit f00cbd7
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 13 deletions.
5 changes: 4 additions & 1 deletion lib/di/injectable.config.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions lib/navigation/main_navigator.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_belgium/navigation/page_route/no_transition_page_route.dart';
import 'package:flutter_navigation_generator_annotations/flutter_navigation_generator_annotations.dart';
Expand All @@ -11,9 +12,46 @@ import 'package:flutter_belgium/navigation/main_navigator.navigator.dart';
class MainNavigator with BaseNavigator {
MainNavigator();

BuildContext get context => navigatorKey.currentContext!;

final List<NavigatorObserver> _navigatorObservers = [];

String get initialRoute => RouteNames.splashScreen;

List<NavigatorObserver> get navigatorObservers => _navigatorObservers;

void showError(String title, {Object? error, StackTrace? trace}) {
Flushbar(
title: title,
message: error.toString(),
icon: const Icon(
Icons.error_outline_rounded,
size: 24,
color: Colors.red,
),
shouldIconPulse: false,
borderRadius: BorderRadius.circular(8),
duration: const Duration(seconds: 3),
margin: const EdgeInsets.all(16),
flushbarPosition: FlushbarPosition.TOP,
leftBarIndicatorColor: Colors.red,
).show(context);
}

void showMessage(String message) {
Flushbar(
message: message.toString(),
icon: const Icon(
Icons.info_outline_rounded,
size: 24,
color: Colors.blue,
),
shouldIconPulse: false,
borderRadius: BorderRadius.circular(8),
duration: const Duration(seconds: 3),
margin: const EdgeInsets.all(16),
flushbarPosition: FlushbarPosition.TOP,
leftBarIndicatorColor: Colors.blue,
).show(context);
}
}
8 changes: 6 additions & 2 deletions lib/screen/raffle_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter_belgium/style/theme_assets.dart';
import 'package:flutter_belgium/widget/admin/shortcut_manager.dart';
import 'package:flutter_belgium/widget/general/button.dart';
import 'package:flutter_belgium/widget/general/loading.dart';
import 'package:flutter_belgium/widget/general/tripple_tap_detector.dart';
import 'package:flutter_belgium/widget/raffle/custom_confetti.dart';
import 'package:flutter_navigation_generator_annotations/flutter_navigation_generator_annotations.dart';
import 'package:flutter_belgium/di/injectable.dart';
Expand Down Expand Up @@ -37,8 +38,11 @@ class RaffleScreen extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
ThemeAssets.flutterBelgiumLogo,
TripleTapDetector(
onTripleTap: viewModel.onTripleTapLogo,
child: SvgPicture.asset(
ThemeAssets.flutterBelgiumLogo,
),
),
const SizedBox(height: 32),
RichText(
Expand Down
3 changes: 2 additions & 1 deletion lib/viewmodel/login_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class LoginViewModel with ChangeNotifier {
_isLoading = false;
notifyListeners();
_mainNavigator.goToRaffleScreen();
} catch (e) {
} catch (error, trace) {
_mainNavigator.showError('Failed to open login', error: error, trace: trace);
_isLoading = false;
notifyListeners();
}
Expand Down
12 changes: 11 additions & 1 deletion lib/viewmodel/raffle_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class RaffleViewModel with ChangeNotifier {
_raffle = raffle;
notifyListeners();
_setupRaffleSpecificStreams(raffle.id);
}, onError: (error, trace) {
_mainNavigator.showError('Failed to get `getRaffle`', error: error, trace: trace);
});
}

Expand All @@ -79,6 +81,8 @@ class RaffleViewModel with ChangeNotifier {
_hasEnteredStreamSubscription = _raffleRepository.hasEnteredRaffle(raffleId).listen((hasEnteredRaffle) {
_hasEnteredRaffle = hasEnteredRaffle;
notifyListeners();
}, onError: (error, trace) {
_mainNavigator.showError('Failed to get `hasEnteredRaffle` status ', error: error, trace: trace);
});
_hasAlreadyWonStreamSubscription?.cancel();
_hasAlreadyWonStreamSubscription = _raffleRepository.hasWonRaffle(raffleId).listen((hasWonRaffle) {
Expand All @@ -91,17 +95,23 @@ class RaffleViewModel with ChangeNotifier {
}
_hasAlreadyWonRaffle = hasWonRaffle;
notifyListeners();
}, onError: (error, trace) {
_mainNavigator.showError('Failed to get `hasWonRaffle` status ', error: error, trace: trace);
});
}

Future<void> onEnterRaffleTapped() async {
final raffle = _raffle;
if (raffle == null) {
//TODO show error
_mainNavigator.showError('No raffle found');
return;
}
await _raffleRepository.enterRaffle(raffle.id);
}

void onStartFortuneWheel() => _mainNavigator.goToRaffleWinnerPickerScreen();

void onTripleTapLogo() {
_mainNavigator.showMessage('Raffle: $_raffle, $_hasAlreadyWonRaffle, $_hasEnteredRaffle');
}
}
19 changes: 11 additions & 8 deletions lib/viewmodel/raffle_winner_picker_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import 'package:confetti/confetti.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_belgium/model/data/raffle/participant.dart';
import 'package:flutter_belgium/model/data/raffle/raffle.dart';
import 'package:flutter_belgium/navigation/main_navigator.dart';
import 'package:flutter_belgium/repo/raffle_repo.dart';
import 'package:flutter_belgium/style/theme_duration.dart';
import 'package:injectable/injectable.dart';

@injectable
class RaffleWinnerPickerViewModel with ChangeNotifier {
final RaffleRepository raffleRepository;
final RaffleRepository _raffleRepository;
final MainNavigator _mainNavigator;

final _confettiController = ConfettiController();
final _selectedIndexStreamController = StreamController<int>.broadcast();
Expand Down Expand Up @@ -39,12 +41,13 @@ class RaffleWinnerPickerViewModel with ChangeNotifier {
bool get hasEnoughParticipants => participants.length > 2;

RaffleWinnerPickerViewModel(
this.raffleRepository,
this._raffleRepository,
this._mainNavigator,
);

void init() {
_subscription?.cancel();
_subscription = raffleRepository.getRaffle().listen((raffle) {
_subscription = _raffleRepository.getRaffle().listen((raffle) {
final winnerIds = raffle?.winners.map((e) => e.userUid) ?? [];
final participants = List<RaffleParticipant>.of(raffle?.participants ?? []);
participants.removeWhere((element) => winnerIds.contains(element.userUid));
Expand All @@ -64,12 +67,12 @@ class RaffleWinnerPickerViewModel with ChangeNotifier {
Future<void> onPickWinnerTapped() async {
final raffleId = _raffle?.id;
if (raffleId == null) {
//todo show error
_mainNavigator.showError('Failed to pick winner');
return;
}
final participants = List<RaffleParticipant>.of(_allowedParticipants);
if (participants.isEmpty) {
//todo show error
_mainNavigator.showError('No participants found');
return;
}
_winner = null;
Expand All @@ -79,7 +82,7 @@ class RaffleWinnerPickerViewModel with ChangeNotifier {
final winner = participants[winnerIndex];
_selectedIndexStreamController.add(winnerIndex);
await Future.delayed(ThemeDuration.raffleWheelDuration);
raffleRepository.setWinner(raffleId: raffleId, winner: winner);
_raffleRepository.setWinner(raffleId: raffleId, winner: winner);
_winner = winner;
notifyListeners();
_confettiController.play();
Expand All @@ -94,9 +97,9 @@ class RaffleWinnerPickerViewModel with ChangeNotifier {
Future<void> onMakeRaffleActiveTapped() async {
final docId = _raffle?.id;
if (docId == null) {
//todo show error
_mainNavigator.showError('Failed to make raffle active (no raffle available)');
return;
}
raffleRepository.setRaffleActive(raffleId: docId, active: true);
_raffleRepository.setRaffleActive(raffleId: docId, active: true);
}
}
54 changes: 54 additions & 0 deletions lib/widget/general/tripple_tap_detector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'dart:async';

class TripleTapDetector extends StatefulWidget {
final Widget child;
final VoidCallback onTripleTap;
final Duration timeWindow;

const TripleTapDetector({
required this.child,
required this.onTripleTap,
this.timeWindow = const Duration(seconds: 1),
super.key,
});

@override
State<TripleTapDetector> createState() => _TripleTapDetectorState();
}

class _TripleTapDetectorState extends State<TripleTapDetector> {
int tapCount = 0;
Timer? tapTimer;

@override
void dispose() {
tapTimer?.cancel();
super.dispose();
}

void handleTap() {
setState(() {
tapCount++;
if (tapCount == 3) {
widget.onTripleTap();
tapCount = 0;
}

tapTimer?.cancel();
tapTimer = Timer(widget.timeWindow, () {
setState(() {
tapCount = 0;
});
});
});
}

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: handleTap,
child: widget.child,
);
}
}
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.13.0"
another_flushbar:
dependency: "direct main"
description:
name: another_flushbar
sha256: "19bf9520230ec40b300aaf9dd2a8fefcb277b25ecd1c4838f530566965befc2a"
url: "https://pub.dev"
source: hosted
version: "1.12.30"
args:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ environment:
sdk: '>=3.0.0 <4.0.0'

dependencies:
another_flushbar: ^1.12.30
ai_barcode_scanner: ^3.4.1
confetti: ^0.7.0
cloud_firestore: ^4.13.1
Expand Down

0 comments on commit f00cbd7

Please sign in to comment.