Skip to content

Commit

Permalink
Merge pull request #20 from dillonfagan/dev
Browse files Browse the repository at this point in the history
v1.1
  • Loading branch information
dillonfagan authored Oct 6, 2023
2 parents ae65f12 + 1ab05f9 commit 6b6a124
Show file tree
Hide file tree
Showing 18 changed files with 734 additions and 272 deletions.
26 changes: 10 additions & 16 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mob_app/pages/setup/setup.dart';
import 'package:mob_app/providers/mob.dart';
import 'package:provider/provider.dart';

void main() {
runApp(const MobApp());
runApp(const ProviderScope(child: MobApp()));
}

class MobApp extends StatelessWidget {
const MobApp({super.key});

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (context, child) {
return MaterialApp(
title: 'Mob Timer',
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
colorScheme: const ColorScheme.dark(primary: Colors.amber),
),
home: const SetupPage(),
);
},
create: (BuildContext context) => MobProvider(),
return MaterialApp(
title: 'Mob Timer',
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
colorScheme: const ColorScheme.dark(primary: Colors.amber),
),
home: const SetupPage(),
);
}
}
29 changes: 15 additions & 14 deletions lib/pages/setup/setup.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mob_app/models/mobber.dart';
import 'package:mob_app/pages/timer/timer.dart';
import 'package:mob_app/providers/mob.dart';
import 'package:provider/provider.dart';
import 'package:mob_app/providers/mobbers_provider.dart';

import 'widgets/mobber_field.dart';
import 'widgets/mobbers_listview.dart';

class SetupPage extends StatefulWidget {
class SetupPage extends ConsumerStatefulWidget {
const SetupPage({super.key});

@override
State<StatefulWidget> createState() {
ConsumerState<ConsumerStatefulWidget> createState() {
return _SetupPageState();
}
}

class _SetupPageState extends State<SetupPage> {
class _SetupPageState extends ConsumerState<SetupPage> {
final focusNode = FocusNode();
final mobberController = TextEditingController();

Mobbers get mobbersNotifier => ref.read(mobbersProvider.notifier);

@override
Widget build(BuildContext context) {
final mob = Provider.of<MobProvider>(context);
final mobbers = mob.mobbers;
final turnLength = mob.turnLength;
final mobbers = ref.watch(mobbersProvider);

return Scaffold(
appBar: AppBar(
Expand All @@ -34,7 +35,7 @@ class _SetupPageState extends State<SetupPage> {
leading: mobbers.length > 1
? IconButton(
onPressed: () {
mob.shuffleMobbers();
mobbersNotifier.shuffle();
},
icon: const Icon(Icons.rotate_left_rounded),
tooltip: 'Shuffle mobbers',
Expand All @@ -52,19 +53,19 @@ class _SetupPageState extends State<SetupPage> {
Card(
child: MobberField(
controller: mobberController,
focusNode: focusNode,
onSubmitted: (value) {
if (value.isEmpty) return;
mobberController.clear();
mobbers.add(Mobber(name: value));
mob.mobbers = mobbers;
mobbersNotifier.add(Mobber(name: value));
focusNode.requestFocus();
},
),
),
MobbersListView(
mobbers: mobbers,
onMobberRemoved: (index) {
mobbers.removeAt(index);
mob.mobbers = mobbers;
mobbersNotifier.removeAt(index);
},
),
],
Expand All @@ -76,7 +77,7 @@ class _SetupPageState extends State<SetupPage> {
child: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: ((context) => TimerPage(seconds: turnLength)),
builder: ((context) => TimerPage()),
));
},
backgroundColor: Colors.amber,
Expand Down
3 changes: 3 additions & 0 deletions lib/pages/setup/widgets/mobber_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ class MobberField extends StatelessWidget {
super.key,
required this.controller,
required this.onSubmitted,
this.focusNode,
});

final TextEditingController controller;
final Function(String) onSubmitted;
final FocusNode? focusNode;

@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
focusNode: focusNode,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20),
decoration: const InputDecoration(
Expand Down
55 changes: 33 additions & 22 deletions lib/pages/timer/timer.dart
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mob_app/pages/timer/helpers/ticker.dart';
import 'package:mob_app/providers/mob.dart';
import 'package:provider/provider.dart';
import 'package:mob_app/providers/break_provider.dart';
import 'package:mob_app/providers/driver_provider.dart';
import 'package:mob_app/providers/mob_controller_provider.dart';
import 'package:mob_app/providers/mob_state_provider.dart';
import 'package:mob_app/providers/turn_length_provider.dart';

import 'widgets/appbar_factory.dart';
import 'widgets/break_button.dart';
import 'widgets/display.dart';
import 'widgets/next_button.dart';

class TimerPage extends StatefulWidget {
TimerPage({super.key, this.seconds = 5});
class TimerPage extends ConsumerStatefulWidget {
TimerPage({super.key});

final int seconds;
final AudioPlayer audioPlayer = AudioPlayer(playerId: '#timer');

@override
State<TimerPage> createState() => _TimerPageState();
ConsumerState<TimerPage> createState() => _TimerPageState();
}

class _TimerPageState extends State<TimerPage> {
class _TimerPageState extends ConsumerState<TimerPage> {
late final _ticker = Ticker(
onTick: _update,
onStop: _playChime,
onStop: _playAlarm,
);

@override
Expand All @@ -42,29 +45,33 @@ class _TimerPageState extends State<TimerPage> {
}

void _start({int? seconds}) {
setState(() => _ticker.start(seconds ?? widget.seconds));
setState(() => _ticker.start(seconds ?? ref.read(turnLengthProvider)));
}

void _stop() {
setState(() => _ticker.stop());
}

void _playChime() async {
void _playAlarm() async {
await widget.audioPlayer.play(
AssetSource('sounds/chime.wav'),
UrlSource('/sounds/alarm.mp3'),
volume: 1.0,
);
}

@override
Widget build(BuildContext context) {
final mob = Provider.of<MobProvider>(context);
final currentMobber = mob.currentMobber;
final nextMobber = mob.nextMobber;
String title = mob.isOnBreak ? 'Break' : currentMobber.name;
final timeToBreak = ref.watch(breakProvider);
final mobState = ref.watch(mobStateProvider);
final driver = ref.watch(driverProvider);
final navigator = ref.watch(navigatorProvider);
String title = mobState == MobState.onBreak ? 'Break' : driver.name;

return Scaffold(
appBar: AppBarFactory.build(context: context),
appBar: AppBarFactory.build(
context: context,
controller: ref.read(mobControllerProvider),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
Expand All @@ -79,18 +86,22 @@ class _TimerPageState extends State<TimerPage> {
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 36),
)
: mob.isTimeForBreak
: timeToBreak
? BreakButton(
onPressed: () {
mob.state = MobState.onBreak;
ref
.read(mobStateProvider.notifier)
.update(MobState.onBreak);
_start(seconds: 600);
},
)
: NextButton(
labelText: nextMobber.name,
labelText: navigator.name,
onPressed: () {
mob.state = MobState.mobbing;
mob.advanceTurn();
ref
.read(mobStateProvider.notifier)
.update(MobState.mobbing);
ref.read(driverIndexProvider.notifier).next();
_start();
},
),
Expand All @@ -102,7 +113,7 @@ class _TimerPageState extends State<TimerPage> {
child: FloatingActionButton(
onPressed: () {
_stop();
mob.state = MobState.waiting;
ref.read(mobStateProvider.notifier).update(MobState.waiting);
},
backgroundColor: Colors.amber,
child: const Icon(
Expand Down
12 changes: 6 additions & 6 deletions lib/pages/timer/widgets/appbar_factory.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:mob_app/pages/setup/setup.dart';
import 'package:mob_app/pages/timer/widgets/end_mob_alert.dart';
import 'package:mob_app/providers/mob.dart';
import 'package:mob_app/providers/mob_controller_provider.dart';

class AppBarFactory {
static AppBar build({required BuildContext context}) {
final mob = Provider.of<MobProvider>(context);

static AppBar build({
required BuildContext context,
required MobController controller,
}) {
return AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
onPressed: () {
mob.reset();
controller.reset();
showDialog(
context: context,
builder: (context) {
Expand Down
12 changes: 12 additions & 0 deletions lib/providers/break_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mob_app/providers/turn_length_provider.dart';
import 'package:mob_app/providers/turns_provider.dart';

const int fortyFiveMinutes = 2700;

final breakProvider = Provider<bool>((ref) {
final turns = ref.watch(turnsProvider);
final turnLength = ref.watch(turnLengthProvider);

return fortyFiveMinutes - turns * turnLength <= 0;
});
42 changes: 42 additions & 0 deletions lib/providers/driver_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mob_app/models/mobber.dart';
import 'package:mob_app/providers/mobbers_provider.dart';

class DriverIndexNotifier extends Notifier<int> {
@override
int build() {
return 0;
}

void reset() {
state = 0;
}

void next() {
if (state == ref.read(mobbersProvider).length - 1) {
state = 0;
} else {
state++;
}
}
}

final driverIndexProvider =
NotifierProvider<DriverIndexNotifier, int>(DriverIndexNotifier.new);

final driverProvider = Provider<Mobber>((ref) {
final driverIndex = ref.watch(driverIndexProvider);
final mobbers = ref.watch(mobbersProvider);

return mobbers[driverIndex];
});

final navigatorProvider = Provider<Mobber>((ref) {
final driverIndex = ref.watch(driverIndexProvider);
final mobbers = ref.watch(mobbersProvider);

final navigatorIndex =
driverIndex == mobbers.length - 1 ? 0 : driverIndex + 1;

return mobbers[navigatorIndex];
});
Loading

0 comments on commit 6b6a124

Please sign in to comment.