Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'package:app_finance/_classes/controller/iterator_controller.dart';
5 : import 'package:app_finance/_classes/storage/app_data.dart';
6 : import 'package:app_finance/_classes/herald/app_locale.dart';
7 : import 'package:app_finance/_classes/structure/bill_app_data.dart';
8 : import 'package:app_finance/_configs/screen_helper.dart';
9 : import 'package:app_finance/_configs/theme_helper.dart';
10 : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
11 : import 'package:app_finance/_ext/date_time_ext.dart';
12 : import 'package:app_finance/design/wrapper/background_wrapper.dart';
13 : import 'package:app_finance/pages/_interfaces/abstract_page_state.dart';
14 : import 'package:app_finance/pages/bill/widgets/bill_line_widget.dart';
15 : import 'package:app_finance/pages/bill/widgets/sliver_header_delegate.dart';
16 : import 'package:app_finance/design/generic/base_header_widget.dart';
17 : import 'package:app_finance/design/generic/base_swipe_widget.dart';
18 : import 'package:flutter/material.dart';
19 : import 'package:intl/intl.dart';
20 :
21 : class BillPage extends StatefulWidget {
22 5 : const BillPage({super.key});
23 :
24 0 : @override
25 0 : BillPageState createState() => BillPageState();
26 : }
27 :
28 : class BillPageState extends AbstractPageState<BillPage> {
29 : InterfaceIterator? stream;
30 : List<Widget> itemsShown = [];
31 : DateTime timer = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day);
32 : final _scrollController = ScrollController();
33 : final batch = 25;
34 :
35 0 : @override
36 : void initState() {
37 0 : super.initState();
38 0 : _scrollController.addListener(() {
39 0 : if (_scrollController.position.extentAfter < 200 && !stream!.isFinished) {
40 0 : setState(() => _addItems());
41 : }
42 : });
43 : }
44 :
45 0 : @override
46 : void dispose() {
47 0 : _scrollController.dispose();
48 0 : super.dispose();
49 : }
50 :
51 0 : void _addItems() {
52 0 : final width = ScreenHelper.state().width - ThemeHelper.getIndent(4);
53 0 : if (itemsShown.isEmpty) {
54 0 : itemsShown.add(
55 0 : SliverToBoxAdapter(
56 0 : child: BaseHeaderWidget(
57 : route: AppRoute.homeRoute,
58 0 : tooltip: AppLocale.labels.homeTooltip,
59 : width: width,
60 0 : total: state.getTotal(AppDataType.bills),
61 0 : title: '${AppLocale.labels.billHeadline}, ${DateFormat.MMMM(AppLocale.code).format(DateTime.now())}',
62 : ),
63 : ),
64 : );
65 : }
66 0 : if (stream == null || stream?.isFinished == true) {
67 : return;
68 : }
69 : String marker = '';
70 0 : List<BillAppData> items = [];
71 : do {
72 0 : marker = timer.yMEd();
73 0 : items = stream!.getTill(0.0 + timer.millisecondsSinceEpoch) as List<BillAppData>;
74 0 : timer = timer.add(const Duration(days: -1));
75 0 : } while (items.isEmpty && !stream!.isFinished);
76 :
77 0 : itemsShown.add(
78 0 : SliverMainAxisGroup(
79 0 : slivers: [
80 0 : SliverPersistentHeader(
81 : pinned: true,
82 0 : delegate: SliverHeaderDelegate(marker),
83 : ),
84 0 : SliverPadding(
85 0 : padding: EdgeInsets.symmetric(vertical: ThemeHelper.getIndent(0.5)),
86 0 : sliver: SliverList.builder(
87 0 : itemCount: items.length,
88 0 : itemBuilder: (context, int index) {
89 0 : final item = items[index];
90 0 : final account = state.getByUuid(item.account);
91 0 : final budget = state.getByUuid(item.category);
92 0 : final countWidth = ThemeHelper.getWidthCount(null, context);
93 0 : return BackgroundWrapper(
94 : index: index,
95 0 : child: BaseSwipeWidget(
96 : routePath: AppRoute.billEditRoute,
97 0 : uuid: item.uuid!,
98 0 : child: BillLineWidget(
99 0 : uuid: item.uuid!,
100 : count: countWidth,
101 0 : title: item.title,
102 0 : description: account != null ? '${account.title} (${account.description})' : '',
103 0 : descriptionColor: account?.color ?? Colors.transparent,
104 0 : details: item.detailsFormatted,
105 0 : progress: item.progress,
106 0 : color: budget?.color ?? Colors.transparent,
107 0 : icon: budget?.icon ?? Icons.radio_button_unchecked_sharp,
108 0 : iconTooltip: budget?.title ?? '?',
109 0 : hidden: item.hidden,
110 : width: width,
111 : route: AppRoute.billViewRoute,
112 : ),
113 : ),
114 : );
115 : },
116 : ),
117 : ),
118 : ],
119 : ),
120 : );
121 0 : WidgetsBinding.instance.addPostFrameCallback((_) {
122 0 : if (_scrollController.position.maxScrollExtent == 0) {
123 0 : setState(() => _addItems());
124 : }
125 : });
126 : }
127 :
128 0 : @override
129 0 : String getTitle() => AppLocale.labels.billHeadline;
130 :
131 0 : @override
132 0 : String getButtonName() => AppLocale.labels.addMainTooltip;
133 :
134 0 : @override
135 : Widget buildButton(BuildContext context, BoxConstraints constraints) {
136 0 : NavigatorState nav = Navigator.of(context);
137 0 : return FloatingActionButton(
138 : heroTag: 'bill_page',
139 0 : onPressed: () => nav.pushNamed(AppRoute.billAddRoute),
140 0 : tooltip: getButtonName(),
141 : child: const Icon(Icons.add),
142 : );
143 : }
144 :
145 0 : @override
146 : Widget buildContent(BuildContext context, BoxConstraints constraints) {
147 0 : if (stream == null) {
148 0 : WidgetsBinding.instance.addPostFrameCallback(
149 0 : (_) => setState(() {
150 0 : stream = state.getStream<BillAppData>(AppDataType.bills);
151 0 : _addItems();
152 : }),
153 : );
154 : }
155 0 : return Padding(
156 0 : padding: EdgeInsets.all(ThemeHelper.getIndent()),
157 0 : child: CustomScrollView(
158 0 : controller: _scrollController,
159 0 : slivers: itemsShown,
160 : ),
161 : );
162 : }
163 : }
|