Skip to content

Instantly share code, notes, and snippets.

@SebastianKlaiber
Last active July 20, 2020 11:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SebastianKlaiber/be46bb4287e341d6160326c283aea84b to your computer and use it in GitHub Desktop.
Save SebastianKlaiber/be46bb4287e341d6160326c283aea84b to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:app/src/i_app_config.dart';
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:meta/meta.dart';
part 'session_timer_bloc.freezed.dart';
part 'session_timer_event.dart';
part 'session_timer_state.dart';
class SessionTimerBloc extends Bloc<SessionTimerEvent, SessionTimerState> {
StreamSubscription<int> _tickerSubscription;
final Ticker _ticker;
final IAppConfig appConfig;
SessionTimerBloc({@required Ticker ticker, @required this.appConfig})
: assert(ticker != null),
_ticker = ticker,
super(Ready(appConfig.accessTokenLifetime));
@override
Stream<SessionTimerState> mapEventToState(
SessionTimerEvent event,
) async* {
yield* event.map(
start: _mapStartToState,
pause: _mapPauseToState,
resume: _mapResumeToState,
reset: _mapResetToState,
tick: _mapTickToState,
);
}
@override
Future<void> close() {
_tickerSubscription?.cancel();
return super.close();
}
Stream<SessionTimerState> _mapStartToState(Start start) async* {
yield Running(start.duration ?? appConfig.accessTokenLifetime);
_tickerSubscription?.cancel();
_tickerSubscription = _ticker.tick(ticks: start.duration).listen((duration) => add(Tick(duration: duration)));
}
Stream<SessionTimerState> _mapPauseToState(Pause pause) async* {
if (state is Running) {
final currentState = state as Running;
_tickerSubscription?.pause();
yield Paused(currentState.duration);
}
}
Stream<SessionTimerState> _mapResumeToState(Resume resume) async* {
if (state is Paused) {
final currentState = state as Paused;
_tickerSubscription?.resume();
yield Running(currentState.duration);
}
}
Stream<SessionTimerState> _mapResetToState(Reset reset) async* {
_tickerSubscription?.cancel();
yield Ready(appConfig.accessTokenLifetime);
}
Stream<SessionTimerState> _mapTickToState(Tick tick) async* {
yield tick.duration > 0 ? Running(tick.duration) : Finished(appConfig.accessTokenLifetime);
}
}
class Ticker {
Stream<int> tick({int ticks}) => Stream.periodic(const Duration(seconds: 1), (x) => ticks - x - 1).take(ticks);
}
class SessionTimerText extends StatelessWidget {
const SessionTimerText({Key key}) : super(key: key);
static final TextStyle style = GoogleFonts.sourceSansPro(
color: textDarkGrey,
fontWeight: FontWeight.w600,
fontSize: 2 * SizeConfig.textMultiplier,
);
@override
Widget build(BuildContext context) {
return BlocConsumer<SessionTimerBloc, SessionTimerState>(
listenWhen: (previous, current) => current is Finished,
listener: (BuildContext context, SessionTimerState state) {
if (state is Finished) {
final isBiometricsEnabled = getIt<IPreference>().isBiometricsEnabled;
if (isBiometricsEnabled) {
context.bloc<AuthenticationBloc>().add(const AppStarted());
} else {
context.bloc<AuthenticationBloc>().add(const RefreshAccessTokenEvent());
}
}
},
builder: (context, state) {
final String minutesStr = ((state.duration / 60) % 60).floor().toString().padLeft(2, '0');
final String secondsStr = (state.duration % 60).floor().toString().padLeft(2, '0');
return Text('$minutesStr:$secondsStr', style: SessionTimerText.style);
},
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment