110 lines
3.3 KiB
Dart
110 lines
3.3 KiB
Dart
/// Named Overview chart filter snapshots (local favourites).
|
|
library;
|
|
|
|
import '../models/transaction_meta.dart';
|
|
import '../widgets/label_filter_dialog.dart';
|
|
|
|
/// Persisted Overview lens: period, metric, and Labels-chart options.
|
|
class OverviewFavourite {
|
|
const OverviewFavourite({
|
|
required this.id,
|
|
required this.name,
|
|
this.display = true,
|
|
this.metric = OverviewMetricMode.flow,
|
|
this.period = OverviewPeriodMode.monthly,
|
|
this.labelIds = const [],
|
|
this.flow = TxFlowFilter.expense,
|
|
this.barStyle = LabelChartBarStyle.parallel,
|
|
this.invertExpensePerspective = false,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
|
|
/// When true, this favourite appears on the Favourites overview view.
|
|
final bool display;
|
|
|
|
final OverviewMetricMode metric;
|
|
final OverviewPeriodMode period;
|
|
|
|
/// Empty = all labels (Labels metric only).
|
|
final List<String> labelIds;
|
|
|
|
final TxFlowFilter flow;
|
|
final LabelChartBarStyle barStyle;
|
|
final bool invertExpensePerspective;
|
|
|
|
OverviewFavourite copyWith({
|
|
String? id,
|
|
String? name,
|
|
bool? display,
|
|
OverviewMetricMode? metric,
|
|
OverviewPeriodMode? period,
|
|
List<String>? labelIds,
|
|
TxFlowFilter? flow,
|
|
LabelChartBarStyle? barStyle,
|
|
bool? invertExpensePerspective,
|
|
}) {
|
|
return OverviewFavourite(
|
|
id: id ?? this.id,
|
|
name: name ?? this.name,
|
|
display: display ?? this.display,
|
|
metric: metric ?? this.metric,
|
|
period: period ?? this.period,
|
|
labelIds: labelIds ?? this.labelIds,
|
|
flow: flow ?? this.flow,
|
|
barStyle: barStyle ?? this.barStyle,
|
|
invertExpensePerspective:
|
|
invertExpensePerspective ?? this.invertExpensePerspective,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'name': name,
|
|
'display': display,
|
|
'metric': metric.name,
|
|
'period': period.name,
|
|
'labelIds': labelIds,
|
|
'flow': flow.name,
|
|
'barStyle': barStyle.name,
|
|
'invertExpensePerspective': invertExpensePerspective,
|
|
};
|
|
|
|
factory OverviewFavourite.fromJson(Map<String, dynamic> json) {
|
|
return OverviewFavourite(
|
|
id: json['id'] as String? ?? 'fav_${DateTime.now().millisecondsSinceEpoch}',
|
|
name: (json['name'] as String?)?.trim().isNotEmpty == true
|
|
? (json['name'] as String).trim()
|
|
: 'Favourite',
|
|
display: json['display'] as bool? ?? true,
|
|
metric: OverviewMetricMode.values.firstWhere(
|
|
(e) => e.name == json['metric'],
|
|
orElse: () => OverviewMetricMode.flow,
|
|
),
|
|
period: OverviewPeriodMode.values.firstWhere(
|
|
(e) => e.name == json['period'],
|
|
orElse: () => OverviewPeriodMode.monthly,
|
|
),
|
|
labelIds: [
|
|
for (final id in (json['labelIds'] as List? ?? const []))
|
|
if (id is String && id.isNotEmpty) id,
|
|
],
|
|
flow: TxFlowFilter.values.firstWhere(
|
|
(e) => e.name == json['flow'],
|
|
orElse: () => TxFlowFilter.expense,
|
|
),
|
|
barStyle: LabelChartBarStyle.values.firstWhere(
|
|
(e) => e.name == json['barStyle'],
|
|
orElse: () => LabelChartBarStyle.parallel,
|
|
),
|
|
invertExpensePerspective:
|
|
json['invertExpensePerspective'] as bool? ?? false,
|
|
);
|
|
}
|
|
}
|
|
|
|
enum OverviewMetricMode { flow, labels }
|
|
|
|
enum OverviewPeriodMode { monthly, yearly }
|