From dac07065ff828fe6a6a41891ebf2d7b51d1db484 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sun, 20 Feb 2022 16:38:51 +0100 Subject: [PATCH] Implement bloc for user switch --- lib/app.dart | 10 +++++-- lib/bloc/user_bloc.dart | 37 +++++++++++++++++++++++++ lib/bloc_provider.dart | 53 ++++++++++++++++++++++++++---------- lib/utils/disposable.dart | 5 ++++ lib/widgets/user_switch.dart | 33 ++++++++++++++-------- 5 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 lib/bloc/user_bloc.dart create mode 100644 lib/utils/disposable.dart diff --git a/lib/app.dart b/lib/app.dart index 0935237..1284a8a 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:thesis_shop/bloc/user_bloc.dart'; import 'package:thesis_shop/bloc_provider.dart'; import 'package:thesis_shop/route_key.dart'; import 'package:thesis_shop/screens/cart/cart_screen.dart'; @@ -11,11 +12,16 @@ class ThesisShopApp extends StatelessWidget { const ThesisShopApp({Key? key, required this.productService}) : super(key: key); + BlocProvider setupBlocs() { + return BlocProvider( + userBloc: UserBloc(), + ); + } + @override Widget build(BuildContext context) { - final blocProvider = BlocProvider(); return AppState( - blocs: blocProvider, + blocProvider: setupBlocs(), child: MaterialApp( title: 'Thesis Shop', theme: ThemeData(primarySwatch: Colors.red), diff --git a/lib/bloc/user_bloc.dart b/lib/bloc/user_bloc.dart new file mode 100644 index 0000000..5fccca1 --- /dev/null +++ b/lib/bloc/user_bloc.dart @@ -0,0 +1,37 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:thesis_shop/utils/disposable.dart'; + +@immutable +class UserEvent { + final bool isSignedIn; + + const UserEvent({required this.isSignedIn}); +} + +class UserBloc implements Disposable { + bool _isSignedIn = false; + bool get isSignedIn => _isSignedIn; + + final _isSignedInController = StreamController.broadcast(); + Stream get isSignedInStream => _isSignedInController.stream; + + final _userEventController = StreamController.broadcast(); + Sink get userEventSink => _userEventController.sink; + + UserBloc() { + _userEventController.stream.listen(_handleEvent); + } + + void _handleEvent(UserEvent event) { + _isSignedIn = event.isSignedIn; + _isSignedInController.add(event.isSignedIn); + } + + @override + Future dispose() async { + await _isSignedInController.close(); + await _userEventController.close(); + } +} diff --git a/lib/bloc_provider.dart b/lib/bloc_provider.dart index 525497e..0e335ba 100644 --- a/lib/bloc_provider.dart +++ b/lib/bloc_provider.dart @@ -1,26 +1,51 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:thesis_shop/bloc/user_bloc.dart'; -class BlocProvider { - // TODO TBD +import 'utils/disposable.dart'; + +class BlocProvider implements Disposable { + final UserBloc userBloc; + + const BlocProvider({required this.userBloc}); + + @override + Future dispose() async { + await Future.wait([ + userBloc.dispose(), + ]); + } } -class AppState extends InheritedWidget { - final BlocProvider blocs; +class AppState extends StatefulWidget { + final Widget child; + final BlocProvider blocProvider; const AppState({ Key? key, - required this.blocs, - required Widget child, - }) : super(key: key, child: child); + required this.blocProvider, + required this.child, + }) : super(key: key); static AppState of(BuildContext context) { - final AppState? result = - context.dependOnInheritedWidgetOfExactType(); - assert(result != null, 'No AppState found in context'); - return result!; + final AppState? state = context.findAncestorWidgetOfExactType(); + if (state == null) { + throw Exception("AppState is not an ancestor of this widget"); + } + return state; + } + + @override + _AppStateState createState() => _AppStateState(); +} + +class _AppStateState extends State { + @override + Widget build(BuildContext context) { + return widget.child; } @override - bool updateShouldNotify(AppState oldWidget) { - return true; + void dispose() { + widget.blocProvider.dispose(); + super.dispose(); } } diff --git a/lib/utils/disposable.dart b/lib/utils/disposable.dart new file mode 100644 index 0000000..d814f89 --- /dev/null +++ b/lib/utils/disposable.dart @@ -0,0 +1,5 @@ +import 'dart:async'; + +abstract class Disposable { + FutureOr dispose(); +} diff --git a/lib/widgets/user_switch.dart b/lib/widgets/user_switch.dart index 63107e7..0841ae4 100644 --- a/lib/widgets/user_switch.dart +++ b/lib/widgets/user_switch.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:thesis_shop/benchmark_counter.dart'; +import 'package:thesis_shop/bloc/user_bloc.dart'; +import 'package:thesis_shop/bloc_provider.dart'; class UserSwitch extends StatelessWidget { final bool isOn; @@ -11,17 +13,26 @@ class UserSwitch extends StatelessWidget { @override Widget build(BuildContext context) { - BenchmarkCounters.userSwitch++; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.account_circle), - Switch( - value: isOn, - onChanged: onChanged, - activeColor: Colors.green, - ) - ], + final UserBloc userBloc = AppState.of(context).blocProvider.userBloc; + return StreamBuilder( + stream: userBloc.isSignedInStream, + initialData: userBloc.isSignedIn, + builder: (context, snapshot) { + BenchmarkCounters.userSwitch++; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.account_circle), + Switch( + value: snapshot.data ?? false, + onChanged: (newValue) => userBloc.userEventSink.add( + UserEvent(isSignedIn: newValue), + ), + activeColor: Colors.green, + ) + ], + ); + }, ); } }