how to save controller.index value into a static variable? - flutter

class SignUpConvert extends StatefulWidget {
const SignUpConvert({ Key? key}) : super(key: key);
#override
_SignUpConvertState createState() => _SignUpConvertState();
}
class _SignUpConvertState extends State<SignUpConvert>
with SingleTickerProviderStateMixin {
TabController? tabController;
#override
void initState() {
super.initState();
tabController = TabController(vsync: this, length: 2);
print(tabController!.index);
}
#override
void dispose() {
super.dispose();
}
I want to reflect the current index in a static variable
class MyVariable{
static int indexCount = 0;
}
so that i can use it to navigate from a same button to different pages
the button is;
onSubmit: (_) {
if (MyVariable.indexCount == 0) {
Navigator.of(context).push(MaterialPageRoute(
builder: (builder) => LogInConvert()));
}
else if (MyVariable.indexCount == 1) {
Navigator.of(context).push(MaterialPageRoute(
builder: (builder) => SignUpConvert()));
}
},
but the controller.index is not saving in MyVariable.indexCount and i'm getting the default value i.e 0.
i am saving index using custom button
CustomButton(
index: widget.tabIndex,
route: widget.pageToNavigate,
backgroundColor: Color(0xff416bbd),
borderColor: Color(0xff416bbd),
name: 'Sign Up',
textColor: Colors.white,
),
the index value is then assigned to MyVariable.indexCount.
but it is not working!!

Use getx Storage to store the static value and read the value and getstorage.read("store");
dependencies:
get_storage: ^2.0.3
example:
static final _otherBox = () => GetStorage('MyPref');
final username = ''.val('username');
final age = 0.val('age');
final price = 1000.val('price', getBox: _otherBox);
// or
final username2 = ReadWriteValue('username', '');
final age2 = ReadWriteValue('age', 0);
final price2 = ReadWriteValue('price', '', _otherBox);

Related

"'key' is required, but there's no corresponding argument" flutter error

How to solve this error?
The named parameter 'key' is required, but there's no corresponding argument. (Documentation) Try adding the required argument.
error
Future<void> onJoin() async {
// update input validation
setState(() {
_channelController.text.isEmpty
? _validateError = true
: _validateError = false;
});
if (_channelController.text.isNotEmpty) {
await _handleCameraAndMic(Permission.camera);
await _handleCameraAndMic(Permission.microphone);
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoCall(
channelName: _channelController.text,
role: _role,
),
),
);
}
}
class VideoCall
class VideoCall extends StatefulWidget {
final String channelName;
final ClientRole role;
const VideoCall({Key key, required this.channelName, required this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}
class _VideoCallState extends State<VideoCall> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
late RtcEngine _engine;
#override
void dispose() {
// clear users
_users.clear();
// destroy sdk
_engine.leaveChannel();
_engine.destroy();
super.dispose();
}
#override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
this is the videoCall class in there no any error shows.
when add "key" show this
When remove required property from key in video call class
show this error
In VideoCall class, key property set as a required, change it to optional:
class VideoCall extends StatefulWidget {
final String? channelName;
final ClientRole? role;
const VideoCall({Key? key, this.channelName, this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}

Provider not updating when property inside nested object changes

I have a model which initializes multiple objects. Whenever a property inside one of the objects changes, the ui does not rebuild. I took care of overwriting the hash and == of the objects using Equatable so provider should detect the changes. Here is a sample from the code that shows the important parts:
class Tag extends ChangeNotifier with EquatableMixin {
Tag(this._title, this._value, this._selected);
final String _title;
String _value;
bool _selected;
#override
List<Object> get props => [_title, _value, _selected];
String get title => _title;
String get value => _value;
set value(String newValue) {
_value = newValue;
notifyListeners();
}
bool get selected => _selected;
set selected(bool newValue) {
_selected = newValue;
notifyListeners();
}
}
class TagModel extends ChangeNotifier {
TagModel() {
_tag1.addListener(notifyListeners);
_tag2.addListener(notifyListeners);
_tag3.addListener(notifyListeners);
}
final Tag _tag1 = Tag("", "", false);
final Tag _tag2 = Tag("", "", false);
final Tag _tag3 = Tag("", "", false);
Tag get tag1 => _tag1;
Tag get tag2 => _tag2;
Tag get tag3 => _tag3;
//this function does not trigger a widget rebuild
void loadTags() {
_tag1.title = "tag 1";
_tag2.title = "tag 2";
_tag3.title = "tag 3";
}
}
class TagPane extends StatelessWidget {
const TagPane({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
//this does not change when loadTags function is called
final tag1 = context.select((TagModel tagModel) => tagModel.tag1)
return Container(
.
.
.
ElevatedButton(
onPressed: () => context.read<TagModel>().loadTags(),
)
);
}
}
did you try adding a call to NotifyListeners() at the end of the method?
Try using Statefull Widget instead of Stateless than setState when pressing Elevated button. e.g
class TagPane extends StatefullWidget {
const TagPane({Key? key}) : super(key: key);
#override
_TagPaneState createState() => _TagPaneState();
}
class _TagPaneState extends State<TagPane>{
#override
Widget build(BuildContext context) {
//this does not change when loadTags function is called
final tag1 = context.select((TagModel tagModel) => tagModel.tag1)
return Container(
.
.
.
ElevatedButton(
onPressed: () => setState(() {
context.read<TagModel>().loadTags());
),
)
);
}
}

Storing certain value in Widget build / Flutter

I've a question:
In my Widget build(BuildContext context), I want to store a certain value,
final userName = book.owner
(book is the reference to the certain value from Firestore)
But it's done not in the right way to my lack of knowledge. I'd appreciate if someone could guide through that.
Thank you in advance!
Snippet of my code
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
DatabaseMethods databaseMethods = new DatabaseMethods();
var userName;
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
Book book;
_BookViewState(this.book);
String userName;
#override
void initState() {
userName = book.owner;
super.initState();
}
// final Book book;
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
List<String> users = [userName, Constants.myName];
Map<String, dynamic> chatRoomMap = {
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
//widget.book;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
...
FlatButton(
child: Text(
"Get contact with",
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () {
createChatroomAndStartConversation(
userName: userName);
...
}
Snippet of Value not in range: 1
getChatRoomId(String a, String b) {
if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) {
return "$b\_$a";
} else {
return "$a\_$b";
}
}
It's not a good practice to store any data in build() method, because this method is invoked too many times to do the such kind of move. Consider using StatefulWidget to store any state you have in the widget, for the very beginning. When you use this widget, you can define this all in such way:
class YourWidget extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
String userName;
#override
void initState() {
userName = book.owner;
super.initState()
}
#override
Widget build(BuildContext context) {
return Container(child: Text(userName),);
}
}
Here, in initState() you can retrieve value from book and set it to userName. But for more complex and bigger applications, consider using StateManagement solutions and some kind of architectural patterns i.e. Riverpod, Provider, MobX, BLoC.. Because changing the state via setState() method will cause rebuilding whole child widget tree, which could freeze whole UI in complex app.
UPD to 'Snippet of my code':
According to your code, if you are using a 'book' from Widget, not its state - use widget.book, in such way you have access to widget members, because of this you don't need a constructor of state. So, due to these changes, your code might looks like:
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
// You DON'T need this here, because you are retrieving these methods
// inside your state via DatabaseMethods constructor
DatabaseMethods databaseMethods = DatabaseMethods();
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
String userName;
#override
void initState() {
// Using widget.book to retrieve Book object from state's widget
userName = widget.book.owner;
super.initState();
}
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
// Also, it's just a recommendation, try to omit local variables types
// because they are already known with List type (String). Also, this
// all is about chatRoomMap
var users = <String>[userName, Constants.myName];
final chatRoomMap = <String, dynamic>{
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
// your widgets here
}
}
UPD 2:
Second trouble and issue with 'Snippet of Value not in range: 1'. I could to reproduce it with given value of 'a' as empty string. So, your function invocation is like getChatRoomId('', 'user123'), because of empty 'userName', substring function can't take values from range [0, 1), so exception is raised.

flutter [Only static members can be accessed in initializers]

I am a true beginner in flutter and dart.
I have a problem concerning playing youtube videos using [ youtube_player_flutter: ^6.1.1]
I create a Json file with youtube links and I want to link it with [ youtube_player_flutter: ^6.1.1]. but it always displays the error message [Only static members can be accessed in initializers]
#override
Widget build(BuildContext context) {
// this function is called before the build so that
// the string assettoload is avialable to the DefaultAssetBuilder
setasset();
// and now we return the FutureBuilder to load and decode JSON
return FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString(assettoload, cache: true),
builder: (context, snapshot) {
List mydata = json.decode(snapshot.data.toString());
if (mydata == null) {
return Scaffold(
body: Center(
child: Text(
"Loading",
),
),
);
} else {
return quizpage(mydata: mydata);
}
},
);
}
}
class quizpage extends StatefulWidget {
final dynamic mydata;
////////var youtubeUrl;
quizpage({Key key, #required this.mydata}) : super(key: key);
#override
_quizpageState createState() => _quizpageState(mydata);
}
class _quizpageState extends State<quizpage> {
var mydata;
_quizpageState(this.mydata);
int marks = 0;
int i = 1;
#override
void setState(fn) {
if (mounted) {
super.setState(fn);
}
}
YoutubePlayerController _controller;
#override
void initState() {
_controller = YoutubePlayerController(
initialVideoId: YoutubePlayer.convertUrlToId(mydata[4]["1"]));
super.initState();
}
void nextquestion() {
setState(() {
if (i < 10) {
i++;
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
The problem is that I want to make the [String videoURL ] plays the list of videos in my json data file.
Thanks in advance.
Possibility is that you coded the variable mydata twice. This is the format you should follow. And in order to make use of the variable from the StatefulWidget from the constructor, use widget.mydata. Don't have to declare it twice.
Code:
class Quizpage extends StatefulWidget {
final dynamic mydata;
quizpage({Key key, #required this.mydata}) : super(key: key);
#override
_QuizpageState createState() => _QuizpageState();
}
class _QuizpageState extends State<Quizpage> {
/*
You can make use of your mydata in this class like this:
widget.mydata, and you will be able to make it work
*/
Color colortoshow = Colors.indigoAccent;
Color right = Colors.green;
Color wrong = Colors.red;
int marks = 0;
int i = 1;
// String videoURL ="https://www.youtube.com/watch?v=2OAdfB2U88A&t=593s";
YoutubePlayerController _controller;
// Use like this to make use of your array mydata
String videoURL = widget.myData[4]["1"];
#override
void initState() {
_controller = YoutubePlayerController(
initialVideoId: YoutubePlayer.convertUrlToId(videoURL));
super.initState();
}
}
Also, this is for coding point of view. Please follow the correct way of naming classes in Flutter. Always use CamelCase or Have your first letter of the class as capital. This is the best practice while you write your code. I hope the above helps you in some sense. Thanks :)

Stop recursively rendering of a widget due to Provider ( misuse, I guess )

Problem
Recursive rendering of the Widget due to incorrect (probably) use of Provider.
This is the main.dart :
void main() {
runApp(MultiProvider(
providers: [
ChangeNotifierProvider<NotesProvider>(
create: (_) => NotesProvider(),
),
ChangeNotifierProvider<ThemeProvider>(
create: (_) => ThemeProvider(),
),
],
child: MyApp(),
));
}
This redirects to outer_page which contains two tabs like this :
It's code goes to like this :
class OuterPage extends StatefulWidget {
static const routeName = '/OuterPage';
#override
State<StatefulWidget> createState() {
return OuterPageState();
}
}
class OuterPageState extends State<OuterPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedTab = 0;
final _pageOptions = [
NoteScreen(), // <- Notes Tab
NotePageScreen(), // <- 'Another' Tab
];
Widget build(BuildContext context) {
var noteProvider = Provider.of<NotesProvider>(context, listen: false);
// https://stackoverflow.com/a/53839983
var customFabButton;
if (_selectedTab == 0) {
~~~ SNIP ~~~
The default tab is the 'Notes' Tab, which works fine.
'Another' tab, is where the issue lies.
class NotePageScreen extends StatefulWidget {
NotePageScreen();
#override
NotePageScreenState createState() => NotePageScreenState();
}
class NotePageScreenState extends State<NotePageScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
List<Note> noteList;
int count = 0;
#override
Widget build(BuildContext context) {
Provider.of<NotesProvider>(context, listen: false).getAllDecryptedNotes();
return Scaffold(
key: _scaffoldKey,
body: Provider.of<NotesProvider>(context, listen:false).decrypted
? NotePage()
: Container(
child: Center(
child: Text("Add a new Note"),
),
));
}
}
What's going on here
I am fetching the decrypted notes from the database.
NoteProvider.dart :
class NotesProvider with ChangeNotifier {
DatabaseHelper _databaseHelper = DatabaseHelper();
List<Note> _noteList, decryptedNoteList;
int _count = 0;
bool _notesDecrypted = false;
UnmodifiableListView<Note> get allNotes => UnmodifiableListView(_noteList);
getNotes() async {
await _databaseHelper.initializeDatabase();
List<Note> noteList = await _databaseHelper.getNoteList();
this._noteList = noteList;
this._count = noteList.length;
notifyListeners();
}
UnmodifiableListView<Note> get allDecryptedNotes =>
UnmodifiableListView(decryptedNoteList);
getAllDecryptedNotes() async {
List<Note> decryptedNoteList = [];
for (var note in this._noteList) {
decryptedNoteList.add(await decryptNote(note));
}
this.decryptedNoteList = decryptedNoteList;
this._notesDecrypted = true;
notifyListeners();
}
int get count => _count;
bool get decrypted => _notesDecrypted;
~~~~ SNIP ~~~~
What's the problem here
So, what happens is the first time there isn't any decrypted data, but when I swtich tabs and come back again to 'Another' tab, there are the decrypted notes.
What I've tried :
If I set listen to True on either of these :
Provider.of<NotesProvider>(context, listen: false).getAllDecryptedNotes();
Provider.of<NotesProvider>(context, listen: false).decrypted
then the page loads in the first attempt but then it goes on rendering recursively.
That's where the error is.
Thanks :)
Update - Adding Repo
Repo : https://github.com/LuD1161/notes_app/
Branch : reusable_components