Created
June 23, 2021 20:38
-
-
Save stargazing-dino/c75c4f7e48f01ab7f72d325d2db378c0 to your computer and use it in GitHub Desktop.
simulatorCard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:async_button_builder/async_button_builder.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_hooks/flutter_hooks.dart'; | |
import 'package:flutter_utils/flutter_utils.dart'; | |
import 'package:hooks_riverpod/hooks_riverpod.dart'; | |
import 'package:nremt_paramedic_prep/data/profile/profile.dart'; | |
import 'package:nremt_paramedic_prep/models/doc/doc.dart'; | |
import 'package:nremt_paramedic_prep/models/test/test.dart'; | |
import 'package:nremt_paramedic_prep/providers/categories.dart'; | |
import 'package:nremt_paramedic_prep/providers/question_count.dart'; | |
import 'package:nremt_paramedic_prep/providers/tests.dart'; | |
import 'package:nremt_paramedic_prep/utils/combine_async.dart'; | |
import 'package:nremt_paramedic_prep/utils/default_error.dart'; | |
import 'package:nremt_paramedic_prep/utils/random_question_ids.dart'; | |
import 'package:nremt_paramedic_prep/utils/shimmer_colors.dart'; | |
import 'package:nremt_paramedic_prep/utils/tests.dart'; | |
import 'package:nremt_paramedic_prep/widgets/test_progress.dart'; | |
import 'package:shimmer/shimmer.dart'; | |
import 'package:typicons_flutter/typicons_flutter.dart'; | |
class SimulatorCard extends HookWidget { | |
final String title; | |
final Doc<Profile> profileDoc; | |
final void Function(MaybeDoc<Test> test, bool shuffle) onTap; | |
final void Function(MaybeDoc<Test> test, bool shuffle) onCreate; | |
const SimulatorCard({ | |
Key? key, | |
required this.title, | |
required this.profileDoc, | |
required this.onTap, | |
required this.onCreate, | |
}) : super(key: key); | |
static final _testKey = 'exam'; | |
static final _maxTestLength = 100.0; | |
@override | |
Widget build(BuildContext context) { | |
final testLength = useState(50.0); | |
final theme = Theme.of(context); | |
final startColor = theme.brightness == Brightness.dark | |
? theme.dividerColor.withOpacity(.04) | |
: theme.primaryColor.withOpacity(.04); | |
final endColor = theme.cardColor.withOpacity(.3); | |
final profile = profileDoc.data; | |
final slidingTile = ListTile( | |
dense: true, | |
leading: ConstrainedBox( | |
constraints: BoxConstraints(minWidth: 100.0), | |
child: Text( | |
'${testLength.value.toInt()} Questions:'.padRight(15), | |
style: theme.textTheme.subtitle2, | |
), | |
), | |
title: Slider( | |
min: 10, | |
max: _maxTestLength, | |
divisions: (_maxTestLength - 10) ~/ 5, | |
value: testLength.value, | |
onChanged: (value) => testLength.value = value, | |
label: '${testLength.value.toInt()}', | |
), | |
); | |
return combineAsync3( | |
useProvider(questionCountDocProvider), | |
useProvider(testDocsProvider(profileDoc)), | |
useProvider(questionCategoryDocsProvider), | |
).when( | |
data: (tupleResults) { | |
final questionCountDoc = tupleResults.item1; | |
final questionCount = questionCountDoc.data; | |
final testDocs = tupleResults.item2; | |
final categoryDocs = tupleResults.item3; | |
final challengeTestDocs = testDocsForKey(testDocs, _testKey); | |
final filteredCategoryDocs = categoryDocs | |
.where((doc) => doc.data.simulatorPercent != 0) | |
.toList(); | |
List<String> _questionIDsForNewTest( | |
double testLength, | |
) { | |
final questionIDs = <String>[]; | |
final maxAmount = testLength.round(); | |
for (final categoryDoc in categoryDocs) { | |
final amountInCategory = | |
(testLength * categoryDoc.data.simulatorPercent).round(); | |
questionIDs.addAll( | |
randomQuestionIDs( | |
questionToCategory: questionCount.questionToCategory, | |
currentQuestionIDs: questionIDs, | |
category: categoryDoc.id, | |
amount: amountInCategory, | |
maxAmount: maxAmount, | |
), | |
); | |
} | |
return questionIDs; | |
} | |
return HookBuilder( | |
builder: (context) { | |
final questionIDs = useState(<String>[]); | |
final testDoc = useMemoized( | |
() { | |
if (challengeTestDocs.isNotEmpty) { | |
final _testDoc = challengeTestDocs.last.copyWith( | |
data: Test.alignWithQuestions( | |
challengeTestDocs.last.data, | |
questionIDs.value, | |
), | |
); | |
questionIDs.value = | |
_testDoc.data.questionsAndAnswers.keys.toList(); | |
return _testDoc; | |
} else { | |
questionIDs.value = _questionIDsForNewTest(testLength.value); | |
return UnsavedDoc( | |
data: Test.alignWithQuestions( | |
Test.empty( | |
title: title, | |
key: _testKey, | |
questionIDs: questionIDs.value, | |
), | |
questionIDs.value, | |
), | |
); | |
} | |
}, | |
[testLength.value], | |
); | |
// final test = useState<Test?>(null); | |
// final testReference = useState<DocumentReference<Test>?>(null); | |
final test = testDoc.data; | |
return Material( | |
elevation: 0.0, | |
color: theme.cardColor, | |
borderRadius: BorderRadius.circular(4.0), | |
child: Column( | |
children: <Widget>[ | |
Container( | |
decoration: BoxDecoration( | |
gradient: LinearGradient( | |
begin: Alignment.topLeft, | |
end: Alignment.bottomRight, | |
colors: [ | |
if (theme.brightness == Brightness.light) endColor, | |
startColor, | |
endColor, | |
], | |
), | |
), | |
child: ListTile( | |
onTap: profile.isNotPremium | |
? null | |
: () => onTap(testDoc, true), | |
title: Text( | |
title, | |
style: theme.textTheme.headline6 | |
?.copyWith(fontWeight: FontWeight.w600), | |
), | |
trailing: profile.isNotPremium | |
? const Icon(Typicons.lock_closed_outline) | |
: TestProgress( | |
percentDone: test.percentDone, | |
testDocs: challengeTestDocs, | |
), | |
), | |
), | |
Padding( | |
padding: const EdgeInsets.symmetric( | |
horizontal: kSize, | |
vertical: kSizeSm, | |
), | |
child: DefaultTextStyle( | |
style: theme.textTheme.caption?.copyWith(height: 1.6) ?? | |
TextStyle(), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: <Widget>[ | |
Text( | |
'Tests are composed of multiple choice questions from the following categories:', | |
style: theme.textTheme.caption?.copyWith( | |
fontWeight: FontWeight.w500, | |
fontSize: 14.0, | |
), | |
), | |
const SizedBox(height: kSizeSm), | |
IntrinsicHeight( | |
child: Row( | |
children: [ | |
Flexible( | |
child: Column( | |
crossAxisAlignment: | |
CrossAxisAlignment.stretch, | |
children: filteredCategoryDocs | |
.take(filteredCategoryDocs.length ~/ 2) | |
.map( | |
(categoryDoc) { | |
final category = categoryDoc.data; | |
return Text( | |
'${category.simulatorPercent * 100}%' | |
' ${category.title}', | |
); | |
}, | |
).toList(), | |
), | |
), | |
const SizedBox(width: kSize), | |
Flexible( | |
child: Column( | |
crossAxisAlignment: | |
CrossAxisAlignment.stretch, | |
mainAxisSize: MainAxisSize.max, | |
mainAxisAlignment: | |
MainAxisAlignment.spaceBetween, | |
children: filteredCategoryDocs | |
.sublist( | |
filteredCategoryDocs.length ~/ 2, | |
filteredCategoryDocs.length, | |
) | |
.map( | |
(categoryDoc) { | |
final category = categoryDoc.data; | |
return Text( | |
'${category.simulatorPercent * 100}%' | |
' ${category.title}', | |
); | |
}, | |
).toList(), | |
), | |
), | |
], | |
), | |
), | |
], | |
), | |
), | |
), | |
if (challengeTestDocs.isEmpty) | |
slidingTile | |
else | |
Theme( | |
data: theme.copyWith(dividerColor: Colors.transparent), | |
child: ExpansionTile( | |
title: Text('Generate New Test'), | |
expandedCrossAxisAlignment: CrossAxisAlignment.stretch, | |
children: [ | |
slidingTile, | |
Padding( | |
padding: const EdgeInsets.symmetric( | |
horizontal: kSize, | |
), | |
child: AsyncButtonBuilder( | |
onPressed: profile.isNotPremium | |
? null | |
: () async { | |
await testDoc.when( | |
(reference, data) async { | |
await reference.delete(); | |
}, | |
unsaved: (data) {}, | |
); | |
questionIDs.value = | |
_questionIDsForNewTest( | |
testLength.value, | |
); | |
final newTestDoc = UnsavedDoc( | |
data: Test.empty( | |
title: 'REMAC Simulator', | |
key: _testKey, | |
questionIDs: questionIDs.value, | |
), | |
); | |
onCreate(newTestDoc, true); | |
}, | |
builder: (context, child, callback, _) { | |
return OutlinedButton.icon( | |
icon: child, | |
label: const Text('CREATE'), | |
onPressed: callback, | |
); | |
}, | |
child: profile.isNotPremium | |
? Icon(Icons.lock) | |
: Icon(Icons.navigate_next), | |
), | |
) | |
], | |
), | |
), | |
], | |
), | |
); | |
}, | |
); | |
}, | |
loading: () => Shimmer.fromColors( | |
baseColor: getBaseColor(theme), | |
highlightColor: getHighlightColor(theme), | |
child: Material( | |
borderRadius: BorderRadius.circular(4.0), | |
child: SizedBox(height: 224.0), | |
), | |
), | |
error: defaultError, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment