I am using Flutter for a mobile app and django for backend API. I want user to be able to login with accounts from Facebook, Google etc. How Can I implement this?
Also I saw that dj-rest-auth provides requests for Social Media Authentication. Should I use something like this?
There is flutter_facebook_login package. You can use it like this:
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
final facebookLogin = FacebookLogin();
final result = await facebookLogin.logInWithReadPermissions(['email']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
_sendTokenToServer(result.accessToken.token);
_showLoggedInUI();
break;
case FacebookLoginStatus.cancelledByUser:
_showCancelledMessage();
break;
case FacebookLoginStatus.error:
_showErrorOnUI(result.errorMessage);
break;
}
And google_sign_in package for the other part of your question. Here is a complete example:
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:convert' show json;
import "package:http/http.dart" as http;
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: <String>[
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
void main() {
runApp(
MaterialApp(
title: 'Google Sign In',
home: SignInDemo(),
),
);
}
class SignInDemo extends StatefulWidget {
#override
State createState() => SignInDemoState();
}
class SignInDemoState extends State<SignInDemo> {
GoogleSignInAccount _currentUser;
String _contactText;
#override
void initState() {
super.initState();
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) {
setState(() {
_currentUser = account;
});
if (_currentUser != null) {
_handleGetContact();
}
});
_googleSignIn.signInSilently();
}
Future<void> _handleGetContact() async {
setState(() {
_contactText = "Loading contact info...";
});
final http.Response response = await http.get(
'https://people.googleapis.com/v1/people/me/connections'
'?requestMask.includeField=person.names',
headers: await _currentUser.authHeaders,
);
if (response.statusCode != 200) {
setState(() {
_contactText = "People API gave a ${response.statusCode} "
"response. Check logs for details.";
});
print('People API ${response.statusCode} response: ${response.body}');
return;
}
final Map<String, dynamic> data = json.decode(response.body);
final String namedContact = _pickFirstNamedContact(data);
setState(() {
if (namedContact != null) {
_contactText = "I see you know $namedContact!";
} else {
_contactText = "No contacts to display.";
}
});
}
String _pickFirstNamedContact(Map<String, dynamic> data) {
final List<dynamic> connections = data['connections'];
final Map<String, dynamic> contact = connections?.firstWhere(
(dynamic contact) => contact['names'] != null,
orElse: () => null,
);
if (contact != null) {
final Map<String, dynamic> name = contact['names'].firstWhere(
(dynamic name) => name['displayName'] != null,
orElse: () => null,
);
if (name != null) {
return name['displayName'];
}
}
return null;
}
Future<void> _handleSignIn() async {
try {
await _googleSignIn.signIn();
} catch (error) {
print(error);
}
}
Future<void> _handleSignOut() => _googleSignIn.disconnect();
Widget _buildBody() {
if (_currentUser != null) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
ListTile(
leading: GoogleUserCircleAvatar(
identity: _currentUser,
),
title: Text(_currentUser.displayName ?? ''),
subtitle: Text(_currentUser.email ?? ''),
),
const Text("Signed in successfully."),
Text(_contactText ?? ''),
RaisedButton(
child: const Text('SIGN OUT'),
onPressed: _handleSignOut,
),
RaisedButton(
child: const Text('REFRESH'),
onPressed: _handleGetContact,
),
],
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
const Text("You are not currently signed in."),
RaisedButton(
child: const Text('SIGN IN'),
onPressed: _handleSignIn,
),
],
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Google Sign In'),
),
body: ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: _buildBody(),
));
}
}
try to use jwt which is JSON web token
Related
I am using AWS Cognito and Flutter framework to build an app.
The cognito suddenly is not working when I changed the layout(?) of the app, please help me out!
When I first built the app I made it so the login page would come up first but now I changed the page layout so the users can login after looking around the app.
Thisis what I get in the console when I hit the login button:
W/CognitoUserSession(22147): CognitoUserSession is not valid because idToken is null.
D/AWSMobileClient(22147): Sending password.
D/AWSMobileClient(22147): Using USER_SRP_AUTH for flow type.
E/UserContextDataProvider(22147): Exception in creating JSON from context data
E/amplify:flutter:auth_cognito(22147): AuthException
I/flutter (22147): Could not login - Sign in failed
this is how my Widget build in main looked like before:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Photo Gallery App',
theme: ThemeData(visualDensity: VisualDensity.adaptivePlatformDensity),
home: StreamBuilder<AuthState>(
stream: _authService.authStateController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Navigator(
pages: [
if (snapshot.data!.authFlowStatus == AuthFlowStatus.login)
MaterialPage(
child: LoginPage(
didProvideCredentials: _authService.loginWithCredentials,
shouldShowSignUp: _authService.showSignUp
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.signUp)
MaterialPage(
child: SignUpPage(
didProvideCredentials: _authService.signUpWithCredentials,
shouldShowLogin: _authService.showLogin
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.verification)
MaterialPage(
child: VerificationPage(
didProvideVerificationCode: _authService.verifyCode
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.session)
MaterialPage(
child: CameraFlow(shouldLogOut: _authService.logOut)
)
],
onPopPage: (route, result) => route.didPop(result),
);
} else {
return Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
);
}
}
)
);}
Now, it looks like this:
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'App',
theme: ThemeData(visualDensity: VisualDensity.adaptivePlatformDensity),
home: StreamBuilder<AuthState>(
stream: AuthService.authStateController.stream, // PREVIOUS: _authService.authStateController.stream
builder: (context, snapshot) {
if (snapshot.hasData) {
return Navigator(
pages: [
if (snapshot.data!.authFlowStatus == AuthFlowStatus.none || snapshot.data!.authFlowStatus == AuthFlowStatus.session)
MaterialPage(
child: TabBarFlow(
authFlowStatus: snapshot.data!.authFlowStatus,
shouldShowSignUp: _authService.showSignUp,
shouldShowLogin: _authService.showLogin,
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.login)
MaterialPage(
child: LoginPage(
didProvideCredentials: _authService.loginWithCredentials,
shouldShowSignUp: _authService.showSignUp,
shouldShowNone: _authService.showNone,
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.signUp)
MaterialPage(
child: SignUpPage(
didProvideCredentials: _authService.signUpWithCredentials,
shouldShowLogin: _authService.showLogin,
shouldShowNone: _authService.showNone,
)
),
if (snapshot.data!.authFlowStatus == AuthFlowStatus.verification)
MaterialPage(
child: VerificationPage(
didProvideVerificationCode: _authService.verifyCode
)
)
],
onPopPage: (route, result) => route.didPop(result),
);
} else {
return Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
);
}
}
),
);}
I think the problem might be coming from TabbarFlow which looks like this:
#override
void initState() {
super.initState();
_widgetOptions = <Widget>[
HomePage(),
SearchAvatarPage(),
SelectAvatarPage(),
MyPage(),
SettingsPage(
authFlowStatus: widget.authFlowStatus,
shouldShowSignUp: widget.shouldShowSignUp,
shouldShowLogin: widget.shouldShowLogin
)
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.grey,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: ''
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: ''
),
BottomNavigationBarItem(
icon: ClipOval(
child: Container(
width: 35,
height: 35,
color:Color.fromRGBO(37, 67, 117, 1),
child: Icon(Icons.add, color: Colors.white)
)
),
label: ''
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
label: ''
),
BottomNavigationBarItem(
icon: Icon(Icons.menu_outlined),
label: ''
)
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);}
Amplify logic
import 'dart:async';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify.dart';
import 'auth_credentials.dart';
enum AuthFlowStatus { none, login, signUp, verification, session }
class AuthState {
final AuthFlowStatus authFlowStatus;
AuthState({required this.authFlowStatus});
}
class AuthService {
static final authStateController = StreamController<AuthState>();
late AuthCredentials _credentials;
void showNone() {
final state = AuthState(authFlowStatus: AuthFlowStatus.none);
authStateController.add(state);
}
void showSignUp() {
final state = AuthState(authFlowStatus: AuthFlowStatus.signUp);
authStateController.add(state);
}
void showLogin() {
final state = AuthState(authFlowStatus: AuthFlowStatus.login);
authStateController.add(state);
}
void loginWithCredentials(AuthCredentials credentials) async {
try {
final result = await Amplify.Auth.signIn(
username: credentials.username, password: credentials.password
);
if (result.isSignedIn) {
final state = AuthState(authFlowStatus: AuthFlowStatus.session);
authStateController.add(state);
} else {
print('User could not be signed in');
}
} on AuthException catch (authError) {
print('Could not login - ${authError.message}');
}
}
void signUpWithCredentials(SignUpCredentials credentials) async {
try {
final userAttributes = {'email': credentials.email};
final result = await Amplify.Auth.signUp(
username: credentials.username,
password: credentials.password,
options: CognitoSignUpOptions(userAttributes: userAttributes)
);
if (result.isSignUpComplete) {
loginWithCredentials(credentials);
} else {
this._credentials = credentials;
final state = AuthState(authFlowStatus: AuthFlowStatus.verification);
authStateController.add(state);
}
} on AuthException catch (authError) {
print('Failed to sign up - ${authError.message}');
}
}
void verifyCode(String verificationCode) async {
try {
final result = await Amplify.Auth.confirmSignUp(
username: _credentials.username, confirmationCode: verificationCode
);
if (result.isSignUpComplete) {
loginWithCredentials(_credentials);
} else {
// Add later
}
} on AuthException catch (authError) {
print('Could not verify code - ${authError.message}');
}
}
void checkAuthStatus() async {
try {
await Amplify.Auth.fetchAuthSession();
final state = AuthState(authFlowStatus: AuthFlowStatus.session);
authStateController.add(state);
} catch (_) {
final state = AuthState(authFlowStatus: AuthFlowStatus.none);
authStateController.add(state);
}
}
static void logOut() async {
try {
await Amplify.Auth.signOut();
final state = AuthState(authFlowStatus: AuthFlowStatus.none);
authStateController.add(state);
} on AuthException catch (authError) {
print('Could not log out - ${authError.message}');
}
}
}
My question is if I can put a List in a Doc from Firebase.
Here is my Code:
Future getPosts() async {
var test = await FirebaseFirestore.instance
.collection("Profiles")
.doc(auth.currentUser.displayName)
.collection("Following")
.doc()
.get()
.asStream()
.toList();
print(test);
qn = await FirebaseFirestore.instance
.collection("Posts")
.doc() // here I want the string of All documents from the List
.collection("_Posts")
.get();
}
The Code is pretty shitty but yeah hope you can Help.
Here is a working code implementing both FutureBuilder() and StreamBuilder():
class PlayGround extends StatefulWidget {
const PlayGround({Key? key}) : super(key: key);
#override
_PlayGroundState createState() => _PlayGroundState();
}
class _PlayGroundState extends State<PlayGround> {
FirebaseFirestore _db = FirebaseFirestore.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
//using a Future ( Fetch once )
Expanded(
child: FutureBuilder<List<PostsModel>>(
future: fetchUserPosts('someUID'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return LinearProgressIndicator();
}
return ListView.builder(itemBuilder: (context, index) {
return Container(
child: Text(snapshot.data![index].title.toString()));
});
},
)),
//using a stream (Real Time)
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: _db
.collection('Users')
.doc('someUID')
.collection('Posts')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return LinearProgressIndicator();
}
List<PostsModel> _postsStream = snapshot.data!.docs
.map((e) =>
PostsModel.fromMap(e.data() as Map<String, dynamic>))
.toList();
return ListView.builder(itemBuilder: (context, index) {
return Container(
child: Text(_postsStream[index].title.toString()));
});
},
)),
],
),
);
}
//to get list of posts from Firestore
Future<List<PostsModel>> fetchUserPosts(userID) async {
var result = await _db
.collection('Users')
.doc(userID)
.collection('Posts')
// .orderBy("SomeThing")
.get();
List<PostsModel> postsModel =
result.docs.map((doc) => PostsModel.fromMap(doc.data())).toList();
return postsModel;
}
}
class PostsModel {
final String? title;
final num? likes;
PostsModel({
this.title,
this.likes,
});
factory PostsModel.fromMap(Map<String, dynamic> json) => PostsModel(
title: json["title"],
likes: json["likes"],
);
Map<String, dynamic> toMap() => {
"title": title,
"likes": likes,
};
}
I'm trying to save and read a list called "teams" as a shared_preference so every time I switch back to this screen and take a look at my teams list it isn't empty and shows the old values. No matter how I set it up it doesn't seem to work. Then I come back the list is empty. Do you guys have any ideas?
Here is my code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class TeamScreen extends StatefulWidget {
#override
_TeamScreenState createState() => _TeamScreenState();
}
class _TeamScreenState extends State<TeamScreen> {
List<String> teams = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) {
return Team(
teams[index],
() => removeTeam(teams[index]),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => newTeam(),
child: Icon(
CupertinoIcons.add,
),
),
);
}
void addTeam(String name) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
teams.add(name);
});
Navigator.of(context).pop();
prefs.setStringList('teams', teams);
}
void newTeam() {
showDialog<AlertDialog>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Name auswählen: '),
content: TextField(
onSubmitted: addTeam,
),
);
},
);
}
void removeTeam(String name) {
setState(() {
teams.remove(name);
});
}
}
class Team extends StatelessWidget {
final String name;
final Function remove;
const Team(this.name, this.remove);
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 22),
child: ListTile(
leading: Icon(Icons.sports_volleyball_outlined),
contentPadding: EdgeInsets.symmetric(vertical: 8.0),
title: Text(
name,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w600,
),
),
trailing: IconButton(
icon: Icon(CupertinoIcons.delete),
onPressed: () => remove(),
),
),
);
}
}
Your code seems almost perfect! just you didn't initialized your teams variable with the SharedPreferences in initState.
lets fix that :
Define a prefs variable
class _TeamScreenState extends State<TeamScreen> {
List<String> teams = [];
late SharedPreferences prefs; //Declare your prefs variable here but with late initializer.
...
Check if teams list is stored in local -> fetch it or if not -> create it with empty list.
void initState() {
super.initState();
tryListFetch(); // defined async function
}
void tryListFetch() async {
prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('teams')) {
prefs.setStringList('teams', []); // created empty teams list on local storage
print('On device data is not available.');
return;
}
print('data avaialble');
teams = prefs.getStringList('teams') as List<String>;
}
Update your local data whenever you make changes in teams variable :
prefs.setStringList('teams', teams);
like in your removeTeam function :
void removeTeam(String name) {
setState(() {
teams.remove(name);
});
prefs.setStringList('teams', teams); //updated local storage's list
}
And in your addTeam function :
void addTeam(String name) async {
// SharedPreferences prefs = await SharedPreferences.getInstance(); //no need to initialize it here as we have already initialized it globally!
setState(() {
teams.add(name);
});
Navigator.of(context).pop();
prefs.setStringList('teams', teams);
}
Done !
I want to create a list, those people location = "Barishal". That's why, I created a function and try to push data ( which data I obtained from getSpecific() function ) to a new list ( myList ). But It created a problem ....
here is my code-
class BookData extends ChangeNotifier {
List<MyModel> data = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
List<MyModel> get getMydata{
return data;
}
getSpecific (){
for(int i=0;i<data.length;i++){
if(data[i].location=="Barishal"){
print(data[i]);
return data[i];
}
}
}
List myList = getSpecific();
}
How can I fix this problem ?
You can copy paste run full code below
You can provide search string and use UnmodifiableListView<MyModel> and filter with _myData.where
code snippet
class BookData extends ChangeNotifier {
final List<MyModel> _myData = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
String _searchString = "";
UnmodifiableListView<MyModel> get books => _searchString.isEmpty
? UnmodifiableListView(_myData)
: UnmodifiableListView(
_myData.where((dog) => dog.location.contains(_searchString)));
void getSpecific(String searchString) {
_searchString = searchString;
print(_searchString);
notifyListeners();
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:collection';
import 'package:provider/provider.dart';
class BookData extends ChangeNotifier {
final List<MyModel> _myData = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
String _searchString = "";
UnmodifiableListView<MyModel> get books => _searchString.isEmpty
? UnmodifiableListView(_myData)
: UnmodifiableListView(
_myData.where((dog) => dog.location.contains(_searchString)));
void getSpecific(String searchString) {
_searchString = searchString;
print(_searchString);
notifyListeners();
}
}
class MyModel {
final String name;
final String location;
MyModel({this.name, this.location});
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => BookData(),
child: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _controller = TextEditingController();
String _searchText;
#override
void initState() {
_controller.addListener(
() {
setState(() {
_searchText = _controller.text;
});
},
);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example',
home: Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(4.0),
),
),
),
onChanged: (value) {
Provider.of<BookData>(context, listen: false)
.getSpecific(value);
},
),
Consumer<BookData>(builder: (context, bookData, child) {
print(bookData.books.toString());
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: bookData.books.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(bookData.books[index].name),
),
)),
);
}),
],
),
),
);
}
}
When you need to filter a list, you can use the where method.
Here's a simple example.
List<MyModel> myNewList = data.where((item) => item.location == "Barishal").toList();
Anyway, your code seems to be returning just the first item, not a list.
I fixed your code like below
List<MyModel> getSpecific (){
List<MyModel> result = [];
for(int i=0;i<data.length;i++){
if(data[i].location=="Barishal"){
print(data[i]);
result.add(data[i]);
}
}
return result;
}
I want to cache two lists that got from Firebase to use to later when the user is offline
This is the full code for my list display screen -
import 'package:flutter/material.dart';
import 'package:naamaa/calculations/name-list-calc.dart';
List namesList = List();
List meaningsList = List();
class NameList extends StatefulWidget {
#override
_NameListState createState() => _NameListState();
}
class _NameListState extends State<NameList> {
Future<String> getPosts() async {
var names = await NameListCalc().nameListCalc();
namesList.addAll(names[0]);
meaningsList.addAll(names[1]);
String s = 'test';
return s;
}
#override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: getPosts(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: ListView.builder(
padding: EdgeInsets.zero,
itemBuilder: (context, position) {
return Row(
children: <Widget>[
Container(
width: 100,
child: Text(namesList[position]),
),
Container(
child: Text(meaningsList[position]),
)
],
);
},
itemCount: namesList.length,
),
);
} else {
return Text(':(');
}
},
);
}
}
I want to cache namesList and meaningsList for later use.
If someone can help it would be great :)
I didn't get complete requirement by your question description but you can use shared_preferences library to store the data list as following
Add following line pubspec.yaml
dependencies:
flutter:
sdk: flutter
shared_preferences:
You can use this example and add more utility methods as per you requirement.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async {
AppConfig.init(() {
runApp(MyApp());
});
}
class CustomModel {
int id;
String name;
CustomModel({this.id, this.name});
factory CustomModel.fromJson(Map<String, dynamic> json) {
return CustomModel(id: json["id"], name: json["name"]);
}
Map<String, dynamic> toJson() => {"id": id, "name": name};
#override
String toString() {
return "id: $id, name: $name";
}
}
class AppConfig {
static Future init(VoidCallback callback) async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPreferenceUtils.init();
callback();
}
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class SharedPreferenceUtils {
static SharedPreferences prefs;
static init() async {
prefs = await SharedPreferences.getInstance();
// storing lists
await putStringList("m_list", ["abc", "def"]);
await putObjectList("data",
[CustomModel(id: 1, name: "Bob"), CustomModel(id: 2, name: "Alice")]);
}
static Future<bool> putStringList(String key, List<String> list) async {
return prefs.setStringList(key, list);
}
static List<String> getStringList(String key) {
return prefs.getStringList(key);
}
static Future<bool> putObjectList(String key, List<Object> list) async {
if (prefs == null) return null;
List<String> _dataList = list?.map((value) {
return json.encode(value);
})?.toList();
return prefs.setStringList(key, _dataList);
}
static List<T> getObjList<T>(String key, T f(Map v),
{List<T> defValue = const []}) {
if (prefs == null) return null;
List<Map> dataList = getObjectList(key);
List<T> list = dataList?.map((value) {
return f(value);
})?.toList();
return list ?? defValue;
}
static List<Map> getObjectList(String key) {
if (prefs == null) return null;
List<String> dataList = prefs.getStringList(key);
return dataList?.map((value) {
Map _dataMap = json.decode(value);
return _dataMap;
})?.toList();
}
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(SharedPreferenceUtils.getStringList("m_list").toString()),
Text(SharedPreferenceUtils.getObjList<CustomModel>(
"data", (v) => CustomModel.fromJson(v)).toString()),
],
),
),
),
);
}
}
You don't need to store the lists in init() as it's done for this example. You can also pass data from one widget to others in multiple ways and if you are looking for state management then you can use BLOC or providers.