Compare commits
	
		
			5 Commits
		
	
	
		
			master
			...
			master-gen
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1f39653594 | |||
| e9aad1cdf5 | |||
| 2c0ae00103 | |||
| 000f409052 | |||
| 64baa04a47 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -44,5 +44,6 @@ app.*.map.json
 | 
			
		||||
/android/app/release
 | 
			
		||||
 | 
			
		||||
#generated files
 | 
			
		||||
lib/**/*.g.dart
 | 
			
		||||
# lib/**/*.g.dart
 | 
			
		||||
.direnv/
 | 
			
		||||
*.tar.gz
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								.ignore
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.ignore
									
									
									
									
									
								
							@ -5,4 +5,4 @@ linux
 | 
			
		||||
.metadata
 | 
			
		||||
analysis_options.yaml
 | 
			
		||||
pubspec.lock
 | 
			
		||||
// lib/**/*.g.dart
 | 
			
		||||
lib/**/*.g.dart
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ android {
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
 | 
			
		||||
        applicationId "com.example.rluv"
 | 
			
		||||
        applicationId "com.fosscat.rluv"
 | 
			
		||||
        // You can update the following values to match your application needs.
 | 
			
		||||
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
 | 
			
		||||
        minSdkVersion flutter.minSdkVersion
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="com.example.rluv">
 | 
			
		||||
    package="com.fosscat.rluv">
 | 
			
		||||
    <!-- The INTERNET permission is required for development. Specifically,
 | 
			
		||||
         the Flutter tool needs it to communicate with the running application
 | 
			
		||||
         to allow setting breakpoints, to provide hot reload, etc.
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="com.example.rluv">
 | 
			
		||||
    package="com.fosscat.rluv">
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 | 
			
		||||
    <application
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package com.example.rluv
 | 
			
		||||
package com.fosscat.rluv
 | 
			
		||||
 | 
			
		||||
import io.flutter.embedding.android.FlutterActivity
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="com.example.rluv">
 | 
			
		||||
    package="com.fosscat.rluv">
 | 
			
		||||
    <!-- The INTERNET permission is required for development. Specifically,
 | 
			
		||||
         the Flutter tool needs it to communicate with the running application
 | 
			
		||||
         to allow setting breakpoints, to provide hot reload, etc.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								assets/app_icon512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/app_icon512.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 42 KiB  | 
							
								
								
									
										27
									
								
								build-flutter-app.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								build-flutter-app.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Build the Flutter app and package into an archive.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Exit if any command fails
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
# Echo all commands for debug purposes
 | 
			
		||||
set -x
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
projectName=rluvApp
 | 
			
		||||
archiveName=$projectName-Linux-Portable.tar.gz
 | 
			
		||||
baseDir=$(pwd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ----------------------------- Build Flutter app ---------------------------- #
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
flutter pub get
 | 
			
		||||
flutter build linux
 | 
			
		||||
 | 
			
		||||
cd build/linux/arm64/release/bundle || exit
 | 
			
		||||
tar -czaf $archiveName ./*
 | 
			
		||||
mv $archiveName "$baseDir"/
 | 
			
		||||
							
								
								
									
										6
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							@ -114,11 +114,11 @@
 | 
			
		||||
    },
 | 
			
		||||
    "nixpkgs_2": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1712608508,
 | 
			
		||||
        "narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
 | 
			
		||||
        "lastModified": 1716948383,
 | 
			
		||||
        "narHash": "sha256-SzDKxseEcHR5KzPXLwsemyTR/kaM9whxeiJohbL04rs=",
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "repo": "nixpkgs",
 | 
			
		||||
        "rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
 | 
			
		||||
        "rev": "ad57eef4ef0659193044870c731987a6df5cf56b",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								flake.nix
									
									
									
									
									
								
							@ -32,21 +32,6 @@
 | 
			
		||||
            platforms-android-34
 | 
			
		||||
            emulator
 | 
			
		||||
          ]);
 | 
			
		||||
        # See below link for configuring ruby env with bundix
 | 
			
		||||
        # https://github.com/the-nix-way/nix-flake-dev-environments/tree/main/ruby-on-rails
 | 
			
		||||
        rubyEnv = pkgs.bundlerEnv {
 | 
			
		||||
          name = "ruby-env";
 | 
			
		||||
          inherit (pkgs) ruby;
 | 
			
		||||
          gemdir = ./android;
 | 
			
		||||
        };
 | 
			
		||||
        # buildNodeJs = pkgs.callPackage "${nixpkgs}/pkgs/development/web/nodejs/nodejs.nix" {
 | 
			
		||||
        #   python = pkgs.python3;
 | 
			
		||||
        # };
 | 
			
		||||
        # nodejs = buildNodeJs {
 | 
			
		||||
        #   enableNpm = true;
 | 
			
		||||
        #   version = "20.0.0";
 | 
			
		||||
        #   sha256 = "sha256-Q5xxqi84woYWV7+lOOmRkaVxJYBmy/1FSFhgScgTQZA=";
 | 
			
		||||
        # };
 | 
			
		||||
      in 
 | 
			
		||||
        pkgs.mkShell {
 | 
			
		||||
          # Fix an issue with Flutter using an older version of aapt2, which does not know
 | 
			
		||||
@ -60,13 +45,6 @@
 | 
			
		||||
            # pkg-config
 | 
			
		||||
            jdk17
 | 
			
		||||
            android-sdk
 | 
			
		||||
            rubyEnv
 | 
			
		||||
            rubyEnv.wrappedRuby
 | 
			
		||||
            # fastlane
 | 
			
		||||
            bundix
 | 
			
		||||
            # gems
 | 
			
		||||
            firebase-tools
 | 
			
		||||
            # nodejs
 | 
			
		||||
          ];
 | 
			
		||||
          shellHook = ''
 | 
			
		||||
            export PATH="$PATH":"$HOME/.pub-cache/bin" 
 | 
			
		||||
 | 
			
		||||
@ -296,7 +296,7 @@
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
				);
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
 | 
			
		||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
			
		||||
				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
@ -424,7 +424,7 @@
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
				);
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
 | 
			
		||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
			
		||||
				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 | 
			
		||||
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 | 
			
		||||
@ -446,7 +446,7 @@
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
				);
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.rluv;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = com.fosscat.rluv;
 | 
			
		||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
			
		||||
				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>$(DEVELOPMENT_LANGUAGE)</string>
 | 
			
		||||
	<key>CFBundleDisplayName</key>
 | 
			
		||||
	<string>Rluv</string>
 | 
			
		||||
	<string>rluv</string>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>$(EXECUTABLE_NAME)</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
@ -13,7 +13,7 @@
 | 
			
		||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>CFBundleName</key>
 | 
			
		||||
	<string>rluv</string>
 | 
			
		||||
	<string>fosscatrluv</string>
 | 
			
		||||
	<key>CFBundlePackageType</key>
 | 
			
		||||
	<string>APPL</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:rluv/features/account/signup.dart';
 | 
			
		||||
import 'package:rluv/global/styles.dart';
 | 
			
		||||
 | 
			
		||||
@ -13,8 +12,7 @@ class AccountCreateScreen extends ConsumerStatefulWidget {
 | 
			
		||||
  const AccountCreateScreen({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<AccountCreateScreen> createState() =>
 | 
			
		||||
      _AccountCreateScreenState();
 | 
			
		||||
  ConsumerState<AccountCreateScreen> createState() => _AccountCreateScreenState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum _AccountScreen { options, login, signup }
 | 
			
		||||
@ -40,7 +38,7 @@ class _AccountCreateScreenState extends ConsumerState<AccountCreateScreen> {
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      backgroundColor: Styles.purpleNurple,
 | 
			
		||||
      body: SafeArea(
 | 
			
		||||
@ -60,11 +58,8 @@ class _AccountCreateScreenState extends ConsumerState<AccountCreateScreen> {
 | 
			
		||||
                        Padding(
 | 
			
		||||
                          padding: const EdgeInsets.symmetric(vertical: 40.0),
 | 
			
		||||
                          child: Image.asset("assets/app_icon.png",
 | 
			
		||||
                              height:
 | 
			
		||||
                                  screen.width > 500 ? 250 : screen.width * 0.5,
 | 
			
		||||
                              width: screen.width > 500
 | 
			
		||||
                                  ? 250
 | 
			
		||||
                                  : screen.width * 0.5),
 | 
			
		||||
                              height: screen.width > 500 ? 250 : screen.width * 0.5,
 | 
			
		||||
                              width: screen.width > 500 ? 250 : screen.width * 0.5),
 | 
			
		||||
                        ),
 | 
			
		||||
                        UiButton(
 | 
			
		||||
                          color: Styles.sunflower,
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
 | 
			
		||||
import '../../global/api.dart';
 | 
			
		||||
import '../../global/styles.dart';
 | 
			
		||||
@ -19,7 +18,7 @@ class Login extends ConsumerStatefulWidget {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _LoginState extends ConsumerState<Login> {
 | 
			
		||||
  bool usingUsername = false;
 | 
			
		||||
  bool usingUsername = true;
 | 
			
		||||
  final emailController = TextEditingController();
 | 
			
		||||
  final usernameController = TextEditingController();
 | 
			
		||||
  final passwordController = TextEditingController();
 | 
			
		||||
@ -32,7 +31,7 @@ class _LoginState extends ConsumerState<Login> {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    return Form(
 | 
			
		||||
      key: widget.formKey,
 | 
			
		||||
      child: Stack(
 | 
			
		||||
@ -134,7 +133,7 @@ class _LoginState extends ConsumerState<Login> {
 | 
			
		||||
                  text: 'Password: ',
 | 
			
		||||
                  validatorFunc: (s) {
 | 
			
		||||
                    if (s != null && s.length < 6) {
 | 
			
		||||
                      return 'Please do a better password (you have to)';
 | 
			
		||||
                      return 'Please do a better password, at least 6 characters (you have to)';
 | 
			
		||||
                    }
 | 
			
		||||
                    return null;
 | 
			
		||||
                  },
 | 
			
		||||
@ -205,35 +204,21 @@ class _LoginState extends ConsumerState<Login> {
 | 
			
		||||
 | 
			
		||||
  Future login() async {
 | 
			
		||||
    try {
 | 
			
		||||
      if (widget.formKey.currentState != null &&
 | 
			
		||||
          !widget.formKey.currentState!.validate()) {
 | 
			
		||||
      if (widget.formKey.currentState != null && !widget.formKey.currentState!.validate()) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      final data =
 | 
			
		||||
          await ref.read(apiProvider.notifier).post(path: 'auth/login', data: {
 | 
			
		||||
        'username':
 | 
			
		||||
            usernameController.text.isEmpty ? null : usernameController.text,
 | 
			
		||||
      final Map<String, dynamic>? data = await ref.read(apiProvider.notifier).post(path: 'auth/login', data: {
 | 
			
		||||
        'username': usernameController.text.isEmpty ? null : usernameController.text,
 | 
			
		||||
        'email': emailController.text.isEmpty ? null : emailController.text,
 | 
			
		||||
        'password': passwordController.text,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      String message = 'Login unsuccessful';
 | 
			
		||||
      bool success = data?['success'] == 'false';
 | 
			
		||||
      if (data != null) {
 | 
			
		||||
        if (data['message'] != null) {
 | 
			
		||||
          message = data['message'];
 | 
			
		||||
        } else if (success) {
 | 
			
		||||
          message = 'Logged in!';
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // final bool success = data?['success'] ?? false;
 | 
			
		||||
      printAmber(data);
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: message,
 | 
			
		||||
          type: !success ? SnackType.error : SnackType.success);
 | 
			
		||||
      bool success = data?['success'] ?? false;
 | 
			
		||||
      String message = data?['message'] ?? (success ? 'Login success!' : 'Login unsuccessful.');
 | 
			
		||||
      printColor(data, textColor: TextColor.yellow);
 | 
			
		||||
      showSnack(ref: ref, text: message, type: success ? SnackType.success : SnackType.error);
 | 
			
		||||
    } catch (err, st) {
 | 
			
		||||
      printRed('Error in login: $err\n$st');
 | 
			
		||||
      printColor('Error in login: $err\n$st', textColor: TextColor.red);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
 | 
			
		||||
import '../../global/api.dart';
 | 
			
		||||
import '../../global/styles.dart';
 | 
			
		||||
@ -36,7 +35,7 @@ class _SignupState extends ConsumerState<Signup> {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    return Form(
 | 
			
		||||
      key: widget.formKey,
 | 
			
		||||
      child: Stack(
 | 
			
		||||
@ -126,8 +125,7 @@ class _SignupState extends ConsumerState<Signup> {
 | 
			
		||||
                            ),
 | 
			
		||||
                            UiButton(
 | 
			
		||||
                              width: screen.width * 0.4,
 | 
			
		||||
                              icon: const Icon(Icons.cancel,
 | 
			
		||||
                                  color: Styles.washedStone, size: 20),
 | 
			
		||||
                              icon: const Icon(Icons.cancel, color: Styles.washedStone, size: 20),
 | 
			
		||||
                              onPressed: () {
 | 
			
		||||
                                setState(
 | 
			
		||||
                                  () => hasFamilyCode = false,
 | 
			
		||||
@ -140,9 +138,7 @@ class _SignupState extends ConsumerState<Signup> {
 | 
			
		||||
                      : Padding(
 | 
			
		||||
                          padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                          child: UiButton(
 | 
			
		||||
                            width: screen.width * 0.5 > 400
 | 
			
		||||
                                ? 400
 | 
			
		||||
                                : screen.width * 0.5,
 | 
			
		||||
                            width: screen.width * 0.5 > 400 ? 400 : screen.width * 0.5,
 | 
			
		||||
                            text: 'JOIN FAMILY',
 | 
			
		||||
                            // color: Styles.flounderBlue,
 | 
			
		||||
                            onPressed: () {
 | 
			
		||||
@ -190,8 +186,7 @@ class _SignupState extends ConsumerState<Signup> {
 | 
			
		||||
                  text,
 | 
			
		||||
                  style: TextStyle(fontSize: size.width < 350 ? 16 : 20),
 | 
			
		||||
                ),
 | 
			
		||||
                if (subtext != null)
 | 
			
		||||
                  Text(subtext, style: const TextStyle(fontSize: 12)),
 | 
			
		||||
                if (subtext != null) Text(subtext, style: const TextStyle(fontSize: 12)),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
@ -223,36 +218,29 @@ class _SignupState extends ConsumerState<Signup> {
 | 
			
		||||
 | 
			
		||||
  Future signup() async {
 | 
			
		||||
    try {
 | 
			
		||||
      if (widget.formKey.currentState != null &&
 | 
			
		||||
          !widget.formKey.currentState!.validate()) {
 | 
			
		||||
      if (widget.formKey.currentState != null && !widget.formKey.currentState!.validate()) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      final data =
 | 
			
		||||
          await ref.read(apiProvider.notifier).post(path: 'auth/signup', data: {
 | 
			
		||||
      final data = await ref.read(apiProvider.notifier).post(path: 'auth/signup', data: {
 | 
			
		||||
        'name': nameCotroller.text,
 | 
			
		||||
        'username':
 | 
			
		||||
            usernameController.text.isEmpty ? null : usernameController.text,
 | 
			
		||||
        'username': usernameController.text.isEmpty ? null : usernameController.text,
 | 
			
		||||
        'email': emailController.text.isEmpty ? null : emailController.text,
 | 
			
		||||
        'password': passwordController.text,
 | 
			
		||||
        'family_code': familyCodeController.text.isEmpty
 | 
			
		||||
            ? null
 | 
			
		||||
            : familyCodeController.text.toUpperCase(),
 | 
			
		||||
        'family_code': familyCodeController.text.isEmpty ? null : familyCodeController.text.toUpperCase(),
 | 
			
		||||
        'budget_name': 'Budget'
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      final success = data?['success'] ?? false;
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: data?['message'] ?? success
 | 
			
		||||
              ? 'Login successful'
 | 
			
		||||
              : 'Login unsuccessful',
 | 
			
		||||
          text: data?['message'] ?? success ? 'Login successful' : 'Login unsuccessful',
 | 
			
		||||
          type: !success ? SnackType.error : SnackType.success);
 | 
			
		||||
 | 
			
		||||
      printAmber(data);
 | 
			
		||||
      printColor(data, textColor: TextColor.yellow);
 | 
			
		||||
      // final user = User.fromJson(data?['user']);
 | 
			
		||||
      // ref.read(tokenProvider.notifier).state =
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      printRed(err);
 | 
			
		||||
      printColor(err, textColor: TextColor.red);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers.dart';
 | 
			
		||||
import 'package:rluv/features/budget/screens/transactions_listview.dart';
 | 
			
		||||
import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
 | 
			
		||||
import 'package:rluv/features/budget/widgets/budget_category_bar.dart';
 | 
			
		||||
@ -19,8 +18,7 @@ class BudgetOverviewScreen extends ConsumerStatefulWidget {
 | 
			
		||||
  final Map<String, dynamic> initialData;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<BudgetOverviewScreen> createState() =>
 | 
			
		||||
      _BudgetOverviewScreenState();
 | 
			
		||||
  ConsumerState<BudgetOverviewScreen> createState() => _BudgetOverviewScreenState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
@ -30,23 +28,18 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
    final budget = ref.watch(budgetProvider);
 | 
			
		||||
    final budgetCategories = ref.watch(budgetCategoriesProvider);
 | 
			
		||||
    final transactions = ref.watch(transactionsProvider);
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    double netExpense = 0.0;
 | 
			
		||||
    double netIncome = 0.0;
 | 
			
		||||
    double expectedExpenses = 0.0;
 | 
			
		||||
    Map<int, double> budgetCategoryNetMap = {};
 | 
			
		||||
    netExpense = transactions
 | 
			
		||||
        .where((t) => t.type == TransactionType.expense)
 | 
			
		||||
        .fold(netExpense, (net, t) => net + t.amount);
 | 
			
		||||
    netIncome = transactions
 | 
			
		||||
        .where((t) => t.type == TransactionType.income)
 | 
			
		||||
        .fold(netIncome, (net, t) => net + t.amount);
 | 
			
		||||
    netExpense =
 | 
			
		||||
        transactions.where((t) => t.type == TransactionType.expense).fold(netExpense, (net, t) => net + t.amount);
 | 
			
		||||
    netIncome = transactions.where((t) => t.type == TransactionType.income).fold(netIncome, (net, t) => net + t.amount);
 | 
			
		||||
    for (final bud in budgetCategories) {
 | 
			
		||||
      double net = 0.0;
 | 
			
		||||
      expectedExpenses += bud.amount;
 | 
			
		||||
      net = transactions
 | 
			
		||||
          .where((t) => t.budgetCategoryId == bud.id)
 | 
			
		||||
          .fold(net, (net, t) => net + t.amount);
 | 
			
		||||
      net = transactions.where((t) => t.budgetCategoryId == bud.id).fold(net, (net, t) => net + t.amount);
 | 
			
		||||
      budgetCategoryNetMap[bud.id!] = net;
 | 
			
		||||
    }
 | 
			
		||||
    return Stack(
 | 
			
		||||
@ -64,23 +57,14 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                  const Spacer(flex: 2),
 | 
			
		||||
                  Text(
 | 
			
		||||
                    formatDate(DateTime.now()),
 | 
			
		||||
                    style: const TextStyle(
 | 
			
		||||
                        fontSize: 16, color: Styles.electricBlue),
 | 
			
		||||
                    style: const TextStyle(fontSize: 16, color: Styles.electricBlue),
 | 
			
		||||
                  ),
 | 
			
		||||
                  const Spacer(),
 | 
			
		||||
                  const Text('MONTHLY',
 | 
			
		||||
                      style:
 | 
			
		||||
                          TextStyle(fontSize: 42, color: Styles.electricBlue)),
 | 
			
		||||
                  const Text('MONTHLY', style: TextStyle(fontSize: 42, color: Styles.electricBlue)),
 | 
			
		||||
                  const Spacer(flex: 2),
 | 
			
		||||
                  BudgetNetBar(
 | 
			
		||||
                      isPositive: true,
 | 
			
		||||
                      net: netIncome,
 | 
			
		||||
                      expected: budget?.expectedIncome ?? 0.0),
 | 
			
		||||
                  BudgetNetBar(isPositive: true, net: netIncome, expected: budget?.expectedIncome ?? 0.0),
 | 
			
		||||
                  const Spacer(),
 | 
			
		||||
                  BudgetNetBar(
 | 
			
		||||
                      isPositive: false,
 | 
			
		||||
                      net: netExpense,
 | 
			
		||||
                      expected: expectedExpenses),
 | 
			
		||||
                  BudgetNetBar(isPositive: false, net: netExpense, expected: expectedExpenses),
 | 
			
		||||
                  const Spacer(),
 | 
			
		||||
                ],
 | 
			
		||||
              ),
 | 
			
		||||
@ -107,8 +91,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                              padding: EdgeInsets.all(8.0),
 | 
			
		||||
                              child: Text(
 | 
			
		||||
                                'BUDGET',
 | 
			
		||||
                                style: TextStyle(
 | 
			
		||||
                                    fontSize: 28, color: Styles.electricBlue),
 | 
			
		||||
                                style: TextStyle(fontSize: 28, color: Styles.electricBlue),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                            budgetCategories.isEmpty
 | 
			
		||||
@ -120,25 +103,18 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                                        children: [
 | 
			
		||||
                                          const Padding(
 | 
			
		||||
                                            padding: EdgeInsets.all(8.0),
 | 
			
		||||
                                            child: Text(
 | 
			
		||||
                                                'No budget categories created yet, add some!'),
 | 
			
		||||
                                            child: Text('No budget categories created yet, add some!'),
 | 
			
		||||
                                          ),
 | 
			
		||||
                                          UiButton(
 | 
			
		||||
                                            onPressed:
 | 
			
		||||
                                                ref.watch(budgetProvider) ==
 | 
			
		||||
                                                        null
 | 
			
		||||
                                                    ? null
 | 
			
		||||
                                                    : () => showDialog(
 | 
			
		||||
                                                          context: context,
 | 
			
		||||
                                                          builder: (context) => Dialog(
 | 
			
		||||
                                                              shape: Styles
 | 
			
		||||
                                                                  .dialogShape,
 | 
			
		||||
                                                              backgroundColor:
 | 
			
		||||
                                                                  Styles
 | 
			
		||||
                                                                      .dialogColor,
 | 
			
		||||
                                                              child:
 | 
			
		||||
                                                                  const BudgetCategoryDialog()),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                            onPressed: ref.watch(budgetProvider) == null
 | 
			
		||||
                                                ? null
 | 
			
		||||
                                                : () => showDialog(
 | 
			
		||||
                                                      context: context,
 | 
			
		||||
                                                      builder: (context) => Dialog(
 | 
			
		||||
                                                          shape: Styles.dialogShape,
 | 
			
		||||
                                                          backgroundColor: Styles.dialogColor,
 | 
			
		||||
                                                          child: const BudgetCategoryDialog()),
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                            text: 'Add Category',
 | 
			
		||||
                                          ),
 | 
			
		||||
                                        ],
 | 
			
		||||
@ -146,55 +122,42 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  )
 | 
			
		||||
                                : Padding(
 | 
			
		||||
                                    padding: const EdgeInsets.symmetric(
 | 
			
		||||
                                        horizontal: 2.0, vertical: 4.0),
 | 
			
		||||
                                    padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 4.0),
 | 
			
		||||
                                    child: SizedBox(
 | 
			
		||||
                                      height: screen.height * 0.36,
 | 
			
		||||
                                      child: Scrollbar(
 | 
			
		||||
                                        controller: budgetListScrollController,
 | 
			
		||||
                                        thumbVisibility: true,
 | 
			
		||||
                                        child: ListView(
 | 
			
		||||
                                          physics:
 | 
			
		||||
                                              const BouncingScrollPhysics(),
 | 
			
		||||
                                          controller:
 | 
			
		||||
                                              budgetListScrollController,
 | 
			
		||||
                                          physics: const BouncingScrollPhysics(),
 | 
			
		||||
                                          controller: budgetListScrollController,
 | 
			
		||||
                                          shrinkWrap: true,
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            ...budgetCategories
 | 
			
		||||
                                                .mapIndexed((i, category) {
 | 
			
		||||
                                            ...budgetCategories.map((category) {
 | 
			
		||||
                                              final int i = budgetCategories.indexOf(category);
 | 
			
		||||
                                              return BudgetCategoryBar(
 | 
			
		||||
                                                budgetCategory: category,
 | 
			
		||||
                                                currentAmount:
 | 
			
		||||
                                                    budgetCategoryNetMap[
 | 
			
		||||
                                                        category.id]!,
 | 
			
		||||
                                                currentAmount: budgetCategoryNetMap[category.id]!,
 | 
			
		||||
                                                index: i,
 | 
			
		||||
                                              );
 | 
			
		||||
                                            }).toList(),
 | 
			
		||||
                                            const SizedBox(height: 20),
 | 
			
		||||
                                            Row(
 | 
			
		||||
                                              mainAxisAlignment:
 | 
			
		||||
                                                  MainAxisAlignment.center,
 | 
			
		||||
                                              mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                                              children: [
 | 
			
		||||
                                                SizedBox(
 | 
			
		||||
                                                  width: 140,
 | 
			
		||||
                                                  child: ElevatedButton(
 | 
			
		||||
                                                    onPressed: ref.watch(
 | 
			
		||||
                                                                budgetProvider) ==
 | 
			
		||||
                                                            null
 | 
			
		||||
                                                    onPressed: ref.watch(budgetProvider) == null
 | 
			
		||||
                                                        ? null
 | 
			
		||||
                                                        : () => showDialog(
 | 
			
		||||
                                                              context: context,
 | 
			
		||||
                                                              builder: (context) => Dialog(
 | 
			
		||||
                                                                  shape: Styles
 | 
			
		||||
                                                                      .dialogShape,
 | 
			
		||||
                                                                  backgroundColor:
 | 
			
		||||
                                                                      Styles
 | 
			
		||||
                                                                          .dialogColor,
 | 
			
		||||
                                                                  child:
 | 
			
		||||
                                                                      const BudgetCategoryDialog()),
 | 
			
		||||
                                                                  shape: Styles.dialogShape,
 | 
			
		||||
                                                                  backgroundColor: Styles.dialogColor,
 | 
			
		||||
                                                                  child: const BudgetCategoryDialog()),
 | 
			
		||||
                                                            ),
 | 
			
		||||
                                                    child: const Text(
 | 
			
		||||
                                                        'Add Category'),
 | 
			
		||||
                                                    child: const Text('Add Category'),
 | 
			
		||||
                                                  ),
 | 
			
		||||
                                                ),
 | 
			
		||||
                                              ],
 | 
			
		||||
@ -214,8 +177,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                      children: [
 | 
			
		||||
                        Expanded(
 | 
			
		||||
                          child: Padding(
 | 
			
		||||
                            padding:
 | 
			
		||||
                                const EdgeInsets.only(left: 20.0, right: 15.0),
 | 
			
		||||
                            padding: const EdgeInsets.only(left: 20.0, right: 15.0),
 | 
			
		||||
                            child: Container(
 | 
			
		||||
                              height: 70,
 | 
			
		||||
                              decoration: BoxDecoration(
 | 
			
		||||
@ -225,8 +187,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                              child: InkWell(
 | 
			
		||||
                                child: const Center(
 | 
			
		||||
                                  child: Padding(
 | 
			
		||||
                                    padding: EdgeInsets.symmetric(
 | 
			
		||||
                                        horizontal: 20.0, vertical: 14.0),
 | 
			
		||||
                                    padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 14.0),
 | 
			
		||||
                                    child: FittedBox(
 | 
			
		||||
                                      child: Text(
 | 
			
		||||
                                        'Transaction History',
 | 
			
		||||
@ -238,10 +199,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
                                ),
 | 
			
		||||
                                onTap: () {
 | 
			
		||||
                                  Navigator.push(
 | 
			
		||||
                                      context,
 | 
			
		||||
                                      MaterialPageRoute(
 | 
			
		||||
                                          builder: (context) =>
 | 
			
		||||
                                              const TransactionsListview()));
 | 
			
		||||
                                      context, MaterialPageRoute(builder: (context) => const TransactionsListview()));
 | 
			
		||||
                                },
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
@ -292,8 +250,7 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
 | 
			
		||||
            child: IconButton(
 | 
			
		||||
              icon: const Icon(Icons.loop),
 | 
			
		||||
              color: Styles.seaweedGreen,
 | 
			
		||||
              onPressed: () =>
 | 
			
		||||
                  ref.read(dashboardProvider.notifier).fetchDashboard(),
 | 
			
		||||
              onPressed: () => ref.read(dashboardProvider.notifier).fetchDashboard(),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:rluv/features/budget/widgets/transaction_list_item.dart';
 | 
			
		||||
import 'package:rluv/global/styles.dart';
 | 
			
		||||
import 'package:rluv/models/transaction_model.dart';
 | 
			
		||||
@ -12,8 +11,7 @@ class TransactionsListview extends ConsumerStatefulWidget {
 | 
			
		||||
  const TransactionsListview({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<TransactionsListview> createState() =>
 | 
			
		||||
      _TransactionsListviewState();
 | 
			
		||||
  ConsumerState<TransactionsListview> createState() => _TransactionsListviewState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
@ -23,8 +21,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
  void initState() {
 | 
			
		||||
    // TODO: implement initState
 | 
			
		||||
    WidgetsBinding.instance.addPostFrameCallback((_) {
 | 
			
		||||
      ref.read(selectedTransactionSortProvider.notifier).state =
 | 
			
		||||
          TransactionSort.all;
 | 
			
		||||
      ref.read(selectedTransactionSortProvider.notifier).state = TransactionSort.all;
 | 
			
		||||
      ref.read(selectedSortDateProvider.notifier).state = SortDate.decending;
 | 
			
		||||
    });
 | 
			
		||||
    super.initState();
 | 
			
		||||
@ -34,8 +31,8 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final budgetCategories = ref.watch(budgetCategoriesProvider);
 | 
			
		||||
    if (ref.read(selectedCategory) == null && budgetCategories.isNotEmpty) {
 | 
			
		||||
      WidgetsBinding.instance.addPostFrameCallback((_) =>
 | 
			
		||||
          ref.read(selectedCategory.notifier).state = budgetCategories.first);
 | 
			
		||||
      WidgetsBinding.instance
 | 
			
		||||
          .addPostFrameCallback((_) => ref.read(selectedCategory.notifier).state = budgetCategories.first);
 | 
			
		||||
    }
 | 
			
		||||
    final sortType = ref.watch(selectedTransactionSortProvider);
 | 
			
		||||
    final sortDate = ref.watch(selectedSortDateProvider);
 | 
			
		||||
@ -60,8 +57,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
        if (ref.read(selectedCategory) != null) {
 | 
			
		||||
          transactions = transactions
 | 
			
		||||
              .where(
 | 
			
		||||
                (element) =>
 | 
			
		||||
                    element.budgetCategoryId == ref.read(selectedCategory)!.id,
 | 
			
		||||
                (element) => element.budgetCategoryId == ref.read(selectedCategory)!.id,
 | 
			
		||||
              )
 | 
			
		||||
              .toList();
 | 
			
		||||
        }
 | 
			
		||||
@ -79,15 +75,15 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WidgetsBinding.instance.addPostFrameCallback((_) =>
 | 
			
		||||
        ref.read(transactionHistoryListProvider.notifier).state = transactions);
 | 
			
		||||
    WidgetsBinding.instance
 | 
			
		||||
        .addPostFrameCallback((_) => ref.read(transactionHistoryListProvider.notifier).state = transactions);
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      endDrawer: Drawer(
 | 
			
		||||
        backgroundColor: Styles.purpleNurple,
 | 
			
		||||
        child: SafeArea(
 | 
			
		||||
          child: Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              SizedBox(height: BuildMedia(context).height * 0.15),
 | 
			
		||||
              SizedBox(height: MediaQuery.of(context).size.height * 0.15),
 | 
			
		||||
              DropdownButton<TransactionSort>(
 | 
			
		||||
                  dropdownColor: Styles.lavender,
 | 
			
		||||
                  value: ref.watch(selectedTransactionSortProvider),
 | 
			
		||||
@ -108,8 +104,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
                      .toList(),
 | 
			
		||||
                  onChanged: (TransactionSort? value) {
 | 
			
		||||
                    if (value != null) {
 | 
			
		||||
                      ref.read(selectedTransactionSortProvider.notifier).state =
 | 
			
		||||
                          value;
 | 
			
		||||
                      ref.read(selectedTransactionSortProvider.notifier).state = value;
 | 
			
		||||
                    }
 | 
			
		||||
                  }),
 | 
			
		||||
              const SizedBox(height: 20),
 | 
			
		||||
@ -137,8 +132,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
                    }
 | 
			
		||||
                  }),
 | 
			
		||||
              const SizedBox(height: 20),
 | 
			
		||||
              if (ref.read(selectedTransactionSortProvider) ==
 | 
			
		||||
                  TransactionSort.category)
 | 
			
		||||
              if (ref.read(selectedTransactionSortProvider) == TransactionSort.category)
 | 
			
		||||
                DropdownButton<BudgetCategory>(
 | 
			
		||||
                  dropdownColor: Styles.lavender,
 | 
			
		||||
                  value: ref.watch(selectedCategory),
 | 
			
		||||
@ -154,8 +148,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
                                width: 18,
 | 
			
		||||
                                decoration: BoxDecoration(
 | 
			
		||||
                                  shape: BoxShape.circle,
 | 
			
		||||
                                  border: Border.all(
 | 
			
		||||
                                      color: Colors.black, width: 1.5),
 | 
			
		||||
                                  border: Border.all(color: Colors.black, width: 1.5),
 | 
			
		||||
                                  color: e.color,
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
@ -186,9 +179,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
                alignment: Alignment.topLeft,
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.only(left: 8.0, top: 16.0),
 | 
			
		||||
                  child: IconButton(
 | 
			
		||||
                      icon: const Icon(Icons.chevron_left),
 | 
			
		||||
                      onPressed: () => Navigator.pop(context)),
 | 
			
		||||
                  child: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              const Center(
 | 
			
		||||
@ -201,14 +192,11 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
                  Row(mainAxisAlignment: MainAxisAlignment.center, children: [
 | 
			
		||||
                    Padding(
 | 
			
		||||
                      padding: const EdgeInsets.only(left: 8.0, top: 16.0),
 | 
			
		||||
                      child: IconButton(
 | 
			
		||||
                          icon: const Icon(Icons.chevron_left),
 | 
			
		||||
                          onPressed: () => Navigator.pop(context)),
 | 
			
		||||
                      child: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)),
 | 
			
		||||
                    ),
 | 
			
		||||
                    const Spacer(),
 | 
			
		||||
                    const Padding(
 | 
			
		||||
                      padding:
 | 
			
		||||
                          EdgeInsets.symmetric(vertical: 18.0, horizontal: 0.0),
 | 
			
		||||
                      padding: EdgeInsets.symmetric(vertical: 18.0, horizontal: 0.0),
 | 
			
		||||
                      child: Text(
 | 
			
		||||
                        'Transaction History',
 | 
			
		||||
                        style: TextStyle(fontSize: 28),
 | 
			
		||||
@ -245,8 +233,7 @@ class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void toggleDrawer() {
 | 
			
		||||
    if (scaffoldKey.currentState != null &&
 | 
			
		||||
        scaffoldKey.currentState!.isDrawerOpen) {
 | 
			
		||||
    if (scaffoldKey.currentState != null && scaffoldKey.currentState!.isDrawerOpen) {
 | 
			
		||||
      scaffoldKey.currentState!.openDrawer();
 | 
			
		||||
    } else if (scaffoldKey.currentState != null) {
 | 
			
		||||
      scaffoldKey.currentState!.openEndDrawer();
 | 
			
		||||
@ -292,8 +279,7 @@ final selectedTransactionSortProvider = StateProvider<TransactionSort>(
 | 
			
		||||
  (ref) => TransactionSort.all,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
final selectedSortDateProvider =
 | 
			
		||||
    StateProvider<SortDate>((ref) => SortDate.decending);
 | 
			
		||||
final selectedSortDateProvider = StateProvider<SortDate>((ref) => SortDate.decending);
 | 
			
		||||
 | 
			
		||||
final transactionHistoryListProvider = StateProvider<List<Transaction>>(
 | 
			
		||||
  (ref) => [],
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:rluv/global/styles.dart';
 | 
			
		||||
import 'package:rluv/models/budget.dart';
 | 
			
		||||
import 'package:rluv/models/budget_category_model.dart';
 | 
			
		||||
@ -17,12 +16,10 @@ class BudgetCategoryDialog extends ConsumerStatefulWidget {
 | 
			
		||||
  final BudgetCategory? category;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<BudgetCategoryDialog> createState() =>
 | 
			
		||||
      _AddBudgetCategoryDialogState();
 | 
			
		||||
  ConsumerState<BudgetCategoryDialog> createState() => _AddBudgetCategoryDialogState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _AddBudgetCategoryDialogState
 | 
			
		||||
    extends ConsumerState<BudgetCategoryDialog> {
 | 
			
		||||
class _AddBudgetCategoryDialogState extends ConsumerState<BudgetCategoryDialog> {
 | 
			
		||||
  late final Budget? budget;
 | 
			
		||||
  final categoryNameController = TextEditingController();
 | 
			
		||||
  final amountController = TextEditingController();
 | 
			
		||||
@ -65,12 +62,11 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
      return Container();
 | 
			
		||||
    }
 | 
			
		||||
    return SizedBox(
 | 
			
		||||
      width: BuildMedia(context).width * Styles.dialogScreenWidthFactor,
 | 
			
		||||
      width: MediaQuery.of(context).size.width * Styles.dialogScreenWidthFactor,
 | 
			
		||||
      child: Stack(
 | 
			
		||||
        children: [
 | 
			
		||||
          Padding(
 | 
			
		||||
            padding:
 | 
			
		||||
                const EdgeInsets.symmetric(vertical: 18.0, horizontal: 32.0),
 | 
			
		||||
            padding: const EdgeInsets.symmetric(vertical: 18.0, horizontal: 32.0),
 | 
			
		||||
            child: Form(
 | 
			
		||||
              key: formKey,
 | 
			
		||||
              child: Column(
 | 
			
		||||
@ -78,9 +74,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                children: [
 | 
			
		||||
                  Padding(
 | 
			
		||||
                    padding: const EdgeInsets.only(bottom: 18.0),
 | 
			
		||||
                    child: Text(widget.category == null
 | 
			
		||||
                        ? 'Add Category:'
 | 
			
		||||
                        : 'Edit Category'),
 | 
			
		||||
                    child: Text(widget.category == null ? 'Add Category:' : 'Edit Category'),
 | 
			
		||||
                  ),
 | 
			
		||||
                  Row(
 | 
			
		||||
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
			
		||||
@ -149,8 +143,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                  Padding(
 | 
			
		||||
                    padding: const EdgeInsets.symmetric(
 | 
			
		||||
                        vertical: 6.0, horizontal: 16.0),
 | 
			
		||||
                    padding: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 16.0),
 | 
			
		||||
                    child: SizedBox(
 | 
			
		||||
                      height: 76,
 | 
			
		||||
                      child: ListView.builder(
 | 
			
		||||
@ -164,23 +157,21 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                              } else {
 | 
			
		||||
                                setState(() => selectedColorIndex = -1);
 | 
			
		||||
                              }
 | 
			
		||||
                              printBlue(selectedColorIndex);
 | 
			
		||||
                              printColor(selectedColorIndex, textColor: TextColor.blue);
 | 
			
		||||
                            },
 | 
			
		||||
                            child: Padding(
 | 
			
		||||
                              padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                              child: AnimatedContainer(
 | 
			
		||||
                                decoration: selectedColorIndex == index
 | 
			
		||||
                                    ? BoxDecoration(
 | 
			
		||||
                                        borderRadius:
 | 
			
		||||
                                            BorderRadius.circular(15.0),
 | 
			
		||||
                                        borderRadius: BorderRadius.circular(15.0),
 | 
			
		||||
                                        border: Border.all(
 | 
			
		||||
                                          color: Styles.washedStone,
 | 
			
		||||
                                          width: 2.0,
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      )
 | 
			
		||||
                                    : BoxDecoration(
 | 
			
		||||
                                        borderRadius:
 | 
			
		||||
                                            BorderRadius.circular(5.0),
 | 
			
		||||
                                        borderRadius: BorderRadius.circular(5.0),
 | 
			
		||||
                                        border: Border.all(
 | 
			
		||||
                                          color: Colors.transparent,
 | 
			
		||||
                                          width: 2.0,
 | 
			
		||||
@ -205,8 +196,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                                        decoration: BoxDecoration(
 | 
			
		||||
                                          color: colors[index],
 | 
			
		||||
                                          shape: BoxShape.circle,
 | 
			
		||||
                                          border: Border.all(
 | 
			
		||||
                                              color: Colors.black, width: 1.5),
 | 
			
		||||
                                          border: Border.all(color: Colors.black, width: 1.5),
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ],
 | 
			
		||||
@ -227,8 +217,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                        color: Styles.expensesRed,
 | 
			
		||||
                        text: 'DELETE',
 | 
			
		||||
                        onPressed: () {
 | 
			
		||||
                          if (formKey.currentState != null &&
 | 
			
		||||
                              formKey.currentState!.validate()) {
 | 
			
		||||
                          if (formKey.currentState != null && formKey.currentState!.validate()) {
 | 
			
		||||
                            removeCategory().then((success) {
 | 
			
		||||
                              Navigator.pop(context);
 | 
			
		||||
                              if (success) {
 | 
			
		||||
@ -254,8 +243,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
                    color: Styles.lavender,
 | 
			
		||||
                    text: 'SAVE',
 | 
			
		||||
                    onPressed: () {
 | 
			
		||||
                      if (formKey.currentState != null &&
 | 
			
		||||
                          formKey.currentState!.validate()) {
 | 
			
		||||
                      if (formKey.currentState != null && formKey.currentState!.validate()) {
 | 
			
		||||
                        submitCategory(colors[selectedColorIndex]).then((_) {
 | 
			
		||||
                          Navigator.pop(context);
 | 
			
		||||
                          showSnack(
 | 
			
		||||
@ -282,7 +270,7 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
 | 
			
		||||
  Future submitCategory(Color categoryColor) async {
 | 
			
		||||
    if (formKey.currentState != null && !formKey.currentState!.validate()) {
 | 
			
		||||
      printPink('Failed validation');
 | 
			
		||||
      printColor('Failed validation', textColor: TextColor.red);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    Map<String, dynamic>? budgetData;
 | 
			
		||||
@ -296,58 +284,41 @@ class _AddBudgetCategoryDialogState
 | 
			
		||||
        name: categoryNameController.text,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      budgetData = await ref
 | 
			
		||||
          .read(apiProvider.notifier)
 | 
			
		||||
          .post(path: 'budget_category', data: newBudget.toJson());
 | 
			
		||||
      budgetData = await ref.read(apiProvider.notifier).post(path: 'budget_category', data: newBudget.toJson());
 | 
			
		||||
      success = budgetData != null ? budgetData['success'] as bool : false;
 | 
			
		||||
      if (success) {
 | 
			
		||||
        ref
 | 
			
		||||
            .read(dashboardProvider.notifier)
 | 
			
		||||
            .add({'budget_categories': budgetData});
 | 
			
		||||
        ref.read(dashboardProvider.notifier).add({'budget_categories': budgetData});
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      final newBudget =
 | 
			
		||||
          BudgetCategory.copyWith(category: widget.category!, data: {
 | 
			
		||||
      final newBudget = BudgetCategory.copyWith(category: widget.category!, data: {
 | 
			
		||||
        'amount': double.parse(amountController.text),
 | 
			
		||||
        'color': categoryColor,
 | 
			
		||||
        'name': categoryNameController.text
 | 
			
		||||
      });
 | 
			
		||||
      budgetData = await ref
 | 
			
		||||
          .read(apiProvider.notifier)
 | 
			
		||||
          .put(path: 'budget_category', data: newBudget.toJson());
 | 
			
		||||
      budgetData = await ref.read(apiProvider.notifier).put(path: 'budget_category', data: newBudget.toJson());
 | 
			
		||||
      success = budgetData != null ? budgetData['success'] as bool : false;
 | 
			
		||||
      if (success) {
 | 
			
		||||
        ref
 | 
			
		||||
            .read(dashboardProvider.notifier)
 | 
			
		||||
            .update({'budget_categories': budgetData});
 | 
			
		||||
        ref.read(dashboardProvider.notifier).update({'budget_categories': budgetData});
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (success) {
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: widget.category == null
 | 
			
		||||
              ? 'Added budget category!'
 | 
			
		||||
              : 'Updated category!',
 | 
			
		||||
          text: widget.category == null ? 'Added budget category!' : 'Updated category!',
 | 
			
		||||
          type: SnackType.error);
 | 
			
		||||
    } else {
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: widget.category == null
 | 
			
		||||
              ? 'Could not add budget category'
 | 
			
		||||
              : 'Could not update category',
 | 
			
		||||
          text: widget.category == null ? 'Could not add budget category' : 'Could not update category',
 | 
			
		||||
          type: SnackType.error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<bool> removeCategory() async {
 | 
			
		||||
    final res = await ref
 | 
			
		||||
        .read(apiProvider.notifier)
 | 
			
		||||
        .delete(path: 'budget_category', data: {'id': widget.category!.id});
 | 
			
		||||
    final res = await ref.read(apiProvider.notifier).delete(path: 'budget_category', data: {'id': widget.category!.id});
 | 
			
		||||
    final success = res != null ? res['success'] as bool : false;
 | 
			
		||||
    if (success) {
 | 
			
		||||
      ref
 | 
			
		||||
          .read(dashboardProvider.notifier)
 | 
			
		||||
          .removeWithId('budget_categories', widget.category!.id!);
 | 
			
		||||
      ref.read(dashboardProvider.notifier).removeWithId('budget_categories', widget.category!.id!);
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:rluv/global/utils.dart';
 | 
			
		||||
 | 
			
		||||
import '../../../global/api.dart';
 | 
			
		||||
@ -18,8 +17,7 @@ class TransactionDialog extends ConsumerStatefulWidget {
 | 
			
		||||
  final Transaction? transaction;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<TransactionDialog> createState() =>
 | 
			
		||||
      _AddTransactionDialogState();
 | 
			
		||||
  ConsumerState<TransactionDialog> createState() => _AddTransactionDialogState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
@ -37,8 +35,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    if (widget.transaction != null) {
 | 
			
		||||
      amountController =
 | 
			
		||||
          TextEditingController(text: widget.transaction!.amount.toString());
 | 
			
		||||
      amountController = TextEditingController(text: widget.transaction!.amount.toString());
 | 
			
		||||
      memoController = TextEditingController(text: widget.transaction!.memo);
 | 
			
		||||
      transactionType = widget.transaction!.type;
 | 
			
		||||
      selectedDate = widget.transaction!.date;
 | 
			
		||||
@ -53,8 +50,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
    }
 | 
			
		||||
    final u = ref.read(userProvider);
 | 
			
		||||
    if (u == null) {
 | 
			
		||||
      WidgetsBinding.instance.addPostFrameCallback(
 | 
			
		||||
          (_) => ref.read(jwtProvider.notifier).revokeToken());
 | 
			
		||||
      WidgetsBinding.instance.addPostFrameCallback((_) => ref.read(jwtProvider.notifier).revokeToken());
 | 
			
		||||
    } else {
 | 
			
		||||
      user = u;
 | 
			
		||||
    }
 | 
			
		||||
@ -65,10 +61,9 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    if (user == null) return Container();
 | 
			
		||||
    final List<BudgetCategory> budgetCategories =
 | 
			
		||||
        ref.read(budgetCategoriesProvider);
 | 
			
		||||
    final List<BudgetCategory> budgetCategories = ref.read(budgetCategoriesProvider);
 | 
			
		||||
    return SizedBox(
 | 
			
		||||
        width: BuildMedia(context).width * Styles.dialogScreenWidthFactor,
 | 
			
		||||
        width: MediaQuery.of(context).size.width * Styles.dialogScreenWidthFactor,
 | 
			
		||||
        child: budgetCategories.isEmpty
 | 
			
		||||
            ? const Padding(
 | 
			
		||||
                padding: EdgeInsets.all(8.0),
 | 
			
		||||
@ -91,25 +86,21 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                              onTap: transactionType == TransactionType.expense
 | 
			
		||||
                                  ? null
 | 
			
		||||
                                  : () {
 | 
			
		||||
                                      setState(() => transactionType =
 | 
			
		||||
                                          TransactionType.expense);
 | 
			
		||||
                                      setState(() => transactionType = TransactionType.expense);
 | 
			
		||||
                                    },
 | 
			
		||||
                              child: AnimatedContainer(
 | 
			
		||||
                                height: 38,
 | 
			
		||||
                                width: 80,
 | 
			
		||||
                                decoration: BoxDecoration(
 | 
			
		||||
                                    borderRadius: const BorderRadius.only(
 | 
			
		||||
                                        topLeft: Radius.circular(8.0),
 | 
			
		||||
                                        topRight: Radius.circular(8.0)),
 | 
			
		||||
                                    color: transactionType ==
 | 
			
		||||
                                            TransactionType.expense
 | 
			
		||||
                                        topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0)),
 | 
			
		||||
                                    color: transactionType == TransactionType.expense
 | 
			
		||||
                                        ? Styles.lavender
 | 
			
		||||
                                        : Styles.washedStone),
 | 
			
		||||
                                duration: const Duration(milliseconds: 300),
 | 
			
		||||
                                child: const Padding(
 | 
			
		||||
                                  padding: EdgeInsets.all(8.0),
 | 
			
		||||
                                  child: Text('Expense',
 | 
			
		||||
                                      style: TextStyle(fontSize: 16)),
 | 
			
		||||
                                  child: Text('Expense', style: TextStyle(fontSize: 16)),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
@ -117,25 +108,20 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                            onTap: transactionType == TransactionType.income
 | 
			
		||||
                                ? null
 | 
			
		||||
                                : () {
 | 
			
		||||
                                    setState(() => transactionType =
 | 
			
		||||
                                        TransactionType.income);
 | 
			
		||||
                                    setState(() => transactionType = TransactionType.income);
 | 
			
		||||
                                  },
 | 
			
		||||
                            child: AnimatedContainer(
 | 
			
		||||
                              height: 38,
 | 
			
		||||
                              width: 80,
 | 
			
		||||
                              decoration: BoxDecoration(
 | 
			
		||||
                                  borderRadius: const BorderRadius.only(
 | 
			
		||||
                                      topLeft: Radius.circular(8.0),
 | 
			
		||||
                                      topRight: Radius.circular(8.0)),
 | 
			
		||||
                                      topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0)),
 | 
			
		||||
                                  color:
 | 
			
		||||
                                      transactionType == TransactionType.income
 | 
			
		||||
                                          ? Styles.lavender
 | 
			
		||||
                                          : Styles.washedStone),
 | 
			
		||||
                                      transactionType == TransactionType.income ? Styles.lavender : Styles.washedStone),
 | 
			
		||||
                              duration: const Duration(milliseconds: 300),
 | 
			
		||||
                              child: const Padding(
 | 
			
		||||
                                padding: EdgeInsets.all(8.0),
 | 
			
		||||
                                child: Text('Income',
 | 
			
		||||
                                    style: TextStyle(fontSize: 16)),
 | 
			
		||||
                                child: Text('Income', style: TextStyle(fontSize: 16)),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
@ -208,9 +194,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                                                    width: 18,
 | 
			
		||||
                                                    decoration: BoxDecoration(
 | 
			
		||||
                                                      shape: BoxShape.circle,
 | 
			
		||||
                                                      border: Border.all(
 | 
			
		||||
                                                          color: Colors.black,
 | 
			
		||||
                                                          width: 1.5),
 | 
			
		||||
                                                      border: Border.all(color: Colors.black, width: 1.5),
 | 
			
		||||
                                                      color: e.color,
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                                  ),
 | 
			
		||||
@ -226,8 +210,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                                          if (kDebugMode) {
 | 
			
		||||
                                            print('${value.name} selected');
 | 
			
		||||
                                          }
 | 
			
		||||
                                          setState(() =>
 | 
			
		||||
                                              selectedBudgetCategory = value);
 | 
			
		||||
                                          setState(() => selectedBudgetCategory = value);
 | 
			
		||||
                                        }
 | 
			
		||||
                                      },
 | 
			
		||||
                                    ),
 | 
			
		||||
@ -247,7 +230,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                    Container(
 | 
			
		||||
                      width: BuildMedia(context).width * 0.65,
 | 
			
		||||
                      width: MediaQuery.of(context).size.width * 0.65,
 | 
			
		||||
                      height: 100,
 | 
			
		||||
                      decoration: Styles.boxLavenderBubble,
 | 
			
		||||
                      child: TextFormField(
 | 
			
		||||
@ -269,9 +252,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
                        Navigator.pop(context);
 | 
			
		||||
                        showSnack(
 | 
			
		||||
                          ref: ref,
 | 
			
		||||
                          text: widget.transaction != null
 | 
			
		||||
                              ? 'Transaction updated!'
 | 
			
		||||
                              : 'Transaction added!',
 | 
			
		||||
                          text: widget.transaction != null ? 'Transaction updated!' : 'Transaction added!',
 | 
			
		||||
                          type: SnackType.success,
 | 
			
		||||
                        );
 | 
			
		||||
                      }),
 | 
			
		||||
@ -289,9 +270,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
          data: Transaction.copyWith(widget.transaction!, {
 | 
			
		||||
            'memo': memoController.text.isNotEmpty ? memoController.text : null,
 | 
			
		||||
            'amount': double.parse(amountController.text),
 | 
			
		||||
            'budget_category_id': transactionType == TransactionType.income
 | 
			
		||||
                ? null
 | 
			
		||||
                : selectedBudgetCategory.id,
 | 
			
		||||
            'budget_category_id': transactionType == TransactionType.income ? null : selectedBudgetCategory.id,
 | 
			
		||||
          }).toJson());
 | 
			
		||||
    } else {
 | 
			
		||||
      data = await ref.read(apiProvider.notifier).post(
 | 
			
		||||
@ -299,15 +278,11 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
          data: Transaction(
 | 
			
		||||
                  amount: double.parse(amountController.text),
 | 
			
		||||
                  createdByUserId: user!.id!,
 | 
			
		||||
                  budgetCategoryId: transactionType == TransactionType.income
 | 
			
		||||
                      ? null
 | 
			
		||||
                      : selectedBudgetCategory.id,
 | 
			
		||||
                  budgetCategoryId: transactionType == TransactionType.income ? null : selectedBudgetCategory.id,
 | 
			
		||||
                  budgetId: user!.budgetId,
 | 
			
		||||
                  date: DateTime.now(),
 | 
			
		||||
                  type: transactionType,
 | 
			
		||||
                  memo: memoController.text.isNotEmpty
 | 
			
		||||
                      ? memoController.text
 | 
			
		||||
                      : null)
 | 
			
		||||
                  memo: memoController.text.isNotEmpty ? memoController.text : null)
 | 
			
		||||
              .toJson());
 | 
			
		||||
    }
 | 
			
		||||
    final success = data != null ? data['success'] as bool : false;
 | 
			
		||||
@ -320,9 +295,7 @@ class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
 | 
			
		||||
    } else {
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: widget.transaction != null
 | 
			
		||||
              ? 'Failed to edit transaction'
 | 
			
		||||
              : 'Failed to add transaction',
 | 
			
		||||
          text: widget.transaction != null ? 'Failed to edit transaction' : 'Failed to add transaction',
 | 
			
		||||
          type: SnackType.error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:rluv/features/budget/widgets/add_budget_category_dialog.dart';
 | 
			
		||||
import 'package:rluv/global/utils.dart';
 | 
			
		||||
import 'package:rluv/models/budget_category_model.dart';
 | 
			
		||||
@ -45,8 +44,7 @@ class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    final innerHeight = widget.height - widget.innerPadding * 2;
 | 
			
		||||
    final isBright =
 | 
			
		||||
        getBrightness(widget.budgetCategory.color) == Brightness.light;
 | 
			
		||||
    final isBright = getBrightness(widget.budgetCategory.color) == Brightness.light;
 | 
			
		||||
    final textStyle = TextStyle(
 | 
			
		||||
        fontSize: 14,
 | 
			
		||||
        fontWeight: FontWeight.bold,
 | 
			
		||||
@ -155,7 +153,6 @@ class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
 | 
			
		||||
    if (!name.contains(' ') || name.indexOf(' ') == name.length - 1) {
 | 
			
		||||
      return name;
 | 
			
		||||
    }
 | 
			
		||||
    printLime('here');
 | 
			
		||||
    final words = name.split(' ');
 | 
			
		||||
    int index = 0;
 | 
			
		||||
    String firstLine = words[index];
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,9 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:helpers/helpers.dart';
 | 
			
		||||
import 'package:rluv/global/styles.dart';
 | 
			
		||||
import 'package:rluv/global/utils.dart';
 | 
			
		||||
 | 
			
		||||
class BudgetNetBar extends StatelessWidget {
 | 
			
		||||
  const BudgetNetBar(
 | 
			
		||||
      {super.key,
 | 
			
		||||
      required this.isPositive,
 | 
			
		||||
      required this.net,
 | 
			
		||||
      required this.expected});
 | 
			
		||||
  const BudgetNetBar({super.key, required this.isPositive, required this.net, required this.expected});
 | 
			
		||||
 | 
			
		||||
  final bool isPositive;
 | 
			
		||||
  final double net;
 | 
			
		||||
@ -16,7 +11,7 @@ class BudgetNetBar extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final screenWidth = BuildMedia(context).width;
 | 
			
		||||
    final screenWidth = MediaQuery.of(context).size.width;
 | 
			
		||||
    return Container(
 | 
			
		||||
      width: screenWidth * 0.85,
 | 
			
		||||
      decoration: BoxDecoration(
 | 
			
		||||
@ -25,8 +20,7 @@ class BudgetNetBar extends StatelessWidget {
 | 
			
		||||
      ),
 | 
			
		||||
      child: Padding(
 | 
			
		||||
        padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0),
 | 
			
		||||
        child:
 | 
			
		||||
            Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
 | 
			
		||||
        child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
 | 
			
		||||
          Text(
 | 
			
		||||
            isPositive ? 'Income' : 'Expenses',
 | 
			
		||||
            style: const TextStyle(
 | 
			
		||||
@ -35,9 +29,7 @@ class BudgetNetBar extends StatelessWidget {
 | 
			
		||||
          ),
 | 
			
		||||
          Text(
 | 
			
		||||
            '${net.currency()} / ${expected.currency()}',
 | 
			
		||||
            style: TextStyle(
 | 
			
		||||
                fontSize: 20,
 | 
			
		||||
                color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
 | 
			
		||||
            style: TextStyle(fontSize: 20, color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
 | 
			
		||||
          ),
 | 
			
		||||
        ]),
 | 
			
		||||
      ),
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:intl/intl.dart';
 | 
			
		||||
import 'package:rluv/features/budget/screens/transactions_listview.dart';
 | 
			
		||||
import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
 | 
			
		||||
@ -19,8 +18,7 @@ class TransactionListItem extends ConsumerStatefulWidget {
 | 
			
		||||
  final int index;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  ConsumerState<TransactionListItem> createState() =>
 | 
			
		||||
      _TransactionListItemState();
 | 
			
		||||
  ConsumerState<TransactionListItem> createState() => _TransactionListItemState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
@ -54,17 +52,13 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
      child: Padding(
 | 
			
		||||
        padding: const EdgeInsets.only(top: 8.0, left: 8.0, bottom: 8.0),
 | 
			
		||||
        child: ClipRRect(
 | 
			
		||||
          borderRadius: const BorderRadius.only(
 | 
			
		||||
              topLeft: Radius.circular(10.0),
 | 
			
		||||
              bottomLeft: Radius.circular(10.0)),
 | 
			
		||||
          borderRadius: const BorderRadius.only(topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)),
 | 
			
		||||
          child: AnimatedContainer(
 | 
			
		||||
            curve: Curves.easeOut,
 | 
			
		||||
            duration: const Duration(milliseconds: 200),
 | 
			
		||||
            height: cardHeight,
 | 
			
		||||
            decoration: const BoxDecoration(
 | 
			
		||||
              borderRadius: BorderRadius.only(
 | 
			
		||||
                  topLeft: Radius.circular(10.0),
 | 
			
		||||
                  bottomLeft: Radius.circular(10.0)),
 | 
			
		||||
              borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)),
 | 
			
		||||
              color: Styles.washedStone,
 | 
			
		||||
            ),
 | 
			
		||||
            child: Row(
 | 
			
		||||
@ -74,19 +68,16 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
                    duration: const Duration(milliseconds: 200),
 | 
			
		||||
                    height: cardHeight,
 | 
			
		||||
                    width: 6,
 | 
			
		||||
                    color: transaction!.type == TransactionType.income
 | 
			
		||||
                        ? Styles.incomeBlue
 | 
			
		||||
                        : Styles.expensesOrange),
 | 
			
		||||
                    color: transaction!.type == TransactionType.income ? Styles.incomeBlue : Styles.expensesOrange),
 | 
			
		||||
                SizedBox(
 | 
			
		||||
                  width: BuildMedia(context).width * 0.65,
 | 
			
		||||
                  width: MediaQuery.of(context).size.width * 0.65,
 | 
			
		||||
                  child: Padding(
 | 
			
		||||
                    padding: const EdgeInsets.only(left: 8.0),
 | 
			
		||||
                    child: Column(
 | 
			
		||||
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
			
		||||
                      crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
                      children: [
 | 
			
		||||
                        Text(DateFormat('EEE MMM d, h:mm a')
 | 
			
		||||
                            .format(transaction!.date)),
 | 
			
		||||
                        Text(DateFormat('EEE MMM d, h:mm a').format(transaction!.date)),
 | 
			
		||||
                        Row(
 | 
			
		||||
                          children: [
 | 
			
		||||
                            const SizedBox(
 | 
			
		||||
@ -101,9 +92,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
                              ),
 | 
			
		||||
                            ],
 | 
			
		||||
                            Text(
 | 
			
		||||
                              transaction!.type == TransactionType.income
 | 
			
		||||
                                  ? 'Income'
 | 
			
		||||
                                  : budgetCategory!.name,
 | 
			
		||||
                              transaction!.type == TransactionType.income ? 'Income' : budgetCategory!.name,
 | 
			
		||||
                              style: const TextStyle(fontSize: 20),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ],
 | 
			
		||||
@ -125,9 +114,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
                      transaction!.amount.currency(),
 | 
			
		||||
                      style: TextStyle(
 | 
			
		||||
                          fontSize: 24,
 | 
			
		||||
                          color: transaction!.type == TransactionType.income
 | 
			
		||||
                              ? Styles.incomeGreen
 | 
			
		||||
                              : Styles.expensesRed),
 | 
			
		||||
                          color: transaction!.type == TransactionType.income ? Styles.incomeGreen : Styles.expensesRed),
 | 
			
		||||
                    ),
 | 
			
		||||
                    if (showDetails) ...[
 | 
			
		||||
                      IconButton(
 | 
			
		||||
@ -140,8 +127,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
                            builder: (context) => Dialog(
 | 
			
		||||
                              backgroundColor: Styles.dialogColor,
 | 
			
		||||
                              shape: Styles.dialogShape,
 | 
			
		||||
                              child:
 | 
			
		||||
                                  TransactionDialog(transaction: transaction),
 | 
			
		||||
                              child: TransactionDialog(transaction: transaction),
 | 
			
		||||
                            ),
 | 
			
		||||
                          );
 | 
			
		||||
                        },
 | 
			
		||||
@ -182,21 +168,14 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future deleteTransaction() async {
 | 
			
		||||
    final res = await ref
 | 
			
		||||
        .read(apiProvider.notifier)
 | 
			
		||||
        .delete(path: 'transaction', data: {'id': transaction!.id});
 | 
			
		||||
    final res = await ref.read(apiProvider.notifier).delete(path: 'transaction', data: {'id': transaction!.id});
 | 
			
		||||
 | 
			
		||||
    final success = res != null ? res['success'] as bool : false;
 | 
			
		||||
    if (success) {
 | 
			
		||||
      ref
 | 
			
		||||
          .read(dashboardProvider.notifier)
 | 
			
		||||
          .removeWithId('transactions', transaction!.id!);
 | 
			
		||||
      ref.read(dashboardProvider.notifier).removeWithId('transactions', transaction!.id!);
 | 
			
		||||
      showSnack(ref: ref, text: 'Transaction removed', type: SnackType.success);
 | 
			
		||||
    } else {
 | 
			
		||||
      showSnack(
 | 
			
		||||
          ref: ref,
 | 
			
		||||
          text: 'Could not delete transaction',
 | 
			
		||||
          type: SnackType.error);
 | 
			
		||||
      showSnack(ref: ref, text: 'Could not delete transaction', type: SnackType.error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:rluv/global/utils.dart';
 | 
			
		||||
import 'package:rluv/models/shared_note.dart';
 | 
			
		||||
 | 
			
		||||
@ -22,7 +21,7 @@ class SharedNotesScreen extends ConsumerStatefulWidget {
 | 
			
		||||
class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    final sharedNotes = ref.watch(sharedNotesProvider);
 | 
			
		||||
    return Column(
 | 
			
		||||
      children: [
 | 
			
		||||
@ -47,14 +46,10 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
 | 
			
		||||
              ),
 | 
			
		||||
              itemBuilder: (BuildContext context, int index) {
 | 
			
		||||
                final note = sharedNotes[index];
 | 
			
		||||
                final colorBrightness = note.color == null
 | 
			
		||||
                    ? Brightness.light
 | 
			
		||||
                    : getBrightness(note.color!);
 | 
			
		||||
                final colorBrightness = note.color == null ? Brightness.light : getBrightness(note.color!);
 | 
			
		||||
                final textStyle = TextStyle(
 | 
			
		||||
                  fontSize: 16.0,
 | 
			
		||||
                  color: colorBrightness == Brightness.light
 | 
			
		||||
                      ? Colors.black54
 | 
			
		||||
                      : Colors.white70,
 | 
			
		||||
                  color: colorBrightness == Brightness.light ? Colors.black54 : Colors.white70,
 | 
			
		||||
                );
 | 
			
		||||
                return Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(8.0),
 | 
			
		||||
@ -67,14 +62,10 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
 | 
			
		||||
                          padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                          child: Column(
 | 
			
		||||
                            children: [
 | 
			
		||||
                              FittedBox(
 | 
			
		||||
                                  child: Text(note.title,
 | 
			
		||||
                                      style: const TextStyle(fontSize: 20))),
 | 
			
		||||
                              FittedBox(child: Text(note.title, style: const TextStyle(fontSize: 20))),
 | 
			
		||||
                              Flexible(
 | 
			
		||||
                                child: Text(
 | 
			
		||||
                                  note.content.length > 80
 | 
			
		||||
                                      ? "${note.content.substring(0, 75)}..."
 | 
			
		||||
                                      : note.content,
 | 
			
		||||
                                  note.content.length > 80 ? "${note.content.substring(0, 75)}..." : note.content,
 | 
			
		||||
                                  style: textStyle,
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
@ -93,9 +84,7 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
 | 
			
		||||
                          context: context,
 | 
			
		||||
                          builder: (BuildContext context) {
 | 
			
		||||
                            return Padding(
 | 
			
		||||
                              padding: EdgeInsets.only(
 | 
			
		||||
                                  bottom:
 | 
			
		||||
                                      MediaQuery.of(context).viewInsets.bottom),
 | 
			
		||||
                              padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
 | 
			
		||||
                              child: NoteBottomSheet(
 | 
			
		||||
                                index: index,
 | 
			
		||||
                              ),
 | 
			
		||||
@ -121,8 +110,7 @@ class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
 | 
			
		||||
                    context: context,
 | 
			
		||||
                    builder: (BuildContext context) {
 | 
			
		||||
                      return Padding(
 | 
			
		||||
                        padding: EdgeInsets.only(
 | 
			
		||||
                            bottom: MediaQuery.of(context).viewInsets.bottom),
 | 
			
		||||
                        padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
 | 
			
		||||
                        child: const NoteBottomSheet(
 | 
			
		||||
                          index: null,
 | 
			
		||||
                        ),
 | 
			
		||||
@ -182,19 +170,14 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final screen = BuildMedia(context).size;
 | 
			
		||||
    final screen = MediaQuery.of(context).size;
 | 
			
		||||
    return Container(
 | 
			
		||||
      width: screen.width,
 | 
			
		||||
      decoration: BoxDecoration(
 | 
			
		||||
          color: newNote.color ?? Styles.washedStone,
 | 
			
		||||
          borderRadius: const BorderRadius.only(
 | 
			
		||||
              topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
 | 
			
		||||
          borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
 | 
			
		||||
          boxShadow: const [
 | 
			
		||||
            BoxShadow(
 | 
			
		||||
                color: Colors.black26,
 | 
			
		||||
                spreadRadius: 5.0,
 | 
			
		||||
                blurRadius: 2.0,
 | 
			
		||||
                offset: Offset(0, -2))
 | 
			
		||||
            BoxShadow(color: Colors.black26, spreadRadius: 5.0, blurRadius: 2.0, offset: Offset(0, -2))
 | 
			
		||||
          ]),
 | 
			
		||||
      child: Padding(
 | 
			
		||||
        padding: const EdgeInsets.all(16.0),
 | 
			
		||||
@ -218,8 +201,7 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
 | 
			
		||||
              // decoration: Styles.inputLavenderBubble(),
 | 
			
		||||
            ),
 | 
			
		||||
            Padding(
 | 
			
		||||
              padding:
 | 
			
		||||
                  const EdgeInsets.symmetric(vertical: 28.0, horizontal: 36.0),
 | 
			
		||||
              padding: const EdgeInsets.symmetric(vertical: 28.0, horizontal: 36.0),
 | 
			
		||||
              child: UiButton(
 | 
			
		||||
                onPressed: !noteChanged(oldNote, newNote)
 | 
			
		||||
                    ? null
 | 
			
		||||
@ -229,41 +211,26 @@ class _NoteBottomSheetState extends ConsumerState<NoteBottomSheet> {
 | 
			
		||||
                        try {
 | 
			
		||||
                          Response? res;
 | 
			
		||||
                          if (widget.index == null) {
 | 
			
		||||
                            res = await ref
 | 
			
		||||
                                .read(apiProvider)
 | 
			
		||||
                                .post('shared_note', data: newNote.toJson());
 | 
			
		||||
                            res = await ref.read(apiProvider).post('shared_note', data: newNote.toJson());
 | 
			
		||||
                          } else {
 | 
			
		||||
                            res = await ref
 | 
			
		||||
                                .read(apiProvider)
 | 
			
		||||
                                .put('shared_note', data: newNote.toJson());
 | 
			
		||||
                            res = await ref.read(apiProvider).put('shared_note', data: newNote.toJson());
 | 
			
		||||
                          }
 | 
			
		||||
                          if (res.data != null && res.data['success']) {
 | 
			
		||||
                            if (widget.index == null) {
 | 
			
		||||
                              ref
 | 
			
		||||
                                  .read(dashboardProvider.notifier)
 | 
			
		||||
                                  .add({'shared_notes': res.data});
 | 
			
		||||
                              ref.read(dashboardProvider.notifier).add({'shared_notes': res.data});
 | 
			
		||||
                            } else {
 | 
			
		||||
                              ref
 | 
			
		||||
                                  .read(dashboardProvider.notifier)
 | 
			
		||||
                                  .update({'shared_notes': res.data});
 | 
			
		||||
                              ref.read(dashboardProvider.notifier).update({'shared_notes': res.data});
 | 
			
		||||
                            }
 | 
			
		||||
                            showSnack(
 | 
			
		||||
                                ref: ref,
 | 
			
		||||
                                text: 'Added note',
 | 
			
		||||
                                type: SnackType.success);
 | 
			
		||||
                            showSnack(ref: ref, text: 'Added note', type: SnackType.success);
 | 
			
		||||
                          } else {
 | 
			
		||||
                            showSnack(
 | 
			
		||||
                                ref: ref,
 | 
			
		||||
                                text: res.data['message'] ??
 | 
			
		||||
                                    'Unexpected error occurred',
 | 
			
		||||
                                text: res.data['message'] ?? 'Unexpected error occurred',
 | 
			
		||||
                                type: SnackType.error);
 | 
			
		||||
                          }
 | 
			
		||||
                        } catch (err) {
 | 
			
		||||
                          showSnack(
 | 
			
		||||
                              ref: ref,
 | 
			
		||||
                              text: 'Unexpected error occurred',
 | 
			
		||||
                              type: SnackType.error);
 | 
			
		||||
                          printRed(err);
 | 
			
		||||
                          showSnack(ref: ref, text: 'Unexpected error occurred', type: SnackType.error);
 | 
			
		||||
                          printColor(err, textColor: TextColor.red);
 | 
			
		||||
                        }
 | 
			
		||||
                        // ignore: use_build_context_synchronously
 | 
			
		||||
                        Navigator.pop(context);
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:jwt_decoder/jwt_decoder.dart';
 | 
			
		||||
import 'package:rluv/global/store.dart';
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import '../models/token.dart';
 | 
			
		||||
 | 
			
		||||
final tokenProvider = StateProvider<Token?>((ref) {
 | 
			
		||||
  final jwt = ref.watch(jwtProvider);
 | 
			
		||||
  printLime('Current token: $jwt');
 | 
			
		||||
  printColor('Current token: $jwt', textColor: TextColor.green);
 | 
			
		||||
  if (jwt == null) return null;
 | 
			
		||||
  try {
 | 
			
		||||
    return Token.fromJson(JwtDecoder.decode(jwt));
 | 
			
		||||
@ -37,12 +37,12 @@ class _JwtNotifier extends StateNotifier<String?> {
 | 
			
		||||
 | 
			
		||||
  void setToken(String jwt) {
 | 
			
		||||
    state = jwt;
 | 
			
		||||
    printCyan('Loaded jwt into client: $jwt');
 | 
			
		||||
    printColor('Loaded jwt into client: $jwt', textColor: TextColor.cyan);
 | 
			
		||||
    ref.read(prefsProvider)?.setString('jwt', jwt);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void revokeToken() {
 | 
			
		||||
    printCyan('jwt token revoked');
 | 
			
		||||
    printColor('jwt token revoked', textColor: TextColor.cyan);
 | 
			
		||||
    state = null;
 | 
			
		||||
    ref.read(prefsProvider)?.remove('jwt');
 | 
			
		||||
  }
 | 
			
		||||
@ -58,8 +58,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
    // dio.options.baseUrl = "http://localhost:8081/";
 | 
			
		||||
    dio.options.baseUrl = "https://rluv.fosscat.com/";
 | 
			
		||||
    dio.interceptors.addAll([
 | 
			
		||||
      InterceptorsWrapper(onRequest:
 | 
			
		||||
          (RequestOptions options, RequestInterceptorHandler handler) {
 | 
			
		||||
      InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
 | 
			
		||||
        final jwt = ref.read(jwtProvider);
 | 
			
		||||
        if (jwt != null) {
 | 
			
		||||
          options.headers['token'] = jwt;
 | 
			
		||||
@ -69,12 +68,10 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
        if (response.statusCode != null) {
 | 
			
		||||
          if (response.statusCode == 200) {
 | 
			
		||||
            try {
 | 
			
		||||
              if ((response.data as Map<String, dynamic>)
 | 
			
		||||
                  .containsKey('success')) {
 | 
			
		||||
              if ((response.data as Map<String, dynamic>).containsKey('success')) {
 | 
			
		||||
                if (!response.data['success']) return handler.next(response);
 | 
			
		||||
              }
 | 
			
		||||
              if ((response.data as Map<String, dynamic>)
 | 
			
		||||
                  .containsKey('token')) {
 | 
			
		||||
              if ((response.data as Map<String, dynamic>).containsKey('token')) {
 | 
			
		||||
                final jwt = response.data['token'];
 | 
			
		||||
                if (jwt != null) {
 | 
			
		||||
                  ref.read(jwtProvider.notifier).setToken(jwt);
 | 
			
		||||
@ -83,7 +80,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            } catch (err) {
 | 
			
		||||
              printRed('Error in interceptor for token: $err');
 | 
			
		||||
              printColor('Error in interceptor for token: $err', textColor: TextColor.red);
 | 
			
		||||
              return handler.next(response);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
@ -115,8 +112,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Map<String, dynamic>?> put(
 | 
			
		||||
      {required String path, Object? data}) async {
 | 
			
		||||
  Future<Map<String, dynamic>?> put({required String path, Object? data}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      final res = await dio.put(path, data: data);
 | 
			
		||||
 | 
			
		||||
@ -129,8 +125,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Map<String, dynamic>?> post(
 | 
			
		||||
      {required String path, Object? data}) async {
 | 
			
		||||
  Future<Map<String, dynamic>?> post({required String path, Object? data}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      final res = await dio.post(path, data: data);
 | 
			
		||||
 | 
			
		||||
@ -143,8 +138,7 @@ class _ApiNotifier extends StateNotifier<Dio> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Map<String, dynamic>?> delete(
 | 
			
		||||
      {required String path, Object? data}) async {
 | 
			
		||||
  Future<Map<String, dynamic>?> delete({required String path, Object? data}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      final res = await dio.delete(path, data: data);
 | 
			
		||||
 | 
			
		||||
@ -162,8 +156,7 @@ class _LoggingInterceptor extends Interceptor {
 | 
			
		||||
  _LoggingInterceptor();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future onRequest(
 | 
			
		||||
      RequestOptions options, RequestInterceptorHandler handler) async {
 | 
			
		||||
  Future onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
 | 
			
		||||
    logPrint('///*** REQUEST ***\\\\\\');
 | 
			
		||||
    printKV('URI', options.uri);
 | 
			
		||||
    printKV('METHOD', options.method);
 | 
			
		||||
@ -177,7 +170,7 @@ class _LoggingInterceptor extends Interceptor {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void onError(DioException err, ErrorInterceptorHandler handler) {
 | 
			
		||||
    printRed('///*** ERROR RESPONSE ***\\\\\\');
 | 
			
		||||
    printColor('///*** ERROR RESPONSE ***\\\\\\', textColor: TextColor.red);
 | 
			
		||||
    logPrint('URI: ${err.requestOptions.uri}');
 | 
			
		||||
    if (err.response != null) {
 | 
			
		||||
      logPrint('STATUS CODE: ${err.response?.statusCode?.toString()}');
 | 
			
		||||
@ -192,8 +185,7 @@ class _LoggingInterceptor extends Interceptor {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future onResponse(
 | 
			
		||||
      Response response, ResponseInterceptorHandler handler) async {
 | 
			
		||||
  Future onResponse(Response response, ResponseInterceptorHandler handler) async {
 | 
			
		||||
    logPrint('///*** RESPONSE ***\\\\\\');
 | 
			
		||||
    printKV('URI', response.requestOptions.uri);
 | 
			
		||||
    printKV('STATUS CODE', response.statusCode ?? '');
 | 
			
		||||
@ -206,7 +198,7 @@ class _LoggingInterceptor extends Interceptor {
 | 
			
		||||
 | 
			
		||||
  void printKV(String key, Object v) {
 | 
			
		||||
    if (kDebugMode) {
 | 
			
		||||
      printOrange('$key: $v');
 | 
			
		||||
      printColor('$key: $v', textColor: TextColor.orange);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -215,21 +207,21 @@ class _LoggingInterceptor extends Interceptor {
 | 
			
		||||
      final data = (s as Map<String, dynamic>?);
 | 
			
		||||
      if (kDebugMode) {
 | 
			
		||||
        if (data == null) {
 | 
			
		||||
          printAmber({});
 | 
			
		||||
          printColor({}, textColor: TextColor.yellow);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        JsonEncoder encoder = const JsonEncoder.withIndent('  ');
 | 
			
		||||
        String prettyprint = encoder.convert(s);
 | 
			
		||||
        printAmber(prettyprint);
 | 
			
		||||
        printColor(prettyprint, textColor: TextColor.yellow);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (_) {
 | 
			
		||||
      printAmber(s);
 | 
			
		||||
      printColor(s, textColor: TextColor.yellow);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void logPrint(String s) {
 | 
			
		||||
    if (kDebugMode) {
 | 
			
		||||
      printOrange(s);
 | 
			
		||||
      printColor(s, textColor: TextColor.yellow);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:rluv/global/api.dart';
 | 
			
		||||
import 'package:rluv/models/budget.dart';
 | 
			
		||||
import 'package:rluv/models/budget_category_model.dart';
 | 
			
		||||
@ -13,8 +13,7 @@ import '../models/shared_note.dart';
 | 
			
		||||
import '../models/transaction_model.dart';
 | 
			
		||||
import '../models/user.dart';
 | 
			
		||||
 | 
			
		||||
StateProvider<SharedPreferences?> prefsProvider =
 | 
			
		||||
    StateProvider<SharedPreferences?>((ref) => null);
 | 
			
		||||
StateProvider<SharedPreferences?> prefsProvider = StateProvider<SharedPreferences?>((ref) => null);
 | 
			
		||||
 | 
			
		||||
// final StateProvider<Token?> tokenProvider = StateProvider<Token?>((ref) {
 | 
			
		||||
//   // final tokenStr = prefs.getString('jwt');
 | 
			
		||||
@ -42,8 +41,7 @@ final Provider<FamilyModel?> familyProvider = Provider<FamilyModel?>(
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
final Provider<List<BudgetCategory>> budgetCategoriesProvider =
 | 
			
		||||
    Provider<List<BudgetCategory>>((ref) {
 | 
			
		||||
final Provider<List<BudgetCategory>> budgetCategoriesProvider = Provider<List<BudgetCategory>>((ref) {
 | 
			
		||||
  final dash = ref.watch(dashboardProvider);
 | 
			
		||||
  if (dash == null) return [];
 | 
			
		||||
  final categoriesData = dash['budget_categories'] as List<dynamic>;
 | 
			
		||||
@ -55,7 +53,7 @@ final Provider<List<BudgetCategory>> budgetCategoriesProvider =
 | 
			
		||||
 | 
			
		||||
  final prefs = ref.read(prefsProvider);
 | 
			
		||||
  final budgetJson = jsonEncode({'budget_categories': categoriesData});
 | 
			
		||||
  printBlue('updated prefs stored categories');
 | 
			
		||||
  printColor('updated prefs stored categories', textColor: TextColor.blue);
 | 
			
		||||
  prefs?.setString('budget_categories', budgetJson);
 | 
			
		||||
 | 
			
		||||
  return categories;
 | 
			
		||||
@ -71,8 +69,7 @@ final Provider<Budget?> budgetProvider = Provider<Budget?>(
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
final Provider<List<Transaction>> transactionsProvider =
 | 
			
		||||
    Provider<List<Transaction>>((ref) {
 | 
			
		||||
final Provider<List<Transaction>> transactionsProvider = Provider<List<Transaction>>((ref) {
 | 
			
		||||
  final dash = ref.watch(dashboardProvider);
 | 
			
		||||
  if (dash == null) return [];
 | 
			
		||||
  final transactions = dash['transactions'] as List<dynamic>;
 | 
			
		||||
@ -83,8 +80,7 @@ final Provider<List<Transaction>> transactionsProvider =
 | 
			
		||||
      .toList();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
final Provider<List<SharedNote>> sharedNotesProvider =
 | 
			
		||||
    Provider<List<SharedNote>>(
 | 
			
		||||
final Provider<List<SharedNote>> sharedNotesProvider = Provider<List<SharedNote>>(
 | 
			
		||||
  (ref) {
 | 
			
		||||
    final dash = ref.watch(dashboardProvider);
 | 
			
		||||
    if (dash == null) return [];
 | 
			
		||||
@ -97,8 +93,7 @@ final Provider<List<SharedNote>> sharedNotesProvider =
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
final dashboardProvider =
 | 
			
		||||
    StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
 | 
			
		||||
final dashboardProvider = StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
 | 
			
		||||
  (ref) {
 | 
			
		||||
    return DashBoardStateNotifier(ref);
 | 
			
		||||
  },
 | 
			
		||||
@ -119,10 +114,10 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
    );
 | 
			
		||||
    final token = ref.read(tokenProvider);
 | 
			
		||||
    if (token?.familyId == null) {
 | 
			
		||||
      printPink('No token, cannot fetch dashboard');
 | 
			
		||||
      printColor('No token, cannot fetch dashboard', textColor: TextColor.red);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    printAmber('Fetching dashboard');
 | 
			
		||||
    printColor('Fetching dashboard', textColor: TextColor.yellow);
 | 
			
		||||
    state = await ref.read(apiProvider.notifier).get("dashboard");
 | 
			
		||||
    WidgetsBinding.instance.addPostFrameCallback(
 | 
			
		||||
      (_) => ref.read(loadingStateProvider.notifier).state = false,
 | 
			
		||||
@ -131,7 +126,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
 | 
			
		||||
  void update(Map<String, dynamic> data) {
 | 
			
		||||
    if (state == null) {
 | 
			
		||||
      printPink('Cant update data, state is null');
 | 
			
		||||
      printColor('Cant update data, state is null', textColor: TextColor.red);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (data.keys.length != 1 || data.values.length != 1) {
 | 
			
		||||
@ -149,9 +144,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
            )
 | 
			
		||||
            .toList();
 | 
			
		||||
        subStateListObj.removeWhere(
 | 
			
		||||
          (element) =>
 | 
			
		||||
              element['id'] ==
 | 
			
		||||
              (data.values.first as Map<String, dynamic>)['id'],
 | 
			
		||||
          (element) => element['id'] == (data.values.first as Map<String, dynamic>)['id'],
 | 
			
		||||
        );
 | 
			
		||||
        subStateListObj.add(data.values.first);
 | 
			
		||||
 | 
			
		||||
@ -167,7 +160,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
 | 
			
		||||
  void add(Map<String, dynamic> data) {
 | 
			
		||||
    if (state == null) {
 | 
			
		||||
      printPink('Cant add data, state is null');
 | 
			
		||||
      printColor('Cant add data, state is null', textColor: TextColor.red);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (data.keys.length != 1 || data.values.length != 1) {
 | 
			
		||||
@ -192,7 +185,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
 | 
			
		||||
  void removeWithId(String stateKey, int id) {
 | 
			
		||||
    if (state == null) {
 | 
			
		||||
      printPink('Cant remove data, state is null');
 | 
			
		||||
      printColor('Cant remove data, state is null', textColor: TextColor.red);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    switch (stateKey) {
 | 
			
		||||
@ -201,8 +194,7 @@ class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
 | 
			
		||||
      case 'shared_noted':
 | 
			
		||||
        final subStateList = state![stateKey] as List<dynamic>;
 | 
			
		||||
        final newState = state;
 | 
			
		||||
        subStateList
 | 
			
		||||
            .removeWhere((e) => (e as Map<String, dynamic>)['id'] == id);
 | 
			
		||||
        subStateList.removeWhere((e) => (e as Map<String, dynamic>)['id'] == id);
 | 
			
		||||
        newState![stateKey] = subStateList;
 | 
			
		||||
        state = {...newState};
 | 
			
		||||
        // printBlue(state);
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:colorful_print/colorful_print.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/print.dart';
 | 
			
		||||
import 'package:intl/intl.dart';
 | 
			
		||||
import 'package:rluv/global/styles.dart';
 | 
			
		||||
import 'package:rluv/main.dart';
 | 
			
		||||
@ -20,20 +20,16 @@ bool boolFromJson(int value) => value == 1;
 | 
			
		||||
 | 
			
		||||
int boolToJson(bool hide) => hide ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
String colorToJson(Color color) =>
 | 
			
		||||
    color.toString().split('(0x')[1].split(')')[0];
 | 
			
		||||
String colorToJson(Color color) => color.toString().split('(0x')[1].split(')')[0];
 | 
			
		||||
 | 
			
		||||
Color colorFromJson(String hex) => Color(int.parse(hex, radix: 16));
 | 
			
		||||
 | 
			
		||||
String? optionalColorToJson(Color? optionalColor) => optionalColor == null
 | 
			
		||||
    ? null
 | 
			
		||||
    : optionalColor.toString().split('(0x')[1].split(')')[0];
 | 
			
		||||
String? optionalColorToJson(Color? optionalColor) =>
 | 
			
		||||
    optionalColor == null ? null : optionalColor.toString().split('(0x')[1].split(')')[0];
 | 
			
		||||
 | 
			
		||||
Color? optionalColorFromJson(String? hex) =>
 | 
			
		||||
    hex == null ? null : Color(int.parse(hex, radix: 16));
 | 
			
		||||
Color? optionalColorFromJson(String? hex) => hex == null ? null : Color(int.parse(hex, radix: 16));
 | 
			
		||||
 | 
			
		||||
Brightness getBrightness(Color color) =>
 | 
			
		||||
    ThemeData.estimateBrightnessForColor(color);
 | 
			
		||||
Brightness getBrightness(Color color) => ThemeData.estimateBrightnessForColor(color);
 | 
			
		||||
 | 
			
		||||
List<Color> generateColorList() {
 | 
			
		||||
  List<Color> colors = [];
 | 
			
		||||
@ -60,7 +56,7 @@ extension MonetaryExtension on double {
 | 
			
		||||
      return "\$${pieces.first}.00";
 | 
			
		||||
    } else {
 | 
			
		||||
      if (pieces.length > 2) {
 | 
			
		||||
        printBlue(pieces);
 | 
			
		||||
        printColor(pieces, textColor: TextColor.blue);
 | 
			
		||||
      }
 | 
			
		||||
      return '\$${pieces[0]}.${pieces[1].padRight(2, "0")}';
 | 
			
		||||
    }
 | 
			
		||||
@ -83,7 +79,7 @@ void showSnack(
 | 
			
		||||
    Duration duration = const Duration(seconds: 2)}) {
 | 
			
		||||
  final messengerKey = ref.read(scaffoldMessengerKeyProvider);
 | 
			
		||||
  if (messengerKey.currentState == null) {
 | 
			
		||||
    printPink('Cannot show snackbar, state == null');
 | 
			
		||||
    printColor('Cannot show snackbar, state == null', textColor: TextColor.red);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  final color = type == SnackType.info
 | 
			
		||||
@ -99,8 +95,7 @@ void showSnack(
 | 
			
		||||
    elevation: 8,
 | 
			
		||||
    backgroundColor: Styles.deepPurpleNurple,
 | 
			
		||||
    shape: const RoundedRectangleBorder(
 | 
			
		||||
      borderRadius: BorderRadius.only(
 | 
			
		||||
          topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
 | 
			
		||||
      borderRadius: BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
 | 
			
		||||
    ),
 | 
			
		||||
    content: Padding(
 | 
			
		||||
      padding: const EdgeInsets.all(8.0),
 | 
			
		||||
@ -108,9 +103,7 @@ void showSnack(
 | 
			
		||||
        children: [
 | 
			
		||||
          Padding(
 | 
			
		||||
            padding: const EdgeInsets.only(right: 14.0),
 | 
			
		||||
            child: Icon(
 | 
			
		||||
                type == SnackType.success ? Icons.check_circle : Icons.info,
 | 
			
		||||
                color: color),
 | 
			
		||||
            child: Icon(type == SnackType.success ? Icons.check_circle : Icons.info, color: color),
 | 
			
		||||
          ),
 | 
			
		||||
          Text(text, style: textStyle),
 | 
			
		||||
        ],
 | 
			
		||||
@ -120,8 +113,7 @@ void showSnack(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool isEmailValid(String email) {
 | 
			
		||||
  final RegExp regex =
 | 
			
		||||
      RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$");
 | 
			
		||||
  final RegExp regex = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$");
 | 
			
		||||
  return regex.hasMatch(email);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:animated_splash_screen/animated_splash_screen.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
			
		||||
import 'package:helpers/helpers/misc_build/build_media.dart';
 | 
			
		||||
import 'package:rluv/features/account/account_create_screen.dart';
 | 
			
		||||
import 'package:rluv/features/budget/screens/budget_overview.dart';
 | 
			
		||||
import 'package:rluv/features/notes/screens/notes_screen.dart';
 | 
			
		||||
@ -74,8 +73,7 @@ class _HomeState extends ConsumerState<Home> {
 | 
			
		||||
    }
 | 
			
		||||
    WidgetsBinding.instance.addPostFrameCallback(
 | 
			
		||||
      (_) {
 | 
			
		||||
        ref.read(currentHomePageProvider.notifier).state =
 | 
			
		||||
            const BudgetOverviewScreen(initialData: {});
 | 
			
		||||
        ref.read(currentHomePageProvider.notifier).state = const BudgetOverviewScreen(initialData: {});
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
    super.initState();
 | 
			
		||||
@ -92,8 +90,7 @@ class _HomeState extends ConsumerState<Home> {
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (ref.watch(currentHomePageProvider).toString() ==
 | 
			
		||||
        "BudgetOverviewScreen") {
 | 
			
		||||
    if (ref.watch(currentHomePageProvider).toString() == "BudgetOverviewScreen") {
 | 
			
		||||
      initData = {};
 | 
			
		||||
    }
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
@ -104,15 +101,13 @@ class _HomeState extends ConsumerState<Home> {
 | 
			
		||||
        child: SafeArea(
 | 
			
		||||
          child: Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              SizedBox(height: BuildMedia(context).height * 0.15),
 | 
			
		||||
              SizedBox(height: MediaQuery.of(context).size.height * 0.15),
 | 
			
		||||
              UiButton(
 | 
			
		||||
                text: 'Budget',
 | 
			
		||||
                color: drawerColors[4],
 | 
			
		||||
                onPressed: () {
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() !=
 | 
			
		||||
                      "BudgetOverviewScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state =
 | 
			
		||||
                        BudgetOverviewScreen(initialData: initData);
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() != "BudgetOverviewScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state = BudgetOverviewScreen(initialData: initData);
 | 
			
		||||
                  }
 | 
			
		||||
                  toggleDrawer();
 | 
			
		||||
                },
 | 
			
		||||
@ -121,10 +116,8 @@ class _HomeState extends ConsumerState<Home> {
 | 
			
		||||
                text: 'Notes',
 | 
			
		||||
                color: drawerColors[5],
 | 
			
		||||
                onPressed: () {
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() !=
 | 
			
		||||
                      "SharedNotesScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state =
 | 
			
		||||
                        SharedNotesScreen(initialData: initData);
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() != "SharedNotesScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state = SharedNotesScreen(initialData: initData);
 | 
			
		||||
                  }
 | 
			
		||||
                  toggleDrawer();
 | 
			
		||||
                },
 | 
			
		||||
@ -134,10 +127,8 @@ class _HomeState extends ConsumerState<Home> {
 | 
			
		||||
                text: 'Settings',
 | 
			
		||||
                color: drawerColors[0],
 | 
			
		||||
                onPressed: () {
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() !=
 | 
			
		||||
                      "SettingsScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state =
 | 
			
		||||
                        const SettingsScreen();
 | 
			
		||||
                  if (ref.read(currentHomePageProvider).toString() != "SettingsScreen") {
 | 
			
		||||
                    ref.read(currentHomePageProvider.notifier).state = const SettingsScreen();
 | 
			
		||||
                  }
 | 
			
		||||
                  toggleDrawer();
 | 
			
		||||
                },
 | 
			
		||||
@ -190,5 +181,4 @@ final appBarTitleProvider = Provider<String>(
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
final scaffoldMessengerKeyProvider =
 | 
			
		||||
    Provider<GlobalKey<ScaffoldMessengerState>>(
 | 
			
		||||
        (ref) => GlobalKey<ScaffoldMessengerState>());
 | 
			
		||||
    Provider<GlobalKey<ScaffoldMessengerState>>((ref) => GlobalKey<ScaffoldMessengerState>());
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								lib/models/budget.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/models/budget.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'budget.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
Budget _$BudgetFromJson(Map<String, dynamic> json) => Budget(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      familyId: json['family_id'] as int,
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      expectedIncome: (json['expected_income'] as num?)?.toDouble(),
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$BudgetToJson(Budget instance) => <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'family_id': instance.familyId,
 | 
			
		||||
      'expected_income': instance.expectedIncome,
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
							
								
								
									
										31
									
								
								lib/models/budget_category_model.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/models/budget_category_model.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'budget_category_model.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
BudgetCategory _$BudgetCategoryFromJson(Map<String, dynamic> json) =>
 | 
			
		||||
    BudgetCategory(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      budgetId: json['budget_id'] as int,
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      color: colorFromJson(json['color'] as String),
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      amount: (json['amount'] as num).toDouble(),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$BudgetCategoryToJson(BudgetCategory instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'budget_id': instance.budgetId,
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'amount': instance.amount,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'color': colorToJson(instance.color),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
							
								
								
									
										24
									
								
								lib/models/family_model.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/models/family_model.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'family_model.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
FamilyModel _$FamilyModelFromJson(Map<String, dynamic> json) => FamilyModel(
 | 
			
		||||
      id: json['id'] as int,
 | 
			
		||||
      code: json['code'] as String?,
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$FamilyModelToJson(FamilyModel instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'code': instance.code,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
							
								
								
									
										38
									
								
								lib/models/shared_note.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/models/shared_note.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'shared_note.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
SharedNote _$SharedNoteFromJson(Map<String, dynamic> json) => SharedNote(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      familyId: json['family_id'] as int,
 | 
			
		||||
      createdByUserId: json['created_by_user_id'] as int,
 | 
			
		||||
      content: json['content'] as String,
 | 
			
		||||
      title: json['title'] as String,
 | 
			
		||||
      color: optionalColorFromJson(json['color'] as String?),
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      tagIds: _tagIdsFromJson(json['tag_ids'] as String),
 | 
			
		||||
      isMarkdown: json['is_markdown'] == null
 | 
			
		||||
          ? false
 | 
			
		||||
          : boolFromJson(json['is_markdown'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$SharedNoteToJson(SharedNote instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'family_id': instance.familyId,
 | 
			
		||||
      'created_by_user_id': instance.createdByUserId,
 | 
			
		||||
      'content': instance.content,
 | 
			
		||||
      'title': instance.title,
 | 
			
		||||
      'tag_ids': _tagIdsToJson(instance.tagIds),
 | 
			
		||||
      'color': optionalColorToJson(instance.color),
 | 
			
		||||
      'is_markdown': boolToJson(instance.isMarkdown),
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
							
								
								
									
										33
									
								
								lib/models/tag.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/models/tag.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'tag.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
Tag _$TagFromJson(Map<String, dynamic> json) => Tag(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      familyId: json['family_id'] as int,
 | 
			
		||||
      createdByUserId: json['created_by_user_id'] as int,
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      type: $enumDecode(_$TagTypeEnumMap, json['type']),
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$TagToJson(Tag instance) => <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'family_id': instance.familyId,
 | 
			
		||||
      'created_by_user_id': instance.createdByUserId,
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'type': _$TagTypeEnumMap[instance.type]!,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
const _$TagTypeEnumMap = {
 | 
			
		||||
  TagType.note: 'note',
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										21
									
								
								lib/models/token.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/models/token.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'token.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
Token _$TokenFromJson(Map<String, dynamic> json) => Token(
 | 
			
		||||
      userId: json['user_id'] as int,
 | 
			
		||||
      familyId: json['family_id'] as int,
 | 
			
		||||
      generatedAt: dateFromJson(json['generated_at'] as int),
 | 
			
		||||
      expiresAt: dateFromJson(json['expires_at'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$TokenToJson(Token instance) => <String, dynamic>{
 | 
			
		||||
      'family_id': instance.familyId,
 | 
			
		||||
      'user_id': instance.userId,
 | 
			
		||||
      'generated_at': dateToJson(instance.generatedAt),
 | 
			
		||||
      'expires_at': dateToJson(instance.expiresAt),
 | 
			
		||||
    };
 | 
			
		||||
							
								
								
									
										41
									
								
								lib/models/transaction_model.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								lib/models/transaction_model.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'transaction_model.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      amount: (json['amount'] as num).toDouble(),
 | 
			
		||||
      type: $enumDecode(_$TransactionTypeEnumMap, json['type']),
 | 
			
		||||
      budgetId: json['budget_id'] as int,
 | 
			
		||||
      budgetCategoryId: json['budget_category_id'] as int?,
 | 
			
		||||
      createdByUserId: json['created_by_user_id'] as int,
 | 
			
		||||
      date: dateFromJson(json['date'] as int),
 | 
			
		||||
      memo: json['memo'] as String?,
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$TransactionToJson(Transaction instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'budget_category_id': instance.budgetCategoryId,
 | 
			
		||||
      'budget_id': instance.budgetId,
 | 
			
		||||
      'created_by_user_id': instance.createdByUserId,
 | 
			
		||||
      'amount': instance.amount,
 | 
			
		||||
      'memo': instance.memo,
 | 
			
		||||
      'type': _$TransactionTypeEnumMap[instance.type]!,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'date': dateToJson(instance.date),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
const _$TransactionTypeEnumMap = {
 | 
			
		||||
  TransactionType.income: 'income',
 | 
			
		||||
  TransactionType.expense: 'expense',
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										33
									
								
								lib/models/user.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/models/user.g.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'user.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
User _$UserFromJson(Map<String, dynamic> json) => User(
 | 
			
		||||
      id: json['id'] as int?,
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      familyId: json['family_id'] as int,
 | 
			
		||||
      budgetId: json['budget_id'] as int,
 | 
			
		||||
      email: json['email'] as String?,
 | 
			
		||||
      username: json['username'] as String?,
 | 
			
		||||
      createdAt: dateFromJson(json['created_at'] as int),
 | 
			
		||||
      updatedAt: dateFromJson(json['updated_at'] as int),
 | 
			
		||||
      lastActivityAt: dateFromJson(json['last_activity_at'] as int),
 | 
			
		||||
      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
 | 
			
		||||
      'id': instance.id,
 | 
			
		||||
      'family_id': instance.familyId,
 | 
			
		||||
      'budget_id': instance.budgetId,
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'username': instance.username,
 | 
			
		||||
      'email': instance.email,
 | 
			
		||||
      'hide': boolToJson(instance.hide),
 | 
			
		||||
      'created_at': dateToJson(instance.createdAt),
 | 
			
		||||
      'updated_at': dateToJson(instance.updatedAt),
 | 
			
		||||
      'last_activity_at': dateToJson(instance.lastActivityAt),
 | 
			
		||||
    };
 | 
			
		||||
@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
 | 
			
		||||
set(BINARY_NAME "rluv")
 | 
			
		||||
# The unique GTK application identifier for this application. See:
 | 
			
		||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
 | 
			
		||||
set(APPLICATION_ID "com.example.rluv")
 | 
			
		||||
set(APPLICATION_ID "com.fosscat.rluv")
 | 
			
		||||
 | 
			
		||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
 | 
			
		||||
# versions of CMake.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								package_rename_config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								package_rename_config.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
package_rename_config:
 | 
			
		||||
  android:
 | 
			
		||||
    app_name: rluv
 | 
			
		||||
    package_name: com.fosscat.rluv
 | 
			
		||||
    override_old_package: com.example.rluv
 | 
			
		||||
    lang: kotlin
 | 
			
		||||
 | 
			
		||||
  ios:
 | 
			
		||||
    app_name: rluv
 | 
			
		||||
    bundle_name: fosscatrluv
 | 
			
		||||
    package_name: com.fosscat.rluv
 | 
			
		||||
 | 
			
		||||
  web:
 | 
			
		||||
    app_name: rluv
 | 
			
		||||
    description: Package to change project configurations.
 | 
			
		||||
 | 
			
		||||
  linux:
 | 
			
		||||
    app_name: rluv
 | 
			
		||||
    package_name: com.fosscat.rluv
 | 
			
		||||
    exe_name: rluv
 | 
			
		||||
							
								
								
									
										12
									
								
								packaging/linux/com.fosscat.rluv.desktop
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packaging/linux/com.fosscat.rluv.desktop
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
[Desktop Entry]
 | 
			
		||||
Version=1.0
 | 
			
		||||
Type=Application
 | 
			
		||||
 | 
			
		||||
Name=rluv
 | 
			
		||||
Comment=Budget App
 | 
			
		||||
Categories=Utility;
 | 
			
		||||
 | 
			
		||||
Icon=com.fosscat.rluv
 | 
			
		||||
Exec=rluv
 | 
			
		||||
Terminal=false
 | 
			
		||||
StartupWMClass=rluv
 | 
			
		||||
							
								
								
									
										32
									
								
								packaging/linux/com.fosscat.rluv.metainfo.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packaging/linux/com.fosscat.rluv.metainfo.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!-- 
 | 
			
		||||
    Generator for metainfo & .desktop files: 
 | 
			
		||||
    https://www.freedesktop.org/software/appstream/metainfocreator/#/
 | 
			
		||||
-->
 | 
			
		||||
<component type="desktop-application">
 | 
			
		||||
  <id>com.fosscat.rluv</id>
 | 
			
		||||
  <name>rluv</name>
 | 
			
		||||
  <summary>A budget app made with love</summary>
 | 
			
		||||
  <developer_name>Nate Anderson</developer_name>
 | 
			
		||||
  <url type="homepage">https://git.fosscat.com/n8r/rluv_client</url>
 | 
			
		||||
  <metadata_license></metadata_license>
 | 
			
		||||
  <project_license></project_license>
 | 
			
		||||
  <supports>
 | 
			
		||||
    <control>pointing</control>
 | 
			
		||||
    <control>keyboard</control>
 | 
			
		||||
    <control>touch</control>
 | 
			
		||||
  </supports>
 | 
			
		||||
  <description>
 | 
			
		||||
    <p>A budgeting app for my needs. Maybe your too?</p>
 | 
			
		||||
  </description>
 | 
			
		||||
  <launchable type="desktop-id">com.fosscat.rluv.desktop</launchable>
 | 
			
		||||
  <screenshots>
 | 
			
		||||
    <!-- <screenshot type="default"> -->
 | 
			
		||||
      <!-- <image>https://raw.githubusercontent.com/Merrit/flutter_flatpak_example/main/screenshots/screenshot.png</image> -->
 | 
			
		||||
    <!-- </screenshot> -->
 | 
			
		||||
  </screenshots>
 | 
			
		||||
  <content_rating type="oars-1.1" />
 | 
			
		||||
  <releases>
 | 
			
		||||
    <release version="0.0.1" date="2024-06-02" />
 | 
			
		||||
  </releases>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										77
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								pubspec.lock
									
									
									
									
									
								
							@ -161,6 +161,14 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.18.0"
 | 
			
		||||
  colorful_print:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
      name: colorful_print
 | 
			
		||||
      sha256: "2c9784a0d5e6dcd480a0d4ab67b7263e19d31644a30a8bc7f67ceb6db89549c7"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.1.2"
 | 
			
		||||
  convert:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -177,14 +185,14 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "3.0.3"
 | 
			
		||||
  cupertino_icons:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
  csslib:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: cupertino_icons
 | 
			
		||||
      sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
 | 
			
		||||
      name: csslib
 | 
			
		||||
      sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.0.5"
 | 
			
		||||
    version: "1.0.0"
 | 
			
		||||
  custom_refresh_indicator:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
@ -304,15 +312,6 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.3.1"
 | 
			
		||||
  helpers:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
      path: "."
 | 
			
		||||
      ref: main
 | 
			
		||||
      resolved-ref: e9486562cb1ec5ac31fdd91ff573e99d51b2d57f
 | 
			
		||||
      url: "https://github.com/mitch2na/helpers.git"
 | 
			
		||||
    source: git
 | 
			
		||||
    version: "1.2.0"
 | 
			
		||||
  highlight:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -321,6 +320,14 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.7.0"
 | 
			
		||||
  html:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: html
 | 
			
		||||
      sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.15.4"
 | 
			
		||||
  http_multi_server:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -405,26 +412,26 @@ packages:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: leak_tracker
 | 
			
		||||
      sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
 | 
			
		||||
      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "10.0.0"
 | 
			
		||||
    version: "10.0.4"
 | 
			
		||||
  leak_tracker_flutter_testing:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: leak_tracker_flutter_testing
 | 
			
		||||
      sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
 | 
			
		||||
      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.0.1"
 | 
			
		||||
    version: "3.0.3"
 | 
			
		||||
  leak_tracker_testing:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: leak_tracker_testing
 | 
			
		||||
      sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
 | 
			
		||||
      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.0.1"
 | 
			
		||||
    version: "3.0.1"
 | 
			
		||||
  lints:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -433,6 +440,14 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.1.1"
 | 
			
		||||
  logger:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: logger
 | 
			
		||||
      sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.3.0"
 | 
			
		||||
  logging:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -477,10 +492,10 @@ packages:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: meta
 | 
			
		||||
      sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
 | 
			
		||||
      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.11.0"
 | 
			
		||||
    version: "1.12.0"
 | 
			
		||||
  mime:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -497,6 +512,14 @@ packages:
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.1.0"
 | 
			
		||||
  package_rename:
 | 
			
		||||
    dependency: "direct dev"
 | 
			
		||||
    description:
 | 
			
		||||
      name: package_rename
 | 
			
		||||
      sha256: "5066d021830f7a984f66a3d6912b0b95efb1d91f14322ba26ceacce2a62fd312"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.6.0"
 | 
			
		||||
  page_transition:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -762,10 +785,10 @@ packages:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: test_api
 | 
			
		||||
      sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
 | 
			
		||||
      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.6.1"
 | 
			
		||||
    version: "0.7.0"
 | 
			
		||||
  timing:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -882,10 +905,10 @@ packages:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: vm_service
 | 
			
		||||
      sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
 | 
			
		||||
      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
 | 
			
		||||
      url: "https://pub.dev"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "13.0.0"
 | 
			
		||||
    version: "14.2.1"
 | 
			
		||||
  watcher:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -936,4 +959,4 @@ packages:
 | 
			
		||||
    version: "3.1.2"
 | 
			
		||||
sdks:
 | 
			
		||||
  dart: ">=3.3.0 <4.0.0"
 | 
			
		||||
  flutter: ">=3.19.0"
 | 
			
		||||
  flutter: ">=3.18.0-18.0.pre.54"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										70
									
								
								pubspec.yaml
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								pubspec.yaml
									
									
									
									
									
								
							@ -1,47 +1,18 @@
 | 
			
		||||
name: rluv
 | 
			
		||||
description: A new Flutter project.
 | 
			
		||||
# The following line prevents the package from being accidentally published to
 | 
			
		||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
 | 
			
		||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 | 
			
		||||
description: A budget app for lovers
 | 
			
		||||
publish_to: 'none'
 | 
			
		||||
 | 
			
		||||
# The following defines the version and build number for your application.
 | 
			
		||||
# A version number is three numbers separated by dots, like 1.2.43
 | 
			
		||||
# followed by an optional build number separated by a +.
 | 
			
		||||
# Both the version and the builder number may be overridden in flutter
 | 
			
		||||
# build by specifying --build-name and --build-number, respectively.
 | 
			
		||||
# In Android, build-name is used as versionName while build-number used as versionCode.
 | 
			
		||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
 | 
			
		||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
 | 
			
		||||
# Read more about iOS versioning at
 | 
			
		||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
			
		||||
# In Windows, build-name is used as the major, minor, and patch parts
 | 
			
		||||
# of the product and file versions while build-number is used as the build suffix.
 | 
			
		||||
version: 1.0.0+1
 | 
			
		||||
 | 
			
		||||
environment:
 | 
			
		||||
  sdk: '>=2.19.6 <3.0.0'
 | 
			
		||||
 | 
			
		||||
# Dependencies specify other packages that your package needs in order to work.
 | 
			
		||||
# To automatically upgrade your package dependencies to the latest versions
 | 
			
		||||
# consider running `flutter pub upgrade --major-versions`. Alternatively,
 | 
			
		||||
# dependencies can be manually updated by changing the version numbers below to
 | 
			
		||||
# the latest version available on pub.dev. To see which dependencies have newer
 | 
			
		||||
# versions available, run `flutter pub outdated`.
 | 
			
		||||
dependencies:
 | 
			
		||||
  flutter:
 | 
			
		||||
    sdk: flutter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  # The following adds the Cupertino Icons font to your application.
 | 
			
		||||
  # Use with the CupertinoIcons class for iOS style icons.
 | 
			
		||||
  cupertino_icons: ^1.0.2
 | 
			
		||||
  dio: ^5.2.1+1
 | 
			
		||||
  flutter_riverpod: ^2.1.3
 | 
			
		||||
  helpers:
 | 
			
		||||
    git:
 | 
			
		||||
      url: https://github.com/mitch2na/helpers.git
 | 
			
		||||
      ref: main
 | 
			
		||||
  uuid: ^3.0.7
 | 
			
		||||
  colorful_print: ^0.1.2
 | 
			
		||||
  json_annotation: ^4.8.0
 | 
			
		||||
  shared_preferences: ^2.1.2
 | 
			
		||||
  intl: ^0.18.1
 | 
			
		||||
@ -53,52 +24,19 @@ dependencies:
 | 
			
		||||
dev_dependencies:
 | 
			
		||||
  flutter_test:
 | 
			
		||||
    sdk: flutter
 | 
			
		||||
 | 
			
		||||
  build_runner: ^2.3.3
 | 
			
		||||
  json_serializable: ^6.6.0
 | 
			
		||||
  flutter_lints: ^2.0.0
 | 
			
		||||
  icons_launcher: ^2.1.3
 | 
			
		||||
  package_rename: ^1.6.0
 | 
			
		||||
 | 
			
		||||
# For information on the generic Dart part of this file, see the
 | 
			
		||||
# following page: https://dart.dev/tools/pub/pubspec
 | 
			
		||||
 | 
			
		||||
# The following section is specific to Flutter packages.
 | 
			
		||||
flutter:
 | 
			
		||||
 | 
			
		||||
  # The following line ensures that the Material Icons font is
 | 
			
		||||
  # included with your application, so that you can use the icons in
 | 
			
		||||
  # the material Icons class.
 | 
			
		||||
  uses-material-design: true
 | 
			
		||||
 | 
			
		||||
  # To add assets to your application, add an assets section, like this:
 | 
			
		||||
  assets:
 | 
			
		||||
    - assets/
 | 
			
		||||
 | 
			
		||||
  # An image asset can refer to one or more resolution-specific "variants", see
 | 
			
		||||
  # https://flutter.dev/assets-and-images/#resolution-aware
 | 
			
		||||
 | 
			
		||||
  # For details regarding adding assets from package dependencies, see
 | 
			
		||||
  # https://flutter.dev/assets-and-images/#from-packages
 | 
			
		||||
 | 
			
		||||
  # To add custom fonts to your application, add a fonts section here,
 | 
			
		||||
  # in this "flutter" section. Each entry in this list should have a
 | 
			
		||||
  # "family" key with the font family name, and a "fonts" key with a
 | 
			
		||||
  # list giving the asset and other descriptors for the font. For
 | 
			
		||||
  # example:
 | 
			
		||||
  # fonts:
 | 
			
		||||
  #   - family: Schyler
 | 
			
		||||
  #     fonts:
 | 
			
		||||
  #       - asset: fonts/Schyler-Regular.ttf
 | 
			
		||||
  #       - asset: fonts/Schyler-Italic.ttf
 | 
			
		||||
  #         style: italic
 | 
			
		||||
  #   - family: Trajan Pro
 | 
			
		||||
  #     fonts:
 | 
			
		||||
  #       - asset: fonts/TrajanPro.ttf
 | 
			
		||||
  #       - asset: fonts/TrajanPro_Bold.ttf
 | 
			
		||||
  #         weight: 700
 | 
			
		||||
  #
 | 
			
		||||
  # For details regarding fonts from package dependencies,
 | 
			
		||||
  # see https://flutter.dev/custom-fonts/#from-packages
 | 
			
		||||
icons_launcher:
 | 
			
		||||
  image_path: "assets/app_icon.png"
 | 
			
		||||
  platforms:
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,4 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<!DOCTYPE html><html><head>
 | 
			
		||||
  <!--
 | 
			
		||||
    If you are serving your web app in a path other than the root, change the
 | 
			
		||||
    href value below to reflect the base path you are serving from.
 | 
			
		||||
@ -18,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
  <meta charset="UTF-8">
 | 
			
		||||
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
 | 
			
		||||
  <meta name="description" content="A new Flutter project.">
 | 
			
		||||
  <meta name="description" content="Package to change project configurations.">
 | 
			
		||||
 | 
			
		||||
  <!-- iOS meta tags & icons -->
 | 
			
		||||
  <meta name="apple-mobile-web-app-capable" content="yes">
 | 
			
		||||
@ -27,7 +25,7 @@
 | 
			
		||||
  <link rel="apple-touch-icon" href="icons/Icon-192.png">
 | 
			
		||||
 | 
			
		||||
  <!-- Favicon -->
 | 
			
		||||
  <link rel="icon" type="image/png" href="favicon.png"/>
 | 
			
		||||
  <link rel="icon" type="image/png" href="favicon.png">
 | 
			
		||||
 | 
			
		||||
  <title>rluv</title>
 | 
			
		||||
  <link rel="manifest" href="manifest.json">
 | 
			
		||||
@ -37,7 +35,7 @@
 | 
			
		||||
    var serviceWorkerVersion = null;
 | 
			
		||||
  </script>
 | 
			
		||||
  <!-- This script adds the flutter initialization JS code -->
 | 
			
		||||
  <script src="flutter.js" defer></script>
 | 
			
		||||
  <script src="flutter.js" defer=""></script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
  <script>
 | 
			
		||||
@ -55,5 +53,7 @@
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</body></html>
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
    "display": "standalone",
 | 
			
		||||
    "background_color": "#0175C2",
 | 
			
		||||
    "theme_color": "#0175C2",
 | 
			
		||||
    "description": "A new Flutter project.",
 | 
			
		||||
    "description": "Package to change project configurations.",
 | 
			
		||||
    "orientation": "portrait-primary",
 | 
			
		||||
    "prefer_related_applications": false,
 | 
			
		||||
    "icons": [
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user