Part1 Lab Flutter React
Part1 Lab Flutter React
Tracker (Part 1)
Copyright [email protected]. 2022
____________________________________________________________________
//main.dart
import 'package:flutter/material.dart';
import 'MyApp.dart';
void main() {
runApp(const MyApp());
}
____________________________________________________________________
//MyApp.dart
import 'package:flutter/material.dart';
import 'screens/Login.dart';
//screens/Login.dart
import 'Register.dart';
import 'package:flutter/material.dart';
class Login extends StatefulWidget {
const Login({Key? key}) : super(key: key);
@override
State<Login> createState() => _LoginState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[50],
appBar: AppBar(
title: Text('Covid Tracker'),
actions: [
FlatButton.icon(
onPressed: (){
Navigator.push(context,
MaterialPageRoute(builder: (context)=>Register()));
},
icon: Icon(Icons.person),
label: Text('Register'))
],
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20,
horizontal: 50),
child: Form(
key: _formKey,
child: ListView(
children: [
Image.asset('assets/images/covid.png'),
SizedBox(height: 50.0,),
TextFormField(
decoration: InputDecoration(
hintText: 'email',
prefixIcon: Icon(Icons.person),
fillColor: Colors.white,
filled: true
),
onChanged: (val) {
setState(() {
email = val;
});
},
validator: (val) => val!.isEmpty ? 'Enter a
valid email':null,
),
SizedBox(height: 20.0,),
TextFormField(
decoration: InputDecoration(
hintText: 'password',
prefixIcon: Icon(Icons.lock),
fillColor: Colors.white,
filled: true
),
onChanged: (val) {
setState(() {
password = val;
});
},
validator: (val) => val!.length < 6 ?
'Enter a valid password 6+ Chars':null,
obscureText: true,
),
SizedBox(height: 20.0,),
RaisedButton(
color: Colors.pink,
child: Text('Sign In',style:
TextStyle(color: Colors.white),),
onPressed: () {
if(_formKey.currentState!.validate()){
print('ok !!!');
}
},
],
),
),
),
);
}
}
____________________________________________________________________
//screens/Register.dart
import 'package:flutter/material.dart';
class Register extends StatefulWidget {
const Register({Key? key}) : super(key: key);
@override
State<Register> createState() => _RegisterState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber[200],
appBar: AppBar(
title: Text('Covid Tracker Register'),
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20,
horizontal: 50),
child: Form(
key: _formKey,
child: ListView(
children: [
Image.asset('assets/images/covid.png'),
SizedBox(height: 50.0,),
TextFormField(
decoration: InputDecoration(
hintText: 'email',
prefixIcon: Icon(Icons.person),
fillColor: Colors.white,
filled: true
),
onChanged: (val) {
setState(() {
email = val;
});
},
validator: (val) => val!.isEmpty ? 'Enter a
valid email':null,
),
SizedBox(height: 20.0,),
TextFormField(
decoration: InputDecoration(
hintText: 'password',
prefixIcon: Icon(Icons.lock),
fillColor: Colors.white,
filled: true
),
onChanged: (val) {
setState(() {
password = val;
});
},
validator: (val) => val!.length < 6 ?
'Enter a valid password 6+ Chars':null,
obscureText: true,
),
SizedBox(height: 20.0,),
RaisedButton(
color: Colors.amber,
child: Text('Sign UP',style:
TextStyle(color: Colors.white),),
onPressed: () {
if(_formKey.currentState!.validate()){
print('ok !!!');
}
},
],
),
),
),
);
}
}
____________________________________________________________________
// API/TMDBApi.js
// API/TMDBApi.js
const API_TOKEN = "your Key";
export function getFilmsFromApiWithSearchedText (text,
page) {
const url = 'https://api.themoviedb.org/3/search/movie?
api_key=' + API_TOKEN + '&language=fr&query=' + text +
"&page=" + page
return fetch(url)
.then((response) => response.json())
.catch((error) => console.error(error))
}
// API/TMDBApi.js
**************
// App.js
**************************
// Components/Search.js
constructor(props) {
super(props)
this.searchedText = ""
this.page = 0
this.totalPages = 0
this.state = {
films: [],
isLoading: false
}
}
_loadFilms() {
if (this.searchedText.length > 0) {
this.setState({ isLoading: true })
getFilmsFromApiWithSearchedText(this.searchedText,
this.page+1).then(data => {
this.page = data.page
this.totalPages = data.total_pages
this.setState({
films:
[ ...this.state.films, ...data.results ],
isLoading: false
})
})
}
}
_searchTextInputChanged(text) {
this.searchedText = text
}
_searchFilms() {
this.page = 0
this.totalPages = 0
this.setState({
films: [],
}, () => {
this._loadFilms()
})
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
</View>
)
}
}
render() {
return (
<View style={styles.main_container}>
<TextInput
style={styles.textinput}
placeholder='Titre du film'
onChangeText={(text) =>
this._searchTextInputChanged(text)}
onSubmitEditing={() => this._searchFilms()}
/>
<Button title='Rechercher' onPress={() =>
this._searchFilms()}/>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem film={item}/>}
onEndReachedThreshold={0.5}
onEndReached={() => {
if (this.page < this.totalPages) {
this._loadFilms()
}
}}
/>
{this._displayLoading()}
</View>
)
}
}
***********************
// Components/FilmItem.js
render() {
const film = this.props.film
return (
<View style={styles.main_container}>
<Image
style={styles.image}
source={{uri: getImageFromApi(film.poster_path)}}
/>
<View style={styles.content_container}>
<View style={styles.header_container}>
<Text style={styles.title_text}>{film.title}</
Text>
<Text style={styles.vote_text}
>{film.vote_average}</Text>
</View>
<View style={styles.description_container}>
<Text style={styles.description_text}
numberOfLines={6}>{film.overview}</Text>
</View>
<View style={styles.date_container}>
<Text style={styles.date_text}>Sorti le
{film.release_date}</Text>
</View>
</View>
</View>
)
}
}