diff --git a/trackeroo/assets/data/transaction_data.json b/trackeroo/assets/data/transaction_data.json new file mode 100644 index 0000000000000000000000000000000000000000..58a45d21e7f5ea2cab7a8040f5b43a1586dab8a1 --- /dev/null +++ b/trackeroo/assets/data/transaction_data.json @@ -0,0 +1,1082 @@ +[ + { + "title": "eu enim. Etiam", + "amount": -957.0, + "category_id": "shopping", + "created_at": "2021-01-08 18:15:44" + }, + { + "title": "ipsum ac mi eleifend", + "amount": -414.0, + "category_id": "education", + "created_at": "2020-11-03 12:15:59" + }, + { + "title": "nunc ac mattis", + "amount": -983.0, + "category_id": "transport_and_car", + "created_at": "2020-06-24 07:57:16" + }, + { + "title": "orci, in consequat", + "amount": -646.0, + "category_id": "transport_and_car", + "created_at": "2021-07-11 13:41:23" + }, + { + "title": "pharetra", + "amount": -412.0, + "category_id": "household_and_utilities", + "created_at": "2021-02-21 04:03:41" + }, + { + "title": "est tempor", + "amount": -736.0, + "category_id": "education", + "created_at": "2023-01-05 02:03:02" + }, + { + "title": "natoque penatibus et magnis", + "amount": -464.0, + "category_id": "bars_and_restaurants", + "created_at": "2020-11-24 10:56:41" + }, + { + "title": "enim nec", + "amount": -862.0, + "category_id": "travel_and_holidays", + "created_at": "2023-01-23 21:11:58" + }, + { + "title": "gravida mauris", + "amount": -730.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2021-02-20 08:59:33" + }, + { + "title": "diam. Pellentesque habitant", + "amount": -492.0, + "category_id": "household_and_utilities", + "created_at": "2023-05-30 11:12:27" + }, + { + "title": "malesuada", + "amount": -932.0, + "category_id": "atm", + "created_at": "2021-04-11 08:30:13" + }, + { + "title": "justo", + "amount": -743.0, + "category_id": "family_and_friends", + "created_at": "2021-04-08 01:58:07" + }, + { + "title": "ut, molestie", + "amount": -145.0, + "category_id": "shopping", + "created_at": "2022-03-10 03:09:33" + }, + { + "title": "ad litora", + "amount": -384.0, + "category_id": "travel_and_holidays", + "created_at": "2022-10-30 05:46:58" + }, + { + "title": "augue, eu", + "amount": -378.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2023-02-17 16:25:30" + }, + { + "title": "Cras eu tellus", + "amount": -6.0, + "category_id": "household_and_utilities", + "created_at": "2023-09-01 18:05:04" + }, + { + "title": "elit elit", + "amount": -763.0, + "category_id": "travel_and_holidays", + "created_at": "2023-01-14 00:53:13" + }, + { + "title": "auctor, nunc nulla vulputate", + "amount": -944.0, + "category_id": "transport_and_car", + "created_at": "2021-01-26 06:17:12" + }, + { + "title": "Cras convallis convallis", + "amount": -249.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-03-24 21:07:22" + }, + { + "title": "Curabitur ut odio vel", + "amount": -854.0, + "category_id": "transport_and_car", + "created_at": "2020-01-25 04:29:01" + }, + { + "title": "ornare. Fusce", + "amount": -75.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -6.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -85.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -97.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -76.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -49.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -52.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -66.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -6.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -83.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -88.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -60.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -97.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -8.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -12.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -35.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -56.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -94.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -72.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -64.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "ornare. Fusce", + "amount": -8.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -7.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -1.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -9.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -7.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -7.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -3.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -7.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -9.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -6.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -1.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -6.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -7.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -2.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -7.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -32.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -10.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -3.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -9.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -6.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "ornare. Fusce", + "amount": -50.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -44.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -23.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -7.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -9.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -12.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -22.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -44.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -3.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -10.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -20.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -32.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -26.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -44.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -28.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -27.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -29.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -15.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -9.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -24.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "ornare. Fusce", + "amount": -13.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -4.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -27.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -41.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -27.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -16.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -3.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -13.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -24.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -15.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -19.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -19.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -2.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -1.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -6.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -23.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -3.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -12.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -15.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -16.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "ornare. Fusce", + "amount": -57.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -3.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -43.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -49.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -37.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -64.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -27.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -26.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -68.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -11.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -34.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -9.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -51.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -56.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -70.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -5.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -30.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -36.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -22.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -61.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "ornare. Fusce", + "amount": -4.0, + "category_id": "media_and_electronics", + "created_at": "2022-04-09 17:02:27" + }, + { + "title": "dictum sapien. Aenean", + "amount": -4.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2024-01-26 06:53:49" + }, + { + "title": "Integer urna.", + "amount": -15.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-02-21 15:42:13" + }, + { + "title": "at pede. Cras vulputate", + "amount": -2.0, + "category_id": "shopping", + "created_at": "2023-11-01 19:15:00" + }, + { + "title": "luctus et ultrices", + "amount": -20.0, + "category_id": "education", + "created_at": "2020-02-26 19:27:07" + }, + { + "title": "id sapien. Cras", + "amount": -18.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-07-11 23:08:14" + }, + { + "title": "at sem", + "amount": -20.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-08-16 16:12:36" + }, + { + "title": "dui,", + "amount": -16.0, + "category_id": "household_and_utilities", + "created_at": "2023-10-15 08:18:05" + }, + { + "title": "sed pede.", + "amount": -7.0, + "category_id": "transport_and_car", + "created_at": "2021-01-14 16:35:48" + }, + { + "title": "Cras vehicula", + "amount": -17.0, + "category_id": "education", + "created_at": "2022-04-12 02:58:33" + }, + { + "title": "urna suscipit", + "amount": -12.0, + "category_id": "transport_and_car", + "created_at": "2020-03-15 07:35:01" + }, + { + "title": "fermentum fermentum arcu. Vestibulum", + "amount": -7.0, + "category_id": "leisure_and_entertainment", + "created_at": "2022-04-26 14:48:33" + }, + { + "title": "mauris a", + "amount": -2.0, + "category_id": "transport_and_car", + "created_at": "2022-06-15 02:07:11" + }, + { + "title": "Duis at lacus.", + "amount": -20.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-08-08 06:05:47" + }, + { + "title": "Aenean gravida nunc", + "amount": -8.0, + "category_id": "transport_and_car", + "created_at": "2024-04-17 22:37:54" + }, + { + "title": "velit. Quisque", + "amount": -6.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-02-12 13:32:09" + }, + { + "title": "in aliquet", + "amount": -12.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-04-18 19:36:41" + }, + { + "title": "Vivamus rhoncus. Donec est.", + "amount": -14.0, + "category_id": "travel_and_holidays", + "created_at": "2023-12-15 06:15:41" + }, + { + "title": "urna. Vivamus molestie", + "amount": -16.0, + "category_id": "household_and_utilities", + "created_at": "2020-05-07 23:31:51" + }, + { + "title": "nec", + "amount": -13.0, + "category_id": "shopping", + "created_at": "2022-06-12 09:55:41" + }, + { + "title": "justo eu", + "amount": -15.0, + "category_id": "shopping", + "created_at": "2024-02-03 14:52:56" + }, + { + "title": "faucibus orci luctus", + "amount": -20.0, + "category_id": "family_and_friends", + "created_at": "2024-05-27 18:37:16" + }, + { + "title": "litora torquent per", + "amount": -23.0, + "category_id": "travel_and_holidays", + "created_at": "2023-02-03 10:55:41" + }, + { + "title": "ad litora", + "amount": -16.0, + "category_id": "family_and_friends", + "created_at": "2020-04-01 13:59:13" + }, + { + "title": "cursus,", + "amount": -15.0, + "category_id": "media_and_electronics", + "created_at": "2021-12-30 01:11:55" + }, + { + "title": "est mauris, rhoncus", + "amount": -26.0, + "category_id": "transport_and_car", + "created_at": "2024-06-10 13:25:53" + }, + { + "title": "elit. Curabitur sed", + "amount": -7.0, + "category_id": "transport_and_car", + "created_at": "2021-07-21 01:39:22" + }, + { + "title": "nulla vulputate dui, nec", + "amount": -14.0, + "category_id": "leisure_and_entertainment", + "created_at": "2021-02-22 22:53:38" + }, + { + "title": "lectus justo eu", + "amount": -12.0, + "category_id": "transport_and_car", + "created_at": "2021-07-24 19:02:59" + }, + { + "title": "Nullam suscipit, est", + "amount": -14.0, + "category_id": "shopping", + "created_at": "2024-02-18 08:52:28" + }, + { + "title": "tortor at", + "amount": -7.0, + "category_id": "bars_and_restaurants", + "created_at": "2023-02-27 16:20:51" + }, + { + "title": "facilisi. Sed neque.", + "amount": -17.0, + "category_id": "transport_and_car", + "created_at": "2023-04-18 19:05:54" + }, + { + "title": "Nullam nisl. Maecenas", + "amount": -7.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-11-01 02:16:41" + }, + { + "title": "ligula.", + "amount": -25.0, + "category_id": "transport_and_car", + "created_at": "2024-02-19 02:18:50" + }, + { + "title": "Morbi sit", + "amount": -19.0, + "category_id": "atm", + "created_at": "2022-05-06 03:51:18" + }, + { + "title": "Vivamus nibh dolor,", + "amount": -13.0, + "category_id": "media_and_electronics", + "created_at": "2023-09-16 20:06:18" + }, + { + "title": "ultrices", + "amount": -1.0, + "category_id": "travel_and_holidays", + "created_at": "2024-02-06 07:14:31" + }, + { + "title": "tincidunt dui", + "amount": -5.0, + "category_id": "travel_and_holidays", + "created_at": "2021-05-15 05:01:31" + }, + { + "title": "habitant", + "amount": -24.0, + "category_id": "transport_and_car", + "created_at": "2020-07-19 15:04:01" + }, + { + "title": "Donec", + "amount": -5.0, + "category_id": "transport_and_car", + "created_at": "2023-07-08 02:05:24" + }, + { + "title": "Ut sagittis", + "amount": -10.0, + "category_id": "household_and_utilities", + "created_at": "2021-12-01 17:31:42" + }, + { + "title": "id, mollis", + "amount": -4.0, + "category_id": "travel_and_holidays", + "created_at": "2021-10-12 18:00:12" + }, + { + "title": "mattis.", + "amount": -27.0, + "category_id": "travel_and_holidays", + "created_at": "2023-10-23 20:42:33" + }, + { + "title": "In scelerisque scelerisque dui.", + "amount": -18.0, + "category_id": "leisure_and_entertainment", + "created_at": "2021-09-24 01:09:51" + }, + { + "title": "Praesent interdum ligula", + "amount": -3.0, + "category_id": "household_and_utilities", + "created_at": "2022-06-09 20:57:03" + }, + { + "title": "Nunc commodo auctor velit.", + "amount": -11.0, + "category_id": "shopping", + "created_at": "2021-12-19 09:07:36" + }, + { + "title": "non magna.", + "amount": -20.0, + "category_id": "education", + "created_at": "2023-01-29 01:08:37" + }, + { + "title": "rutrum urna, nec", + "amount": -9.0, + "category_id": "bars_and_restaurants", + "created_at": "2022-06-21 23:56:06" + }, + { + "title": "egestas", + "amount": -29.0, + "category_id": "food_and_groceries", + "created_at": "2024-01-09 10:59:32" + }, + { + "title": "neque tellus, imperdiet", + "amount": -1.0, + "category_id": "bars_and_restaurants", + "created_at": "2021-01-08 21:11:22" + }, + { + "title": "facilisis, magna tellus", + "amount": -22.0, + "category_id": "atm", + "created_at": "2024-01-05 08:20:18" + }, + { + "title": "tincidunt. Donec vitae", + "amount": -14.0, + "category_id": "family_and_friends", + "created_at": "2021-03-24 10:59:34" + }, + { + "title": "facilisis eget, ipsum.", + "amount": -21.0, + "category_id": "leisure_and_entertainment", + "created_at": "2020-10-17 06:24:06" + }, + { + "title": "Mauris", + "amount": -1.0, + "category_id": "transport_and_car", + "created_at": "2021-09-11 17:07:52" + }, + { + "title": "diam at", + "amount": -1.0, + "category_id": "education", + "created_at": "2021-11-08 21:25:26" + }, + { + "title": "posuere cubilia", + "amount": -22.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2022-07-25 11:22:17" + }, + { + "title": "et, euismod et, commodo", + "amount": -25.0, + "category_id": "healthcare_and_drug_stores", + "created_at": "2020-04-05 23:56:30" + }, + { + "title": "erat. Sed", + "amount": -24.0, + "category_id": "travel_and_holidays", + "created_at": "2021-07-27 06:33:46" + }, + { + "title": "lobortis augue", + "amount": -13.0, + "category_id": "family_and_friends", + "created_at": "2023-05-18 20:35:24" + }, + { + "title": "ut mi. Duis", + "amount": -25.0, + "category_id": "family_and_friends", + "created_at": "2023-12-27 14:28:14" + } +] diff --git a/trackeroo/lib/frontend/utils/category_chip.dart b/trackeroo/lib/frontend/utils/category_chip.dart new file mode 100644 index 0000000000000000000000000000000000000000..94776b8d460865bb49813f8e24abdf3f2c6cb36b --- /dev/null +++ b/trackeroo/lib/frontend/utils/category_chip.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:trackeroo/logic/models/category.dart'; + +class CategoryChip extends StatelessWidget { + const CategoryChip({Key? key, required this.category}) : super(key: key); + + final Category category; + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.only(right: 5.0, bottom: 5.0), + padding: const EdgeInsets.symmetric(horizontal: 7.0, vertical: 3.0), + decoration: BoxDecoration( + border: Border.all(width: 0.2), + borderRadius: const BorderRadius.all(Radius.circular(3.0)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), + size: 16.0, + color: Color(category.colorValue) + ), + const SizedBox(width: 5.0), + Text(category.title) + ], + ), + ); + } +} diff --git a/trackeroo/lib/frontend/utils/onboarding/category_chip.dart b/trackeroo/lib/frontend/utils/onboarding/category_chip.dart deleted file mode 100644 index 3ffa517adcfbfb38d7beab2555fc8b0a51e0ad33..0000000000000000000000000000000000000000 --- a/trackeroo/lib/frontend/utils/onboarding/category_chip.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:trackeroo/logic/models/category.dart'; - -class CategoryChip extends StatelessWidget { - const CategoryChip({Key? key, required this.category}) : super(key: key); - - final Category category; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(right: 5.0), - child: ActionChip( - avatar: Icon( - IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), - color: Color(category.colorValue), - ), - label: Text(category.title), - onPressed: () => {}, - ), - ); - } -} \ No newline at end of file diff --git a/trackeroo/lib/frontend/utils/transaction_listtile.dart b/trackeroo/lib/frontend/utils/transaction_listtile.dart index eb5e29955e8d05ea51a176519adc393232ac41bd..1c96942474d4f94b84e34e465d16100047e61096 100644 --- a/trackeroo/lib/frontend/utils/transaction_listtile.dart +++ b/trackeroo/lib/frontend/utils/transaction_listtile.dart @@ -16,7 +16,7 @@ class TransactionListtile extends StatefulWidget { } class _TransactionListtileState extends State<TransactionListtile> { - final monthsGer = const ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']; + final monthsGer = const ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; @override Widget build(BuildContext context) { @@ -52,34 +52,38 @@ class _TransactionListtileState extends State<TransactionListtile> { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - children: [ - Container( - width: 50.0, - height: 50.0, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - color: Theme.of(context).colorScheme.surface + SizedBox( + width: 280.0, + child: Row( + children: [ + Container( + width: 50.0, + height: 50.0, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + color: Theme.of(context).colorScheme.surface + ), + child: Icon(IconData(category.iconCodePoint, fontFamily: category.iconFontFamily)), ), - child: Icon(IconData(category.iconCodePoint, fontFamily: category.iconFontFamily)), - ), - const SizedBox(width: 17.0), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.transaction.title, - style: const TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold + const SizedBox(width: 17.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.transaction.title, + overflow: TextOverflow.fade, + style: const TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold + ), ), - ), - Text( - "${widget.transaction.createdAt.day}.${monthsGer[widget.transaction.createdAt.month]} · ${widget.transaction.createdAt.hour < 10 ? 0 : ''}${widget.transaction.createdAt.hour}:${widget.transaction.createdAt.minute < 10 ? 0 : ''}${widget.transaction.createdAt.minute}" - ) - ], - ), - ], + Text( + "${widget.transaction.createdAt.day}.${monthsGer[widget.transaction.createdAt.month - 1]} ${widget.transaction.createdAt.year} · ${widget.transaction.createdAt.hour < 10 ? 0 : ''}${widget.transaction.createdAt.hour}:${widget.transaction.createdAt.minute < 10 ? 0 : ''}${widget.transaction.createdAt.minute}" + ) + ], + ), + ], + ), ), Text( '${widget.transaction.amount.toString()} €', diff --git a/trackeroo/lib/frontend/views/details_view.dart b/trackeroo/lib/frontend/views/details_view.dart index 1ad2adcbaa702dd1b57b1c93b5269db6161ce808..e37cf15cf5ab20c4ba66df8bc1fdbb3c299fd94e 100644 --- a/trackeroo/lib/frontend/views/details_view.dart +++ b/trackeroo/lib/frontend/views/details_view.dart @@ -2,8 +2,10 @@ import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/frontend/utils/transaction_listtile.dart'; +import 'package:trackeroo/logic/models/app_state.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/transaction.dart'; +import 'package:trackeroo/logic/services/app_state_controller.dart'; import 'package:trackeroo/logic/services/categories_controller.dart'; import 'package:trackeroo/logic/services/locator.dart'; import 'package:trackeroo/logic/services/transactions_controller.dart'; @@ -20,7 +22,8 @@ class _DetailsViewState extends State<DetailsView> { TransactionsController transactionsController = locator.get<TransactionsController>(); DateTimeRange timespan = DateTimeRange(start: DateTime.now(), end: DateTime.now()); - List<String> selectedCategories = []; + // List<String> selectedCategoryIds = ; + AppState appState = locator.get<AppStateController>().appState; @override void initState() { @@ -38,227 +41,220 @@ class _DetailsViewState extends State<DetailsView> { return SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: ValueListenableBuilder( - valueListenable: locator.get<TransactionsController>().transactionsBox.listenable(), - builder: (context, Box<Transaction> box, child) { - List<Transaction> filteredTransList = box.values.toList(); - filteredTransList.sort((b, a) => a.createdAt.compareTo(b.createdAt)); - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - const Text( - 'Datails chart', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), - ), - const SizedBox(height: 20.0), - Center( - child : Container( - width: 400, - height: 250, - padding: const EdgeInsets.only(right: 20.0), - child: LineChart( - LineChartData( - borderData: FlBorderData( - show: true, - border: Border.symmetric( - horizontal: BorderSide( - color: Theme.of(context).colorScheme.onSurface, - width: 0.5 - ) - ) - ), - gridData: FlGridData( - show: true, - getDrawingHorizontalLine: (value) { - return FlLine( - color: Theme.of(context).colorScheme.onSurface, - strokeWidth: 0.5 - ); - }, - drawVerticalLine: false, - ), - titlesData: FlTitlesData( - show: true, - rightTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - topTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false) - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 30, - interval: 1, + valueListenable: locator.get<AppStateController>().appStateBox.listenable(), + builder: (context, Box<dynamic> appStateBox, child) { + return ValueListenableBuilder( + valueListenable: locator.get<TransactionsController>().transactionsBox.listenable(), + builder: (context, Box<Transaction> box, child) { + List<Transaction> filteredTransList = box.values.toList().where((element) => appState.detailsTransactionsFilter.contains(element.categoryId)).toList(); + filteredTransList.sort((b, a) => a.createdAt.compareTo(b.createdAt)); + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + const Text( + 'Datails chart', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.bold + ), + ), + const SizedBox(height: 20.0), + Center( + child : Container( + width: 400, + height: 250, + padding: const EdgeInsets.only(right: 20.0), + child: LineChart( + LineChartData( + borderData: FlBorderData( + show: true, + border: Border.symmetric( + horizontal: BorderSide( + color: Theme.of(context).colorScheme.onSurface, + width: 0.5 + ) + ) ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - // interval: 50, - reservedSize: 42, + gridData: FlGridData( + show: true, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Theme.of(context).colorScheme.onSurface, + strokeWidth: 0.5 + ); + }, + drawVerticalLine: false, ), - ), - ), - maxX: 12, - // maxY: 200, - minY: 0, - minX: 0, - lineBarsData: buildBarData() - ) - ) - ) - ), - const SizedBox(height: 5.0), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - IconButton.filledTonal( - visualDensity: VisualDensity.compact, - onPressed: () => showModalBottomSheet( - useSafeArea: true, - showDragHandle: true, - isScrollControlled: true, - context: context, - builder: (context) => StatefulBuilder( - builder: (BuildContext context, StateSetter setState) => Container( - height: 650.0, - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Choose categories', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold - ), + titlesData: FlTitlesData( + show: true, + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false) + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + // interval: 1, + reservedSize: 30, ), - for(Category category in locator.get<CategoriesController>().categories.values) CheckboxListTile( - title: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Icon( - IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), - color: Color(category.colorValue), - size: 18.0, - ), - const SizedBox(width: 10.0), - Text( - category.title, - style: const TextStyle( - fontSize: 15.0 - ), - ), - ], - ), - value: selectedCategories.contains(category.id), - contentPadding: const EdgeInsets.all(0.0), - dense: true, - onChanged: (value) => setState(() { - if(selectedCategories.contains(category.id)) { - selectedCategories.remove(category.id); - } else { - selectedCategories.add(category.id); - } - }) + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + // interval: 50, + reservedSize: 42, ), - ] + ), ), - ), + // maxX: 12, + // maxY: 200, + minY: 0, + minX: 0, + lineBarsData: buildBarData(filteredTransList) + ) ) - ), - icon: const Row( - children: [ - Icon( - Icons.category_rounded, - size: 14.0, - ), - SizedBox(width: 5.0), - Text('Categories') - ], ) ), - const SizedBox(width: 10.0), - IconButton.filledTonal( - visualDensity: VisualDensity.compact, - onPressed: () => { - showDateRangePicker( - context: context, - firstDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.first.createdAt : DateTime.now(), - lastDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.last.createdAt : DateTime.now(), - helpText: 'Choose timespan', - saveText: 'Done' - ), - }, - // onPressed: () => showModalBottomSheet( - // useSafeArea: true, - // showDragHandle: true, - // context: context, - // builder: (context) => Container( - // width: double.infinity, - // padding: const EdgeInsets.symmetric(horizontal: 20.0), - // child: const Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // 'Choose categories', - // style: TextStyle( - // fontSize: 16.0, - // fontWeight: FontWeight.bold - // ), - // ) - // ], - // ), - // ), - // ), - icon: const Row( - children: [ - Icon( - Icons.date_range_rounded, - size: 14.0, + const SizedBox(height: 5.0), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton.filledTonal( + visualDensity: VisualDensity.compact, + onPressed: () => showModalBottomSheet( + useSafeArea: true, + showDragHandle: true, + isScrollControlled: true, + context: context, + builder: (context) => StatefulBuilder( + builder: (BuildContext context, StateSetter setState) => Container( + height: 650.0, + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Choose categories', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold + ), + ), + for(Category category in locator.get<CategoriesController>().categories.values) CheckboxListTile( + title: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Icon( + IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), + color: Color(category.colorValue), + size: 18.0, + ), + const SizedBox(width: 10.0), + Text( + category.title, + style: const TextStyle( + fontSize: 15.0 + ), + ), + ], + ), + value: appState.detailsTransactionsFilter.contains(category.id), + contentPadding: const EdgeInsets.all(0.0), + dense: true, + onChanged: (value) => setState(() { + if(appState.detailsTransactionsFilter.contains(category.id)) { + appState.detailsTransactionsFilter.remove(category.id); + } else { + appState.detailsTransactionsFilter.add(category.id); + } + locator.get<AppStateController>().safeAppState(); + }) + ), + ] + ), + ), + ) ), - SizedBox(width: 5.0), - Text('Timespan') - ], - ) + icon: const Row( + children: [ + Icon( + Icons.category_rounded, + size: 14.0, + ), + SizedBox(width: 5.0), + Text('Categories') + ], + ) + ), + const SizedBox(width: 10.0), + IconButton.filledTonal( + visualDensity: VisualDensity.compact, + onPressed: () => { + showDateRangePicker( + context: context, + firstDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.first.createdAt : DateTime.now(), + lastDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.last.createdAt : DateTime.now(), + helpText: 'Choose timespan', + saveText: 'Done' + ), + }, + icon: const Row( + children: [ + Icon( + Icons.date_range_rounded, + size: 14.0, + ), + SizedBox(width: 5.0), + Text('Timespan') + ], + ) + ), + ], ), - ], - ), - const SizedBox(height: 10.0), - const Text( - 'Transactions', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), - ), - const SizedBox(height: 5.0), - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: filteredTransList.length, - itemBuilder: (context, index) => TransactionListtile(transaction: filteredTransList[index]), - ), - const SizedBox(height: 65.0) - ] + const SizedBox(height: 10.0), + const Text( + 'Transactions', + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.bold + ), + ), + const SizedBox(height: 5.0), + ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: filteredTransList.length, + itemBuilder: (context, index) => TransactionListtile(transaction: filteredTransList[index]), + ), + const SizedBox(height: 65.0) + ] + ); + } ); } ), ); } - List<LineChartBarData> buildBarData() { + List<LineChartBarData> buildBarData(List<Transaction> transactionsList) { List<LineChartBarData> categoryBars = []; + List<Category> selectedCategories = []; + for(String categoryId in appState.detailsTransactionsFilter) { + if(locator.get<CategoriesController>().categories.containsKey(categoryId)) { + selectedCategories.add(locator.get<CategoriesController>().categories[categoryId]!); + } + } for (Category category in locator.get<CategoriesController>().categories.values) { List<FlSpot> categoryDataPoints = [const FlSpot(0.0, 0.0)]; - for(Transaction transaction in transactionsController.transactionsList) { + int xVal = 1; + for(Transaction transaction in transactionsList) { if(transaction.categoryId == category.id) { - categoryDataPoints.add(FlSpot(transaction.createdAt.day.toDouble(), transaction.amount.abs())); + categoryDataPoints.add(FlSpot(xVal.toDouble(), transaction.amount.abs())); + xVal++; } } categoryBars.add( @@ -266,9 +262,16 @@ class _DetailsViewState extends State<DetailsView> { spots: categoryDataPoints, isCurved: false, color: Color(category.colorValue), - barWidth: 3, + barWidth: 2, isStrokeCapRound: true, - dotData: FlDotData(show: false) + dotData: FlDotData( + show: true, + getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter( + radius: 2.5, + color: Color(category.colorValue), + strokeColor: Colors.transparent + ) + ) ) ); } diff --git a/trackeroo/lib/frontend/views/edit_transaction_view.dart b/trackeroo/lib/frontend/views/edit_transaction_view.dart index f92a07ad3f8cf05e5a3fe6c02f817d49ae1712ae..cdd6f66587be3a80f20ef9a43db31ba942cf024f 100644 --- a/trackeroo/lib/frontend/views/edit_transaction_view.dart +++ b/trackeroo/lib/frontend/views/edit_transaction_view.dart @@ -247,6 +247,7 @@ class _EditTransactionViewState extends State<EditTransactionView> { title: _titleController.text, amount: isExpense ? -double.parse(_amountController.text) : double.parse(_amountController.text), categoryId: categoryId, + createdAt: DateTime.now(), dueDate: dueDate ); return await locator.get<TransactionsController>().saveTransaction(newTransaction); diff --git a/trackeroo/lib/frontend/views/home_view.dart b/trackeroo/lib/frontend/views/home_view.dart index 3c90e71bcbe2c7d8761b2fcba76d2321c763c3cf..3503ed6e96983990b15bfe1a8922372fd4165e85 100644 --- a/trackeroo/lib/frontend/views/home_view.dart +++ b/trackeroo/lib/frontend/views/home_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:hive_flutter/hive_flutter.dart'; -import 'package:trackeroo/frontend/utils/onboarding/category_chip.dart'; +import 'package:trackeroo/frontend/utils/category_chip.dart'; import 'package:trackeroo/frontend/utils/transaction_listtile.dart'; // import 'package:trackeroo/frontend/views/onboarding_view.dart'; import 'package:trackeroo/logic/models/category.dart'; @@ -85,6 +85,9 @@ class _HomeViewState extends State<HomeView> { PieChartData( centerSpaceRadius: 30.0, sections: transContr.transactionsList.isNotEmpty ? buildPieChartSectionList(context) : null, + pieTouchData: PieTouchData( + enabled: true + ) ), swapAnimationDuration: const Duration(milliseconds: 500), swapAnimationCurve: Curves.easeInOut, @@ -105,62 +108,59 @@ class _HomeViewState extends State<HomeView> { ), ], ), - const SizedBox(height: 15.0), - AbsorbPointer( - absorbing: true, - child: Wrap( - children: [ - for(Category cat in inChartShownCats) CategoryChip(category: cat) - ], - ), - ), - const SizedBox(height: 10.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + const SizedBox(height: 20.0), + Wrap( children: [ - FilterChip( - onSelected: (value) => setState(() { - timespanView = Timespan.daily; - }), - label: const Text('Daily'), - selected: timespanView == Timespan.daily, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - timespanView = Timespan.weekly; - }), - label: const Text('Weekly'), - selected: timespanView == Timespan.weekly, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - timespanView = Timespan.monthly; - }), - label: const Text('Monthly'), - selected: timespanView == Timespan.monthly, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - timespanView = Timespan.yearly; - }), - label: const Text('Yearly'), - selected: timespanView == Timespan.yearly, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - timespanView = Timespan.all; - }), - label: const Text('All'), - selected: timespanView == Timespan.all, - showCheckmark: false - ) + for(Category cat in inChartShownCats) CategoryChip(category: cat) ], ), - const SizedBox(height: 20.0), + const SizedBox(height: 10.0), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.daily; + // }), + // label: const Text('Daily'), + // selected: timespanView == Timespan.daily, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.weekly; + // }), + // label: const Text('Weekly'), + // selected: timespanView == Timespan.weekly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.monthly; + // }), + // label: const Text('Monthly'), + // selected: timespanView == Timespan.monthly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.yearly; + // }), + // label: const Text('Yearly'), + // selected: timespanView == Timespan.yearly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.all; + // }), + // label: const Text('All'), + // selected: timespanView == Timespan.all, + // showCheckmark: false + // ) + // ], + // ), + // const SizedBox(height: 20.0), const Text( 'Transactions', style: TextStyle( @@ -180,15 +180,6 @@ class _HomeViewState extends State<HomeView> { itemCount: transContr.transactionsList.length <= 25 ? transContr.transactionsList.length : 25, itemBuilder: (context, index) => TransactionListtile(transaction: transContr.transactionsList[index]) ), - // FilledButton( - // onPressed: () { - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => const OnboardingView()) - // ); - // }, - // child: const Text('onboarding') - // ), const SizedBox(height: 65.0) ], ); @@ -238,13 +229,13 @@ class _HomeViewState extends State<HomeView> { inChartShownCats.add(cat); sectionList.add(PieChartSectionData( value: double.parse(avg.toStringAsFixed(2)).abs(), - showTitle: true, + showTitle: false, title: avg.toStringAsFixed(2), color: Color(cat.colorValue), radius: 70.0, badgeWidget: Container( - height: 40.0, - width: 40.0, + height: 30.0, + width: 30.0, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, shape: BoxShape.circle, @@ -256,6 +247,7 @@ class _HomeViewState extends State<HomeView> { fontFamily: cat.iconFontFamily, ), color: Color(cat.colorValue), + size: 18.0, ) ) ), @@ -263,7 +255,7 @@ class _HomeViewState extends State<HomeView> { titleStyle: TextStyle( color: Theme.of(context).colorScheme.onSurface ), - badgePositionPercentageOffset: 1.1 + badgePositionPercentageOffset: 1 )); } } @@ -276,13 +268,13 @@ class _HomeViewState extends State<HomeView> { )); sectionList.add(PieChartSectionData( value: double.parse(other.toStringAsFixed(2)).abs(), - showTitle: true, + showTitle: false, title: other.toStringAsFixed(2), color: Colors.grey, radius: 70.0, badgeWidget: Container( - height: 40.0, - width: 40.0, + height: 30.0, + width: 30.0, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, shape: BoxShape.circle @@ -291,6 +283,7 @@ class _HomeViewState extends State<HomeView> { child: Icon( Icons.category_rounded, color: Colors.grey, + size: 18.0, ) ) ), @@ -298,7 +291,7 @@ class _HomeViewState extends State<HomeView> { titleStyle: TextStyle( color: Theme.of(context).colorScheme.onSurface ), - badgePositionPercentageOffset: 1.1 + badgePositionPercentageOffset: 1 )); } return sectionList; diff --git a/trackeroo/lib/logic/models/app_state.dart b/trackeroo/lib/logic/models/app_state.dart index 4a5ebf9ce5e571745245026cabc32b699f547676..99b97fd43cf225cef4ce3dc460cf3d8ebc71e322 100644 --- a/trackeroo/lib/logic/models/app_state.dart +++ b/trackeroo/lib/logic/models/app_state.dart @@ -1,5 +1,6 @@ class AppState { - AppState({required this.isFirstOpening}); + AppState({required this.isFirstOpening, required this.detailsTransactionsFilter}); bool isFirstOpening; -} \ No newline at end of file + List<String> detailsTransactionsFilter; +} diff --git a/trackeroo/lib/logic/models/transaction.dart b/trackeroo/lib/logic/models/transaction.dart index 55170d53e207adf6a7f7cecc4b086da30b439910..e25781a1a9a8295e4913dcadde4958e763675926 100644 --- a/trackeroo/lib/logic/models/transaction.dart +++ b/trackeroo/lib/logic/models/transaction.dart @@ -16,7 +16,7 @@ class Transaction { String categoryId; @HiveField(4) - DateTime createdAt = DateTime.now(); + DateTime createdAt; @HiveField(5) DateTime dueDate; @@ -26,7 +26,8 @@ class Transaction { required this.title, required this.amount, required this.categoryId, - required this.dueDate + required this.createdAt, + required this.dueDate, }); factory Transaction.fromJson(Map<String, dynamic> parsedJson) { @@ -34,7 +35,8 @@ class Transaction { title: parsedJson['title'], amount: parsedJson['amount'], categoryId: parsedJson['category_id'], - dueDate: parsedJson['due_date'] + createdAt: DateTime.parse(parsedJson['created_at']), + dueDate: DateTime.parse(parsedJson['created_at']) ); } } diff --git a/trackeroo/lib/logic/models/transaction.g.dart b/trackeroo/lib/logic/models/transaction.g.dart index 227a0e9a385c7c1dda2be059a0b74f0854933082..6c3772b74de44a9a0fe46fa378e020988b0f4914 100644 --- a/trackeroo/lib/logic/models/transaction.g.dart +++ b/trackeroo/lib/logic/models/transaction.g.dart @@ -21,8 +21,9 @@ class TransactionAdapter extends TypeAdapter<Transaction> { title: fields[1] as String, amount: fields[2] as double, categoryId: fields[3] as String, + createdAt: fields[4] as DateTime, dueDate: fields[5] as DateTime, - )..createdAt = fields[4] as DateTime; + ); } @override diff --git a/trackeroo/lib/logic/services/app_state_controller.dart b/trackeroo/lib/logic/services/app_state_controller.dart index fe6ba8ef45db9a2643b17c4d69241dd01c2ae5db..ef3c527884f2240e40c2e96393e7bd9ba0baf578 100644 --- a/trackeroo/lib/logic/services/app_state_controller.dart +++ b/trackeroo/lib/logic/services/app_state_controller.dart @@ -9,5 +9,6 @@ class AppStateController { void safeAppState() { appStateBox.put('is_first_opening', appState.isFirstOpening); + appStateBox.put('details_transactions_filter', appState.detailsTransactionsFilter); } } diff --git a/trackeroo/lib/logic/services/locator.dart b/trackeroo/lib/logic/services/locator.dart index 51b71879272417216cdd4cf0f1905de5568614e3..5e124dc2fc7652a7feebcea62873ea26a100eb1e 100644 --- a/trackeroo/lib/logic/services/locator.dart +++ b/trackeroo/lib/logic/services/locator.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; + +import 'package:flutter/services.dart'; import 'package:hive/hive.dart'; import 'package:get_it/get_it.dart'; import 'package:trackeroo/logic/constants/selecable_colors.dart'; @@ -17,7 +20,8 @@ Future<void> setupLocatorService() async { var appStateBox = await Hive.openBox('app_state_box'); Map<dynamic, dynamic> appStateMap = appStateBox.toMap(); AppState appState = AppState( - isFirstOpening: appStateMap['is_first_opening'] ?? true + isFirstOpening: appStateMap['is_first_opening'] ?? true, + detailsTransactionsFilter: appStateMap['details_transactions_filter'] ); AppStateController appStateController = AppStateController(appStateBox: appStateBox, appState: appState); locator.registerLazySingleton<AppStateController>(() => appStateController); @@ -49,6 +53,17 @@ Future<void> setupLocatorService() async { locator.registerLazySingleton<CategoriesController>(() => categoriesController); Box<Transaction> transactionsBox = await Hive.openBox<Transaction>('transactions_box'); + + // TODO: remove for prod, only here for dev/test purposes + await transactionsBox.clear(); + List<Transaction> transactionsFromJson = []; + final String response = await rootBundle.loadString('assets/data/transaction_data.json'); + final jsonList = await json.decode(response); + for(var json in jsonList) { + transactionsFromJson.add(Transaction.fromJson(json)); + } + transactionsBox.addAll(transactionsFromJson); + double balance = 0; double income = 0; double expenses = 0; @@ -67,5 +82,9 @@ Future<void> setupLocatorService() async { income: income, expenses: expenses ); + + // TODO: remove for prod, only here for dev/test purposes + + locator.registerLazySingleton<TransactionsController>(() => transactionsController); } diff --git a/trackeroo/pubspec.yaml b/trackeroo/pubspec.yaml index f5c57614cf3ff75168af11f65b7203532a3eaa82..e5b06fb98f76e337ac7c5c3b528d80127bb97f10 100644 --- a/trackeroo/pubspec.yaml +++ b/trackeroo/pubspec.yaml @@ -69,6 +69,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/rive/ + - assets/data/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware