flutter_fortune_wheel spins on page load | Flutter - flutter

I am using flutter_fortune_wheel: ^1.2.0 from pub.dev
https://pub.dev/packages/flutter_fortune_wheel
I have the Problem when i open the Page the wheel spins automatically. I want it to only spin when i Click it.
return Scaffold(
body: GestureDetector(
onHorizontalDragEnd: (DragEndDetails details) {
setState(() {
selected.add(
Random().nextInt(tricklist.length),
);
});
},
onVerticalDragEnd: (DragEndDetails details) {
setState(() {
selected.add(
Random().nextInt(tricklist.length),
);
});
},
onTap: () {
setState(() {
selected.add(
Random().nextInt(tricklist.length),
);
});
},
child: Stack(
//fit: StackFit.expand,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.center,
child: FortuneWheel(
items: [
for (var items in tricklist)
FortuneItem(
child: Text(items),
),
],
indicators: const <FortuneIndicator>[
FortuneIndicator(
alignment: Alignment.topCenter,
child: TriangleIndicator(color: Colors.black)),
],
selected: selected.stream,
),
),
),
],
),
),
);
Thx for your help

Make the animateFirst flag to false like so:
animateFirst: false
and use the onFling callback to add the behavior you want when the touches the wheel.

Related

What can replace FocusTrap in flutter 3.7.0?

I updated flutter to 3.7.0 and found that the FocusTrap widget has been removed.
What can I replace it with? for example source from pinput library:
return _PinputFormField(
enabled: isEnabled,
validator: _validator,
child: FocusTrap(
focusNode: effectiveFocusNode,
child: MouseRegion(
cursor: _effectiveMouseCursor,
onEnter: (PointerEnterEvent event) => _handleHover(true),
onExit: (PointerExitEvent event) => _handleHover(false),
child: IgnorePointer(
ignoring: !isEnabled || !widget.useNativeKeyboard,
child: AnimatedBuilder(
animation: _effectiveController,
builder: (_, Widget? child) => Semantics(
maxValueLength: widget.length,
currentValueLength: _currentLength,
onTap: widget.readOnly ? null : _semanticsOnTap,
onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus,
child: child,
),
child: _gestureDetectorBuilder.buildGestureDetector(
behavior: HitTestBehavior.translucent,
child: Stack(
alignment: Alignment.topCenter,
children: [
_buildEditable(textSelectionControls),
_buildFields(),
],
),
),
),
),
),
),
);
The offical replacement is TapRegionSurface(flutter.dev) and TapRegion
See https://github.com/flutter/flutter/pull/107262

Flutter How to make an image not show on a condition

I need an image to show or not show, on a condition and the condition is that if the answer of the user is correct than the button will show but if the answer of the question is wrong than the image will not display. the condition is if (joinedWords !=
data[widget.CurrentIndex].sentence // dont display the next
level image. if the
asnwer is correct than the button will show.
String joinedWords =
selectedWords.join(" ").toString();
String _setRatingOnAlert() {
//print(controller.duration?.inSeconds);
print(data![widget.CurrentIndex].timer);
print(data[widget.CurrentIndex].level);
print(joinedWords);
print(data[widget.CurrentIndex].sentence);
print(widget.CurrentIndex);
if (joinedWords ==
data[widget.CurrentIndex].sentence) {
starsRating = 'assets/threestars_small.png';
} else {
starsRating = 'assets/zerostars_small.png';
}
return starsRating;
}
return Container(
child: Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding:
const EdgeInsets.only(right: 110),
child: FlatButton(
onPressed: () {
setState(() {
selectedWords.clear();
Navigator.pop(context);
});
},
child: Image.asset(
'assets/restartbutton.small.png',
height: 80,
width: 80,
),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding:
const EdgeInsets.only(left: 110),
child: FlatButton(
onPressed: () {
Navigator.pop(context);
/// E close munu
Navigator.pop(context);
/// E hek current quiz page
Navigator.push(
/// E qel next level quiz
context,
MaterialPageRoute(
builder: (context) =>
RenditFjaletButton(
QuizList: widget
.AllQuizLists[
widget.CurrentIndex +
1]
.word,
AllQuizLists:
widget.AllQuizLists,
CurrentIndex:
widget.CurrentIndex + 1,
),
),
);
},
child: Image.asset(
'assets/next_small.png', // this is the button that i
dont want to show if the
answer is wrong
height: 80,
width: 80,
),
),
),
),
use ternary operator in this case.
bool answer = false;
//do some operation with answer;
(answer)? ShowImage():Container();
Widget showImage(){
return Container(
child: Image.network(
'imagePath',
fit: BoxFit.fitWidth,
);
}
You can use ternary operator incase you need the conditions.Do as follows:
isTrue? Image.asset():Container()

Force navDrawer state update from outside state scope

I am currently developing an e-commerce mobile app.
Right now I am working on my navigation. There's a bunch of categories that can have subcategories and the subcategories can have their own subcategories. I retrieve a list of all categories via an API on app init and then I store it.
Here's an example of my dataset:
{
"id":"41490",
"name":"Electrical Equipment",
"subCategories":[
{
"id":"41492",
"name":"Breakers",
"subCategories":[
{
"id":"167542",
"name":"1 Pole",
"subCategories":[
{
"id":"167577",
"name":"15 Amp",
"subCategories":null
},
{
"id":"167585",
"name":"20 Amp",
"subCategories":null
},
{
"id":"167600",
"name":"30 Amp",
"subCategories":null
},
{
"id":"167606",
"name":"40 Amp",
"subCategories":null
}
]
},
I am using a listview and a listview builder to make my category list.
The listview builder also calls a recursive function to make the subcategories.
I've managed to get everything to generate dynamically meaning that if on the website we add a bunch of categories then the app will update itself automatically via the API.
My problem now is that when I click my categories, the navDrawer doesn't redraw. I have to close the categories and re-open them to make it redraw. I need some new concepts, been scratching my head on this one for a while.
I think there might be an issue with the structure of my code since I initialize the categories outside the state.
Here's my navDrawer class:
class navDrawer extends StatefulWidget {
bool _expandCategories = false;
bool _expandAccount = false;
List _categories;
var _categoryList;
List _tempSubCats;
void flickCategories(){
//_expandCategories = !_expandCategories;
//sleep(const Duration(microseconds: 100));
//_expandCategories = !_expandCategories;
}
void setCategories(List categories){
_categories = categories;
int catCount = categories.length;
_categoryList = new ListView.builder(
//shrinkWrap: true,
//physics: ClampingScrollPhysics(),
padding:EdgeInsets.all(0.0),
itemCount: catCount,
itemBuilder: (BuildContext context, int index) => buildCategories(context, index),
);
}
Widget buildCategories(BuildContext context, int index){
if(_categories[index]['subCategories']!=null){
if(idHandler.isIdOpen(_categories[index]['id'])){
_tempSubCats = [];
buildSubCategories(_categories[index],2);
ListView subCategories = new ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: _tempSubCats.length,
itemBuilder: (BuildContext ct, int i){
return _tempSubCats[i];
}
);
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(" " + _categories[index]['name']),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap: () {
flickCategories();
idHandler.toggleId(_categories[index]['id']);
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
),
MediaQuery.removePadding(
removeTop: true,
removeBottom: true,
removeLeft: true,
removeRight: true,
context: context,
child: subCategories
)
]
);
} else {
return Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(" " + _categories[index]['name']),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: () {
flickCategories();
idHandler.toggleId(_categories[index]['id']);
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
} else {
return Container(
height: 30.0,
child: ListTile(
title: Text(" "+_categories[index]['name']),
onTap: () {
//TODO: implement category navigation
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
}
void buildSubCategories(var parent, int depth){
if(parent['subCategories']!=null){
List subCategoryList = parent['subCategories'];
int subCategoryCount = subCategoryList.length;
//Column subCats = new Column();
if(idHandler.isIdOpen(parent['id'])) {
for (var i = 0; i < subCategoryCount; i++) {
String formattedCategory = indentCategory(parent['subCategories'][i]['name'], depth);
_tempSubCats.add(
parent['subCategories'][i]['subCategories']!=null ?
Container(
height:20.0,
child:
ListTile(
title: idHandler.isIdOpen(parent['subCategories'][i]['id']) ?
Row(
children:[
Text(formattedCategory),
Transform.rotate(
angle:-math.pi/2,
child:
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
)
]
)
:
Row(
children: [
Text(formattedCategory),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: (){
flickCategories();
idHandler.toggleId(parent['subCategories'][i]['id']);
}
)
)
:
Container(
height:20.0,
child:
ListTile(
title: Text(formattedCategory),
onTap: (){
//TODO: implement category navigation
}
)
)
);
buildSubCategories(parent['subCategories'][i], depth+1);
}
}
}
}
String indentCategory(String input, int amount){
String output='';
for(var i=0; i<amount; i++){
output += ' ';
}
output+=input;
return output;
}
#override
_navDrawerState createState() => _navDrawerState();
}
class _navDrawerState extends State<navDrawer>{
#override
Widget build(BuildContext Context){
return Drawer(
child:
Container(
padding:EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 5),
child:
Column(
children:[
Container(
height:80.0,
width:double.infinity,
child:
DrawerHeader(
child: Text('Menu'),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
Colors.grey,
Colors.red
])
)
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Expanded(
child:
ListView(
padding:EdgeInsets.zero,
children: <Widget>[
widget._expandCategories?
Column(
children:[
Container(
height:40.0,
child: ListTile(
title: Row(
children: [
Text('Categories'),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap:() {
_expandCat();
}
)
),
MediaQuery.removePadding(
removeTop:true,
context: context,
child:
SizedBox(
height:300.0,
child: widget._categoryList,
)
)
]
)
:Container(
height:40.0,
child:
ListTile(
title: Row(
children: [
Text('Categories'),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap:(){
_expandCat();
//Update state of the app
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Container(
height:40.0,
child:
ListTile(
title:Text('Your quotes'),
onTap:(){
//Update state of the app
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
widget._expandAccount?
Column(
children:[
Container(
height:40.0,
child:
ListTile(
title: Row(
children:[
Text('Your account'),
Transform.rotate(
angle:-math.pi/2,
child:
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap:(){
_expandAcc();
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Your Information'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Your Address'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Listed Equipment'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Add Equipment'),
onTap:(){
}
)
),
]
)
:Container(
height:40.0,
child:
ListTile(
title: Row(
children:[
Text('Your account'),
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap:(){
_expandAcc();
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
)
]
),
)
]
)
)
);
}
void _expandCat(){
setState((){
widget._expandCategories=!widget._expandCategories;
});
}
void _expandAcc(){
setState((){
widget._expandAccount=!widget._expandAccount;
});
}
}
NOTE: idHandler is a public member of main.dart.
NOTE2: flickCategories() is one of my attempts at updating the state.
In the screenshot below you can see what I mean:
If I click Electrical Equipment then I have to click Categories twice to make it redraw and I have to scroll back to where it was in the list.
So, how do I make the state update when one of my categories gets clicked?
Do I need something like a stateful category widget?
I'm trying to make it look responsive with arrows and indents and etc.
I figured this out on my own.
I needed to make a productCategory stateful widget and update its state from within the widget.
Each productCategory widget has a List representing the subCategories. During my recursion I add to the subCategories for each productCategory.
The productCategory widget redraws itself properly because I call setState() which has the added bonus of keeping the scroll position where it is.
Here's my productCategory widget:
class productCategory extends StatefulWidget{
String _id = '';
String _name = '';
List<productCategory> _subCategories = [];
productCategory(String id, String name){
_id = id;
_name = name;
}
void addAllSubCategories(List<productCategory> subCats){
_subCategories.addAll(subCats);
}
void addSubCategory(productCategory cat){
_subCategories.add(cat);
}
void setName(String name){
_name = name;
}
void setId(String id){
_id = id;
}
#override
_productCategoryState createState() => _productCategoryState();
}
class _productCategoryState extends State<productCategory>{
#override
Widget build(BuildContext context) {
if(widget._subCategories.isNotEmpty){
if(idHandler.isIdOpen(widget._id)){
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(widget._name),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap: () {
setState((){
idHandler.toggleId(widget._id);
});
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
),
MediaQuery.removePadding(
removeTop: true,
removeBottom: true,
removeLeft: true,
removeRight: true,
context: context,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.all(0.0),
itemCount: widget._subCategories.length,
itemBuilder: (BuildContext context, int index){
return widget._subCategories[index];
}
)
)
]
);
} else {
return Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(widget._name),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: () {
setState((){
idHandler.toggleId(widget._id);
});
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
} else {
return Container(
height: 30.0,
child: ListTile(
title: Text(widget._name),
onTap: () {
//TODO: implement category navigation
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
}
}

Load/Stream video while watching just like youtube or instagram in flutter

I want my video to be loaded just like instagram or youtube loads i.e part by part(stream video) but my code is first loading the whole video then it plays it. Can you help me?
Code:-
VisibilityDetector(
key: Key(url),
onVisibilityChanged: (VisibilityInfo info) {
debugPrint("${info.visibleFraction} of my widget is visible");
if(info.visibleFraction <0.55){
_videoPlayerController.pause();
}
else{
_videoPlayerController.play();
if(!views.contains(currentUser.id))
{
controlViews();
}
}
},
child: ValueListenableBuilder(
valueListenable: _videoPlayerController,
builder: (context,value,child){
return _videoPlayerController.value.initialized?Stack(
children: <Widget>[
GestureDetector(
onDoubleTap: (){controlAudio();},
onTap: (){controlVideoPauseAndPlay();},
child: Container(
color: _darkTheme?Colors.black54:Colors.grey[200],
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height/2
),
alignment: Alignment.center,
child: AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: CachedVideoPlayer(_videoPlayerController,)
),
),
),
Container(padding: EdgeInsets.only(left: 6,top: 6),child: Text((value.duration.inSeconds-value.position.inSeconds).toString()+"s",style: TextStyle(fontSize: 16.5),)),
],
):Center(child: CircularProgressIndicator(),);
},
),
),
And I have initialized the cachedvideoplayer in initState as:-
_videoPlayerController = CachedVideoPlayerController.network(url)..setLooping(true)..initialize().then((_) {
setState(() { });
});

Customize Stepper in Flutter

I want to customize the Steppers in flutter.
How can I place the Step title to the left of each step bar?
How can I change the line bar to the dotted bar of the stepper?
And how can I customize the state of the step other than the 5 StepState provided like a round bubble?
Here is my code.
Container(
child: Stepper(
currentStep: 0,
controlsBuilder: (BuildContext context, {
VoidCallback onStepContinue,
VoidCallback onStepCancel
}) => Container(),
steps: [
Step(
content: Container(
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text('9:00Am - 10:00AM'),
Text(
'Everest Tour',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
),
title: Text('9:00 AM'),
),
Step(
content: Text('2nd Data'),
title: Text('10:00 AM'),
state: StepState.editing,
isActive: true,
subtitle: Text('subtitle')
)
],
),
)
You can customize the Stepper widget by modifying the original Stepper widget class. Here's a customized Stepper widget I've created that can be configured with optional stepIndicatorAlignment and dottedLine arguments. The text on 'Continue' and 'Cancel' buttons can also be modified.
Here's a sample on how it can be implemented.
CustomStepper(
// stepIndicatorAlignment is set to StepIndicatorAlignment.left by default if not configured
stepIndicatorAlignment: StepIndicatorAlignment.right,
// dottedLine is set to false by default if not configured
dottedLine: true,
currentStep: _index,
onStepCancel: () {
if (_index > 0) {
setState(() {
_index -= 1;
});
}
},
onStepContinue: () {
if (_index <= 0) {
setState(() {
_index += 1;
});
}
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
steps: <CustomStep>[
CustomStep(
title: const Text('Step 1 title'),
content: Container(
alignment: Alignment.centerLeft,
child: const Text('Content for Step 1'),
),
continueButtonLabel: 'YES',
cancelButtonLabel: 'NO',
),
CustomStep(
title: Text('Step 2 title'),
content: Container(
alignment: Alignment.centerLeft,
child: Text('Content for Step 2'),
),
),
],
),
In this similar Stack Overflow post, I've explained how I'm able to modify the stock Flutter Stepper widget.