Can save the list of expenses
This commit is contained in:
		
							
								
								
									
										117
									
								
								moneymgr_mobile/lib/services/storage/expenses.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								moneymgr_mobile/lib/services/storage/expenses.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:freezed_annotation/freezed_annotation.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:path/path.dart' as p;
 | 
			
		||||
import 'package:path_provider/path_provider.dart';
 | 
			
		||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
 | 
			
		||||
 | 
			
		||||
part 'expenses.freezed.dart';
 | 
			
		||||
part 'expenses.g.dart';
 | 
			
		||||
 | 
			
		||||
typedef ExpensesList = List<Expense>;
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
abstract class Expense with _$Expense {
 | 
			
		||||
  const Expense._();
 | 
			
		||||
 | 
			
		||||
  const factory Expense({
 | 
			
		||||
    /// Internal id used to identify the expense
 | 
			
		||||
    required int id,
 | 
			
		||||
 | 
			
		||||
    /// Label of the expense
 | 
			
		||||
    required String? label,
 | 
			
		||||
 | 
			
		||||
    /// The cost shall always be a positive value
 | 
			
		||||
    required double cost,
 | 
			
		||||
 | 
			
		||||
    /// Time associated with the expense
 | 
			
		||||
    required int time,
 | 
			
		||||
 | 
			
		||||
    /// Associated file mime type
 | 
			
		||||
    required String mimeType,
 | 
			
		||||
  }) = _Expense;
 | 
			
		||||
 | 
			
		||||
  factory Expense.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$ExpenseFromJson(json);
 | 
			
		||||
 | 
			
		||||
  /// Get associated expense file name
 | 
			
		||||
  String get localFileName {
 | 
			
		||||
    if (mimeType == "application/pdf") return "$id.pdf";
 | 
			
		||||
    if (mimeType == "image/jpeg") return "$id.jpeg";
 | 
			
		||||
    if (mimeType == "image/png") return "$id.png";
 | 
			
		||||
    return id.toString();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@riverpod
 | 
			
		||||
Future<ExpensesManager> expenses(Ref ref) async => ExpensesManager.instance();
 | 
			
		||||
 | 
			
		||||
class ExpensesManager {
 | 
			
		||||
  final String storagePath;
 | 
			
		||||
 | 
			
		||||
  ExpensesManager._({required this.storagePath});
 | 
			
		||||
 | 
			
		||||
  /// Get an instance of this manager
 | 
			
		||||
  static Future<ExpensesManager> instance() async {
 | 
			
		||||
    final appDir = await getApplicationDocumentsDirectory();
 | 
			
		||||
    final subDir = p.join(appDir.absolute.path, "expenses");
 | 
			
		||||
    final result = await Directory(subDir).create(recursive: true);
 | 
			
		||||
 | 
			
		||||
    return ExpensesManager._(storagePath: result.absolute.path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Get expenses list file path
 | 
			
		||||
  File get expenseFile => File(p.join(storagePath, "list.json"));
 | 
			
		||||
 | 
			
		||||
  /// Get the files storage path
 | 
			
		||||
  Directory get filesStoragePath => Directory(p.join(storagePath, "exp_files"));
 | 
			
		||||
 | 
			
		||||
  /// Get the current list of expenses
 | 
			
		||||
  Future<ExpensesList> getList() async {
 | 
			
		||||
    final jsonDec = jsonDecode(await expenseFile.readAsString());
 | 
			
		||||
    return List<Expense>.from(jsonDec.map((m) => Expense.fromJson(m)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Save the list of expenses
 | 
			
		||||
  Future<void> saveList(ExpensesList list) async {
 | 
			
		||||
    final jsonDoc = jsonEncode(list.map((t) => t.toJson()));
 | 
			
		||||
    await expenseFile.writeAsString(jsonDoc);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Add a new expense to the list
 | 
			
		||||
  Future<void> add({
 | 
			
		||||
    required String? label,
 | 
			
		||||
    required double cost,
 | 
			
		||||
    required int time,
 | 
			
		||||
    required List<int> fileContent,
 | 
			
		||||
    required String fileMimeType,
 | 
			
		||||
  }) async {
 | 
			
		||||
    final list = await getList();
 | 
			
		||||
 | 
			
		||||
    final exp = Expense(
 | 
			
		||||
      id: (list.lastOrNull?.id ?? 0) + Random().nextInt(1000),
 | 
			
		||||
      label: label,
 | 
			
		||||
      cost: cost,
 | 
			
		||||
      time: time,
 | 
			
		||||
      mimeType: fileMimeType,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Create files storage directory if required
 | 
			
		||||
    if (!await filesStoragePath.exists()) {
 | 
			
		||||
      await filesStoragePath.create(recursive: true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Save associated file
 | 
			
		||||
    final file = File(
 | 
			
		||||
      p.join(filesStoragePath.absolute.path, exp.localFileName),
 | 
			
		||||
    );
 | 
			
		||||
    await file.writeAsBytes(fileContent);
 | 
			
		||||
 | 
			
		||||
    // Save the list of expenses
 | 
			
		||||
    list.add(exp);
 | 
			
		||||
    await saveList(list);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user