I have deleted my previous question and replaced it by this one may be most clear ,
I receive data from API and convert it to List contain (id , title , description , activity , degree ).
Now I want to display data such as appear in image below :
Note : (the title and description in all rows are same)
class page :
class Digree {
final int index;
final String title_k;
final String title_a;
final String aya;
final String link;
final String activity_k;
final String activity_a;
final String udigree;
Digree(this.index, this.title_k, this.title_a, this.aya, this.link,
this.activity_k, this.activity_a, this.udigree);
}
future function page
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:jiyanUquraan/classes/viewdigree.dart';
class DisplayList extends StatefulWidget {
#override
_DisplayListState createState() => _DisplayListState();
}
class _DisplayListState extends State<DisplayList> {
#override
Widget build(BuildContext context) {
Map rdata = {};
List digrees = [];
double _value = 0;
var widthView = MediaQuery.of(context).size.width;
Future<List> fetchDigrees() async {
Map rdata = ModalRoute.of(context).settings.arguments;
int cm_id = int.parse(rdata['current_m_id'].toString());
int d_id = int.parse(rdata['d_id'].toString());
int w_id = int.parse(rdata['w_id'].toString());
int u_id = int.parse(rdata['u_id'].toString());
var url =
'http://10.0.2.2/jiyan/test/api/digrees/day_digree.php?u_id=$u_id&m_id=$cm_id&d_id=$d_id';
var response = await http.get(url);
var data = jsonDecode(response.body);
for (var x in data) {
Digree newdigree = Digree(
x['index'],
x['title_k'],
x['title_a'],
x['aya'],
x['link'],
x['activity_k'],
x['activity_a'],
x['udigree']);
digrees.add(newdigree);
}
print(digrees.length);
print(data);
return digrees;
}
return FutureBuilder(
future: fetchDigrees(),
builder: (context, snapshot) {
List digrees = snapshot.data;
if (snapshot.data == null) {
return Center(
child: Text("Loading"),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Directionality(
textDirection: TextDirection.rtl,
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(width: 2, color: Colors.white),
color: Color.fromRGBO(230, 200, 200, 0.2)),
width: widthView,
padding: EdgeInsets.all(25),
margin: EdgeInsets.all(25),
child: Column(
children: <Widget>[
Text(
snapshot.data[index].activity_k,
textAlign: TextAlign.justify,
style:
TextStyle(fontSize: 32, color: Colors.white),
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.red[700],
inactiveTrackColor: Colors.red[100],
trackShape: RectangularSliderTrackShape(),
trackHeight: 4.0,
thumbColor: Colors.redAccent,
thumbShape: RoundSliderThumbShape(
enabledThumbRadius: 12.0),
overlayColor: Colors.red.withAlpha(32),
overlayShape: RoundSliderOverlayShape(
overlayRadius: 28.0),
),
child: Slider(
value: 0,
min: 0,
max: 100,
divisions: 10,
label: '$_value',
onChanged: null,
),),],),),],),);});}},);}}
display page :
import 'package:flutter/material.dart';
import 'package:jiyanUquraan/components/daylist.dart';
class Days extends StatefulWidget {
#override
_DaysState createState() => _DaysState();
}
class _DaysState extends State<Days> {
var cm_id;
var d_id;
var w_id;
var u_id;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.pink[900],
title: Text(
'ژیان و قورئان',
style: TextStyle(fontSize: 30),
),
centerTitle: true,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
),
),
child: DisplayList()),
);
}
}
Answer 3.0
So, as far as I have understood the situation correctly, the title_k and aya needs to be called once, and then Directionality() which is getting built by Column(). Which will wrap your Directionality based upon the snapshot.data list
ListView(
shrinkWrap: true,
children: [
Text('title_k'),
Text('aya'),
Column(
children: snapshot.data.map<Widget>((e) => Directionality(...)).toList()
)
]
)
Please note: You must get the data in the Directionality as e.key_of_digree_model. e can be anything, whatever, you will describe map((item))
For example: Text(snapshot.data[index].activity_k) will become Text(item.activity_k) in the Directionality only
Now we will write the normal code which will give you the answer. Specifically, your answer lies in DisplayList() only. So posting that as an answer
Assumption: I can see that your title_k and aya is same for every Digree Model, so I will just get the title_k and aya from the index = 0 only. Like this
// title
Text(snapshot.data[0].title_k)
//Description
Text(snapshot.data[0].aya)
DisplayList()
//specific code only, since Column() has all the data required
// inside your else of FutureBuilder
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView(
shrinkWrap: true,
children: [
//title
Text(snapshot.data[0].title_k),
//for top margin
SizedBox(height: 20.0),
// dexription
Text(snapshot.data[0].aya),
//for top margin
SizedBox(height: 20.0),
// your Directionality
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: snapshot.data.map<Widget>((item){
// for example snapshot.data[index].activity_k will become
// item.activity_k
return Directionality(....);
}).toList()
)
]
)
);
Please read about Mapping a list item StackoverFlow
Related
I have two questions I hope you can help me with. I am building a listview.builder to loop through my array of objects and when I loop and display it displays the widget more than one time(photo is provided)
I am trying to iterate through my prefs of products to get the price of the product and quantity and add them to display the overall price, I tried forEach method but I couldn't quite figure out how.
Thanks for you help
class CheckOutCart extends StatefulWidget {
const CheckOutCart({Key? key}) : super(key: key);
#override
State<CheckOutCart> createState() => _CheckOutCartState();
}
class _CheckOutCartState extends State<CheckOutCart> {
late SharedPreferences sharedPrefs;
List<String>? cart;
// List<List<String ,int>> productsWithQuantity;
List productsWithQuantity = [];
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getPrefs(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// return Text(productsWithQuantity[0][1]);
return buildContainer(productsWithQuantity);
}
return Center(
child: CircularProgressIndicator()); // or some other widget
},
);
}
Future<void> _getPrefs() async {
sharedPrefs = await SharedPreferences.getInstance();
cart = sharedPrefs.getStringList('userCart');
getProductsAsObj(cart);
}
Container buildContainer(productsWithQuantity) {
final Random random = new Random(5);
return Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenWidth(15),
horizontal: getProportionateScreenWidth(30),
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
boxShadow: [
BoxShadow(
offset: Offset(0, -15),
blurRadius: 20,
color: Color(0XFFDADADA).withOpacity(0.15),
),
],
),
child: SafeArea(
child: ListView.builder(
shrinkWrap: true,
itemCount: productsWithQuantity.length, //length of cart
itemBuilder: (context, index) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TotalPriceField(
titleText: "Merchandise Subtotal:\n",
priceText: productsWithQuantity[index][0].retail_price.toString(),
// priceText: productsWithQuantity.forEach((cart) => cart += cart[index][0].retail_price).toString()
// "\$375.5",
),
TotalPriceField(
titleText: "Shipping Total:\n",
priceText: "${random.nextInt(5)}",
),
],
),
SizedBox(
height: getProportionateScreenHeight(20),
),
TotalPriceField(
titleText: "Total Payment:\n",
priceText: "380.5",
),
SizedBox(
height: getProportionateScreenHeight(15),
),
SizedBox(
width: getProportionateScreenWidth(290),
child: DefaultButton(
text: "Check Out",
press: () {},
),
),
],
),
),
),
);
}
void getProductsAsObj(cart) {
for (var i = 0; i < cart.length; i++) {
var item = cart[i];
var items = item.split('-quantity-');
var product_ = items[0];
var quantity_ = items[1];
print(quantity_);
// product_ = '['+product_+']';
Map<String, dynamic> valueMap = json.decode(product_);
var product_obj = Product.fromMap(valueMap);
var itemx = [product_obj, quantity_];
productsWithQuantity.add(itemx);
}
}
}
```[![Listview.builder][1]][1]
[1]: https://i.stack.imgur.com/4wOyi.png
I have a very Strange error in my app. When i try to click on the button "PARIER" it does absolutely Nothing and i Don't see why. I called Prono_Match() but it doesn't work at all, i have no syntax errors and it does Nothing. I have tried called an other page but it is same. Why it ignores totally the call of Prono_Match ??? It is very very Strange :(
My code :
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'menu_member.dart';
import 'globals.dart' as globals;
import 'appbar_draw.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:intl/intl.dart';
import 'prono_match.dart';
// Create a Form widget.
class Affiche_Matchs extends StatefulWidget {
#override
_Affiche_Matchs_State createState() {
return _Affiche_Matchs_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_Matchs_State extends State<Affiche_Matchs> {
#override
bool load=false;
bool visible=false;
String idmatch="";
String prono="";
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Liste_Match_Display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_matchs.php';
var data = {
'id_membre': globals.id_membre,
};
var data_encode = jsonEncode(data);
// Starting Web API Call.
var response = await http.post(url,body: data_encode,headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
var i=0;
for (var u in jsondata) {
i=i+1;
Match match = Match(u["id"],u["equipe1"],u["equipe2"],u["dated"],u["heured"]);
Matchs.add(match);
radioValues.add("");
}
return Matchs;
}
void initState() {
super.initState();
grid = Liste_Match_Display();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
Colors.blue[300],Colors.blue[400]
],
),
),
),
Scaffold(
appBar: drawappbar(true),
backgroundColor: Colors.transparent,
drawer: new DrawerOnly(className: Affiche_Matchs()),
body:
Center(
child : Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height*0.8,
width: MediaQuery.of(context).size.width,
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Center(child: new CircularProgressIndicator(),);
default:
if(snapshot.hasError) {
return new Center(child: new Text('Error: ${snapshot.error}'),);
}
else {
List<Match> values = snapshot.data;
if (values.isEmpty) {
return Container(
child: Center(
child: Text("Aucun match disponible !!!",style: TextStyle(color: Colors.white))
)
);
}
else {
Match lastitem;
lastitem=values[0];
int i=0;
return ListView.builder(itemCount: values.length,itemBuilder: (_,index) {
bool header = lastitem.date_debut !=
values[index].date_debut;
lastitem = values[index];
var parsedDate = DateTime.parse(values[index].date_debut);
final formatter = new DateFormat('dd/MM/yyyy');
var dat = formatter.format(parsedDate);
return Column(
children: [
(header || index == 0)
?
Container(
height: 30,
margin: EdgeInsets.only(top:10),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue[700],
width: 2,
),
color: Colors.blue[700]
),
child : new Text(dat,textAlign: TextAlign.center,style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.w500,color: Colors.white),),
)// here// display header
:
Container(),
Container(
margin: EdgeInsets.only(top:20,bottom:20),
child: Center(
child: Text(values[index].heure_debut,style: TextStyle(color: Colors.white)),
),
),
Container(
margin: const EdgeInsets.only(bottom:10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Text(values[index].equipe1+" - "+values[index].equipe2,style: TextStyle(fontSize:10,color: Colors.white)),
),
]
),
),
Container(
margin: const EdgeInsets.only(left:5),
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text('PARIER'),
onPressed: () {
idmatch=values[index].id;
print(idmatch);
setState(() {
visible=true;
});
Prono_Match(idmatch: idmatch);
},
),
),
]
);
}
);
}
};
};
}
),
),
]
)
)
)
]
);
}
}
class Match {
final String id;
final String equipe1;
final String equipe2;
final String date_debut;
final String heure_debut;
const Match(this.id,this.equipe1, this.equipe2,this.date_debut,this.heure_debut);
}
I'm guessing you're trying to show Prono_Match page when pressing on the button, although that's not how you call a page in flutter, instead do this :
onPressed: () {
idmatch=values[index].id;
print(idmatch);
setState(() {
visible=true;
});
Navigator.push(context,MaterialPageRoute(builder: (context)=>Prono_Match(idmatch: idmatch),),
);
},
Here is the result now :
It is much better but i Don't know why BELSHINA BOBRUISK is not centered vertically. As you can see the others team are centered vertically. FC SMOELVITCHI is centered. Strange. Too i would like display the "2020-06-01" in mobile format so if it is french mobile it will be "01-06-2020".
And another question i Don't know why my mobile app use the theme with fontfamily but not all. I have some pages with a part of data in good family font and the other part in default font, its is really strange
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'package:flutter_app/menu_member.dart';
import 'package:flutter_app/globals.dart' as globals;
import 'package:flutter_app/appbar_draw.dart';
// Create a Form widget.
class Affiche_Matchs extends StatefulWidget {
#override
_Affiche_Matchs_State createState() {
return _Affiche_Matchs_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_Matchs_State extends State<Affiche_Matchs> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Liste_Match_Display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_matchs.php';
// Starting Web API Call.
var response = await http.get(url,headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
var i=0;
for (var u in jsondata) {
i=i+1;
Match match = Match(u["id"],u["equipe1"],u["equipe2"],u["type_prono"],u["date_debut"],u["heure_debut"]);
Matchs.add(match);
radioValues.add("");
}
return Matchs;
}
void initState() {
grid = Liste_Match_Display();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: drawappbar(true),
drawer: new DrawerOnly(className: Affiche_Matchs()),
body:
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Center(child: new CircularProgressIndicator(),);
default:
if(snapshot.hasError) {
return new Center(child: new Text('Error: ${snapshot.error}'),);
}
else {
List<Match> values = snapshot.data;
Match lastitem;
lastitem=values[0];
if (values.isEmpty) {
return Container(
child: Center(
child: Text("Aucun match disponible !!!")
)
);
}
else {
return Form(
key: _formKey,
child: ListView.builder(itemCount: values.length,itemBuilder: (_,index) {
bool header = lastitem.date_debut !=
values[index].date_debut;
lastitem = values[index];
return Column(
children: [
(header || index == 0)
?
Container(
height: 30,
margin: EdgeInsets.only(top:10),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue[700],
width: 2,
),
color: Colors.blue[700]
),
child : new Text(values[index].date_debut,textAlign: TextAlign.center,style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.w500,color: Colors.white),),
)// here display header
:
Container(),
Container(
margin: EdgeInsets.only(top:20,bottom:20),
child: Center(
child: Text(values[index].heure_debut),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(values[index].equipe1,style: TextStyle(fontSize:12)),
draw_grid("1", index, values[index].typeprono),
draw_grid("N", index, values[index].typeprono), //
draw_grid("2", index, values[index].typeprono), //
Text(values[index].equipe2,style: TextStyle(fontSize:12)),
]
),
]
);
}
)
);
}
};
};
}
),
),
);
}
draw_grid (String choix, int index,String type_prono) {
if (type_prono.contains(choix)) {
return new InkWell(
onTap: () {
setState(() {
if (radioValues[index] == choix) {
radioValues[index] = "";
}
else {
radioValues[index] = choix;
}
});
print(radioValues);
},
child:
Container(
height: 30.0,
width: 30.0,
margin: EdgeInsets.only(right: 2,left: 2),
child: new Center(
child: new Text(choix,
style: new TextStyle(
color:
radioValues[index] == choix ? Colors.white : Colors.red,
//fontWeight: FontWeight.bold,
fontSize: 18.0, fontWeight: FontWeight.w900)),
),
decoration: new BoxDecoration(
color: radioValues[index] == choix
? Colors.red
: Colors.white,
border: new Border.all(
width: 2.0,
color: radioValues[index] == choix
? Colors.red
: Colors.red),
borderRadius: const BorderRadius.all(const Radius.circular(5)),
),
),
);
}
else {
return Text("");
}
}
}
class Match {
final String id;
final String equipe1;
final String equipe2;
final String typeprono;
final String date_debut;
final String heure_debut;
const Match(this.id,this.equipe1, this.equipe2, this.typeprono,this.date_debut,this.heure_debut);
}
You have to sort you list base on date and then you can display by checking you have to display header or not.
Following code help you to understand more and then you can implement.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future<List<Match>> Liste_Match_Display() async {
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/display_matchs.php';
// Starting Web API Call.
var response = await http.get(url, headers: {
'content-type': 'application/json',
'accept': 'application/json',
'authorization':
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOjE1ODg5NTQ0NDgsImlhdCI6MTU4ODk1NDQ0OCwiZXhwIjoxNTg5MDE0NDQ4LCJkYXRhIjp7ImlkIjoiMSIsImVtYWlsIjoicGFzMzBAbmV0Y291cnJpZXIuY29tIn19.-jcyoxtkNVWWagune6EOjInjBgObyxf9gweXJrA2MxLL5fRTW1pkFSFrJOW8uYzhVpaZ4CF9A-c_m8akUq74NA '
});
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
var i = 0;
for (var u in jsondata) {
i = i + 1;
Match match = Match(u["id"], u["equipe1"], u["equipe2"], u["type_prono"],
u["date_debut"], u["heure_debut"]);
Matchs.add(match);
radioValues.add("");
}
return Matchs;
}
void initState() {
grid = Liste_Match_Display();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: drawappbar(true),
//drawer: new DrawerOnly(className: Affiche_Matchs()),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Center(
child: new CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return new Center(
child: new Text('Error: ${snapshot.error}'),
);
} else {
List<Match> values = snapshot.data;
Match lastitem;
lastitem = values[0];
if (values.isEmpty) {
return Container(
child: Center(
child: Text("Aucun match disponible !!!")));
} else {
return Form(
key: _formKey,
child: ListView.builder(
itemCount: values.length,
itemBuilder: (_, index) {
bool header = lastitem.date_debut !=
values[index].date_debut;
lastitem = values[index];
return Column(
children: [
(header || index == 0)
? Container(
height: 30,
margin: EdgeInsets.only(top: 10),
width: MediaQuery.of(context)
.size
.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue[700],
width: 2,
),
color: Colors.blue[700]),
child: new Text(
values[index].date_debut,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color: Colors.white),
),
) // here display header
: Container(),
Text(values[index].heure_debut),
Text(values[index].equipe1),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
draw_grid("1", index,
values[index].typeprono),
draw_grid("N", index,
values[index].typeprono), //
draw_grid("2", index,
values[index].typeprono), //
],
),
Text(values[index].equipe2),
// here display whole item
],
);
}));
}
}
;
}
;
}),
),
);
}
draw_grid(String choix, int index, String type_prono) {
if (type_prono.contains(choix)) {
return new InkWell(
onTap: () {
setState(() {
if (radioValues[index] == choix) {
radioValues[index] = "";
} else {
radioValues[index] = choix;
}
});
print(radioValues);
},
child: Container(
height: 40.0,
width: 40.0,
child: new Center(
child: new Text(choix,
style: new TextStyle(
color:
radioValues[index] == choix ? Colors.white : Colors.red,
//fontWeight: FontWeight.bold,
fontSize: 18.0,
fontWeight: FontWeight.w900)),
),
decoration: new BoxDecoration(
color: radioValues[index] == choix ? Colors.red : Colors.white,
border: new Border.all(
width: 2.0,
color: radioValues[index] == choix ? Colors.red : Colors.red),
borderRadius: const BorderRadius.all(const Radius.circular(5)),
),
),
);
} else {
return Text("");
}
}
}
class Match {
final String id;
final String equipe1;
final String equipe2;
final String typeprono;
final String date_debut;
final String heure_debut;
const Match(this.id, this.equipe1, this.equipe2, this.typeprono,
this.date_debut, this.heure_debut);
}
I'm trying to open a PDF dynamically and not from a static string, so that I can upload multiple pdf's and it opens whichever the user has selected. It instantiates using the FullPDFViewerScreen widget below, and I'd like to be able to pass other PDF's and change the title also subjective to the PDF chosen.
Here is my class for it:
import 'data.dart';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_full_pdf_viewer/full_pdf_viewer_scaffold.dart';
import 'dart:typed_data';
class Detail extends StatelessWidget {
final Book book;
Detail(this.book);
final String _documentPath = 'PDFs/test-en.pdf';
#override
Widget build(BuildContext context) {
Future<String> prepareTestPdf() async {
final ByteData bytes =
await DefaultAssetBundle.of(context).load(_documentPath);
final Uint8List list = bytes.buffer.asUint8List();
final tempDir = await getTemporaryDirectory();
final tempDocumentPath = '${tempDir.path}/$_documentPath';
final file = await File(tempDocumentPath).create(recursive: true);
file.writeAsBytesSync(list);
return tempDocumentPath;
}
//app bar
final appBar = AppBar(
elevation: .5,
title: Text(book.title),
);
///detail of book image and it's pages
final topLeft = Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: Hero(
tag: book.title,
child: Material(
elevation: 15.0,
shadowColor: Colors.yellow.shade900,
child: Image(
image: AssetImage(book.image),
fit: BoxFit.cover,
),
),
),
),
text('${book.pages} pages', color: Colors.black38, size: 12)
],
);
///detail top right
final topRight = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
text(book.title,
size: 16, isBold: true, padding: EdgeInsets.only(top: 16.0)),
text(
'by ${book.writer}',
color: Colors.black54,
size: 12,
padding: EdgeInsets.only(top: 8.0, bottom: 16.0),
),
Row(
children: <Widget>[
text(
book.price,
isBold: true,
padding: EdgeInsets.only(right: 8.0),
),
],
),
SizedBox(height: 32.0),
Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.blue.shade200,
elevation: 5.0,
child: MaterialButton(
onPressed: () {
// We need to prepare the test PDF, and then we can display the PDF.
prepareTestPdf().then(
(path) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullPdfViewerScreen(path)),
);
},
);
},
minWidth: 160.0,
color: Colors.blue,
child: text('Read Now', color: Colors.white, size: 13),
),
)
],
);
final topContent = Container(
color: Theme.of(context).primaryColor,
padding: EdgeInsets.only(bottom: 16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Flexible(flex: 2, child: topLeft),
Flexible(flex: 3, child: topRight),
],
),
);
///scrolling text description
final bottomContent = Container(
height: 220.0,
child: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Text(
book.description,
style: TextStyle(fontSize: 13.0, height: 1.5),
),
),
);
return Scaffold(
appBar: appBar,
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
//create text widget
text(String data,
{Color color = Colors.black87,
num size = 14,
EdgeInsetsGeometry padding = EdgeInsets.zero,
bool isBold = false}) =>
Padding(
padding: padding,
child: Text(
data,
style: TextStyle(
color: color,
fontSize: size.toDouble(),
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
),
);
}
class FullPdfViewerScreen extends StatelessWidget {
final String pdfPath;
FullPdfViewerScreen(this.pdfPath);
#override
Widget build(BuildContext context) {
return PDFViewerScaffold(
appBar: AppBar(
title: Text("Document"),
),
path: pdfPath);
}
}
main.dart where it generates the route for the detail page. I need to access the books.path that's where the pdf route is mentioned for each book.
generateRoute(RouteSettings settings) {
final path = settings.name.split('/');
final title = path[1];
Book book = books.firstWhere((it) => it.title == title);
return MaterialPageRoute(
settings: settings,
builder: (context) => Detail(book),
);
}
Update:
It seems, I misunderstood you question.
You just need to pass title and path as a parameter.
Change:
final Book book;
Detail(this.book);
final String _documentPath = 'PDFs/test-en.pdf';
To:
final Book book;
final String documentPath;
Detail(this.book, this.documentPath);
And you can get Title from book.title variable
If you want to get the pdf file from URL, you can use flutter_downloader widget.
Here is a working example.
You can pass the list of files with their file name and url.
Download them using:
task.taskId = await FlutterDownloader.enqueue(
url: task.link,
headers: {"auth": "test_for_sql_encoding"},
savedDir: _localPath,
showNotification: true,
openFileFromNotification: true);
And check if they are completed with:
if(item.task.status == DownloadTaskStatus.complete)
When completed, you can pass _localPath/fileName to FullPdfViewerScreen to open the file. (_localPath is the path you used while downloading the file.
You should also pass the path as parameter. Like this;
class Detail extends StatelessWidget {
final Book book;
final String documentPath; // <-- Add this line
Detail(this.book, this.documentPath); <-- Edit this line
#override
Widget build(BuildContext context) {
Future<String> prepareTestPdf() async {
final ByteData bytes =
await DefaultAssetBundle.of(context).load(documentPath); // Also edit your path
final Uint8List list = bytes.buffer.asUint8List();
final tempDir = await getTemporaryDirectory();
final tempDocumentPath = '${tempDir.path}/$documentPath';
final file = await File(tempDocumentPath).create(recursive: true);
file.writeAsBytesSync(list);
return tempDocumentPath;
}
...
On your generateRoute, you should do like this;
generateRoute(RouteSettings settings) {
final path = settings.name.split('/');
final title = path[1];
Book book = books.firstWhere((it) => it.title == title);
return MaterialPageRoute(
settings: settings,
builder: (context) => Detail(book,settings.name), // <-- This is your path as parameter.
);
}
I want to have all the dates of a month in a horizontal scroll view. The current week 7 days should be displayed first and on scrolling right the previous dates should be shown. later on scrolling left the later weeks dates should be displayed an don tap of a date i should get the date in return. How to do this? I have tried using the below. It displays dates and scrolls horizontally as well but it displays only multiple of 7 and all the exact dates of a month. Also on tapping the date it does not return the position form listview builder as 0 and i returns the index.
Widget displaydates(int week) {
return ListView.builder(
itemCount: 5,
itemBuilder: (BuildContext context, int position) {
return Row(
children: <Widget>[
for (int i = 1; i < 8; i++)
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
print(position);
},
child: Text(
((week * 7) + i).toString() + " ",
style: TextStyle(),
),
),
),
],
);
});
}
I am calling this like:
displaydates(0),
displaydates(1),
displaydates(2),
displaydates(3),
displaydates(4),
UPDATE:
You can get last day of month using below code :
DateTime(year,month + 1).subtract(Duration(days: 1)).day;
You should use ModalBottomSheet for the same and then pop that on selection with the Navigator.of(context).pop(result);
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ListView.builder(
itemCount: 5,
itemBuilder: (BuildContext context, int position) {
return Row(
children: <Widget>[
for (int i = 1; i < 8; i++)
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
Navigator.of(context).pop(position);
},
child: Text(
((week * 7) + i).toString() + " ",
style: TextStyle(),
),
),
),
],
);
}
);
}
);
I have created a widget that let me select date from a list and it is scrollable(along time ago). There lot of code but you can use the selected date under any widget which parent wrapped from InheritedWidget.
Here is the code(Note that I also created a package for this, if you dont like to write this much code for this):
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class MyInheritedWidget extends InheritedWidget {
final DateTime date;
final int selectedDay;
final int monthDateCount;
final bool isDateHolderActive;
final Map<int, bool> dayAvailabilityMap;
final ValueChanged<bool> toggleDateHolderActive;
final ValueChanged<int> setSelectedDay;
MyInheritedWidget({
Key key,
this.date,
this.selectedDay,
this.monthDateCount,
this.isDateHolderActive,
this.dayAvailabilityMap,
this.toggleDateHolderActive,
this.setSelectedDay,
Widget child,
}) : super(key: key, child: child);
#override
bool updateShouldNotify(MyInheritedWidget oldWidget) {
return oldWidget.selectedDay != selectedDay ||
oldWidget.toggleDateHolderActive != toggleDateHolderActive;
}
}
class DateIndicatorPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
DateIndicator(),
Expanded(
child: Container(),
),
],
),
),
);
}
}
class DateIndicator extends StatefulWidget {
static MyInheritedWidget of(BuildContext context) => context.dependOnInheritedWidgetOfExactType();
#override
_DateIndicatorState createState() => _DateIndicatorState();
}
class _DateIndicatorState extends State<DateIndicator> {
DateTime date = DateTime.now();
int selectedDay = 1;
int monthDateCount = 1;
bool isDateHolderActive = false;
Map<int, bool> dayAvailabilityMap = {};
void toggleDateHolderActive(bool flag) {
setState(() {
isDateHolderActive = flag;
});
}
void setSelectedDay(int index) {
setState(() {
selectedDay = index;
});
}
#override
void initState() {
final DateTime dateForValues = new DateTime(date.year, date.month + 1, 0);
monthDateCount = dateForValues.day;
// Just to show how to activate when something exist for this day(from network response or something)
dayAvailabilityMap[1] = true;
dayAvailabilityMap[2] = true;
dayAvailabilityMap[3] = true;
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: 68.0,
padding:
const EdgeInsets.only(left: 7.0, right: 3.0, top: 2.0, bottom: 2.0),
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor,
boxShadow: [
BoxShadow(
color: Colors.blueAccent.withOpacity(.7),
offset: Offset(0.0, .5),
blurRadius: 3.0,
spreadRadius: 0.3),
],
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: monthDateCount, // to avoid showing zero
itemBuilder: (BuildContext context, int index) {
return MyInheritedWidget(
date: date,
selectedDay: selectedDay,
monthDateCount: monthDateCount,
isDateHolderActive: isDateHolderActive,
dayAvailabilityMap: dayAvailabilityMap,
toggleDateHolderActive: toggleDateHolderActive,
setSelectedDay: setSelectedDay,
child: DateHolder(index));
}),
);
}
}
class DateHolder extends StatelessWidget {
DateHolder(this.index);
final int index;
final Widget activeBubble = Container(
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.deepOrangeAccent,
),
);
#override
Widget build(BuildContext context) {
final appState = DateIndicator.of(context);
return InkWell(
onTap: () {
appState.toggleDateHolderActive(true);
appState.setSelectedDay(index);
print("Date ${index} selected!");
},
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
margin: const EdgeInsets.only(right: 5.0),
child: Text(
"${DateFormat('EEEE').format(DateTime(appState.date.year, appState.date.month, index)).substring(0, 1)}",
style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.0),
)),
Container(
width: 45.0,
height: 45.0,
margin: const EdgeInsets.only(right: 5.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: (index == (appState.selectedDay) &&
appState.isDateHolderActive == true)
? Border.all(width: 2.0, color: Theme.of(context).primaryColor)
: Border.all(color: Colors.transparent),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(
"${index + 1}", // to avoid showing zero
style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 16.0),
),
),
),
),
],
),
(appState.dayAvailabilityMap[index] ?? false)
? Positioned(right: 8.0, bottom: 5.0, child: activeBubble)
: Container(),
],
),
);
}
}