Make the pie chart widget reusable
This commit is contained in:
@@ -22,8 +22,7 @@ class AccountIndicator extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
if (trailing != null)
|
||||
trailing!,
|
||||
if (trailing != null) trailing!,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
84
lib/ui/widgets/piechart.dart
Normal file
84
lib/ui/widgets/piechart.dart
Normal file
@@ -0,0 +1,84 @@
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:okane/ui/pages/account/breakdown_card.dart';
|
||||
|
||||
typedef OkanePieChartSection = ({String title, double value, Color color});
|
||||
|
||||
typedef OkanePieChartValueConverter = String Function(double);
|
||||
|
||||
String numToString(double input) {
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
class OkanePieChart extends StatelessWidget {
|
||||
// Width of the pie chart
|
||||
final double width;
|
||||
|
||||
// Height of the pie chart
|
||||
final double height;
|
||||
|
||||
final List<OkanePieChartSection> items;
|
||||
|
||||
final OkanePieChartValueConverter valueConverter;
|
||||
|
||||
const OkanePieChart({
|
||||
required this.items,
|
||||
this.valueConverter = numToString,
|
||||
this.width = 150,
|
||||
this.height = 150,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: SizedBox(
|
||||
width: width,
|
||||
height: height,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: PieChart(
|
||||
PieChartData(
|
||||
borderData: FlBorderData(show: false),
|
||||
sectionsSpace: 5,
|
||||
centerSpaceRadius: 35,
|
||||
sections:
|
||||
items
|
||||
.map(
|
||||
(i) => PieChartSectionData(
|
||||
value: i.value,
|
||||
title: valueConverter(i.value),
|
||||
titleStyle: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
radius: 40,
|
||||
color: i.color,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children:
|
||||
items
|
||||
.map((i) => LegendItem(text: i.title, color: i.color))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
82
lib/ui/widgets/piechart_card.dart
Normal file
82
lib/ui/widgets/piechart_card.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:okane/screen.dart';
|
||||
import 'package:okane/ui/widgets/piechart.dart';
|
||||
|
||||
class ResponsiveCard extends StatelessWidget {
|
||||
final String titleText;
|
||||
final String? subtitleText;
|
||||
|
||||
final Widget child;
|
||||
|
||||
const ResponsiveCard({
|
||||
super.key,
|
||||
required this.titleText,
|
||||
required this.child,
|
||||
this.subtitleText,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenSize = getScreenSize(context);
|
||||
final card = Card(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8, left: 8, right: 8),
|
||||
child: Text(
|
||||
titleText,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleLarge!.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
|
||||
child,
|
||||
|
||||
if (subtitleText != null) Text(subtitleText!),
|
||||
],
|
||||
),
|
||||
);
|
||||
return switch (screenSize) {
|
||||
ScreenSize.small => Row(children: [Expanded(child: card)]),
|
||||
ScreenSize.normal => Container(
|
||||
constraints: BoxConstraints(maxWidth: ScreenSize.normal.size),
|
||||
child: card,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class PieChartCard extends StatelessWidget {
|
||||
final String titleText;
|
||||
|
||||
// Text to display when items is empty.
|
||||
final String fallbackText;
|
||||
|
||||
final OkanePieChartValueConverter valueConverter;
|
||||
|
||||
final List<OkanePieChartSection> items;
|
||||
|
||||
const PieChartCard({
|
||||
super.key,
|
||||
this.valueConverter = numToString,
|
||||
required this.items,
|
||||
required this.fallbackText,
|
||||
required this.titleText,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final child =
|
||||
items.isEmpty
|
||||
? SizedBox(
|
||||
width: 150,
|
||||
height: 150,
|
||||
child: Center(child: Text(fallbackText)),
|
||||
)
|
||||
: OkanePieChart(valueConverter: valueConverter, items: items);
|
||||
|
||||
return ResponsiveCard(titleText: titleText, child: child);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user