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}');
}
}
}
Related
I have a login screen code like below that has a text button that changes the state of the Login button to Signup or reverse, and want to rewrite it to use GetX library. But I don't know how?
enum AuthMode { Signup, Login }
class AuthenticationScreen extends StatelessWidget {
const AuthenticationScreen({Key? key}) : super(key: key);
AuthMode _authMode = AuthMode.Login;
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey();
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
= });
_controller!.forward();
} else {
setState(() {
_authMode = AuthMode.Login;
});
_controller!.reverse();
}
}
return Scaffold(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 400),
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
,
TextButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} '),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: TextStyle(color: Theme.of(context).primaryColor),
),
],
),
),
),
);
}
}
I tried some changes like transferring Authmode to the auth_controller file that extends GetxController and add obs after AuthMode _authMode = AuthMode.Login; and try to use obx(()=>) inside the _switchAuthMode() but didn't work.
Try like this:
final authMode= Rx<AuthMode>(AuthMode.Login);
And then on your switchAuthMode method:
authMode.value = AuthMode.Signup; // without setState
And finally, wrap the Text widget with Obx:
Obx(()=> Text('${authMode.value == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} ')
And you can actually make your widget a StatelessWidget.
I have the following code where I generate a list of items(data is taken from Firebase). I would like to implement a functionality to remove items but I don't know how to access the list and how to remove items:
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Offers')
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,...));
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
This is a dynamic class where I have GestureDetector. The item should be deleted when a user clicks on the it.
dynamic offer(name, category, context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
},
);
}
Removing the offer from within itself is not the best practice but you can accomplish it in a number of ways. The first I can think of is to pass a function that removes it when creating the offer like this:
items.add(offer(name, category, context,..., () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
}));
You'll need to create the index beforehand and increase it each time but I don't recommend doing it.
The way I would done do this is change the offer to be:
dynamic offer(name, category, context,) {
return Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
);
}
And when creating the offer wrap it in the GestureDetector like this:
items.add(GestureDetector(
child: offer(name, category, context,...)),
onTap: () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
},
);
You'll have to do the same thing with the index but I consider it a better approach since the child has no power over the parent and can't change its state which is a good practice.
you need to pass index of item and delete by index:
int index = 0;
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(index, name, category, context,...));
index++;
});
Widget offer(int index, string name, string category, BuildContext context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
items.removeAt(index);
setState((){});
},
);
}
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
Your list is getting build by Stream data the one you provided to your StreamBuilder, do create new list you need to change Stream value, I suggest to keep FirebaseFirestore.instance.collection('Offers') instance in a stream and modify the stream.
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
StreamController _controller = StreamController();
#override
void initState() {
super.initState();
_controller.addStream( FirebaseFirestore.instance
.collection('Offers').snapshots());
}
// dont forgot to close stream
#override
void dispose() {
_controller.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: _controller.stream,
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,(){
// remove function is here
snapshot.data.docs.removeWhere((e) => e.id == element.id);
_controller.add(snapshot.data);
});
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
Also pass onTap to your widget function
dynamic offer(name, category, context, onTap) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: onTap,
);
}
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
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;
}
In the 'Categories' class I have a list of elements. This list will be completed with more categories from Firebase. I want to read this list in another view (showCategories.dart) and thus output it in the other (showCategories.dart) view.
How can I pass the list to another view and access the elements of the list in this other view?
Code for categories.dart
class Categories with ChangeNotifier {
List<Category> _cats = [
Category(
id: 'c1',
titel: 'Kategorie #1',
bezeichnung: 'Erste Kategorie',
gruppe: '1',
),
Category(
id: 'c2',
titel: 'Kategorie #2',
bezeichnung: 'Zweite Kategorie',
gruppe: '2',
),
Category(
id: 'c3',
titel: 'Kategorie #3',
bezeichnung: 'Dritte Kategorie',
gruppe: '3',
),
];
List<Category> get cats {
return [..._cats];
}
get length => null;
Category findById(String id) {
return _cats.firstWhere(
(prod) => prod.id == id
);
}
Future<void> fetchAndSetCategories() async {
const url = 'https://....firebaseio.com/categories.json';
//print(_cats);
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Category> loadedCategories = [];
extractedData.forEach((catId, catData) {
loadedCategories.add(Category(
id: catId,
titel: catData['titel'],
bezeichnung: catData['bezeichnung'],
gruppe: catData['gruppe'],
));
});
_cats = loadedCategories;
notifyListeners();
} catch(error) {
throw error;
}
}
}
Code for viewCategories.dart
class ViewCategories extends StatefulWidget {
#override
_ViewCategoriesState createState() => _ViewCategoriesState();
}
class _ViewCategoriesState extends State<ViewCategories> {
#override
void initState() {
Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
super.initState();
}
}
You can copy paste run full code below
You can directly use Consumer to access data of your model
code snippet
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Categories(),
child: MyApp(),
),
);
}
...
return Scaffold(
body: Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
));
}),
);
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import 'dart:convert';
class ViewCategories extends StatefulWidget {
#override
_ViewCategoriesState createState() => _ViewCategoriesState();
}
class _ViewCategoriesState extends State<ViewCategories> {
#override
void initState() {
//Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
));
}),
);
}
}
class Category {
String id;
String titel;
String bezeichnung;
String gruppe;
Category({this.id, this.titel, this.bezeichnung, this.gruppe});
}
class Categories with ChangeNotifier {
List<Category> _cats = [
Category(
id: 'c1',
titel: 'Kategorie #1',
bezeichnung: 'Erste Kategorie',
gruppe: '1',
),
Category(
id: 'c2',
titel: 'Kategorie #2',
bezeichnung: 'Zweite Kategorie',
gruppe: '2',
),
Category(
id: 'c3',
titel: 'Kategorie #3',
bezeichnung: 'Dritte Kategorie',
gruppe: '3',
),
];
List<Category> get cats {
return [..._cats];
}
get length => null;
Category findById(String id) {
return _cats.firstWhere((prod) => prod.id == id);
}
Future<void> fetchAndSetCategories() async {
const url = 'https://....firebaseio.com/categories.json';
//print(_cats);
try {
/*final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Category> loadedCategories = [];
extractedData.forEach((catId, catData) {
loadedCategories.add(Category(
id: catId,
titel: catData['titel'],
bezeichnung: catData['bezeichnung'],
gruppe: catData['gruppe'],
));
});*/
final List<Category> loadedCategories = [];
loadedCategories.add(Category(
id: "c9",
titel: 'c9 titel',
bezeichnung: 'c9 bezeichnung',
gruppe: 'c9 gruppe',
));
loadedCategories.add(Category(
id: "c19",
titel: 'c19 titel',
bezeichnung: 'c19 bezeichnung',
gruppe: 'c19 gruppe',
));
_cats = loadedCategories;
notifyListeners();
} catch (error) {
throw error;
}
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Categories(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
)),
);
}),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ViewCategories()),
);
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
));
}
}