uaestats_fe/lib/presentation/components/charts/themed_vertical_bar_chart.dart
2026-05-16 11:31:32 +05:30

195 lines
6.0 KiB
Dart
Executable File

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/packages/list.dart';
import 'package:uae_stat/infrastructure/services/packages/material_color.dart';
import 'package:uae_stat/infrastructure/services/packages/num_abbreviation.dart';
import 'package:uae_stat/presentation/components/space.dart';
class ThemedVerticalBarChart extends ConsumerWidget {
const ThemedVerticalBarChart(
this.data, {
super.key,
required this.materialColor,
});
final Map<String, Map<String, num>> data;
final MaterialColor materialColor;
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorList = materialColor.colorListButFewer;
final isOnlyOneChart = data.length == 1;
final legend = Column(
children: List.generate(
data.values.first.length,
(i) {
final e = data.values.first.keys.elementAt(i);
final colorList = materialColor.colorListButFewer;
final color = colorList[i % colorList.length];
return Row(
children: [
Container(
height: 12,
width: 12,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(2),
),
),
12.horizontalSpace,
Expanded(
child: Text(
e,
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 11,
color: Colors.black,
),
),
),
],
);
},
),
);
final maxVal = data.entries.fold<num>(
double.negativeInfinity,
(prev, chart) {
final chartMax = chart.value.values.fold<num>(
double.negativeInfinity,
(p, e) => e > p ? e : p,
);
return chartMax > prev ? chartMax : prev;
},
);
final charts = Row(
children: data.entries.map<Widget>(
(chartData) {
final titleAndTotal = Column(
children: [
Text(
chartData.key,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 10,
),
),
if (!isOnlyOneChart)
Text(
chartData.value.values
.fold<num>(
0,
(prev, e) => prev + e,
)
.toStringWithCommas(
abbreviateIfAbove10powN: 5,
),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 11,
color: Colors.grey.shade700,
),
),
],
);
final chart = Row(
children: List.generate(
chartData.value.length,
(barI) {
final barVal = chartData.value.values.elementAt(barI);
final color = colorList[barI % colorList.length];
final bar = DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(10),
),
color: color,
),
child: FractionallySizedBox(
heightFactor: barVal / maxVal,
child: double.infinity.horizontalSpace,
),
);
final text = Text(
barVal.toStringWithCommas(),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 8,
fontWeight: FontWeight.w600,
),
);
return Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 20,
child: text,
),
Flexible(
child: bar,
),
if (isOnlyOneChart)
SizedBox(
height: 20,
child: Text(
chartData.value.keys.elementAt(barI),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 11,
color: Colors.black,
),
),
),
],
),
);
},
)..intersperseDivider(
4.horizontalSpace,
),
);
return Expanded(
child: Column(
children: [
Expanded(
child: chart,
),
titleAndTotal,
],
),
);
},
).toList()
..intersperseDivider(32.horizontalSpace),
);
return Column(
children: [
if (!isOnlyOneChart) legend,
18.verticalSpace,
Expanded(
child: charts,
),
],
);
}
}