Im using list of images in story view in flutter, i want to get index of the list which is being displayed on the screen.
This is my code
StoryView(
storyItems: images
.map((e) => StoryItem.pageImage(
url: e,
// caption: "",
controller: newController,
))
.toList(),
onStoryShow: (s) {},
onComplete: () {
print("Completed a cycle");
Navigator.pop(context);
},
onVerticalSwipeComplete: (direction) {
if (direction == Direction.down) {
Navigator.pop(context);
}
},
progressPosition: ProgressPosition.top,
repeat: false,
controller: storyController,
),
You can do .asMap() to the list to change the list item to entry, which has the index.
const arr = ['a', 'b', 'c'];
arr.asMap().entries.map((entry) {
int index = entry.key;
String val = entry.value;
return entry;
});
all I could think of was this
Add the key to StoryItem view Image
Then in the onStoryShow add this
view Image
Finally send to server the var "storyId"
Related
I'm building a todo app in which CRUD operations can be carried out. With the help of Sqlflite todo items will be stored/retrieved from the database. When i try to delete todos, it works just as fine except the last item in the list view remains even after deleting it from the database. But, once the app restarts the last item gets removed. Tried setState() manually to refresh the page but nothings works. Help me sort this out and thanks in adavance.
//Holds the todos and will be passed to ListView.builder
List<Todo> listOfValues;
//Holds the indexes of selected items to highlight the items in the ListView
List<int> indexes = [];
//Holds the ids of selected items to perform CRUD
List<int> selectedItems = [];
//This is where the todos are retrieved from the database.
//Following DatabaseModel is a database helper class
DatabaseModel data = DatabaseModel();
data.queryingData().then((value) {
setState(() {
if (value.isNotEmpty) {
listOfValues = value;
}
});
});
Following block builds/returns the body of the main page of the app which is a ListView contains todos.
Widget content() {
return SafeArea(
child: Container(
child: ListView.builder(
itemBuilder: (context, index) {
return Card(
color: (indexes.contains(index))
? Colors.blue.withOpacity(0.5)
: Colors.transparent,
child: ListTile(
title: Text(listOfValues[index].todo),
subtitle: Text('Planned on ${listOfValues[index].date}'),
trailing: Text(listOfValues[index].time),
onLongPress: () {
setState(() {
lonPressEnabled = true;
if (!indexes.contains(index)) {
indexes.add(index);
selectedItems.add(listOfValues[index].id);
}
});
},
onTap: () {
setState(() {
if (indexes.isNotEmpty && lonPressEnabled) {
if (indexes.contains(index)) {
indexes.remove(index);
selectedItems.remove(listOfValues[index].id);
} else {
indexes.add(index);
selectedItems.add(listOfValues[index].id);
}
}
});
},
),
);
},
itemCount: listOfValues.length,
),
),
);}
Following block is used to delete items from database
ElevatedButton(
onPressed: () {
lonPressEnabled = false;
DatabaseModel model = DatabaseModel();
for (int i = 0; i < selectedItems.length; i++) {
model.deletingRecord(selectedItems[i]);
//selectedItems holds the ids of each todos
}
selectedItems = [];
indexes = [];
setState(() {
print();
});
},
child: const Icon(Icons.delete));
Following block deletes todo from the database
deletingRecord(int ids) async {
Database db = await openingDB;
db.rawDelete('delete from ToDos where id=$ids');}
I am using flutter_tags package in my project. when i add text in the TagsTextField and press Enter I get below error and that part becomes red.
Expected a value of type 'DataList', but got one of type 'Null'
Code:
List subs = [];
final GlobalKey<TagsState> _globalKey = GlobalKey<TagsState>();
// Rest of the code
Tags(
key: _globalKey,
itemCount: subs.length,
columns: 6,
textField: TagsTextField(
textStyle: const TextStyle(fontSize: 14),
onSubmitted: (String str) {
setState(() {
subs.add(
Item(title: str),
);
showDialogBox(context, "showing", subs.toString());
});
}),
itemBuilder: (i) {
final currentItem = subs[i]!;
print(currentItem);
return ItemTags(
index: i,
title: currentItem.title,
customData: currentItem.customData,
onPressed: (curr) => print(curr),
onLongPressed: (curr) => print(curr),
removeButton: ItemTagsRemoveButton(
onRemoved: () {
setState(() {
subs.removeAt(i);
});
return true;
},
),
);
},
)
// rest of the code
*Before Clicking Enter
After I Click Enter
remove this line
customData: currentItem.customData,
and it will work.
Edit: Updated my comment.
title: currentItem.title <- the types do not match, one is String and the other is String? You need to read the documentation on how to handle/use null safety in dart.
https://dart.dev/null-safety/understanding-null-safety
Could also be due to your list not being initialized properly. Try the below:
List subs= List.empty(growable: true);
I am using flutter story view for showing stories in our app. The story view runs perfectly but for any single story on tap, if story is complete it will pop on complete function. Now I want to run multiple user stories like WhatsApp, Instagram one-by-one if running story duration is complete show next user story automatically. I can'nt understand how to run next user story automatically. I am new on Flutter.
List<StoryItem> storylist = [];
onTap: () {
storylist.add(StoryItem.pageVideo(
item['video'],
controller: controller,
));
setState(() {});
showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
// storylist = storylist.toSet().toList();
return StoryView(
storyItems: storylist,
onComplete: () {
Navigator.pop(context);
setState(() {});
},
repeat: false,
onVerticalSwipeComplete: (direction) {
if (direction == Direction.down) {
setState(() {});
Navigator.pop(context);
setState(() {});
}
},
controller: controller,
);
},
);
},
You can try AdvStory, this package fits your use case.
AdvStory(
storyCount: 5,
storyBuilder: (index) {
return Story(
// Story media count
contentCount: 5,
contentBuilder: (contentIndex) {
// You can return ImageContent, VideoContent, SimpleCustomContent
// or you can create your own contents, see docs.
return ImageContent(url: '');
},
);
},
trayBuilder: (index) => AdvStoryTray(url: ''),
)
I have 2 DropdownButtonFormFields where I have a selection of cars. I need to change the second selection of buttons according to the car model user has chosen from the first selection in the DropdownButtonFormField (i.e. If a user chooses a Mercedes in the first one, in the DropdownButtonFormField below, I want to display only models of Mercedes and not, let's say, Audi).
How can I achieve this? Here is the code:
String _make, _model;
/// List of cars and models
List<String> carList = [
'Audi',
'BMW',
'Mercedes',
];
List<String> modelAudi = ['A6', 'A8', 'Q7',];
List<String> modelMercedes = ['E-Class', 'S-Class','Maybach'];
List<String> modelBMW = ['3-Series', 'X5', 'X7'];
/*two DropdownButtonFormFields, but the second one needs to match
it's car manufacturer selection from the carList selection
(i.e. if you select Audi, it must only show the modelAudi list (A6,
A8, Q7) in the second DropdownButtonFormField)
*/
DropdownButtonFormField<String>(
value: _make,
items: carList
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_make = value;
print(value);
});
},
),
DropdownButtonFormField<String>(
value: _model,
/* here is where I need to implement logic
that maps out the model names that matches the car maker
*/
items: modelAudi
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_model = value;
print(value);
});
},
),
The DropDown for the first button:
And naturally because I have no logic behind it, I get this as the model selection whatever I chose from the car list, but I want it to map out only models from the car list you chose.
This is a great use case for a switch statement. Define your cases for each car maker according to this example:
String _maker;
List chosenMakerModel;
switch (_maker) {
case 'Audi':
chosenMakerModel = modelAudi;
break;
case 'BMW':
// implement logic:
break;
case 'OTHER MANUFACTURER':
// implement logic;
break;
}
Using the example code above use chosenMakerModel instead of modelAudi
You can create a model selection method to handle this situation, like
List<String> _selectModel(String? modelName) {
return modelName == carList[0]
? modelAudi
: modelName == carList[1]
? modelMercedes
: modelBMW; // initally it will have modelBMW
}
This will decide the second dropdown item. If you click to select the second drop down item 1st, it will through errors. To handle this situation, you need to update the second dropdown value as well. You can set the second dropdown value=null. Therefor we need to use nullable String for selection value.
class MyProfileState extends State<StatefulWidget> {
String? _make, _model;
/// List of cars and models
List<String> carList = ['Audi', 'BMW', 'Mercedes'];
List<String> modelAudi = ['A6', 'A8', 'Q7'];
List<String> modelMercedes = ['E-Class', 'S-Class', 'Maybach'];
List<String> modelBMW = ['3-Series', 'X5', 'X7'];
List<String> _selectModel(String? modelName) {
return modelName == carList[0]
? modelAudi
: modelName == carList[1]
? modelMercedes
: modelBMW;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
DropdownButtonFormField<String>(
value: _make,
items: carList
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_make = value;
_model = null;
print(value);
});
},
),
DropdownButtonFormField<String>(
value: _model,
items: _selectModel(_make)
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_model = value;
print(value);
});
},
),
],
));
}
}
this the constructor I made
class User {
String strength1;
String strength2;
String strength3;
String strength4;
String strength5;
User({this.strength1, this.strength2, this.strength3,this.strength4,this.strength5});
Map<String, dynamic>toMap(){
var map = <String, dynamic>{
'strength1' : strength1,
'strength2' : strength2,
'strength3' : strength3,
'strength4' : strength4,
'strength5' : strength5,
};
return map;
}
User.fromMap(Map <String, dynamic>map){
strength1 = map['strength1'];
strength2 = map['strength2'];
strength3 = map['strength3'];
strength4 = map['strength4'];
strength5 = map['strength5'];
}
}
and then the loop should be
List<Widget> createRadioListUsers() {
List<Widget>widgets = [];
for (User user in users) {
widgets.add(
RadioListTile(
value: user,
groupValue: selectedUser,
title: Text(user.strengths),
onChanged: (currentUser) {
print('Current User ${currentUser.strengths}');
setSelectedUser(currentUser);
},
selected: selectedUser == user,
activeColor: Colors.green,
);
}
return widgets;
}
I learned this loop from a tutorial and tried changing the type of constructor but apparently the values for the radio button won't work since in the tutorial the values were already given but for the program I'm making I have to get the user input from another page to this page and show them in a radio list tile
Here is a solution using StreamBuilder:
First, let's declare the controller, the stream and getter
final BehaviorSubject<User> _radioController = BehaviorSubject<User>();
Stream<User> get radioStream => _radioController.stream;
Function(User) get updateRadio => _radioController.sink.add;
Then, put the builder in your widget
StreamBuilder(
stream: radioStream,
initialData: null,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
for (User user in users) {
widgets.add(
RadioListTile(
value: user,
groupValue: snapshot.data, // The value will be updated when you select an other radio
title: Text(user.strengths),
onChanged: updateRadio, // Update the groupValue
selected: selectedUser == user,
activeColor: Colors.green,
);
},
// Return your widgets, for example Column(children: widgets),
},
),
...