Месячная сетка с дивидендами, купонами, амортизациями и погашениями по дням, выплаченными и ожидаемыми, с сводкой за месяц и списком выплат выбранного дня. Раскладка без прокрутки страницы: высота ячеек подстраивается под окно, на широком экране список справа. Прежний список остался вторым режимом.
89 lines
3.1 KiB
Dart
89 lines
3.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../core/theme/chart_colors.dart';
|
|
|
|
/// Russian labels for the stable keys the income routes send.
|
|
|
|
const incomeKindLabels = {
|
|
'dividend': 'Дивиденд',
|
|
'coupon': 'Купон',
|
|
'amortization': 'Амортизация',
|
|
'repayment': 'Погашение',
|
|
};
|
|
|
|
String incomeKindLabel(String kind) => incomeKindLabels[kind] ?? kind;
|
|
|
|
/// One glyph per kind, so a day cell on the calendar says what is paid without a word. The
|
|
/// colour of the glyph is left to the caller: on the calendar it is the basis, not the kind.
|
|
IconData incomeKindIcon(String kind) => switch (kind) {
|
|
'dividend' => Icons.paid_outlined,
|
|
'coupon' => Icons.receipt_long_outlined,
|
|
'amortization' => Icons.trending_down,
|
|
'repayment' => Icons.flag_outlined,
|
|
_ => Icons.circle_outlined,
|
|
};
|
|
|
|
const basisLabels = {
|
|
'schedule': 'по графику',
|
|
'announced': 'объявлено',
|
|
'history': 'по истории',
|
|
'paid': 'выплачено',
|
|
};
|
|
|
|
/// What each basis actually promises. Shown as a tooltip and spelled out in the legend,
|
|
/// because the difference between «объявлено» and «по истории» is the difference between a
|
|
/// fact and a guess.
|
|
const basisDescriptions = {
|
|
'schedule': 'Арифметика по опубликованному графику выплат эмитента.',
|
|
'announced': 'Объявленный эмитентом факт: размер и дата известны.',
|
|
'history':
|
|
'Экстраполяция по выплатам за последние 24 мес — может ошибаться '
|
|
'на любую величину, в том числе выплаты может не быть вовсе.',
|
|
'paid': 'Уже получено.',
|
|
};
|
|
|
|
String basisLabel(String basis) => basisLabels[basis] ?? basis;
|
|
|
|
String basisDescription(String basis) => basisDescriptions[basis] ?? basis;
|
|
|
|
/// Fixed slot per basis — never cycled, so the same basis is the same colour on the
|
|
/// calendar, in the forecast legend and in the stacked bars.
|
|
Color basisColor(String basis) => switch (basis) {
|
|
'schedule' => ChartColors.slot1Blue,
|
|
'announced' => ChartColors.slot3Aqua,
|
|
'history' => ChartColors.slot4Yellow,
|
|
'paid' => ChartColors.slot5Magenta,
|
|
_ => ChartColors.slot2Orange,
|
|
};
|
|
|
|
/// The basis chip that has to sit on every calendar and forecast row.
|
|
class BasisChip extends StatelessWidget {
|
|
const BasisChip({required this.basis, super.key, this.dense = true});
|
|
|
|
final String basis;
|
|
final bool dense;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final color = basisColor(basis);
|
|
return Tooltip(
|
|
message: basisDescription(basis),
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: dense ? 6 : 10,
|
|
vertical: dense ? 1 : 4,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: color.withValues(alpha: 0.14),
|
|
border: Border.all(color: color.withValues(alpha: 0.5)),
|
|
borderRadius: BorderRadius.circular(6),
|
|
),
|
|
child: Text(
|
|
basisLabel(basis),
|
|
style: Theme.of(context).textTheme.labelSmall?.copyWith(color: color),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|