/// 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 labelIds; final TxFlowFilter flow; final LabelChartBarStyle barStyle; final bool invertExpensePerspective; OverviewFavourite copyWith({ String? id, String? name, bool? display, OverviewMetricMode? metric, OverviewPeriodMode? period, List? 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 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 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 }