Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/colors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,38 @@ class AppColors {
static const darkGreyColor = Color(0xff1c1b1f);
static const errorColor = Colors.redAccent;
static const successColor = Colors.green;
static const List<Color> categoryColors = [
Color(0xFF0A73EB), // Ink Blue
Color(0xFF26A942), // Grass Green
Color(0xFFDE3535), // Danger Red
Color(0xFF9A3CEC), // Voilet
Color(0xFF7CD913), // Parrot Green
Color(0xFFF74186), // Candy Pink
Color(0xFFF6B041), // Fanta
Color(0xFF5DDFEE), // Cyan
Color(0xFFFF6F00), // Dark Orange
Color(0xFFA9B63F), // Pop Green
Color(0xFF001757), // Navy Blue
Color(0xFF2CC990), // Distember Green
Color(0xFFEE8C3D), // Biscuit
Color(0xFF39B4FF), // Dark Sky Blue
Color(0xFF837AF2), // Indigo
Color(0xFFEAD339), // Yellow
Color(0xFF2CBCBD), // Teal
Color(0xFFCE9965), // Brownish Orange
Color(0xFF5D5FB3), // Dark Voilet
Color(0xFF188C8B), // Dark Teal
Color(0xFFD43B99), // Dark Candy
Color(0xFFCFCB51), // Caution Yellow
Color(0xFFDF5F37), // Saffron
Color(0xFF56CA4E), // Venom
Color(0xFFB353CB), // Paint Pink
Color(0xFF8B1650), // Crimson
Color(0xFF8DCCAC), // Gray Green
Color(0xFF00468B), // Blueish Blue
Color(0xFF003D00), // Tree Green
Color(0xFF93B728), // Yellowish Green
];

static ThemeData defaultTheme = ThemeData.dark(useMaterial3: true).copyWith(
pageTransitionsTheme: const PageTransitionsTheme(builders: {
Expand Down
1 change: 1 addition & 0 deletions lib/screens/accounts/accounts_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class AccountsController extends GetxController {
(key, value) => dbController.accounts[key]?.isDeleted == 1);
List<Account> tempAccountList = dbController.accounts.values.toList();
tempAccountList.removeWhere((account) => account.isDeleted == 1);
tempAccountList.sort((a, b) => a.accountName.compareTo(b.accountName));
Map<AccountType, List<Account>> temp = groupBy<Account, AccountType>(
tempAccountList, (account) => account.accountType);
accountList.value = temp;
Expand Down
15 changes: 9 additions & 6 deletions lib/screens/accounts/accounts_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

import 'dart:convert';

Map<int, Account> accountsFromJson(List<Map<String, Object?>> list) =>
Map<int, Account>.fromEntries(list.map((x) {
Account account = Account.fromJson(x);
return MapEntry(account.id!, account);
}));
Map<int, Account> accountsFromJson(List<Map<String, Object?>> list) {
final accountList =
list.map<Account>((account) => Account.fromJson(account)).toList();
accountList.sort((a, b) => a.accountName.compareTo(b.accountName));
return Map<int, Account>.fromEntries(accountList.map((account) {
return MapEntry(account.id!, account);
}));
}

String accountsToJson(List<Account> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
Expand All @@ -32,7 +35,7 @@ class Account {
accountName: json["account_name"],
accountType: AccountType.values[json["account_type"]],
parentId: json["parent_id"],
isDeleted: json['is_deleted']??0);
isDeleted: json['is_deleted'] ?? 0);

Map<String, dynamic> toJson() => {
if (id != null) "id": id,
Expand Down
2 changes: 2 additions & 0 deletions lib/screens/categories/add_category_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_iconpicker/flutter_iconpicker.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:vase/utils.dart';

import '../../const.dart';
import '../../controllers/db_controller.dart';
Expand All @@ -23,6 +24,7 @@ class AddCategoryController extends GetxController {
preFillCategory(Get.arguments['category']);
} else {
categoryType.value = Get.arguments['type'];
selectedColor.value = Utils.getNextColor();
}
}

Expand Down
76 changes: 63 additions & 13 deletions lib/screens/categories/add_edit_category_screen.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_iconpicker/flutter_iconpicker.dart';
import 'package:flutter_material_color_picker/flutter_material_color_picker.dart';
import 'package:get/get.dart';
import 'package:vase/colors.dart';
import 'package:vase/screens/categories/add_category_controller.dart';
Expand Down Expand Up @@ -92,7 +94,8 @@ class AddCategoryScreen extends StatelessWidget {
TextButton(
onPressed: () async {
Color? selectedColor =
await showColorSelectionDialog(context);
await showColorSelectionDialog(context,
controller.selectedColor.value);
controller.onColorChange(selectedColor);
},
child: const Text('Click to choose a Color'),
Expand Down Expand Up @@ -132,20 +135,59 @@ class AddCategoryScreen extends StatelessWidget {
);
}

Future<Color?> showColorSelectionDialog(BuildContext context) async {
Future<Color?> showColorSelectionDialog(
BuildContext context, Color oldColor) async {
Color? selectedColor;
return showDialog(
TextEditingController textController = TextEditingController();
return await showDialog(
context: context,
builder: (_) {
builder: (BuildContext context) {
return AlertDialog(
contentPadding: const EdgeInsets.all(18.0),
title: const Text("Pick a color"),
content: MaterialColorPicker(
onColorChange: (Color color) {
selectedColor = color;
},
selectedColor:
Get.find<AddCategoryController>().selectedColor.value),
scrollable: true,
actionsPadding: const EdgeInsets.all(0),
titlePadding: const EdgeInsets.all(0),
contentPadding: const EdgeInsets.only(top: 16),
content: Column(
children: [
ColorPicker(
pickerColor: oldColor,
onColorChanged: (newColor) {
selectedColor = newColor;
},
colorPickerWidth: 300,
pickerAreaHeightPercent: 0.7,
enableAlpha: false,
displayThumbColor: true,
paletteType: PaletteType.hsvWithHue,
labelTypes: const [],
pickerAreaBorderRadius: const BorderRadius.only(
topLeft: Radius.circular(2),
topRight: Radius.circular(2),
),
hexInputController: textController, // <- here
portraitOnly: true,
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
child: CupertinoTextField(
controller: textController,
style: const TextStyle(color: Colors.white),
prefix: const Padding(
padding: EdgeInsets.only(left: 8),
child: Icon(Icons.tag)),
suffix: IconButton(
icon: const Icon(Icons.content_paste_rounded),
onPressed: () => copyToClipboard(textController.text),
),
maxLength: 9,
inputFormatters: [
UpperCaseTextFormatter(),
FilteringTextInputFormatter.allow(RegExp(kValidHexPattern)),
],
),
)
],
),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
Expand All @@ -162,4 +204,12 @@ class AddCategoryScreen extends StatelessWidget {
},
);
}

void copyToClipboard(String input) {
String textToCopy = input.replaceFirst('#', '').toUpperCase();
if (textToCopy.startsWith('FF') && textToCopy.length == 8) {
textToCopy = textToCopy.replaceFirst('FF', '');
}
Clipboard.setData(ClipboardData(text: '#$textToCopy'));
}
}
2 changes: 1 addition & 1 deletion lib/screens/categories/category_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:flutter/material.dart';
List<Category> categoryFromJson(List<Map<String, Object?>> list) =>
List<Category>.from(
list.map((x) => Category.fromJson(x)),
);
)..sort((a, b) => a.categoryName.compareTo(b.categoryName));

String categoryToJson(List<Category> data) =>
json.encode(List<dynamic>.from(data.map(
Expand Down
16 changes: 15 additions & 1 deletion lib/screens/dashboard/dashboard_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:get/get.dart';
import 'package:vase/const.dart';
import 'package:vase/controllers/db_controller.dart';
import 'package:vase/enums.dart';
import 'package:vase/screens/dashboard/dashboard_model.dart';
import 'package:vase/utils.dart';

Expand All @@ -10,6 +11,7 @@ class DashboardController extends GetxController {
RxList<Sector> sectors = RxList.empty();
DbController dbController = Get.find();
double total = 0;
Rx<VaseState> dashboardState = VaseState.loading.obs;

@override
void onInit() {
Expand All @@ -18,6 +20,7 @@ class DashboardController extends GetxController {
}

Future<void> fetchSectors() async {
dashboardState.value = VaseState.loading;
var transList = await dbController.db.rawQuery(
'''SELECT SUM(${Const.trans}.amount) AS total , count(${Const.categories}.category_name) AS share , ${Const.categories}.category_name ,
${Const.categories}.color, ${Const.categories}.icon from ${Const.trans}
Expand All @@ -34,10 +37,21 @@ class DashboardController extends GetxController {
if (double.parse(transaction['total'].toString()) < 0 &&
transaction['category_name'] != null) {
Sector s = Sector.fromJson(transList[i]);
total += s.amount;
if (s.include) total += s.amount;
sectors.add(s);
}
}
dashboardState.value = VaseState.loaded;
update();
}

void recalculateTotal() {
total = 0;
for (Sector sector in sectors) {
if (sector.include) {
total += sector.amount;
}
}
update();
}

Expand Down
14 changes: 13 additions & 1 deletion lib/screens/dashboard/dashboard_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:vase/colors.dart';
import 'package:vase/enums.dart';
import 'package:vase/extensions.dart';
import 'package:vase/screens/dashboard/dashboard_controller.dart';
import 'package:vase/screens/dashboard/dashboard_model.dart';
import 'package:vase/screens/dashboard/pie_chart.dart';
import 'package:vase/screens/widgets/empty.dart';
import 'package:vase/widgets/category_icon.dart';
import 'package:vase/widgets/focused_layout.dart';
import 'package:vase/widgets/wrapper.dart';
Expand Down Expand Up @@ -33,6 +35,16 @@ class DashboardScreen extends StatelessWidget {
child: GetBuilder<DashboardController>(
init: DashboardController(Get.arguments),
builder: (DashboardController controller) {
if (controller.dashboardState.value == VaseState.loading) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (controller.sectors.isEmpty) {
return const EmptyWidget(
assetName: "assets/img/no_cat.svg",
label: "No Transactions for the selected month");
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand All @@ -46,7 +58,7 @@ class DashboardScreen extends StatelessWidget {
return ListTile(
onTap: () {
sector.switchInclusion();
controller.update();
controller.recalculateTotal();
},
leading: CategoryIcon(
icon: sector.icon,
Expand Down
12 changes: 9 additions & 3 deletions lib/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class Utils {
.toList();
}

static Color getNextColor() {
int categoriesLength = Get.find<DbController>().categories.length;
List<Color> colors = AppColors.categoryColors;
return colors[categoriesLength % colors.length];
}

static void showBottomSnackBar(
{required String title, required String message, required Icon ic}) {
Get.snackbar(
Expand Down Expand Up @@ -62,8 +68,7 @@ class Utils {

static Future<bool> importDb() async {
try {
FilePickerResult? result = await FilePicker.platform
.pickFiles();
FilePickerResult? result = await FilePicker.platform.pickFiles();

if (result != null && result.files.single.path != null) {
File file = File(result.files.single.path!);
Expand Down Expand Up @@ -107,7 +112,8 @@ class Utils {
}

static int getLastDate(DateTime currentDate) {
DateTime dateTime = DateTime(currentDate.year, currentDate.month + 1, 1).subtract(const Duration(seconds: 1));
DateTime dateTime = DateTime(currentDate.year, currentDate.month + 1, 1)
.subtract(const Duration(seconds: 1));
return dateTime.millisecondsSinceEpoch;
}

Expand Down
12 changes: 2 additions & 10 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ packages:
dependency: "direct main"
description:
name: flutter_colorpicker
sha256: "458a6ed8ea480eb16ff892aedb4b7092b2804affd7e046591fb03127e8d8ef8b"
sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
version: "1.1.0"
flutter_driver:
dependency: transitive
description: flutter
Expand All @@ -187,14 +187,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
flutter_material_color_picker:
dependency: "direct main"
description:
name: flutter_material_color_picker
sha256: ca1e7749d228c9155ea24bce98e647cdbffa350e6f334f6c001f841cd3d9c987
url: "https://pub.dev"
source: hosted
version: "1.2.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
Expand Down
5 changes: 2 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.0+8
version: 1.3.1+9

environment:
sdk: ">=2.19.0 <3.0.0"
Expand Down Expand Up @@ -46,8 +46,7 @@ dependencies:
fl_chart: ^0.68.0
flutter_svg: ^2.0.6
flutter_iconpicker: ^3.2.4
flutter_colorpicker: ^1.0.3
flutter_material_color_picker: ^1.2.0
flutter_colorpicker: ^1.1.0
flutter:
sdk: flutter

Expand Down