Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
Add comments for BalanceOverview Widgets (#284)
Browse files Browse the repository at this point in the history
Add comments

Co-authored-by: Stefan Rudi <[email protected]>
  • Loading branch information
stefanrudi2004 and Stefan Rudi authored Jun 13, 2024
1 parent 43fec06 commit e7ea3c1
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import 'total_display.dart';
import 'view_option.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'selection.dart';
import 'package:intl/intl.dart';

/// Custom widget for representing the overview of income, balance and expenses
/// Uses different custom widgets that are refractored in own files under
/// balance_overview directory
///
class BalanceOverview extends StatefulWidget {
//function that return List of all Categories depending on the selectedDate
// Widget expects two list of all Categories depending on the selectedDate
final List<CategoryMock> incomes;
final List<CategoryMock> expenses;

Expand All @@ -25,26 +28,27 @@ class BalanceOverview extends StatefulWidget {
}

class _BalanceOverviewState extends State<BalanceOverview> {
/// At the beginning initialise some attributes
Selection _selectedSegment = Selection.balance;
ViewOption _viewOption = ViewOption.month;
DateTime _selectedDate = DateTime.now();

//angezeigter String auf dem Button
// Text which is shown on the center button and displays the value of _selectedDate
late String buttonText;

// initState() function that is called once when the widget is started for the first time
@override
void initState() {
// TODO: implement initState
super.initState();
buttonText = DateFormat.MMMM().format(_selectedDate);
}

//Berechnung der total Values für Incomes und Expenses
//Calculation of total values for incomes und expenses
double get totalIncomes =>
widget.incomes.fold(0, (sum, item) => sum + item.totalValue);
double get totalExpenses =>
widget.expenses.fold(0, (sum, item) => sum + item.totalValue);

// function that returns the total value depening on selected view [income, balance, expenses]
double get totalValue {
if (_selectedSegment == Selection.income) {
return totalIncomes;
Expand All @@ -60,22 +64,35 @@ class _BalanceOverviewState extends State<BalanceOverview> {
Widget build(BuildContext context) {
return Column(
children: [
// Custom widget that shows the SegmentedControl
SegmentedControlWidget(
selectedSegment: _selectedSegment,
onValueChanged: (Selection? value) {
if (value != null) {
setState(() {
_selectedSegment = value;
_selectedSegment =
value; // Update the selected segment and rebuild the widget
});
}
}),
const SizedBox(height: 20),
TotalDisplay(total: totalValue, selectedSegment: _selectedSegment),
const SizedBox(
height: 20,
),
// Custom widget TotalDisplay that displays totalValue as Text
TotalDisplay(
total: totalValue,
selectedSegment: _selectedSegment,
),
// Call a method to build additional content
_buildContent(),
],
);
}

/// Method to build the content based on the selected segment
/// Income -> builds a pie chart with the list of incomes
/// Balance -> builds the chart that shows the balance between incomes and expenses
/// Expense -> builds a pie chart with the list of expenses
Widget _buildContent() {
if (_selectedSegment == Selection.income) {
return _buildPieChart(widget.incomes);
Expand All @@ -86,6 +103,9 @@ class _BalanceOverviewState extends State<BalanceOverview> {
}
}

/// Method to build a pie chart using a list
/// Using the PieChart widget from the imported fl_chart package
/// PieChart widget needs PieChartData for each section in the pie chart
Widget _buildPieChart(List<CategoryMock> items) {
return Container(
margin: const EdgeInsets.all(20),
Expand All @@ -97,26 +117,29 @@ class _BalanceOverviewState extends State<BalanceOverview> {
child: PieChart(
PieChartData(
sectionsSpace: 0,
sections: _generatePieChartSections(items),
sections: _generatePieChartSections(
items), // Generate the sections of the pie chart
centerSpaceRadius: double.infinity,
),
swapAnimationDuration:
const Duration(milliseconds: 150), // Optional
swapAnimationCurve: Curves.linear, // Optional
),
),
// Call a method to the center button
_buildCenterButton()
],
),
);
}

/// Method to build the center button that shows the selected date for the pie chart
Widget _buildCenterButton() {
return ClipOval(
child: AspectRatio(
aspectRatio: 1,
child: CupertinoButton(
onPressed: () => _selectDate(context),
onPressed: () => _selectDate(context), // Calls the
child: FittedBox(
child: Text(
buttonText,
Expand All @@ -131,6 +154,7 @@ class _BalanceOverviewState extends State<BalanceOverview> {
);
}

// Method that generate and return a list of PieChartSectionData which are required for PieChart
List<PieChartSectionData> _generatePieChartSections(
List<CategoryMock> items) {
return items.map((item) {
Expand All @@ -146,10 +170,13 @@ class _BalanceOverviewState extends State<BalanceOverview> {
}).toList();
}

// Async function that processes the date selection with a modal popup from Cupertino
Future<void> _selectDate(BuildContext context) async {
// Show a Cupertino modal popup to select a date
DateTime? picked = await showCupertinoModalPopup<DateTime>(
context: context,
builder: (BuildContext context) {
// Return a custom date selector popup widget
return DateSelectorPopup(
initialDate: _selectedDate,
initialViewOption: _viewOption,
Expand All @@ -161,26 +188,33 @@ class _BalanceOverviewState extends State<BalanceOverview> {
},
);

// If a date is picked (not null), update the state
if (picked != null) {
setState(() {
_selectedDate = picked;

// Update the button text based on the selected view option
switch (_viewOption) {
case ViewOption.day:
buttonText = DateFormat.yMMMMd().format(picked);
buttonText =
DateFormat.yMMMMd().format(picked); // Format date as day
break;
case ViewOption.month:
buttonText = DateFormat.MMMM().format(picked);
buttonText =
DateFormat.MMMM().format(picked); // Format date as month
break;
case ViewOption.year:
buttonText = DateFormat.y().format(picked);
buttonText = DateFormat.y().format(picked); // Format date as year
break;
}
});
}
}

// Method to build a container displaying the balance information
Widget _buildBalanceContainer() {
// Calculation of the fraction for income and expense
// needed to define the size of each container (income/expense)
double total = totalIncomes + totalExpenses;
double incomeFraction = totalIncomes / total;
double expenseFraction = totalExpenses / total;
Expand All @@ -193,6 +227,7 @@ class _BalanceOverviewState extends State<BalanceOverview> {
children: [
Column(
children: [
// Container to display the total incomes
Container(
height: 400 * incomeFraction,
decoration: BoxDecoration(
Expand Down Expand Up @@ -221,6 +256,7 @@ class _BalanceOverviewState extends State<BalanceOverview> {
),
),
),
// Container to display the total expenses
Container(
height: 400 * expenseFraction,
decoration: BoxDecoration(
Expand Down Expand Up @@ -249,12 +285,14 @@ class _BalanceOverviewState extends State<BalanceOverview> {
),
],
),
// Call a method to the center button
_buildBalanceCenterButton()
],
),
);
}

/// Method to build the center button that shows the selected date for the balance overview
Widget _buildBalanceCenterButton() {
return Padding(
padding: const EdgeInsets.all(70.0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'package:flutter/cupertino.dart';

import 'view_option.dart';
import 'view_segmented_control.dart';

/// Custom Widget for selecting a date with additional options
class DateSelectorPopup extends StatefulWidget {
// Widget required the initial selected date and view
// also a callback for when a date is selected
final DateTime initialDate;
final ViewOption initialViewOption;
final void Function(DateTime, ViewOption) onDateSelected;
Expand Down Expand Up @@ -46,9 +48,11 @@ class _DateSelectorPopupState extends State<DateSelectorPopup> {
selectedSegment: _viewOption,
onValueChanged: (ViewOption? value) {
if (value != null) {
setState(() {
_viewOption = value;
});
setState(
() {
_viewOption = value;
},
);
}
},
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'selection.dart';

/// Custom Widget that represents the SegmentedControlWidget for selection view [income, balance, expense]
/// This widget uses CupertinoSlidingSegmentedControl based on Cupertino Design Guidelines
class SegmentedControlWidget extends StatelessWidget {
// Requires the currently selected segment and the callback to handle value changes
final Selection selectedSegment;
final ValueChanged<Selection?> onValueChanged;

Expand All @@ -17,10 +20,12 @@ class SegmentedControlWidget extends StatelessWidget {
margin: const EdgeInsets.all(10.0),
child: CupertinoSlidingSegmentedControl<Selection>(
backgroundColor: CupertinoColors.systemGrey2,
thumbColor: selectedSegment.color,
groupValue: selectedSegment,
thumbColor: selectedSegment
.color, // Set the color of the thumb based on the selected segment
groupValue: selectedSegment, // currently selected value
onValueChanged: onValueChanged,
children: Selection.values.asMap().map(
// Create a map of the children widgets for each segment
(index, selection) => MapEntry(
selection,
Padding(
Expand Down
14 changes: 11 additions & 3 deletions client/cashcompass/lib/widgets/balance_overview/total_display.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'package:flutter/cupertino.dart';
import 'selection.dart';

/// Custom Widget that displays the totalValue on the screen
/// Depending on the selected view [income, balance, expenses] the color of the text changes
/// income -> green, balance -> green, expense -> red
class TotalDisplay extends StatelessWidget {
// Widget expects the totalValue and the current view
final double total;
final Selection selectedSegment;

Expand All @@ -13,10 +17,13 @@ class TotalDisplay extends StatelessWidget {

@override
Widget build(BuildContext context) {
//format total String for widget
/// Format totalValue String for the Text widget
/// Adds the prefix depending on current view [+, ,-] and adds the currency at the end
/// (Currently hardcoded on Euro, maybe we support different currencies later, then we have to change that fixed code)
final String formattedTotal =
'${selectedSegment.prefix}${total.toStringAsFixed(2)}€';

// Widget consist of two Text widgets that are presented side by side which is implemented via a Row Widget
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expand All @@ -28,11 +35,12 @@ class TotalDisplay extends StatelessWidget {
),
),
Text(
formattedTotal,
formattedTotal, //uses the totalValue which was formatted above
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: selectedSegment.color,
color: selectedSegment
.color, // loads the color of the current view [green, blue, red]
),
)
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'view_option.dart';
import 'package:flutter/cupertino.dart';

/// Custom Widget that represents the SegmentedControlWidget for time view option [day, month, year]
/// This widget uses CupertinoSlidingSegmentedControl based on Cupertino Design Guidelines
class ViewOptionSegmentedControl extends StatelessWidget {
// Requires the currently selected segment and the callback to handle value changes
final ViewOption selectedSegment;
final ValueChanged<ViewOption?> onValueChanged;

Expand All @@ -19,6 +22,7 @@ class ViewOptionSegmentedControl extends StatelessWidget {
onValueChanged: onValueChanged,
thumbColor: CupertinoColors.systemBlue,
children: ViewOption.values.asMap().map(
// Create a map of the children widgets for each segments
(index, viewOption) => MapEntry(
viewOption,
Padding(
Expand Down

0 comments on commit e7ea3c1

Please sign in to comment.