Dart/Flutter widget with optional parameters but at least one required - flutter

I'm trying to create a Flutter widget that can be initialized by various parameters, something like this
class MyWidget extends StatefulWidget {
final int? id;
final String? username;
MyWidget({this.id, this.username});
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
#override
void initState() {
super.initState();
if (widget.id != null) {
// init based on id
} else if (widget.username != null) {
// init based on username
} else {
// this should never happen
}
}
#override
Widget build(BuildContext context) {
return Container(); // build some widget
}
}
As you can see, neither of id and username are required, but I would need that at least one of them present. What would be a good way to approach this?

You can declare the constructor as anyone of these
MyWidget(this.id,{this.username});//ID is required. Usage will be MyWidget(1,usename:'test');
MyWidget(this.username,{this.id});//username is required Usage will be MyWidget('test',id:1);
MyWidget({required this.id, this.username}); //id required
MyWidget({this.id, required this.username});//username required
MyWidget({requried this.id, required this.username});//both required
And you can also use Assert Statement to check values at runtime have a look
MyWidget({this.id, this.username}):assert(id != null && username != null,'Both parameters cannot be null');

class TestWidget extends StatelessWidget {
final String id;
final String name;
const TestWidget.name({this.id, #required this.name});
const TestWidget.id({#required this.id, this.name});
#override
Widget build(BuildContext context) {
return Container(
child: Text(id ?? name),
);
}
}

Related

DocumentSnapshot returning null and new screen stuck on loading

When this widget is called, its stuck on loading animation, and when hot reloaded, it shows the transactions
`
class TransactionList extends StatefulWidget {
final int groupIndex;
final String groupUid;
const TransactionList(
{super.key, required this.groupIndex, required this.groupUid});
#override
State<TransactionList> createState() => _TransactionListState();
}
class _TransactionListState extends State<TransactionList> {
#override
Widget build(BuildContext context) {
final groupTransaction = Provider.of<DocumentSnapshot?>(context);
if (groupTransaction == null) return const Loading();
return transactionItemsBuilder(groupTransaction);
}`
edit:
this is firebase instance created,
class DatabaseServices {
final String? uid;
DatabaseServices({this.uid});
final CollectionReference groupCollection =
FirebaseFirestore.instance.collection('groups');
Stream<DocumentSnapshot> get transactions {
return groupCollection.doc(uid).snapshots();
}
}
and this is my stream provider
StreamProvider<DocumentSnapshot?>.value(
initialData: null,
value: DatabaseServices(uid: widget.item[widget.index].id)
.transactions,
child: TransactionList(
groupIndex: widget.index,
groupUid: widget.item[widget.index].reference.id),
),
Solved this by providing initial data to the stream provider. The data was obtained earlier.

How to create custom types of widgets in Flutter?

I am trying to create a couple of widgets A that all should belong to another type of widget B, so that in the end all of them could be passed to a constructor that accepts only widgets of type B, but not other custom widgets like Container, Text, etc.
I tried something like this:
Parent class:
class ProDynamicWidget {
const ProDynamicWidget({
required this.height
});
final double height;
}
Child classes:
class ProDynamicTitle extends ProDynamicWidget {
final String title;
ProDynamicTitle({
required this.title
}) : super(height: 50.0);
// Here should be a build method for the title
}
############################################################
class ProDynamicImage extends ProDynamicWidget {
final String imageUrl;
ProDynamicImage({
required this.imageUrl
}) : super(height: 70.0);
// Here should be a build method for the image
}
I then wanted to create a widget that only accept widgets of type ProDynamicWidget:
class TestOneWidget extends StatelessWidget {
const TestOneWidget({
Key? key,
required this.widget
}) : super(key: key);
final ProDynamicWidget widget;
#override
Widget build(BuildContext context) {
return Container();
}
}
I do not really get how can now end up with child widgets that have separate build methods and a way the constructur at the end only accepts these child widgets instead of every type of widget.
Make ProDynamicWidget abstract and let it extend StatelessWidget:
abstract class ProDynamicWidget extends StatelessWidget{
const ProDynamicWidget({
required this.height
});
final double height;
}
Next, ProDynamicTitle and ProDynamicImage simply extend ProDynamicWidget and will thus have to define the build method:
class ProDynamicTitle extends ProDynamicWidget {
final String title;
const ProDynamicTitle({
required this.title
}) : super(height: 50.0);
#override
Widget build(BuildContext context) {
return Text(title);
}
}
class ProDynamicImage extends ProDynamicWidget {
final String imageUrl;
const ProDynamicImage({
required this.imageUrl
}) : super(height: 70.0);
#override
Widget build(BuildContext context) {
return Image(image: NetworkImage(imageUrl));
}
}
You can keep TestOneWidget as is. It will only accept descendants of ProDynamicWidget.

boolean expression must not be null | Getting this error when i switch timerState to "true". "False" doesn't give an error, what went wrong?

I am getting bool value timerState through the constructor. When I print the value I get proper results (true or false).
I need to call the function _controller.start() when timerState() == true. However when it is true I get the error: "Failed assertion: boolean expression must not be null".
Surprisingly, when timerState is false, I am not getting this error.
Please help, where can be a problem.
Below is my code:
class PieChart extends StatefulWidget {
final String userId;
final String userName;
final bool timerState;
final Key key;
PieChart(
this.userId,
this.userName,
this.timerState,
{this.key});
#override
State<StatefulWidget> createState() => PieChartEmotionsState(
userId,
userName,
timerState,
);
}
class PieChartEmotionsState extends State {
final String userId;
final String userName;
final bool timerState;
final Key key;
PieChartEmotionsState(
this.userId,
this.userName,
this.timerState,
{this.key});
#override
Widget build(BuildContext context) {
CountDownController _controller = CountDownController();
int _duration = 10;
bool getTimerState() {
print('PIE CHART timerState: $timerState');
return timerState == true;
}
if (getTimerState()) {
_controller.start();
}
return Container(...
I have obviously tried a simpler way:
if(timerState) _controller.start();
even this:
if(timerState ?? false) _controller.start();
But it seems not to have any impact on the issue. I am getting the same error...
What could be the solution?
Many thanks in advance for your support.
Dan
You don't need co create copies of your widget classes variables in the State class. Access them as widget.variable
class PieChart extends StatefulWidget {
final String userId;
final String userName;
final bool timerState;
final Key key;
PieChart(
this.userId,
this.userName,
this.timerState,
{this.key});
#override
State<PieChart> createState() => _PieChartState();
}
class _PieChartState extends State<PieChart> {
bool getTimerState() {
print('PIE CHART timerState: ${widget.timerState}');
return widget.timerState == true;
}
#override
Widget build(BuildContext context) {
CountDownController _controller = CountDownController();
int _duration = 10;
if (getTimerState()) {
_controller.start();
}
return Container(...
and make sure you initialize timerState when creating your PieChart widget as it's declared final.
PieChart('userId', 'userName', true);
If you don't initialize it, it's set to null and the error you get is because you are checking if null == true in your getTimerState() method.

flutter: how to get data from db and using it through the whole app

I am so confused about state management.
Below is I pass down data through widgets.
List<AppUser> userList = List<AppUser>();
List<List<MessageType>> messageLists = new List<List<MessageType>>();
#override
void initState() {
super.initState();
loadUsers();
}
Future<void> loadUsers() async {
userList.clear();
userList.addAll(await AppUser.getRelatedUsers(customer.customerID));
defaultUser = await AppUser.getDefaultUser(customer.customerID);
if (defaultUser != null && !await defaultUser.hideUserTab()) {
userList.add(defaultUser);
}
await loadMessageList();
}
Then I pass the userList and messageList to another stateful widget. But what if I want to have those data through the whole app using inherited widget or provider or bloc.
MessageTypePage(
messageTypeList: messageLists[tabIndex],
currentUser: userList[tabIndex],
);
How can I possible to get the data from db and store them in inherited widget then using those data? I am so confused.
class StateContainer extends StatefulWidget {
final Widget child;
final List<AppUser> userList;
final List<Message> messageList;
StateContainer({#required this.child, this.userList, this.messageList});
static StateContainerState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<_InheritedStateContainer>().data;
}
#override
StateContainerState createState() => new StateContainerState();
}
class StateContainerState extends State<StateContainer> {
List<AppUser> userList = List<AppUser>();
List<List<MessageType>> messageLists = new List<List<MessageType>>();
#override
Widget build(BuildContext context) {
return _InheritedStateContainer(
data: this,
child: widget.child,
);
}
}
class _InheritedStateContainer extends InheritedWidget {
final StateContainerState data;
_InheritedStateContainer({Key key, #required this.data, #required Widget child}) : super(key: key, child: child);
#override
bool updateShouldNotify(_InheritedStateContainer oldWidget) {
return true;
}
}
In my opinion, the best approach is to use Provider or Bloc. There is a flutter codelab that uses Provider to do something very similar to what you are doing. It stores a list of items (in your case that would be Users) that can be used throughout the app. It also shows you how to manipulate the list in various ways.
The codelab is here. I think it would help you out.

I am getting this error styling my portfolio in flutter

import 'package:flutter/material.dart';
class ThemeSwitcher extends InheritedWidget {
final _ThemeSwitcherWidgetState data; // We'll use ThemeSwitcher to get access to the current state of ThemeSwitcherWidget
const ThemeSwitcher({
Key key,
#required this.data,
#required Widget child,
}) : assert(child != null),
super(key: key, child: child);
static _ThemeSwitcherWidgetState of(BuildContext context) { //This method returns the current state of the ThemeSwitcherWidget. This will be used down the tree
return (context.dependOnInheritedWidgetOfExactType(ThemeSwitcher)
as ThemeSwitcher)
.data;
}
#override
bool updateShouldNotify(ThemeSwitcher old) {
return this != old;
}
}
class ThemeSwitcherWidget extends StatefulWidget {
final bool initialDarkModeOn; // this is the initial state of the variable
final Widget child; // child to which this boolean variable should be propagated upon change. This will be our app in this case
ThemeSwitcherWidget({Key key, this.initialDarkModeOn, this.child})
: assert(initialDarkModeOn != null),
assert(child != null),
super(key: key);
#override
_ThemeSwitcherWidgetState createState() => _ThemeSwitcherWidgetState();
}
class _ThemeSwitcherWidgetState extends State<ThemeSwitcherWidget> {
bool isDarkModeOn;
void switchDarkMode() { //method used to toggle dark mode during the runtime of the app
setState(() {
isDarkModeOn = !isDarkModeOn;
});
}
#override
Widget build(BuildContext context) {
isDarkModeOn = isDarkModeOn ?? widget.initialDarkModeOn; // this is the build method which would build the widget tree with the above info
return ThemeSwitcher(
data: this,
child: widget.child,
);
}
}
Too many positional arguments: 0 expected, but 1 found.
Try removing the extra positional arguments, or specifying the name for named arguments.
This is the Error I am continuously facing the issue after trying many methods.
I would like to know how would this problem can be solved as I am not getting any good solution from searches.
Return the following statement in _ThemeSwitcherWidgetState of(BuildContext context) method of your code:
return (context.dependOnInheritedWidgetOfExactType<ThemeSwitcher>()).data;