300 lines
12 KiB
Dart
300 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.02,
|
|
minY: (state.minValue ?? 0) * 0.98,
|
|
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),
|
|
if (state.relatedContents != null)
|
|
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 == 'high') {
|
|
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 == 'high') {
|
|
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),
|
|
],
|
|
);
|
|
}
|
|
}
|