0

The Function of the App

It has a two items in the bottom navigation bar where in the first section (Courses) the user can add a list of courses and it will update their overall GPA and highest average for them each time they add a new one. The other one is a simple "What do I need to get on my final to pass" section (Finals Predictor).

The following is the code for the at the top of the screen that shows the user's overall gpa, number of courses, and highest average

import 'package:flutter/material.dart';
import 'package:gradecalculator/models/course.dart';

class TopDisplay extends StatefulWidget {
  final List<Course> courses;
  final maxAverage;
  final overallGPA;


  TopDisplay(this.courses, this.maxAverage, this.overallGPA);

  @override
  _TopDisplayState createState() => _TopDisplayState();
}

class _TopDisplayState extends State<TopDisplay> {
  @override
  Widget build(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);
    return Card(
      margin: EdgeInsets.all(10),
      elevation: 5,
      color: Colors.grey[400],
      child:Row(
        children: <Widget> [
          Container(
            margin: EdgeInsets.all(10),
            child: CircleAvatar(
              child: widget.courses.isEmpty ? Text(
                "0.0",
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 25,
                ),
              )
                  :  Text(
                "${widget.overallGPA.toStringAsFixed(2)}",
                style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                    fontSize: 25
                ),
              ),
              radius: 45,
              backgroundColor: Colors.red,
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              SizedBox(
                height: mediaQuery.size.height * 0.07,
              ),
              Row(
                children:<Widget> [
                  const Text(
                    'Number of Courses: ',
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 16,
                        fontWeight: FontWeight.bold
                    ),
                  ),
                  Text(
                    '${widget.courses.length}',
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 16
                    ),
                  ),
                ],
              ),
              Row(
                  children: <Widget>[
                    const Text(
                      'Highest Average:  ',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16,
                          fontWeight: FontWeight.bold
                      ),
                    ),
                    widget.courses.isEmpty ? Text(
                      '0.0',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16
                      ),
                    )
                        :
                    Text(
                      '${widget.maxAverage}%',
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 16
                      ),
                    )
                  ]
              ),
            ],
          ),
        ],
      ),
    );
  }
}

The Problem

If I add courses everything will work fine and everything that needs to be displayed will be displayed. If I navigate to the Finals Predictor then back to Courses, the list of courses is still shown but the Overall GPA and Highest Average go back to 0.0.

The Code for the Tabs Screen with bottomNavigationBar

import 'package:flutter/material.dart';

import 'predictions_screens.dart';
import '../models/course.dart';
import 'home_page.dart';

class TabsScreen extends StatefulWidget {
  final List<Course> listedCourses;


  TabsScreen(this.listedCourses);

  @override
  _TabsScreenState createState() => _TabsScreenState();
}

class _TabsScreenState extends State<TabsScreen> {
  final List<Map<String, Object>> _pages = [
    {'page': HomePage(), 'title': 'Courses'},
    {'page': PredictionsScreen(), 'title': 'Final Grade Calculator'}
  ];

  int _selectedPageIndex = 0;

  void _selectPage(int index) {
      setState(() {
        _selectedPageIndex = index;

      });

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(_pages[_selectedPageIndex]['title']),
      ),
      body: _pages[_selectedPageIndex]['page'],
      bottomNavigationBar: BottomNavigationBar(
        onTap: _selectPage,
        backgroundColor: Theme.of(context).primaryColor,
        unselectedItemColor: Colors.white,
        selectedItemColor: Theme.of(context).accentColor,
        currentIndex: _selectedPageIndex,
        items: [
          BottomNavigationBarItem(
              backgroundColor: Theme.of(context).primaryColor,
              icon: Icon(Icons.book),
              title: Text('Courses')),
          BottomNavigationBarItem(
              backgroundColor: Theme.of(context).primaryColor,
              icon: Icon(Icons.scatter_plot),
              title: Text('Finals Predictor'))
        ],
      ),
    );
  }
}

Code in main.dart file

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'screens/predictions_screens.dart';
import 'screens/tabs_screen.dart';
import './models/course.dart';
import './screens/home_page.dart';

void main() {
  //To ensure that the app only is used in portrait mode
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
  runApp(GradeCalculator());
}

class GradeCalculator extends StatefulWidget {
  @override
  _GradeCalculatorState createState() => _GradeCalculatorState();
}

class _GradeCalculatorState extends State<GradeCalculator> {
  List<Course> coursesOnScreen = [];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Grade Calculator",
      theme: ThemeData(
        primarySwatch: Colors.red,
        accentColor: Colors.blueAccent[200],
      ),
     //home: HomePage(),
      routes: {
        '/': (ctx) => TabsScreen(coursesOnScreen),
        HomePage.routeName: (ctx) => HomePage(),
        PredictionsScreen.routeName: (ctx) => PredictionsScreen()
      },
    );
  }
}

Code for course list output

import 'package:flutter/material.dart';
import 'package:gradecalculator/models/course.dart';

class CourseList extends StatelessWidget {
  static const routeName = '/course-list';

  final List<Course> courses;
  final Function deletec;
  final Function setHighestAverage;
  final Function calculateGPA;

  CourseList(this.courses, this.deletec, this.setHighestAverage, this.calculateGPA);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: courses.length,
        itemBuilder: (ctx, index){
          return Card(
            elevation: 5,
            margin: EdgeInsets.symmetric(
              vertical: 5,
              horizontal: 8,
            ),
            child: ListTile(
              leading: CircleAvatar(
                radius: 20,
                child: Padding(
                  padding: EdgeInsets.all(6),
                  child: FittedBox(
                    child: Text(
                        '${courses[index].courseAverage}'
                    ),
                  ),
                ),
              ),
              title: Text(
                courses[index].courseName,
                style: TextStyle(
                    fontWeight: FontWeight.bold
                ),
              ),
              subtitle: Text(
                  'Course Weight: ${courses[index].courseWeight}'
              ),
              trailing: IconButton(
                icon: Icon(
                  Icons.delete,
                  color: Colors.grey,
                ),
                onPressed: () {
                  deletec(courses[index].courseName);
                  setHighestAverage(courses);
                  calculateGPA(courses);
                },
              ),
            ),
          );
        }
    );
  }
}

HomePage File which calls TopDisplay

import 'package:flutter/material.dart';

import '../models/course.dart';
import '../widgets/newCourse.dart';
import '../widgets/course_list.dart';
import '../widgets/top_display.dart';

class HomePage extends StatefulWidget {
  static const routeName = '/home-page';
  final List<Course> visibleCourses = [];

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double maxAverage = 0.00;
  double overallGPA = 0.00;
  //List for courses as users add courses, this is where they will be stored


  //Calculates the total GPA shown in the top chart
  void calculateGPA(List<Course> courseList) {
    double totalWeight = 0;
    double intermediateGPA = 0;
    for (int i = 0; i < courseList.length; i++) {
      totalWeight += courseList[i].courseWeight;
      intermediateGPA +=
      (courseList[i].courseAverage * courseList[i].courseWeight);
      overallGPA = (intermediateGPA / totalWeight);
    }
  }

  //Finds the highest average that is displayed in the top chart
  void setHighestAverage(List<Course> courseList) {
    calculateGPA(courseList);
    for (int i = 0; i < courseList.length; i++) {
      if (courseList[i].courseAverage >= maxAverage) {
        maxAverage = courseList[i].courseAverage;
      }
    }
  }

  //Opens up the modal sheet that the user can use to enter a new course
  void _startAddNewCourse(BuildContext ctx) {
    showModalBottomSheet(
      context: ctx,
      builder: (_) {
        return GestureDetector(
          onTap: () {},
          behavior: HitTestBehavior.opaque,
          child: NewCourse(_addNewCourse),
        );
      },
    );
  }

  //Initializes the new course and adds it to the courses list above
  void _addNewCourse(String cTitle, double cAverage, double cWeight) {
    final newc = Course(
      courseName: cTitle,
      courseAverage: cAverage,
      courseWeight: cWeight,
    );
    setState(() {
      widget.visibleCourses.add(newc);
      setHighestAverage(widget.visibleCourses);
    });
  }

  void _deleteCourse(String courseName) {
    setState(() {
      widget.visibleCourses.removeWhere((c) {
        return c.courseName == courseName;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    //Setting up a mediaquery variable so that sizes can be determined based on phone size
    final mediaQuery = MediaQuery.of(context);
    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              TopDisplay(widget.visibleCourses, maxAverage, overallGPA),
              Container(
                height: mediaQuery.size.height * 0.7,
                child: CourseList(
                    widget.visibleCourses, _deleteCourse, setHighestAverage, calculateGPA),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => _startAddNewCourse(context),
          backgroundColor: Colors.red,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}
  • can you post the code where you call TopDisplay and how you get maxAverage and overallGPA, when you navigate back and forth the build methods of all the widgets rebuilds (because the alst frame is different), maybe when recalculating those values something changed that made them zero – EdwynZN Jun 02 '20 at 20:12
  • it could be that I declared that them as 0 in the state of HomePage but I don't know what I would set them to to fix it @EdwynZN – Rohan Saxena Jun 02 '20 at 21:12
  • I think they're fine, their state should preserve when pushing and poping back, it's kind weird because if you don't do anything to those values when navigating to Finals Predictor, are you just pushing and poping or you're using pushReplacement? try to debug when poping to see if the values changed or the List (but I don't think that changed because you said the courses are still there) – EdwynZN Jun 02 '20 at 22:07

0 Answers0