Thanks for providing a wonderfully useful class to a Flutter novice like me - it's very much appreciated. I'm not sure whether this is an issue with the class itself or (far more likely) my understanding of how inherited widgets work.
import 'package:dailymedicaltrivia2/ui/pages/PrePlayPage.dart';
import 'package:dailymedicaltrivia2/ui/pages/CareerPage.dart';
import 'package:generic_bloc_provider/generic_bloc_provider.dart';
import 'package:dailymedicaltrivia2/data/UserRepository.dart';
import 'package:dailymedicaltrivia2/data/AppDatabaseProvider.dart';
import 'package:dailymedicaltrivia2/data/database/AppDatabase.dart';
import 'package:dailymedicaltrivia2/data/DMTAPIProvider.dart';
import 'package:dailymedicaltrivia2/data/LocalJsonProvider.dart';
import 'package:dailymedicaltrivia2/bloc/User/UserBloc.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
UserBloc userBloc;
_MyAppState() {
UserRepository _userRepository = UserRepository(
apiProvider: DMTAPIProvider(),
dbProvider: AppDatabaseProvider(database: AppDatabase('data.db')),
jsonProvider: LocalJsonProvider(),
);
userBloc = UserBloc(repository: _userRepository);
}
@override
Widget build(BuildContext context) {
return BlocProvider<UserBloc>(
bloc: userBloc,
child: MaterialApp(
debugShowCheckedModeBanner: false,
routes: {
'/': (context) => PrePlayPage(),
'/career': (context) => CareerPage(),
},
title: 'Daily Medical Trivia',
theme: ThemeData(
primarySwatch: Colors.blue,
highlightColor: Colors.white,
fontFamily: 'Montserrat',
),
),
);
}
}
import 'package:dailymedicaltrivia2/ui/pages/CareerPage.dart';
class PrePlayPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Builder(builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.65,
height: MediaQuery.of(context).size.width * 0.65,
child: Image.asset('assets/images/icon.png'),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(15.0),
),
),
);
}),
FlatButton(
child: Text('Play'),
onPressed: () {
Navigator.pushNamed(context, '/career');
},
),
],
),
),
);
}
}
import 'package:dailymedicaltrivia2/ui/CareerGUI.dart';
import 'package:dailymedicaltrivia2/ui/CareerPath.dart';
import 'package:dailymedicaltrivia2/bloc/User/UserBloc.dart';
import 'package:generic_bloc_provider/generic_bloc_provider.dart';
class CareerPage extends StatefulWidget {
@override
_CareerPageState createState() => _CareerPageState();
}
class _CareerPageState extends State<CareerPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<UserState>(
stream: BlocProvider.of<UserBloc>(context).stateStream, //This is <Line18>, does NOT throw
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('An error occurred'));
} else if (!snapshot.hasData) {
return Center(child: Text(''));
} else {
if (snapshot.data.levels.length == 0) {
return Container(
height: double.infinity,
width: double.infinity,
color: const Color.fromRGBO(94, 148, 184, 1),
child: Center(
child: CircularProgressIndicator(
valueColor:
new AlwaysStoppedAnimation<Color>(Colors.white),
),
),
);
} else {
UserBloc bloc = BlocProvider.of<UserBloc>(context); //<Line 38>, does NOT throw
return Stack(
children: <Widget>[
Positioned.fill(
child: Container(
color: const Color.fromRGBO(171, 202, 223, 1.0)),
),
CareerPath(levels: snapshot.data.levels), //This is <Line45>, DOES throw when building
CareerGUI(),
],
);
}
}
}),
);
}
}
import 'package:generic_bloc_provider/generic_bloc_provider.dart';
import 'package:dailymedicaltrivia2/bloc/user/UserBloc.dart';
import 'package:dailymedicaltrivia2/model/Level.dart';
import 'package:dailymedicaltrivia2/ui/dialogs/StartLevelDialog.dart';
class CareerPath extends StatefulWidget {
final List<Level> levels;
CareerPath({
@required this.levels,
});
@override
_CareerPathState createState() => _CareerPathState();
}
class _CareerPathState extends State<CareerPath> {
List<PathChunk> _chunks;
@override
Widget build(BuildContext context) {
UserBloc bloc = BlocProvider.of<UserBloc>(context); //DOES throw
_chunks = _createChunks(widget.levels);
return ListView.builder(
physics: ClampingScrollPhysics(),
reverse: true,
itemCount: _chunks.length,
itemBuilder: (context, i) {
return _chunks[i];
});
}
List<PathChunk> _createChunks(List<Level> _levels) {
int _levelsPerChunk = 32;
int _indexOffset = 0;
int _deepestCompletedIndex = _indexOfDeepestCompletedLevel();
_chunks = [];
while (_levels.length > 0) {
if (_levels.length > _levelsPerChunk) {
_chunks.add(PathChunk(
deepestCompletedIndex: _deepestCompletedIndex,
indexOffset: _indexOffset,
levels: _levels.sublist(0, _levelsPerChunk),
));
_levels = _levels.sublist(_levelsPerChunk + 1);
_indexOffset = _indexOffset + _levelsPerChunk;
} else {
_chunks.add(PathChunk(
deepestCompletedIndex: _deepestCompletedIndex,
indexOffset: _indexOffset,
levels: _levels.sublist(0),
));
_levels = [];
}
}
return _chunks;
}
int _indexOfDeepestCompletedLevel() {
int _index = 0;
widget.levels.forEach((level) {
if (level.isComplete | level.isMastered) {
_index++;
}
});
return _index;
}
}
class PathChunk extends StatelessWidget {
final double _chunkHeight = 600;
final int deepestCompletedIndex;
final int indexOffset;
final int lineOfSight = 3;
final List<Level> levels;
final List<LevelHubLocation> _hubLocations = [
LevelHubLocation(45, 4),
LevelHubLocation(70, 3.5),
LevelHubLocation(90, 6),
LevelHubLocation(87, 19),
LevelHubLocation(67, 20),
LevelHubLocation(47, 18),
LevelHubLocation(24, 18),
LevelHubLocation(4, 26),
LevelHubLocation(17, 37),
LevelHubLocation(39, 35),
LevelHubLocation(60, 33),
LevelHubLocation(84, 34),
LevelHubLocation(100, 44),
LevelHubLocation(88, 52),
LevelHubLocation(67, 49),
LevelHubLocation(46, 47),
LevelHubLocation(27, 53),
LevelHubLocation(47, 60),
LevelHubLocation(72, 58),
LevelHubLocation(95, 62),
LevelHubLocation(88, 75),
LevelHubLocation(63, 73),
LevelHubLocation(32, 68),
LevelHubLocation(8, 71),
LevelHubLocation(4, 85),
LevelHubLocation(26, 88),
LevelHubLocation(48, 86),
LevelHubLocation(70, 83),
LevelHubLocation(70, 83),
LevelHubLocation(95, 83),
LevelHubLocation(92, 96),
LevelHubLocation(72, 95),
LevelHubLocation(50, 95),
LevelHubLocation(35, 100),
];
PathChunk({
@required this.deepestCompletedIndex,
@required this.levels,
@required this.indexOffset,
});
@override
Widget build(BuildContext context) {
return Container(
height: _chunkHeight,
child: Stack(
children: [
Container(
height: double.infinity,
width: double.infinity,
color: Color.fromRGBO(94, 148, 184, 1),
),
_buildLineLayer(), //Line layer
_buildHubLayer(),
],
),
);
}
Widget _buildHubLayer() {
bool _shouldOpenThisLevel;
bool _shouldShowThisLevel;
List<Align> _hubAligns = [];
for (var i = 0; i < levels.length; i++) {
if ((i + this.indexOffset) > this.deepestCompletedIndex) {
_shouldOpenThisLevel = false;
} else {
_shouldOpenThisLevel = true;
}
if ((i + this.indexOffset) >
this.deepestCompletedIndex + this.lineOfSight) {
_shouldShowThisLevel = false;
} else {
_shouldShowThisLevel = true;
}
_hubAligns.add(Align(
alignment: _hubLocations[i].toAlignment(),
child: LevelHub(
index: i,
level: levels[i],
isOpen: _shouldOpenThisLevel,
isVisible: _shouldShowThisLevel,
),
));
}
return Stack(
children: _hubAligns,
);
}
Widget _buildLineLayer() {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/line.png"),
fit: BoxFit.fill,
),
),
child: null /* add child content here */,
);
}
}
class LevelHubLocation {
final double x;
final double y;
LevelHubLocation(this.x, this.y);
Alignment toAlignment() {
var alignX = (this.x / 50) - 1;
var alignY = (this.y / 50) - 1;
return Alignment(alignX, -alignY);
}
}
class LevelHub extends StatelessWidget {
final String iconPath;
final bool isOpen;
final bool isVisible;
final Level level;
final int lineOfSight = 3;
final int index;
final Color baseColor;
final Color topColor;
LevelHub({
this.isOpen = false,
this.isVisible = false,
this.level,
this.index,
}) : topColor = _chooseTopColor(level, isOpen),
baseColor = _chooseBaseColor(level, isOpen),
iconPath = _chooseIconPath(level, isVisible);
static Color _chooseBaseColor(Level _level, bool _isOpen) {
Color _color = const Color.fromRGBO(138, 138, 138, 1);
if (_isOpen) {
_color = const Color.fromRGBO(127, 184, 223, 1);
}
if (_level.isComplete) {
_color = const Color.fromRGBO(0, 173, 72, 1);
}
if (_level.isMastered) {
_color = const Color.fromRGBO(251, 179, 0, 1);
}
return _color;
}
static Color _chooseTopColor(Level _level, bool _isOpen) {
Color _color = const Color.fromRGBO(158, 158, 158, 1);
if (_isOpen) {
_color = const Color.fromRGBO(171, 202, 223, 1);
}
if (_level.isComplete) {
_color = const Color.fromRGBO(0, 200, 83, 1);
}
if (_level.isMastered) {
_color = const Color.fromRGBO(251, 199, 70, 1);
}
return _color;
}
static String _chooseIconPath(Level _level, bool _isVisible) {
if (_isVisible) {
return _level.iconPath;
} else {
return 'assets/levelicons/outofsight.png';
}
}
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (this.isOpen) {
UserBloc bloc = BlocProvider.of<UserBloc>(context);
Navigator.of(context).push(PageRouteBuilder(
transitionDuration: Duration(seconds: 0),
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return StartLevelDialog(
index: this.index,
level: this.level,
);
}));
}
},
child: Container(
height: 40,
width: 40,
foregroundDecoration: _foregroundDecoration(),
decoration: BoxDecoration(
color: topColor,
boxShadow: [
new BoxShadow(
color: baseColor,
offset: Offset(0, 5),
spreadRadius: 0.5,
),
],
borderRadius: BorderRadius.all(Radius.circular(20)),
image: DecorationImage(
image: AssetImage(iconPath),
fit: BoxFit.fill,
),
),
),
);
}
BoxDecoration _foregroundDecoration() {
///Likely not relevant
}
}
flutter: βββ‘ EXCEPTION CAUGHT BY WIDGETS LIBRARY ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
flutter: The following assertion was thrown building CareerPath(dirty, state: _CareerPathState#66b7b):
flutter: Unable to find BLoC of type _BlocProvider.
flutter: Context provided: CareerPath(dirty, state: _CareerPathState#66b7b)
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 _BlocProvider.of (package:generic_bloc_provider/src/bloc_provider.dart:62:7)
flutter: #1 BlocProvider.of (package:generic_bloc_provider/src/bloc_provider.dart:20:21)
flutter: #2 _CareerPathState.build (package:dailymedicaltrivia2/ui/CareerPath.dart:23:34)
flutter: #3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4012:27)
flutter: #4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15)
flutter: #5 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
flutter: #6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5)
flutter: #7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4053:11)
flutter: #8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3902:5)
flutter: #9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3084:14)
flutter: #10 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5198:32)
flutter: #11 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3084:14)
flutter: #12 Element.updateChild (package:flutter/src/widgets/framework.dart:2887:12)
flutter: #13 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3935:16)
flutter: #14 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
flutter: #15 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2340:33)
flutter: #16 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:700:20)
flutter: #17 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:285:5)
flutter: #18 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1016:15)
flutter: #19 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:958:9)
flutter: #20 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:874:5)
flutter: #24 _invoke (dart:ui/hooks.dart:236:10)
flutter: #25 _drawFrame (dart:ui/hooks.dart:194:3)
flutter: (elided 3 frames from package dart:async)
flutter: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
EDIT: I've realised it looks like GitHub does not supply line numbers so I've tagged the relevant lines with the form <Line18>, <Line38>, <Line45>
if you want to find the relevant parts quickly.
Please let me know if you require any more information or a simpler example to help you understand the issue I'm having.