Related
I need help I am developing an app using SQLite, here is my scenario I want to make favorite feature using SQLLITE, if the value does exist then fill the heart icon with red color otherwise remove the color from the heart icon i already implement method check value if already exist but i dont how using in listview.
import 'package:bibleapp/favourite.dart';
import 'package:bibleapp/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:share_plus/share_plus.dart';
import 'package:sqflite/sqflite.dart';
import 'Dbhelper.dart';
import 'package:favorite_button/favorite_button.dart';
class Allverse extends StatefulWidget {
late int booknumber;
late int chapternumber;
late int versenumber;
late String bookname;
#override
_AllverseState createState() => _AllverseState();
Allverse(this.bookname,this.booknumber, this.chapternumber,this.versenumber);
}
class _AllverseState extends State<Allverse> {
final ItemScrollController itemScrollController = ItemScrollController();
late int versenumber;
String _selectedView = 't_kjv';
#override
void initState() {
// TODO: implement initState
super.initState();
versenumber=widget.versenumber-1;
setState(() {
getallverse(_selectedView,widget.booknumber,widget.chapternumber);
Future.delayed(Duration(seconds: 1), () {
itemScrollController.jumpTo(
index: versenumber,
);
});
});
}
var check=false;
List<Map<String, dynamic>> allverse = [];
void getallverse(datbase,booknumber,chapternumber) async {
final data = await Dbhelper.fetchallverse(datbase,booknumber, chapternumber);
setState(() {
allverse= data;
});
}
//add favourite
// Collect Data from DB
FlutterTts flutterTts = FlutterTts();
speak(String txt)async{
await flutterTts.setLanguage('"en-US');
await flutterTts.setPitch(1);
await flutterTts.speak(txt);
}
int? checkfavurite;
//THIS METHOD CHECK IF VALUE ALREADY EXIST THEN RETURN 1
Future<bool>uidExists(id) async {
final db = await Dbhelper().db;
var result = await db?.rawQuery(
'SELECT EXISTS(SELECT 1 FROM favourite WHERE bookid="$id")',
);
checkfavurite= Sqflite.firstIntValue(result!);
print(checkfavurite);
return checkfavurite == 1;
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
flutterTts.stop();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Row(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
onTap: (){
setState(() {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>MyApp(),
transitionDuration: Duration(seconds: 0),
),
);
});
},
child: Icon(Icons.menu_book_sharp)),
Text('Books',style: TextStyle(
fontSize: 9
),),
],
),
SizedBox(width: 10),
Expanded(
child: Text('${widget.bookname} ${widget.chapternumber}:${widget.versenumber}',style: TextStyle(
fontSize: 16
)),
)
]
),
actions: <Widget>[
PopupMenuButton(
initialValue: 0,
// add icon, by default "3 dot" icon
// icon: Icon(Icons.book)
itemBuilder: (context){
return [
PopupMenuItem<int>(
value: 0,
child: Text("King James version"),
),
PopupMenuItem<int>(
value: 1,
child: Text("American Standard-ASV1901"),
),
PopupMenuItem<int>(
value: 2,
child: Text("BIble in Basic English"),
),
PopupMenuItem<int>(
value: 3,
child: Text("Darby English"),
),
PopupMenuItem<int>(
value: 4,
child: Text("Young's Literal Translation"),
),
PopupMenuItem<int>(
value: 5,
child: Text("World Englis bible"),
),
PopupMenuItem<int>(
value: 6,
child: Text("Webster's Bible"),
),
PopupMenuItem<int>(
value: 7,
child: Text("Favourite verse"),
),
];
},
onSelected:(value){
if(value == 0){
setState(() {
getallverse('t_kjv', widget.booknumber, widget.chapternumber);
});
}else if(value == 1){
setState(() {
getallverse('t_asv', widget.booknumber, widget.chapternumber);
});
}else if(value == 2){
setState(() {
getallverse('t_bbe', widget.booknumber, widget.chapternumber);
});
}
else if(value == 3){
setState(() {
getallverse('t_dby', widget.booknumber, widget.chapternumber);
});
}
else if(value == 4){
setState(() {
getallverse('t_ylt', widget.booknumber, widget.chapternumber);
});
}
else if(value == 5){
setState(() {
getallverse('t_web', widget.booknumber, widget.chapternumber);
});
}
else if(value == 6){
setState(() {
getallverse('t_wbt', widget.booknumber, widget.chapternumber);
});
}
else if(value == 7){
setState(() {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>Favourite(),
transitionDuration: Duration(seconds: 0),
),
);
});
}
}
),
],
),
body:Container(
color:Colors.white70,
child: ScrollablePositionedList.builder(
shrinkWrap: true,
itemCount: allverse.length,
itemScrollController: itemScrollController,
itemBuilder:(context,index) {
//HERE IS METHOD CALLING
uidExists(allverse[index]['id']);
return Container(
color: index ==versenumber? Colors.yellow[100]:null,
child: GestureDetector(
onTap:(){
print(index);
},
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 4),
child: CircleAvatar(
backgroundColor: Colors.lightBlueAccent,
radius: 11,
child: Text(
allverse[index]['v'].toString(),style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.bold
),
)
),
),
Expanded(
child: Text.rich(
TextSpan(
children: [
TextSpan(text: allverse[index]['t'],
style: GoogleFonts.heebo(
fontSize: 22,
wordSpacing: 2.0,
color: Colors.black,
fontWeight: FontWeight.w400
)
),
WidgetSpan(
child: GestureDetector(
onTap: (){
speak(allverse[index]['t']);
},
child: Icon(Icons.mic, size: 23)
),
),
],
),
),
),
// Expanded(
// child: RichText(
// text: TextSpan(
//
// text:allverse[index]['t'],
// style: TextStyle(
//
// color: Colors.black, fontSize:19,
//
//
// ),
//
// ),
//
// ),
//
// ),
GestureDetector(
onTap: (){
String verse=allverse[index]['t'];
String versenumber=allverse[index]['v'].toString();
Share.share('${widget.bookname} ${widget.chapternumber}:${versenumber}\n${verse}');
},
child: Icon(
Icons.share,
color: Colors.pinkAccent,
),
)
],
),
Padding(
padding: EdgeInsets.only(left: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
//favourite here....
],
),
)
],
),
// child: Card(
// elevation: 1.1,
// color: index ==versenumber? Colors.yellowAccent:Colors.white,
// child: ListTile(
// leading: CircleAvatar(
// backgroundColor: Colors.lightBlue,
// //backgroundColor:Colors.primaries[Random().nextInt(Colors.primaries.length)] ,
// radius: 12,
// child: Text(allverse[index]['v'].toString(),style: TextStyle(
// color: Colors.white,
// fontSize:12
// ),),
// ),
// title: Column(
// children: [
// RichText(text: TextSpan(
// text: allverse[index]['t'],
// style: TextStyle(
// color: Colors.black, fontSize: 16),
//
// ),),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Icon(
// Icons.favorite_border,
// color: Colors.red[500],
// ),
// Icon(
// Icons.speaker,
// color: Colors.red[500],
// ),
// ],
// )
// ],
//
// ),
//
// trailing: Icon(
// Icons.share,
// color: Colors.red,
// ),
// ),
// ),
),
);
},
),
)
);
}
}
I have created a dialog with StatefulBuilder. Setstate works perfectly within the StatefulBuilder. But I want to change that state from initstate too. But the set state from initstate is not called.
My code:
#override
void initState() {
super.initState();
rest_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 15),
);
rest_controller.addListener(() {
if (rest_controller.isAnimating) {
setState(() {
print("rp"+rest_progress.toString());
rest_progress = rest_controller.value;
});
} else {
setState(() {
print("rp2"+rest_progress.toString());
rest_progress = 1.0;
rest_isPlaying = false;
});
}
});
}
Dialog open function:
showDataAlert() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(
20.0,
),
),
),
backgroundColor: kMainColor,
contentPadding: EdgeInsets.only(
top: 10.0,
),
title: Text(
"Take Rest",
style: TextStyle(fontSize: 24.0, color: kTextColor),
),
content:
Center(
child: Column(
children: [
SizedBox(
height: 10,
),
Expanded(
child: Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: 260,
height: 260,
child: CircularProgressIndicator(
backgroundColor: Colors.grey.shade300,
value: rest_progress,
strokeWidth: 6,
),
),
AnimatedBuilder(
animation: rest_controller,
builder: (context, child) => Text(
restCountText,
style: TextStyle(
fontSize: 50,
fontWeight: FontWeight.bold,
color: kTextColor,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
if (rest_controller.isAnimating) {
rest_controller.stop();
setState(() {
rest_isPlaying = false;
});
} else {
rest_controller.reverse(from: rest_controller.value == 0 ? 1.0 : rest_controller.value);
setState(() {
rest_isPlaying = true;
});
}
},
child: RoundButton(
icon: rest_isPlaying == true ? Icons.pause : Icons.play_arrow,
),
),
GestureDetector(
onTap: () {
rest_controller.reset();
setState(() {
rest_isPlaying = false;
});
},
child: RoundButton(
icon: Icons.stop,
),
),
],
),
)
],
),
),
);
}
);
});
}
Basically, setstate from the initstate is not changing the state. I have tried to change the state from showDataAlert function also, but no luck. Only the state changes if I click the button inside the showdialog.
Im using table_calendar package in my project, but ive faced two problems so far :
The calendar doesnt load todays events below the calendar, i would love to hear some ideas how to get this one done.
Even if i put (code below) in tables parameters, it doesnt allow to switch calendar modes.
code for swiching calendar modes for 2nd bullet point of my problems:
availableCalendarFormats: const {
CalendarFormat.month: '',
CalendarFormat.week: '',
},
Just in case, here is the whole code for page which has problems :
class Lecture_graph extends StatefulWidget {
Lecture_graph({Key key}) : super(key: key);
#override
State<Lecture_graph> createState() => myLectureGraph();
}
class myLectureGraph extends State<Lecture_graph>
with TickerProviderStateMixin {
List _selectedEvents;
DateTime _selectedDate = DateTime.now();
Map<DateTime, List<Lecture>> _events;
CalendarController _calendarController;
AnimationController _animationController;
List<Lecture> _lectures;
String coursecode = "";
bool isJoin, isBreaks = false;
bool isLoading = true;
final Map<DateTime, List> _holidays = {
// DateTime(2021, 1, 1): ['New Year\'s Day'],
// DateTime(2021, 2, 14): ['Valentine\'s Day'],
// DateTime(2021, 3, 8): ['Woman\'s Day'],
};
Future<Map<DateTime, List>> getLectures(DateTime _selectedDate) async {
print("getLectures started.");
setState(() {
isLoading = true;
});
Map<DateTime, List<Lecture>> mapFetch = {};
//get saved course
if (coursecode == "" || coursecode == null) {
coursecode = await _checkSavedCourse();
//debug
print('courscode recieved from sharedprefs');
}
//build request URL
var requestURL =
'https://lekcijas.va.lv/lekcijas_android/getMonthLectures.php?date=' +
DateFormat('yyyy-MM').format(_selectedDate) +
(isBreaks ? "&breaks" : "") +
(isJoin ? "&join" : "") +
"&program=" +
coursecode +
"&lang=" +
AppLocalizations.of(context).translate('request_language');
print("Lecture request url : $requestURL");
//wait for response
var response = await http.get(Uri.parse(requestURL));
var data = json.decode(response.body)["result"];
//clear array after each request
if (_lectures != null) _lectures.clear();
try {
//create lectures from json response
_lectures = List<Lecture>.from(data.map((x) => Lecture.fromJson(x)));
} on Exception catch (_) {
print("Error occured getting lectures");
}
_lectures.forEach((element) {
if (mapFetch[element.lecture_date] != null) {
mapFetch[element.lecture_date] += [element];
} else {
mapFetch[element.lecture_date] = [element];
}
});
setState(() {
isLoading = false;
});
print("getLectures finished.");
return mapFetch;
}
Future<void> _saveVales(String key, bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
print("Sharedpref $key is set to $value now");
prefs.setBool(key, value);
}
Future<void> _checkSavedParameters() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
isBreaks = prefs.getBool('lectures_breaks') == null
? false
: prefs.getBool('lectures_breaks');
isJoin = prefs.getBool('lectures_join') == null
? false
: prefs.getBool('lectures_join');
}
Future<String> _checkSavedCourse() async {
//check saved parameters for lecture requests too
await _checkSavedParameters();
SharedPreferences prefs = await SharedPreferences.getInstance();
String _coursecode = prefs.getString('savedCourse');
if (_coursecode == "" || _coursecode == null) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CourseSelectionPage()),
);
return null;
} else {
return _coursecode;
}
}
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
setState(() {
_selectedEvents = events;
});
}
#override
void initState() {
super.initState();
//enable portrait only mode
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
_selectedEvents = [];
_calendarController = CalendarController();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
WidgetsBinding.instance.addPostFrameCallback((_) {
getLectures(_selectedDate).then((val) => setState(() {
_events = val;
}));
});
}
#override
void dispose() {
_calendarController.dispose();
//unlock orientation mode
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(coursecode +
" | " +
AppLocalizations.of(context).translate('lectures_title')),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
color: Colors.white,
),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
AppLocalizations.of(context).translate('settings')),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
CupertinoSwitch(
value: isJoin,
onChanged: (bool value) {
_saveVales('lectures_join', value);
isJoin = value;
WidgetsBinding.instance
.addPostFrameCallback((_) {
getLectures(_selectedDate)
.then((val) => setState(() {
_events = val;
}));
});
},
),
Text(AppLocalizations.of(context)
.translate('join_lectures'))
],
),
SizedBox(height: 10),
Row(
children: [
CupertinoSwitch(
value: isBreaks,
onChanged: (bool value) {
_saveVales('lectures_breaks', value);
isBreaks = value;
WidgetsBinding.instance
.addPostFrameCallback((_) {
getLectures(_selectedDate)
.then((val) => setState(() {
_events = val;
}));
});
},
),
Text(AppLocalizations.of(context)
.translate('show_breaks'))
],
),
SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: () {
//close popup
Navigator.pop(context);
//close page
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CourseSelectionPage()),
);
},
child: Text(
AppLocalizations.of(context)
.translate('select_course'),
style: TextStyle(color: Colors.lime),
)),
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)
.translate('close')),
),
],
);
},
);
},
);
},
)
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
isLoading
? Expanded(child: Center(child: CircularProgressIndicator()))
: _buildTableCalendarWithBuilders(),
const SizedBox(height: 2.0),
Expanded(child: _buildEventList()),
],
),
),
);
}
Widget _buildTableCalendarWithBuilders() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
color: Colors.white,
margin: const EdgeInsets.all(8.0),
clipBehavior: Clip.antiAlias,
child: TableCalendar(
locale:
AppLocalizations.of(context).translate('request_language') ==
'lv'
? "lv_LV"
: "en_US",
initialSelectedDay: _selectedDate,
calendarController: _calendarController,
events: _events,
holidays: _holidays,
initialCalendarFormat: CalendarFormat.month,
formatAnimation: FormatAnimation.scale,
startingDayOfWeek: StartingDayOfWeek.monday,
availableGestures: AvailableGestures.all,
availableCalendarFormats: const {
CalendarFormat.month: '',
CalendarFormat.week: '',
},
calendarStyle: CalendarStyle(
outsideDaysVisible: false,
weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
),
daysOfWeekStyle: DaysOfWeekStyle(
weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
),
builders: CalendarBuilders(
selectedDayBuilder: (context, date, _) {
return FadeTransition(
opacity:
Tween(begin: 0.0, end: 1.0).animate(_animationController),
child: Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.deepOrange[300],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
),
);
},
todayDayBuilder: (context, date, _) {
return Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.amber[400],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
);
},
markersBuilder: (context, date, events, holidays) {
final children = <Widget>[];
if (events.isNotEmpty) {
children.add(
Positioned(
right: 1,
bottom: 1,
child: _buildEventsMarker(date, events),
),
);
}
if (holidays.isNotEmpty) {
children.add(
Positioned(
right: -2,
top: -2,
child: _buildHolidaysMarker(),
),
);
}
return children;
},
),
onDaySelected: (date, events, holidays) {
_onDaySelected(date, events);
_animationController.forward(from: 0.0);
},
onVisibleDaysChanged: _onVisibleDaysChanged,
),
),
],
);
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
_selectedDate = first;
WidgetsBinding.instance.addPostFrameCallback((_) {
getLectures(_selectedDate).then((val) => setState(() {
_events = val;
}));
});
print('CALLBACK: _onVisibleDaysChanged');
}
Widget _buildEventsMarker(DateTime date, List events) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _calendarController.isSelected(date)
? Colors.brown[500]
: _calendarController.isToday(date)
? Colors.brown[300]
: Colors.green[400],
),
width: 18.0,
height: 18.0,
child: Center(
child: Text(
'${events.length}',
style: TextStyle().copyWith(
color: Colors.white, fontSize: 12.0, fontWeight: FontWeight.w900),
),
),
);
}
Widget _buildHolidaysMarker() {
return Icon(
Icons.add_box,
size: 20.0,
color: Colors.blueGrey[800],
);
}
Widget _buildEventList() {
return ListView(
children: _selectedEvents.reversed
.map((lecture) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.1),
// borderRadius: BorderRadius.circular(2.0),
color: hexToColor(lecture.color),
),
margin:
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 1.5),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
lecture.start + " - " + lecture.end,
style: new TextStyle(
fontSize: 12.0,
color: Colors.black,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Text(lecture.lecture,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
onTap: () => displayDialog(lecture, context),
),
))
.toList(),
);
}
void displayDialog(Lecture selectedLecture, BuildContext ctx) {
//if selected lecture is a break
if (!selectedLecture.lecturer.isEmpty &&
!selectedLecture.classroom.isEmpty &&
!selectedLecture.programs.isEmpty) {
showDialog(
barrierDismissible: true,
context: ctx,
builder: (BuildContext context) => new AlertDialog(
title: new Text(AppLocalizations.of(context).translate('info_title')),
content: new Wrap(
runSpacing: 5,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_time') +
selectedLecture.start +
" - " +
selectedLecture.end),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_lecturer') +
selectedLecture.lecturer),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_classroom') +
selectedLecture.classroom),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_lecture') +
selectedLecture.lecture),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_date') +
DateFormat('yyyy-MM-dd')
.format(selectedLecture.lecture_date)
.toString()),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_programs') +
selectedLecture.programs),
),
],
),
actions: [
new TextButton(
child: Text(AppLocalizations.of(context).translate('close')),
onPressed: () => Navigator.pop(context, true),
),
],
),
);
}
}
}
In case someone wants to see JSON request results, here is the link for that.
So i got this fixed, adding this to TableCalendar() parameters:
(i called selectedEvents variable update once calendar finished building (because im showing CircularProgressIndicator instead of it while i recieve data from http request) )
onCalendarCreated: (d1, d2, cf){WidgetsBinding.instance
.addPostFrameCallback((_) => _onDaySelected(_selectedDate, _events[_selectedDate]));},
changed _onDaySelected method to:
(here i change selectedday variable to day recieved from calendar click and change state of selectedEvents, replacing them with total_events_map[key_which_is_selectedDay])
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
//dates are used with nulled time
_selectedDate = DateTime(day.year, day.month, day.day, 0, 0, 0);
setState(() {
_selectedEvents = _events[_selectedDate];
});
}
and changed _buildEventList() to this :
(so if selectedEvents are empty, it tells user so, if not, generates a list of items from selectedEvents)
Widget _buildEventList() {
if(_selectedEvents == null)
return ListView(
children: [
Card(
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(8.0),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(tr('nothing_planned'),
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
),
),
],
);
else return ListView(
children: _selectedEvents.reversed
.map((lecture) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.1),
// borderRadius: BorderRadius.circular(2.0),
color: hexToColor(lecture.color),
),
margin:
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 1.5),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
lecture.start + " - " + lecture.end,
style: new TextStyle(
fontSize: 12.0,
color: Colors.black,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Text(lecture.lecture,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
onTap: () => displayDialog(lecture, context),
),
))
.toList(),
);
}
This is my code, in which I am playing a video. Now I want to stop(pause) video whenever I am switching the page. Sometime the code is working fine but some time audio of video is coming but video page is not opening. I am beginner in flutter. I have tried to pause the video before switching but unfortunately none on my logic has worked. As per my experience this scenario is coming when video is buffering, and I switched the page.
final feedViewModel = GetIt.instance<FeedViewModel>();
int currentIndex = -1;
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _pageController = 0;
List<Widget> _pages = [FeedScreen(), DiscoverPage(), InboxPage(), MePage()];
counter(int index) {
if (currentIndex >= 0) {
try {
if (feedViewModel.listVideos == null) {
final feed = _FeedScreenState();
if (index == 0) {
feed.load("For you");
}
} else {
feedViewModel.listVideos[currentIndex].controller.pause();
feedViewModel.listVideos = null;
feedViewModel.controller.dispose();
feedViewModel.controller=null;
super.dispose();
}
} catch (e) {
feedViewModel.listVideos = null;
final feed = _FeedScreenState();
if (index == 0) {
feed.load("For you");
}
}
}
_pageController = index;
}
#override
Widget build(BuildContext context) {
// Constants.pref.setBool("loggedIn", true);
return ResponsiveBuilder(
builder: (BuildContext context, SizingInformation sizingInformation) {
return Scaffold(
bottomNavigationBar: Container(
padding: EdgeInsets.symmetric(horizontal: 15),
color: Colors.black,
height: sizingInformation.localWidgetSize.height * 0.08,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
onTap: () {
setState(() {
counter(0);
});
},
child: _navBarItem(
title: "Home",
icon: Icons.home,
),
),
InkWell(
onTap: () {
setState(() {
counter(1);
});
},
child: _navBarItem(
title: "Discover",
icon: Icons.search,
),
),
InkWell(
onTap: () async {
if (Constants.pref.getBool("loggedIn") == true) {
try {
if (currentIndex >= 0) {
try {
if (feedViewModel.listVideos != null) {
if (feedViewModel.listVideos[currentIndex]
.controller.value.isPlaying) {
feedViewModel
.listVideos[currentIndex].controller
.pause();
feedViewModel.listVideos = null;
feedViewModel.controller.dispose();
feedViewModel.controller=null;
super.dispose();
}
}
} catch (e) {}
}
} catch (e) {
print(e.toString());
}
final videoPath = await Navigator.of(context)
.pushNamed(CAMERA_SCREEN);
/* Navigator.push(
context,
MaterialPageRoute(
// builder: (_) => Video()
builder: (_) => HomeScreen2(null)
// builder: (_) => AddVideoPage()
));*/
} else {
toast("Please login/sign up");
}
},
child: Container(
margin: EdgeInsets.only(top: 10),
width: 50,
height: sizingInformation.localWidgetSize.height * 0.07,
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Container(
width: 20,
height: sizingInformation.localWidgetSize.height *
0.05,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10)),
color: Colors.blue),
),
),
Align(
alignment: Alignment.topRight,
child: Container(
width: 20,
height: sizingInformation.localWidgetSize.height *
0.05,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10)),
color: Colors.red),
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
width: 40,
height: sizingInformation.localWidgetSize.height *
0.05,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10)),
color: Colors.white),
child: Icon(
Icons.add,
color: Colors.black,
),
),
)
],),),),
InkWell(
onTap: () {
setState(() {
counter(2);
});
},
child: _navBarItem(
title: "Notification",
icon: Icons.message,
),
),
InkWell(
onTap: () {
setState(() {
counter(3);
});
},
child: _navBarItem(
title: "Profile",
icon: Icons.person,
),
),
],
),
),
// body: Constants.pref.getBool("loggedIn") == true && _pageController==4
// ? _pages[_pageController]
// : ProfileApp());
body: _pages[_pageController]);
},
);
}
Widget _navBarItem({String title, IconData icon}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Icon(icon), Text(title)],
);
}
toast(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1);
}
}
class FeedScreen extends StatefulWidget {
// FeedScreen({Key key}) : super(key: key);
#override
_FeedScreenState createState() => _FeedScreenState();
}
class _FeedScreenState extends State<FeedScreen>with SingleTickerProviderStateMixin {
AnimationController _animationController;
int _followingForYouController = 1;
FullScreenDialog _myDialog;
#override
void initState() {
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 8));
_animationController.repeat();
load("For you");
super.initState();
}
Future<bool> _onWillPop() async {
if (currentIndex >= 0) {
if (feedViewModel.listVideos != null) {
feedViewModel.listVideos[currentIndex].controller.pause();
feedViewModel.listVideos = null;
feedViewModel.controller.dispose();
feedViewModel.controller=null;
super.dispose();
}
}
}
#override
Widget build(BuildContext context) {
return ViewModelBuilder<FeedViewModel>.reactive(
disposeViewModel: false,
builder: (context, model, child) => videoScreen(),
viewModelBuilder: () => feedViewModel);
}
Widget videoScreen() {
return WillPopScope(
onWillPop: _onWillPop,
child: ResponsiveBuilder(
builder: (BuildContext context, SizingInformation sizingInformation) {
return Padding(
padding: const EdgeInsets.all(1),
child: Scaffold(
backgroundColor: GetIt.instance<FeedViewModel>().actualScreen == 0
? Colors.black
: Colors.white,
body: Stack(
children: [
PageView.builder(
itemCount: 1,
onPageChanged: (value) {
print(value);
if (value == 1)
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.dark);
else
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.light);
},
itemBuilder: (context, index) {
return scrollFeed(sizingInformation);
})
],
),
));
}),
);
}
Widget scrollFeed(SizingInformation sizingInformation) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(child: feedVideos(sizingInformation)),
],
);
}
Widget feedVideos(SizingInformation sizingInformation) {
return feedViewModel.listVideos != null
? Scaffold(body: videoPage(sizingInformation))
: Center(child: CircularProgressIndicator());
}
Widget videoPage(SizingInformation sizingInformation) {
return Stack(
children: [
PageView.builder(
controller: PageController(
initialPage: 0,
viewportFraction: 1,
),
itemCount: feedViewModel.listVideos.length,
onPageChanged: (index) {
index = index % (feedViewModel.listVideos.length);
feedViewModel.changeVideo(index);
},
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
currentIndex = index;
index = index % (feedViewModel.listVideos.length);
return videoCard(
feedViewModel.listVideos[index], index, sizingInformation);
},
),
followingForYou(),
],
);
}
Widget videoCard(
Video video, int index, SizingInformation sizingInformation) {
return Stack(
children: [
video.controller != null
? GestureDetector(
onTap: () {
if (video.controller.value.isPlaying) {
video.controller.pause();
} else {
video.controller.play();
}
},
child: SizedBox.expand(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: video.controller.value.size?.width ?? 0,
height: video.controller.value.size?.height ?? 0,
child: VideoPlayer(video.controller),
),
)),
)
: Container(
color: Colors.black,
child: Center(
child: Text("Loading..."),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
VideoDescription(
video.id, video.user, video.videoTitle, video.songName),
_rightWidget(video, index),
// _rightSideButtonsWidgets(index),
// _textDataWidgetBottom(sizingInformation, index)
],
),
SizedBox(height: 20)
],
),
],
);
}
#override
void dispose() {
try {
feedViewModel.controller.dispose();
feedViewModel.controller=null;
super.dispose();
} catch (e) {
print(e.toString());
}
}
load(String type) async {
feedViewModel.listVideos = await getVideoList(type);
setState(() {
feedViewModel.loadVideo(0);
// feedViewModel.loadVideo(1);
});
}
Future<List<Video>> getVideoList(String type) async {
var videoList = <Video>[];
final body = {
"username": Constants.pref.getString("profileId"),
"Type": type,
};
var jsonObj = json.encode(body);
var response = await http.post('https://ssca-api.appspot.com/act/video/',
headers: {"api-Key": "NkHb13BxRBiZ0JSyxLbAU"}, body: jsonObj);
print("${response.request}"); //200 if successful
print("http status: ${response.statusCode}"); //200 if successful
print("http Request: ${jsonObj}"); //200 if successful
print("http Response: ${response.body}");
var data = json.decode(response.body);
// data = jsonDecode(response.body);
for (int i = 0; i < data["video"].length; i++) {
Video video = new Video();
video.id = data["video"][i]["id"];
video.user = data["video"][i]["profileId"];
video.userPic = data["video"][i]["image"];
video.videoTitle = data["video"][i]["description"];
video.songName = "Music name is here";
video.likes = data["video"][i]["liked"];
video.comments = data["video"][i]["comment"];
video.url = data["video"][data["video"].length-1]["video"];
// video.url = data["video"][i]["video"];
video.isLiked = data["video"][i]["isLiked"];
if (data["video"][i]["followstatus"] == 0) {
video.following = false;
} else {
video.following = true;
}
video.isLiked = data["video"][i]["isLiked"];
videoList.add(video);
}
return videoList;
}
toast(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1);
}
// Full dimensions of an action
static const double ActionWidgetSize = 60.0;
// The size of the icon showen for Social Actions
static const double ActionIconSize = 35.0;
// The size of the share social icon
static const double ShareActionIconSize = 25.0;
// The size of the profile image in the follow Action
static const double ProfileImageSize = 50.0;
// The size of the plus icon under the profile image in follow action
static const double PlusIconSize = 20.0;
LinearGradient get musicGradient => LinearGradient(colors: [
Colors.grey[800],
Colors.grey[900],
Colors.grey[900],
Colors.grey[800]
], stops: [
0.0,
0.4,
0.6,
1.0
], begin: Alignment.bottomLeft, end: Alignment.topRight);
Widget _rightWidget(Video video, int index) {
return Container(
width: 100.0,
child: Column(mainAxisSize: MainAxisSize.min, children: [
_getFollowAction(index),
_likeWidget(index),
GestureDetector(
onTap: () {
if (Constants.pref.getBool("loggedIn") == true) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CommentList(feedViewModel.listVideos[index].id)));
} else {
toast("Please login/sign up");
}
},
child: Container(
margin: EdgeInsets.only(top: 15.0),
width: 60.0,
height: 60.0,
child: Column(children: [
Icon(FontAwesomeIcons.comment,
size: 35.0, color: Colors.grey[300]),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: Text(video.comments,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 12.0)),
)
])),
),
GestureDetector(
onTap: () {
// _shareImageAndText(video);
Share.share('check out my video ' + video.url);
},
child: Container(
margin: EdgeInsets.only(top: 15.0),
width: 60.0,
height: 60.0,
child: Column(children: [
Icon(FontAwesomeIcons.share,
size: 25.0, color: Colors.grey[300]),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: Text('Share',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 12.0)),
)
])),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => _myDialog =
new FullScreenDialog(feedViewModel.listVideos[index].id),
fullscreenDialog: true,
));
},
child: Container(
margin: EdgeInsets.only(top: 15.0),
width: 60.0,
height: 60.0,
child: Column(children: [
Icon(FontAwesomeIcons.angry,
size: 25.0, color: Colors.grey[300]),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: Text('Report',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 12.0)),
)
])),
),
CircleImageAnimation(
child: _getMusicPlayerAction(video.userPic),
)
]),
);
}
Widget _likeWidget(int index) {
return GestureDetector(
onTap: () {
if (Constants.pref.getBool("loggedIn") == true) {
setState(() {
if (feedViewModel.listVideos[index].isLiked) {
feedViewModel.listVideos[index].isLiked = false;
} else {
feedViewModel.listVideos[index].isLiked = true;
}
final body = {
"username": Constants.pref.getString("profileId"),
"videoId": feedViewModel.listVideos[index].id,
"like": feedViewModel.listVideos[index].isLiked,
};
ApiService.like(body).then((success) {
if (success.statusCode == 200) {
var response = json.decode(success.body);
if (response["response"]["confirmation"] != 0) {
feedViewModel.listVideos[index].likes =
response["response"]["TotalLiked"];
} else {
ShowAlertDialog(context, response["success"]["message"]);
}
} else {
ShowAlertDialog(context, ParameterConstant.STATUS);
}
});
});
} else {
toast("Please login/sign up");
}
},
child: Container(
margin: EdgeInsets.only(top: 15.0),
width: 60.0,
height: 60.0,
child: Column(children: [
Icon(
FontAwesomeIcons.solidHeart,
size: 35.0,
color:
feedViewModel.listVideos[index].isLiked ? Colors.red : null,
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: Text(feedViewModel.listVideos[index].likes,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 12.0)),
)
])),
);
}
Widget _getFollowAction(int index) {
return GestureDetector(
onTap: () {
if (Constants.pref.getBool("loggedIn") == true) {
setState(() {
if (feedViewModel.listVideos[index].following) {
feedViewModel.listVideos[index].following = false;
} else {
feedViewModel.listVideos[index].following = true;
}
final body = {
"profileId": Constants.pref.getString("profileId"),
"followupId": feedViewModel.listVideos[index].user,
};
ApiService.follow(body).then((success) {
if (success.statusCode == 200) {
var response = json.decode(success.body);
// if (response["confirmation"] != 0) {
/* if (feedViewModel.listVideos[index].following) {
feedViewModel.listVideos[index].following = false;
} else {
feedViewModel.listVideos[index].following = true;
}*/
// } else {
// ShowAlertDialog(context, response["message"]);
// }
} else {
ShowAlertDialog(context, ParameterConstant.STATUS);
}
});
});
} else {
toast("Please login/sign up");
}
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
width: 60.0,
height: 60.0,
child: Stack(children: [
_getProfilePicture(feedViewModel.listVideos[index].userPic),
_getPlusIcon(index)
])),
);
}
Widget _getProfilePicture(userPic) {
return Positioned(
left: (ActionWidgetSize / 2) - (ProfileImageSize / 2),
child: Container(
padding: EdgeInsets.all(1.0),
// Add 1.0 point padding to create border
height: ProfileImageSize,
// ProfileImageSize = 50.0;
width: ProfileImageSize,
// ProfileImageSize = 50.0;
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(ProfileImageSize / 2)),
// import 'package:cached_network_image/cached_network_image.dart'; at the top to use CachedNetworkImage
child: ClipRRect(
borderRadius: BorderRadius.circular(10000.0),
child: CachedNetworkImage(
imageUrl: userPic,
placeholder: (context, url) =>
new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
))));
}
Widget _getPlusIcon(int index) {
return Positioned(
bottom: 0,
left: ((ActionWidgetSize / 2) - (PlusIconSize / 2)),
child: Container(
width: PlusIconSize, // PlusIconSize = 20.0;
height: PlusIconSize, // PlusIconSize = 20.0;
decoration: BoxDecoration(
color: Color.fromARGB(255, 255, 43, 84),
borderRadius: BorderRadius.circular(15.0)),
child: Icon(
feedViewModel.listVideos[index].following
? Icons.remove
: Icons.add,
color: Colors.white,
size: 20.0,
)),
);
// import_contacts, clear,forward,gesture
}
Widget _getMusicPlayerAction(userPic) {
return Container(
margin: EdgeInsets.only(top: 10.0),
width: ActionWidgetSize,
height: ActionWidgetSize,
child: Column(children: [
Container(
padding: EdgeInsets.all(11.0),
height: ProfileImageSize,
width: ProfileImageSize,
decoration: BoxDecoration(
gradient: musicGradient,
borderRadius: BorderRadius.circular(ProfileImageSize / 2)),
child: ClipRRect(
borderRadius: BorderRadius.circular(10000.0),
child: CachedNetworkImage(
imageUrl: userPic,
placeholder: (context, url) =>
new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
))),
]));
}
TextStyle _textStyleFollowingForYou(Color color) {
return TextStyle(fontSize: 18, color: color, fontWeight: FontWeight.w500);
}
Widget followingForYou() {
return SafeArea(
child: Container(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
if (Constants.pref.getBool("loggedIn") == true) {
_followingForYouController = 0;
setState(() {
feedViewModel.listVideos[currentIndex].controller
.pause();
feedViewModel.listVideos = null;
load("Following");
});
} else {
toast("Please login/sign up");
}
});
},
child: Text("Following",
style: _textStyleFollowingForYou(
_followingForYouController == 0
? Colors.white
: Colors.white60))),
SizedBox(
width: 15,
),
GestureDetector(
onTap: () {
setState(() {
try {
feedViewModel.listVideos[currentIndex].controller
.pause();
} catch (e) {
print(e.toString());
}
_followingForYouController = 1;
feedViewModel.listVideos = null;
load("For you");
});
},
child: Text("For you",
style: _textStyleFollowingForYou(
_followingForYouController == 1
? Colors.white
: Colors.white60)))
],
),
]),
),
);
}
}
My code was working fine but now I'm unable to see the Profile page as it generates an error and I'm unable to identify, even though I tried to return a Container() at the end of buildProfileButton() but it did not solve the issue as I updated the code of that function later on.
class Profile extends StatefulWidget {
final String profileId;
Profile({this.profileId});
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
final String currentUserId = currentUser?.id;
bool isLoading = false;
int postCount = 0;
bool isFollowing = false;
int followerCount = 0;
int followingCount = 0;
List<Post> posts = [];
#override
void initState() {
super.initState();
getProfilePosts();
getFollowers();
getFollowing();
checkIfFollowing();
}
checkIfFollowing() async {
DocumentSnapshot doc = await followersRef
.document(widget.profileId)
.collection('userFollowers')
.document(currentUserId)
.get();
setState(() {
isFollowing = doc.exists;
});
}
getFollowers() async {
QuerySnapshot snapshot = await followersRef
.document(widget.profileId)
.collection('userFollowers')
.getDocuments();
setState(() {
followerCount = snapshot.documents.length;
});
}
getFollowing() async {
QuerySnapshot snapshot = await followingRef
.document(widget.profileId)
.collection('userFollowing')
.getDocuments();
setState(() {
followingCount = snapshot.documents.length;
});
}
getProfilePosts() async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await postsRef
.document(widget.profileId)
.collection('userPosts')
.orderBy('rating', descending: true)
.getDocuments();
setState(() {
isLoading = false;
postCount = snapshot.documents.length;
posts = snapshot.documents.map((doc) => Post.fromDocument(doc)).toList();
});
}
Column buildCountColumn(String label, int count) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
count.toString(),
style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold),
),
Container(
margin: EdgeInsets.only(top: 4.0),
child: Text(
label,
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
fontWeight: FontWeight.w400,
),
),
),
],
);
}
editProfile() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditProfile(currentUserId: currentUserId)));
}
Container buildButton({String text, Function function}) {
return Container(
padding: EdgeInsets.only(top: 2.0),
child: FlatButton(
onPressed: function,
child: Container(
width: 210.0,
height: 27.0,
child: Text(
text,
style: TextStyle(
color:
isFollowing ? Colors.white : Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
alignment: Alignment.center,
decoration: BoxDecoration(
color: isFollowing ? Theme.of(context).primaryColor : Colors.white,
border: Border.all(
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(5.0),
),
),
),
);
}
buildProfileButton() {
bool isProfileOwner = currentUserId == widget.profileId;
if (isProfileOwner) {
return buildButton(
text: "Edit Profile",
function: editProfile,
);
} else if (isFollowing) {
return buildButton(
text: "Unfollow",
function: handleUnfollowUser,
);
} else if (!isFollowing) {
return buildButton(
text: "Follow",
function: handleFollowUser,
);
}
}
handleUnfollowUser() {
setState(() {
isFollowing = false;
});
followersRef
.document(widget.profileId)
.collection('userFollowers')
.document(currentUserId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
followingRef
.document(currentUserId)
.collection('userFollowing')
.document(widget.profileId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
activityFeedRef
.document(widget.profileId)
.collection('feedItems')
.document(currentUserId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
}
handleFollowUser() {
setState(() {
isFollowing = true;
});
followersRef
.document(widget.profileId)
.collection('userFollowers')
.document(currentUserId)
.setData({});
followingRef
.document(currentUserId)
.collection('userFollowing')
.document(widget.profileId)
.setData({});
activityFeedRef
.document(widget.profileId)
.collection('feedItems')
.document(currentUserId)
.setData({
"type": "follow",
"ownerId": widget.profileId,
"username": currentUser.username,
"userId": currentUserId,
"userProfileImg": currentUser.photoUrl,
"timestamp": timestamp,
});
}
buildProfileHeader() {
return FutureBuilder(
future: usersRef.document(widget.profileId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
User user = User.fromDocument(snapshot.data);
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(
radius: 40.0,
backgroundColor: Colors.grey,
backgroundImage: CachedNetworkImageProvider(user.photoUrl),
),
Expanded(
flex: 1,
child: Column(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildCountColumn("Videos", postCount),
buildCountColumn("Followers", followerCount),
buildCountColumn("Following", followingCount),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[buildProfileButton()],
),
],
),
),
],
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 12.0),
child: Text(
user.username,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 4.0),
child: Text(
user.displayName,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(top: 2.0),
child: Text(
user.bio,
),
),
],
),
);
},
);
}
buildProfilePosts() {
if (isLoading) {
return circularProgress();
} else if (posts.isEmpty) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/images/no_content.svg', height: 260.0),
Padding(
padding: EdgeInsets.only(top: 20.0),
child: Text(
"No Posts",
style: TextStyle(
color: Colors.redAccent,
fontSize: 40.0,
fontWeight: FontWeight.bold),
),
),
],
),
);
}
return Column(
children: posts,
);
}
buildTogglePostOrientation() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.videocam,
size: 30.0, color: Theme.of(context).primaryColor),
onPressed: null,
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: header(context, titleText: "PROFILE"),
body: ListView(
children: <Widget>[
buildProfileHeader(),
Divider(),
buildTogglePostOrientation(),
Divider(
height: 0.0,
),
buildProfilePosts(),
],
),
);
}
}
The debug console says that: A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 285 pos 10: 'data != null'
The relevant error-causing widget was
FutureBuilder
Instead of writing Text(description), write Text(description ?? '') so the Text widget will be empty if description is null.
When using the property of an object, instead of writing Text(user.bio) write Text(user?.bio ?? '') for the Text widget to get an empty string if user or user.bio is null.
You can Also make sure that the strings your using in the Text widget are never null.
Not related to the question but I see that you use a lot of functions to build your UI,
I suggest that you turn each of them to a separate widget to improve your app's performance. see this post to learn more.