Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a new Fortune wheel #14

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .fvm/fvm_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"flutterSdkVersion": "3.27.3"
}
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutter": "3.27.1",
"flutter": "3.27.3",
"flavors": {}
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.27.1",
"dart.flutterSdkPath": ".fvm/versions/3.27.3",
"dart.sdkPath": ".fvm/flutter_sdk/bin/cache/dart-sdk",
"dart.lineLength": 180,
"search.exclude": {
Expand Down
7 changes: 6 additions & 1 deletion lib/repo/remote_config.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';

import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_belgium/model/data/remote_config/remote_config_data.dart';
import 'package:flutter_belgium/util/flavor/flavor_config.dart';
import 'package:impaktfull_architecture/impaktfull_architecture.dart';
Expand Down Expand Up @@ -34,7 +35,11 @@ class AppRemoteConfigRepository extends ImpaktfullRemoteConfigRepository<RemoteC
Future<RemoteConfigData> getDefault() async => RemoteConfigData(
latestVersionCode: 1,
minVersionCode: 1,
updateUrl: Platform.isAndroid ? 'https://play.google.com/store/apps/details?id=be.flutterbelgium.app' : 'https://apps.apple.com/us/app/flutter-belgium/id6479450596',
updateUrl: kIsWeb
? ''
: Platform.isAndroid
? 'https://play.google.com/store/apps/details?id=be.flutterbelgium.app'
: 'https://apps.apple.com/us/app/flutter-belgium/id6479450596',
adminIds: [],
);

Expand Down
7 changes: 4 additions & 3 deletions lib/screen/login/login_screen.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_belgium/di/injectable.dart';
import 'package:flutter_belgium/model/data/login/login_type.dart';
import 'package:flutter_belgium/theme/theme_assets.dart';
import 'package:flutter_belgium/viewmodel/login/login_viewmodel.dart';
import 'package:flutter_belgium/widget/provider/provider_widget.dart';
import 'package:flutter_belgium/widget/social_login/social_login_button.dart';
import 'package:flutter_navigation_generator_annotations/flutter_navigation_generator_annotations.dart';
import 'package:flutter_belgium/di/injectable.dart';
import 'package:flutter_belgium/widget/provider/provider_widget.dart';
import 'package:impaktfull_architecture/impaktfull_architecture.dart';

@FlutterRoute(
Expand Down Expand Up @@ -45,7 +46,7 @@ class LoginScreen extends StatelessWidget {
onTap: viewModel.onLoginTapped,
loginType: LoginType.github,
),
if (Platform.isIOS) ...[
if (!kIsWeb && Platform.isIOS) ...[
SocialLoginButton(
onTap: viewModel.onLoginTapped,
loginType: LoginType.apple,
Expand Down
16 changes: 11 additions & 5 deletions lib/screen/raffle/raffle_winner_picker_screen.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_belgium/di/injectable.dart';
import 'package:flutter_belgium/theme/theme_colors.dart';
import 'package:flutter_belgium/viewmodel/raffle/raffle_winner_picker_viewmodel.dart';
import 'package:flutter_belgium/widget/general/button.dart';
import 'package:flutter_belgium/widget/provider/provider_widget.dart';
import 'package:flutter_belgium/widget/raffle/custom_confetti.dart';
import 'package:flutter_belgium/widget/raffle/custom_fortune_wheel.dart';
import 'package:flutter_navigation_generator_annotations/flutter_navigation_generator_annotations.dart';
import 'package:flutter_belgium/di/injectable.dart';
import 'package:flutter_belgium/widget/provider/provider_widget.dart';
import 'package:impaktfull_architecture/impaktfull_architecture.dart';

@FlutterRoute(
navigationType: NavigationType.push,
)
class RaffleWinnerPickerScreen extends StatelessWidget {
class RaffleWinnerPickerScreen extends StatefulWidget {
const RaffleWinnerPickerScreen({
super.key,
});

@override
State<RaffleWinnerPickerScreen> createState() => _RaffleWinnerPickerScreenState();
}

class _RaffleWinnerPickerScreenState extends State<RaffleWinnerPickerScreen> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return ProviderWidget<RaffleWinnerPickerViewModel>(
create: () => getIt()..init(),
create: () => getIt()..init(this),
builder: (context, viewModel) => ImpaktfullUiScreen(
child: Builder(builder: (context) {
if (viewModel.hasInactiveRaffle) {
Expand Down Expand Up @@ -57,7 +62,8 @@ class RaffleWinnerPickerScreen extends StatelessWidget {
);
}
return CustomFortuneWheel(
selected: viewModel.selectedIndexStream,
winnerIndex: viewModel.raffleWinnerIndex,
animation: viewModel.raffleAnimation,
participants: viewModel.participants,
);
},
Expand Down
3 changes: 1 addition & 2 deletions lib/theme/theme_duration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ class ThemeDuration {
const ThemeDuration._();

static const confettiDuration = Duration(seconds: 5);
static const raffleWheelDuration = Duration(seconds: 3);

static const nextRoundDelayDuration = Duration(seconds: 5);
static const raffleWheelDuration = Duration(seconds: 10);
}
27 changes: 17 additions & 10 deletions lib/viewmodel/raffle/raffle_winner_picker_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import 'dart:async';
import 'dart:math';

import 'package:confetti/confetti.dart';
import 'package:flutter/material.dart';
import 'package:flutter_belgium/model/data/raffle/participant.dart';
import 'package:flutter_belgium/model/data/raffle/raffle.dart';
import 'package:flutter_belgium/navigator/main_navigator.dart';
import 'package:flutter_belgium/repo/raffle/raffle_repo.dart';
import 'package:flutter_belgium/theme/theme_duration.dart';
import 'package:flutter_crazy_fortune_wheel/flutter_crazy_fortune_wheel.dart';
import 'package:impaktfull_architecture/impaktfull_architecture.dart';

@injectable
Expand All @@ -15,7 +17,9 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {
final MainNavigator _mainNavigator;

final _confettiController = ConfettiController();
final _selectedIndexStreamController = StreamController<int>.broadcast();
late final AnimationController _raffleAnimationController;
late final Animation<double> _raffleAnimation;
int _raffleWinnerIndex = 0;
StreamSubscription<Raffle?>? _subscription;

Raffle? _raffle;
Expand All @@ -27,7 +31,9 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {

ConfettiController get confettiController => _confettiController;

Stream<int> get selectedIndexStream => _selectedIndexStreamController.stream;
Animation<double> get raffleAnimation => _raffleAnimation;

int get raffleWinnerIndex => _raffleWinnerIndex;

int get minRequiredParticipants => 2;

Expand All @@ -46,7 +52,9 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {
this._mainNavigator,
);

void init() {
void init(TickerProvider vsync) {
_raffleAnimationController = AnimationController(vsync: vsync, duration: ThemeDuration.raffleWheelDuration);
_raffleAnimation = CurvedAnimation(parent: _raffleAnimationController, curve: FortuneWheelCurve());
_subscription?.cancel();
_subscription = _raffleRepository.getRaffle().listen((raffle) {
final winnerIds = raffle?.winners.map((e) => e.userUid) ?? [];
Expand All @@ -61,7 +69,7 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {
@override
void dispose() {
_subscription?.cancel();
_selectedIndexStreamController.close();
_raffleAnimationController.dispose();
super.dispose();
}

Expand All @@ -78,18 +86,17 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {
}
_winner = null;
_lockedParticipants = participants;
_raffleWinnerIndex = Random.secure().nextInt(participants.length);
notifyListeners();
final winnerIndex = Random().nextInt(participants.length);
final winner = participants[winnerIndex];
_selectedIndexStreamController.add(winnerIndex);
await Future.delayed(ThemeDuration.raffleWheelDuration);
final winner = participants[_raffleWinnerIndex];
await _raffleAnimationController.forward(from: 0);
_raffleRepository.setWinner(raffleId: raffleId, winner: winner);
_winner = winner;
notifyListeners();
_confettiController.play();
await Future.delayed(ThemeDuration.confettiDuration);
_confettiController.stop();
await Future.delayed(ThemeDuration.nextRoundDelayDuration);
vanlooverenkoen marked this conversation as resolved.
Show resolved Hide resolved
_raffleAnimationController.reset();
_winner = null;
_lockedParticipants = null;
notifyListeners();
Expand All @@ -107,7 +114,7 @@ class RaffleWinnerPickerViewModel extends ChangeNotifierEx {
Future<void> onAddParticipantTapped() async {
final docId = _raffle?.id;
if (docId == null) {
_mainNavigator.showErrorMessage('Failed to make raffle active (no raffle available)');
_mainNavigator.showErrorMessage('Failed to add participant (no raffle available)');
return;
}
final name = await _mainNavigator.goToAddParticipantDialog();
Expand Down
2 changes: 2 additions & 0 deletions lib/widget/raffle/add_participant_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ class _AddParticipantDialogState extends State<AddParticipantDialog> {
],
child: TextField(
controller: textController,
onSubmitted: (_) => Navigator.of(context).pop(textController.text),
cursorColor: ThemeColors.primary,
focusNode: FocusNode()..requestFocus(),
decoration: InputDecoration(
hintText: localization.dialogRaffleNewParticipantInputName,
focusedBorder: UnderlineInputBorder(
Expand Down
52 changes: 16 additions & 36 deletions lib/widget/raffle/custom_fortune_wheel.dart
Original file line number Diff line number Diff line change
@@ -1,58 +1,38 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_belgium/model/data/raffle/participant.dart';
import 'package:flutter_belgium/theme/theme_colors.dart';
import 'package:flutter_belgium/theme/theme_duration.dart';
import 'package:flutter_fortune_wheel/flutter_fortune_wheel.dart';
import 'package:flutter_crazy_fortune_wheel/flutter_crazy_fortune_wheel.dart';

class CustomFortuneWheel extends StatelessWidget {
final Stream<int> selected;
final int winnerIndex;
final Animation<double> animation;
final List<RaffleParticipant> participants;

const CustomFortuneWheel({
required this.selected,
required this.winnerIndex,
required this.animation,
required this.participants,
super.key,
});

@override
Widget build(BuildContext context) {
return FortuneWheel(
selected: selected,
animateFirst: false,
duration: ThemeDuration.raffleWheelDuration,
rotationCount: Random().nextInt(10) + 20,
indicators: const [
FortuneIndicator(
alignment: Alignment.topCenter,
child: TriangleIndicator(
color: ThemeColors.primary,
),
),
],
physics: CircularPanPhysics(
duration: const Duration(seconds: 1),
curve: Curves.decelerate,
),
items: [
for (final participant in participants)
FortuneItem(
child: Text(
return RandomWheel(
animation: animation,
winnerIndex: winnerIndex,
wheelType: WheelType.values[participants.length % WheelType.values.length],
children: participants
.map(
(participant) => Text(
participant.name,
style: TextStyle(
style: const TextStyle(
color: ThemeColors.primary,
fontSize: participants.length > 30 ? 16 : 24,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
style: const FortuneItemStyle(
color: ThemeColors.primaryUltraLight, // <-- custom circle slice fill color
borderColor: ThemeColors.primary,
borderWidth: 2,
),
),
],
)
.toList(),
);
}
}
36 changes: 22 additions & 14 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -435,22 +435,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_fortune_wheel:
flutter_crazy_fortune_wheel:
dependency: "direct main"
description:
name: flutter_fortune_wheel
sha256: "8f93144fab448ec95579d320e77dcf189b71bc363545985e41d3ba57fa42664e"
name: flutter_crazy_fortune_wheel
sha256: a6b299961a4bed63a3244462bd2512296f78bd37170a350022c8c332d5fcf13f
url: "https://pub.dev"
source: hosted
version: "1.3.2"
flutter_hooks:
dependency: transitive
description:
name: flutter_hooks
sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70
url: "https://pub.dev"
source: hosted
version: "0.20.5"
version: "1.0.1"
flutter_lints:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -536,6 +528,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_shader_snap:
dependency: transitive
description:
name: flutter_shader_snap
sha256: a97fd2767391ca49dce96b15643aafe34dd3823da5b996e18bf06c3f7f02b513
url: "https://pub.dev"
source: hosted
version: "0.0.3"
flutter_shaders:
dependency: transitive
description:
name: flutter_shaders
sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2"
url: "https://pub.dev"
source: hosted
version: "0.1.3"
flutter_svg:
dependency: transitive
description:
Expand Down Expand Up @@ -582,10 +590,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
google_identity_services_web:
dependency: transitive
description:
Expand Down
4 changes: 3 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
firebase_remote_config: ^5.3.0
flutter:
sdk: flutter
flutter_fortune_wheel: ^1.3.2
flutter_crazy_fortune_wheel: ^1.0.1
flutter_localizations:
sdk: flutter
flutter_navigation_generator_annotations: ^2.1.0
Expand Down Expand Up @@ -51,6 +51,8 @@ flutter:
- family: Ubuntu
fonts:
- asset: assets/font/ubuntu/ubuntu_regular.ttf
shaders:
- packages/flutter_crazy_fortune_wheel/shaders/sliced_wheel_shader.frag

impaktfull_translations:
api_key: caca1cf8-fd65-428e-bd5b-8f5e2a3fdf23
Expand Down