didvan-app/lib/views/home/statistic/statistic_details/statistic_details.dart

299 lines
12 KiB
Dart

import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/views/home/statistic/statistic_details/statistic_details_state.dart';
import 'package:didvan/views/home/widgets/categories_list.dart';
import 'package:didvan/views/home/widgets/overview/multitype.dart';
import 'package:didvan/views/home/widgets/tag_item.dart';
import 'package:didvan/views/widgets/didvan/card.dart';
import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/scaffold.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart' as intl;
class StatisticDetails extends StatefulWidget {
final Map<String, dynamic> pageData;
const StatisticDetails({Key? key, required this.pageData}) : super(key: key);
@override
State<StatisticDetails> createState() => _StatisticDetailsState();
}
class _StatisticDetailsState extends State<StatisticDetails> {
@override
void initState() {
final state = context.read<StatisticDetailsState>();
state.label = widget.pageData['label'];
state.marked = widget.pageData['marked'];
state.currentDateRangeId = 0;
Future.delayed(Duration.zero, state.getStatisticDetails);
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<StatisticDetailsState>(
builder: (context, state, child) => DidvanScaffold(
padding: EdgeInsets.zero,
appBarData: AppBarData(
title: widget.pageData['title'],
hasBack: true,
subtitle: 'رادار قیمت‌ها',
trailing: DidvanIconButton(
icon: state.marked ? Icons.star : Icons.star_border,
color: state.marked
? Theme.of(context).colorScheme.yellow
: Theme.of(context).colorScheme.focusedBorder,
size: 32,
onPressed: () {
state.marked = !state.marked;
state.update();
widget.pageData['onMarkChanged'](state.marked);
},
),
),
children: [
StateHandler<StatisticDetailsState>(
topPadding: MediaQuery.of(context).size.height / 3,
builder: (context, state) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: DidvanText('نمودار تغییرات'),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SizedBox(
width: double.infinity,
height: 120,
child: state.chartState == AppState.busy
? SpinKitThreeBounce(
color: Theme.of(context).colorScheme.primary,
size: 24,
)
: LineChart(
LineChartData(
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor:
Theme.of(context).colorScheme.navigation,
getTooltipItems: (data) => [
LineTooltipItem(
state.datas[data.first.spotIndex].tEn! +
'\n' +
intl.NumberFormat("###,000", "en_US")
.format(
data.first.bar
.spots[data.first.spotIndex].y,
),
Theme.of(context)
.textTheme
.caption!
.copyWith(
color: Colors.white,
),
),
],
),
),
minX: 0,
maxX: state.datas.length.toDouble() - 1,
maxY: state.maxValue * 1.001,
minY: state.minValue,
gridData: FlGridData(show: false),
borderData: FlBorderData(show: false),
titlesData: FlTitlesData(show: false),
lineBarsData: [
LineChartBarData(
spots: [
for (var i = 0; i < state.datas.length; i++)
FlSpot(
i.toDouble(),
_stringToDouble(state.datas[i].p),
)
],
barWidth: 2,
dotData: FlDotData(
getDotPainter: (p0, p1, p2, p3) =>
FlDotCirclePainter(
color: Colors.transparent,
strokeWidth: 1,
strokeColor:
Theme.of(context).colorScheme.success,
),
),
color: Theme.of(context).colorScheme.success,
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
tileMode: TileMode.decal,
colors: [
Theme.of(context)
.colorScheme
.background,
const Color(0XFFF5B763)
.withOpacity(0.2),
],
),
),
),
],
),
),
),
),
const SizedBox(height: 20),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: DidvanText('بازه نمایش:'),
),
const SizedBox(height: 20),
CategoriesList(
isColapsed: false,
isAppBar: false,
selectedCats: [state.currentDateRange],
categories: state.dateRanges,
onSelected: (id) {
state.currentDateRangeId = id;
state.getStatisticDetails();
},
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: DidvanCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDataItem('قیمت لحظه‌ای', state.data!.p),
const DidvanDivider(verticalPadding: 8),
_buildDataItem('بالاترین قیمت روز', state.data!.h),
const SizedBox(height: 8),
_buildDataItem('پایین‌ترین قیمت روز', state.data!.l),
const SizedBox(height: 8),
_buildDataItem(
'درصد تغییر نسبت به دیروز',
'${state.data!.dp}%',
icon: _diffIcon(state),
color: _diffColor(state),
),
const SizedBox(height: 8),
_buildDataItem(
'میزان تغییر نسبت به دیروز',
state.data!.d,
icon: _diffIcon(state),
color: _diffColor(state),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
for (var i = 0; i < state.tags.length; i++)
TagItem(
tag: state.tags[i],
onMarkChanged: (_, __) {},
type: 'statistic',
),
],
),
],
),
),
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: DidvanCard(
child: Column(
children: [
if (state.relatedContents.isEmpty)
for (var i = 0; i < 3; i++) ...[
MultitypeOverview.placeholder,
if (i != 2) const SizedBox(height: 16)
],
for (var i = 0;
i < state.relatedContents.length;
i++) ...[
MultitypeOverview(
item: state.relatedContents[i],
onMarkChanged: (id, value) {},
),
if (i != state.relatedContents.length - 1)
const SizedBox(height: 16)
]
],
),
),
),
const SizedBox(height: 16),
],
),
onRetry: state.getStatisticDetails,
state: state,
)
],
),
);
}
double _stringToDouble(String value) =>
double.parse(value.replaceAll(',', ''));
Color? _diffColor(StatisticDetailsState state) {
if (state.data!.dp == 0) {
return null;
}
if (state.data!.dt == 'low') {
return Theme.of(context).colorScheme.success;
} else {
return Theme.of(context).colorScheme.error;
}
}
IconData? _diffIcon(StatisticDetailsState state) {
if (state.data!.dp == 0) {
return null;
}
if (state.data!.dt == 'low') {
return DidvanIcons.angle_up_regular;
} else {
return DidvanIcons.angle_down_regular;
}
}
Widget _buildDataItem(
String title,
String value, {
IconData? icon,
bool isBold = false,
Color? color,
}) {
return Row(
children: [
DidvanText(
title,
style: isBold
? Theme.of(context).textTheme.bodyText1
: Theme.of(context).textTheme.bodyText2,
),
const Spacer(),
if (icon != null) Icon(icon, color: color),
DidvanText(value, color: color),
],
);
}
}