diff --git a/.gitignore b/.gitignore index 9dcd8a0..aa891ed 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ migrate_working_dir/ *.ipr *.iws .idea/ +.vscode/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line diff --git a/ferndi/ferndi.xcodeproj/project.pbxproj b/ferndi/ferndi.xcodeproj/project.pbxproj deleted file mode 100644 index 4c74a86..0000000 --- a/ferndi/ferndi.xcodeproj/project.pbxproj +++ /dev/null @@ -1,480 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 56; - objects = { - -/* Begin PBXBuildFile section */ - 846573B12A424E80000BCDAE /* ferndi.docc in Sources */ = {isa = PBXBuildFile; fileRef = 846573B02A424E80000BCDAE /* ferndi.docc */; }; - 846573B72A424E80000BCDAE /* ferndi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846573AC2A424E80000BCDAE /* ferndi.framework */; }; - 846573BC2A424E80000BCDAE /* ferndiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846573BB2A424E80000BCDAE /* ferndiTests.swift */; }; - 846573BD2A424E80000BCDAE /* ferndi.h in Headers */ = {isa = PBXBuildFile; fileRef = 846573AF2A424E80000BCDAE /* ferndi.h */; settings = {ATTRIBUTES = (Public, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 846573B82A424E80000BCDAE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 846573A32A424E80000BCDAE /* Project object */; - proxyType = 1; - remoteGlobalIDString = 846573AB2A424E80000BCDAE; - remoteInfo = ferndi; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 846573AC2A424E80000BCDAE /* ferndi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ferndi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 846573AF2A424E80000BCDAE /* ferndi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ferndi.h; sourceTree = ""; }; - 846573B02A424E80000BCDAE /* ferndi.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = ferndi.docc; sourceTree = ""; }; - 846573B62A424E80000BCDAE /* ferndiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ferndiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 846573BB2A424E80000BCDAE /* ferndiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ferndiTests.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 846573A92A424E80000BCDAE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 846573B32A424E80000BCDAE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 846573B72A424E80000BCDAE /* ferndi.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 846573A22A424E80000BCDAE = { - isa = PBXGroup; - children = ( - 846573AE2A424E80000BCDAE /* ferndi */, - 846573BA2A424E80000BCDAE /* ferndiTests */, - 846573AD2A424E80000BCDAE /* Products */, - ); - sourceTree = ""; - }; - 846573AD2A424E80000BCDAE /* Products */ = { - isa = PBXGroup; - children = ( - 846573AC2A424E80000BCDAE /* ferndi.framework */, - 846573B62A424E80000BCDAE /* ferndiTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 846573AE2A424E80000BCDAE /* ferndi */ = { - isa = PBXGroup; - children = ( - 846573AF2A424E80000BCDAE /* ferndi.h */, - 846573B02A424E80000BCDAE /* ferndi.docc */, - ); - path = ferndi; - sourceTree = ""; - }; - 846573BA2A424E80000BCDAE /* ferndiTests */ = { - isa = PBXGroup; - children = ( - 846573BB2A424E80000BCDAE /* ferndiTests.swift */, - ); - path = ferndiTests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 846573A72A424E80000BCDAE /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 846573BD2A424E80000BCDAE /* ferndi.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 846573AB2A424E80000BCDAE /* ferndi */ = { - isa = PBXNativeTarget; - buildConfigurationList = 846573C02A424E80000BCDAE /* Build configuration list for PBXNativeTarget "ferndi" */; - buildPhases = ( - 846573A72A424E80000BCDAE /* Headers */, - 846573A82A424E80000BCDAE /* Sources */, - 846573A92A424E80000BCDAE /* Frameworks */, - 846573AA2A424E80000BCDAE /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ferndi; - productName = ferndi; - productReference = 846573AC2A424E80000BCDAE /* ferndi.framework */; - productType = "com.apple.product-type.framework"; - }; - 846573B52A424E80000BCDAE /* ferndiTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 846573C32A424E80000BCDAE /* Build configuration list for PBXNativeTarget "ferndiTests" */; - buildPhases = ( - 846573B22A424E80000BCDAE /* Sources */, - 846573B32A424E80000BCDAE /* Frameworks */, - 846573B42A424E80000BCDAE /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 846573B92A424E80000BCDAE /* PBXTargetDependency */, - ); - name = ferndiTests; - productName = ferndiTests; - productReference = 846573B62A424E80000BCDAE /* ferndiTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 846573A32A424E80000BCDAE /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1430; - LastUpgradeCheck = 1430; - TargetAttributes = { - 846573AB2A424E80000BCDAE = { - CreatedOnToolsVersion = 14.3.1; - }; - 846573B52A424E80000BCDAE = { - CreatedOnToolsVersion = 14.3.1; - }; - }; - }; - buildConfigurationList = 846573A62A424E80000BCDAE /* Build configuration list for PBXProject "ferndi" */; - compatibilityVersion = "Xcode 14.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 846573A22A424E80000BCDAE; - productRefGroup = 846573AD2A424E80000BCDAE /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 846573AB2A424E80000BCDAE /* ferndi */, - 846573B52A424E80000BCDAE /* ferndiTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 846573AA2A424E80000BCDAE /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 846573B42A424E80000BCDAE /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 846573A82A424E80000BCDAE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 846573B12A424E80000BCDAE /* ferndi.docc in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 846573B22A424E80000BCDAE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 846573BC2A424E80000BCDAE /* ferndiTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 846573B92A424E80000BCDAE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 846573AB2A424E80000BCDAE /* ferndi */; - targetProxy = 846573B82A424E80000BCDAE /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 846573BE2A424E80000BCDAE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 846573BF2A424E80000BCDAE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 846573C12A424E80000BCDAE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = rasheedstarlet.ferndi; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 846573C22A424E80000BCDAE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = rasheedstarlet.ferndi; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 846573C42A424E80000BCDAE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = rasheedstarlet.ferndiTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 846573C52A424E80000BCDAE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = rasheedstarlet.ferndiTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 846573A62A424E80000BCDAE /* Build configuration list for PBXProject "ferndi" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 846573BE2A424E80000BCDAE /* Debug */, - 846573BF2A424E80000BCDAE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 846573C02A424E80000BCDAE /* Build configuration list for PBXNativeTarget "ferndi" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 846573C12A424E80000BCDAE /* Debug */, - 846573C22A424E80000BCDAE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 846573C32A424E80000BCDAE /* Build configuration list for PBXNativeTarget "ferndiTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 846573C42A424E80000BCDAE /* Debug */, - 846573C52A424E80000BCDAE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 846573A32A424E80000BCDAE /* Project object */; -} diff --git a/ferndi/ferndi.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ferndi/ferndi.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/ferndi/ferndi.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/ferndi/ferndi.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ferndi/ferndi.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/ferndi/ferndi.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ferndi/ferndi.xcodeproj/project.xcworkspace/xcuserdata/Starlet.xcuserdatad/UserInterfaceState.xcuserstate b/ferndi/ferndi.xcodeproj/project.xcworkspace/xcuserdata/Starlet.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 3cf19de..0000000 Binary files a/ferndi/ferndi.xcodeproj/project.xcworkspace/xcuserdata/Starlet.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/ferndi/ferndi.xcodeproj/xcuserdata/Starlet.xcuserdatad/xcschemes/xcschememanagement.plist b/ferndi/ferndi.xcodeproj/xcuserdata/Starlet.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index a4fe3a7..0000000 --- a/ferndi/ferndi.xcodeproj/xcuserdata/Starlet.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - ferndi.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/ferndi/ferndi/ferndi.docc/ferndi.md b/ferndi/ferndi/ferndi.docc/ferndi.md deleted file mode 100755 index dff1fce..0000000 --- a/ferndi/ferndi/ferndi.docc/ferndi.md +++ /dev/null @@ -1,13 +0,0 @@ -# ``ferndi`` - -Summary - -## Overview - -Text - -## Topics - -### Group - -- ``Symbol`` \ No newline at end of file diff --git a/ferndi/ferndi/ferndi.h b/ferndi/ferndi/ferndi.h deleted file mode 100644 index 9372c3c..0000000 --- a/ferndi/ferndi/ferndi.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// ferndi.h -// ferndi -// -// Created by Rasheed Starlet on 20/06/2023. -// - -#import - -//! Project version number for ferndi. -FOUNDATION_EXPORT double ferndiVersionNumber; - -//! Project version string for ferndi. -FOUNDATION_EXPORT const unsigned char ferndiVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/ferndi/ferndiTests/ferndiTests.swift b/ferndi/ferndiTests/ferndiTests.swift deleted file mode 100644 index 0aed61b..0000000 --- a/ferndi/ferndiTests/ferndiTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// ferndiTests.swift -// ferndiTests -// -// Created by Rasheed Starlet on 20/06/2023. -// - -import XCTest -@testable import ferndi - -class ferndiTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/lib/Insights/cards/delightful.dart b/lib/Insights/cards/delightful.dart new file mode 100644 index 0000000..3ba2a12 --- /dev/null +++ b/lib/Insights/cards/delightful.dart @@ -0,0 +1,48 @@ +import "package:flutter/material.dart"; + +class DelightfulCard extends StatelessWidget { + const DelightfulCard({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + transform: GradientRotation(3.142 / 6), + colors: [ + Color.fromARGB(255, 255, 42, 42), + Color.fromARGB(255, 237, 211, 255), + ] + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: const Padding( + padding: EdgeInsets.all(20), + child: Column( + children: [ + Column( + children: [ + Text("Delightful Spending", + style: TextStyle( + fontSize: 30.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ) + ), + Text("Starts here!", + style: TextStyle( + fontSize: 30.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + ) + ), + ], + ), + ], + ), + ) + ); + } +} diff --git a/lib/Insights/cards/spendInfo.dart b/lib/Insights/cards/spendInfo.dart new file mode 100644 index 0000000..c80d3d9 --- /dev/null +++ b/lib/Insights/cards/spendInfo.dart @@ -0,0 +1,55 @@ +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + + +class SpendInfoCard extends StatelessWidget { + + const SpendInfoCard({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: Border.all( + color: Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: const Padding( + padding: EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + backgroundColor: Color.fromARGB(255, 246, 220, 236), + child: FaIcon( + FontAwesomeIcons.featherPointed, + size: 20.0, + color: Color.fromARGB(255, 255, 0, 93), + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("56", + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 12, 12, 12), + ) + ), + Text("Starts here!", + style: TextStyle( + // fontSize: 30.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 12, 12, 12), + ) + ), + ], + ), + ], + ), + ) + ); + } +} diff --git a/lib/Insights/cards/spendsInfoCard.dart b/lib/Insights/cards/spendsInfoCard.dart new file mode 100644 index 0000000..9e9813a --- /dev/null +++ b/lib/Insights/cards/spendsInfoCard.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:app/providers/spends_provider.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +class SpendInfoCard2 extends ConsumerWidget { + const SpendInfoCard2({super.key}); + + @override + Widget build(BuildContext context, ref) { + final all_spends = ref.watch(spendsCountProvider); + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + const Row( + children: [ + Text( + "Spending Insights", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + ], + ), + const Divider( + height: 10, + color: Color.fromARGB(255, 227, 226, 226), + ), + const SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const CircleAvatar( + backgroundColor: Color.fromARGB(255, 246, 220, 236), + child: FaIcon( + FontAwesomeIcons.arrowUp, + size: 20.0, + color: Color.fromARGB(255, 255, 0, 93), + ), + ), + const SizedBox( + height: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("$all_spends", + style: const TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 12, 12, 12), + )), + const Text("this week", + style: TextStyle( + color: Color.fromARGB(255, 12, 12, 12), + )), + ], + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const CircleAvatar( + backgroundColor: Color.fromARGB(255, 246, 220, 236), + child: FaIcon( + FontAwesomeIcons.arrowUp, + size: 20.0, + color: Color.fromARGB(255, 255, 0, 93), + ), + ), + const SizedBox( + height: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("$all_spends", + style: const TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 12, 12, 12), + )), + const Text("this month", + style: TextStyle( + color: Color.fromARGB(255, 12, 12, 12), + )), + ], + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const CircleAvatar( + backgroundColor: Color.fromARGB(255, 246, 220, 236), + child: FaIcon( + FontAwesomeIcons.arrowUp, + size: 20.0, + color: Color.fromARGB(255, 255, 0, 93), + ), + ), + const SizedBox( + height: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("$all_spends", + style: const TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 12, 12, 12), + )), + const Text("all spends", + style: TextStyle( + color: Color.fromARGB(255, 12, 12, 12), + )), + ], + ), + ], + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/Insights/categories.dart b/lib/Insights/categories.dart new file mode 100644 index 0000000..4626874 --- /dev/null +++ b/lib/Insights/categories.dart @@ -0,0 +1,73 @@ +import "package:app/ops/create/addCategory.dart"; +import "package:app/Insights/category.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +class Categories extends StatefulWidget { + const Categories({super.key}); + + @override + SpendsPageState createState() => SpendsPageState(); +} + +class SpendsPageState extends State { + void _addCategory() { + showModalBottomSheet( + showDragHandle: true, + context: context, + isScrollControlled: true, + builder: (ctx) => const AddCategoryCard(), + ); + } + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: AppBar( + actions: [ + IconButton( + onPressed: _addCategory, + icon: const Icon( + Icons.add, + size: 34, + color: Color.fromARGB(255, 163, 9, 71), + )) + ], + ), + body: ListView( + padding: const EdgeInsets.all(15), + children: [ + Row( + children: [ + const Text( + "All Categories", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const Spacer(), + const FaIcon(FontAwesomeIcons.arrowRightLong, + size: 23, color: Color.fromARGB(255, 151, 151, 151)), + Text( + " $categoriesCount ", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 151, 151, 151), + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + const SizedBox( + height: 5600, + child: CategoryCard(), + ), + ], + )); + } +} diff --git a/lib/Insights/category.dart b/lib/Insights/category.dart new file mode 100644 index 0000000..eab319d --- /dev/null +++ b/lib/Insights/category.dart @@ -0,0 +1,175 @@ +import "package:flutter/material.dart"; +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:app/ops/update/editCategory.dart"; +import "package:flutter_slidable/flutter_slidable.dart"; +import "package:realm/realm.dart"; + +class CategoryItem extends StatelessWidget { + const CategoryItem(this.category, {super.key}); + + final Category category; + + void _showCategoryEditForm(BuildContext context, Category category) { + Navigator.of(context).push(MaterialPageRoute( + builder: (ctx) => EditCategoryCard(category: category))); + } + + @override + Widget build(BuildContext context) { + final int spendsPerCategory = getSpendsByCategory(category.name).length; + // final int totalSpendAmountPerCategory = getSpendsByCategory(category.name) + // .map((spend) => (spend.amount)) + // .reduce((value, element) => value + element); + + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + Slidable( + // Specify a key if the Slidable is dismissible. + key: ValueKey(key), + + // The start action pane is the one at the left or the top side. + startActionPane: ActionPane( + // A motion is a widget used to control how the pane animates. + motion: const ScrollMotion(), + + // A pane can dismiss the Slidable. + dismissible: DismissiblePane(onDismissed: () { + deleteCategory(category); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Category Deleted", + style: + TextStyle(color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + }), + + // All actions are defined in the children parameter. + children: [ + // A SlidableAction can have an icon and/or a label. + SlidableAction( + onPressed: (context) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Slide through to delete", + style: TextStyle( + color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); + }, + backgroundColor: const Color(0xFFFE4A49), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Delete', + ), + SlidableAction( + onPressed: (context) { + _showCategoryEditForm(context, category); + }, + backgroundColor: const Color.fromARGB(255, 96, 150, 249), + foregroundColor: Colors.white, + icon: Icons.edit, + label: 'Edit', + ), + ], + ), + + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Color.fromARGB(50, 57, 154, 1), + child: Text( + category.emoji, + style: const TextStyle( + fontSize: 27, + color: Color.fromARGB(255, 153, 152, 153), + ), + ), + ), + subtitle: Text("${spendsPerCategory} Transactions"), + title: Text( + category.name, + style: const TextStyle( + fontSize: 20, + ), + ), + trailing: Text( + // "- GHS ${totalSpendAmountPerCategory.toString()}", + "-", + style: const TextStyle( + fontSize: 20, + color: Color.fromARGB(255, 163, 9, 71), + ), + ), + ), + ), + ), + const Divider( + height: 0, + color: Color.fromARGB(255, 227, 226, 226), + ), + ], + ), + ); + } +} + +class CategoryCard extends StatelessWidget { + const CategoryCard({super.key}); + + @override + Widget build(BuildContext context) { + return CategoryList(categories: categories); + } +} + +class CategoryList extends StatelessWidget { + const CategoryList({super.key, required this.categories}); + + final RealmResults categories; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), + child: ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: categories.length, + itemBuilder: (BuildContext context, int index) { + return CategoryItem(categories[index]); + }), + )) + ], + ); + } +} diff --git a/lib/accounts/accounts.dart b/lib/accounts/accounts.dart index 82cddcd..17b7e98 100644 --- a/lib/accounts/accounts.dart +++ b/lib/accounts/accounts.dart @@ -1,7 +1,12 @@ -import "package:app/cards/addCategory.dart"; -import "package:app/cards/addWallet.dart"; +import "package:app/ops/create/addCategory.dart"; +import "package:app/ops/create/addWallet.dart"; + import "package:app/cards/wallets.dart"; import "package:app/cards/savings.dart"; + +import "package:app/utility/schema/methods.dart"; + +import "package:avatar_glow/avatar_glow.dart"; import "package:flutter/material.dart"; @@ -16,15 +21,16 @@ class AccountsState extends State { void _addCategory() { showModalBottomSheet( showDragHandle: true, - context: context, + context: context, isScrollControlled: true, builder: (ctx) => const AddCategoryCard(), ); } + void _addWallet() { showModalBottomSheet( showDragHandle: true, - context: context, + context: context, isScrollControlled: true, builder: (ctx) => const AddWalletCard(), ); @@ -35,95 +41,94 @@ class AccountsState extends State { return MaterialApp( title: "Accounts", theme: ThemeData(fontFamily: 'Gilroy'), - home: Scaffold( - appBar: AppBar( - actions: [ - IconButton(onPressed: _addCategory, icon: const Icon(Icons.add, color: Colors.white,)) - ], - title: const Text( - "Accounts", - style: TextStyle( - color: Colors.white - ),), - backgroundColor: const Color.fromARGB(255, 5, 61, 135), + home: Scaffold( + appBar: AppBar( + actions: [ + IconButton( + onPressed: _addCategory, + icon: const Icon( + Icons.add, + size: 34, + color: Color.fromARGB(255, 255, 255, 255), + )) + ], + title: const Text( + "Accounts", + style: TextStyle( + color: Color.fromARGB(255, 255, 255, 255), + ), ), - floatingActionButton: FloatingActionButton( + backgroundColor: const Color.fromARGB(255, 19, 194, 110), + ), + floatingActionButton: AvatarGlow( + glowColor: const Color.fromARGB(255, 48, 136, 6), + child: FloatingActionButton( + heroTag: "AvatarGlow", shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0) - ), - backgroundColor: const Color.fromARGB(255, 5, 61, 135), + borderRadius: BorderRadius.circular(50.0)), + backgroundColor: const Color.fromARGB(255, 48, 136, 6), onPressed: _addWallet, - child: const Icon(Icons.add, color: Colors.white), + child: const Icon( + Icons.add, + color: Colors.white, + size: 35, ), - body: CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: 300, - backgroundColor: Color.fromARGB(255, 5, 61, 135), - flexibleSpace: FlexibleSpaceBar( - background: Padding( - padding: EdgeInsets.all(20.0), - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - savingsCard(), - savingsCard(), - savingsCard(), - savingsCard(), - savingsCard(), - - ], - ) - // savingsCard(), + ), + ), + body: CustomScrollView( + slivers: [ + SliverAppBar( + backgroundColor: const Color.fromARGB(255, 19, 194, 110), + expandedHeight: 200, + flexibleSpace: FlexibleSpaceBar( + background: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + transform: GradientRotation(3.142 / 6), + colors: [ + Color.fromARGB(255, 19, 194, 110), + Color.fromARGB(255, 201, 249, 226), + ]) ), + child: PageView( + children: [ + SelectedWallets(wallet: income), + SelectedWallets(wallet: savings), + SelectedWallets(wallet: debts), + SelectedWallets(wallet: flexible), + ] ), - ), - - SliverToBoxAdapter( - child: Column( - // padding: const EdgeInsets.all(15), - children: [ - // Text( - // "Savings", - // style: TextStyle( - // fontSize: 30.0, - // color: Color.fromARGB(255, 5, 61, 135), - // fontWeight: FontWeight.w700, - // // fontFamily: "WorkSans" - // ), - // ), - // SizedBox( - // height: 12, - // ), - // savingsCard(), - SizedBox( - height: 12, - ), - Text( - "Wallets", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - - SizedBox( - height: 12, - ), - - Divider(), - - SizedBox( - height: 700, - child: WalletsCard(), - ) - ], - ), + )), ), - ], - - ), - )); + const SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.fromLTRB(20, 10.0, 20, 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Your Wallets", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 48, 136, 6), + fontWeight: FontWeight.w700, + ), + ), + SizedBox( + height: 10, + ), + SizedBox( + height: 2800, + child: WalletsCard(), + ), + ], + ), + )), + ], + ) + ) + ); } } diff --git a/lib/accounts/transaction.dart b/lib/accounts/transaction.dart new file mode 100644 index 0000000..b511499 --- /dev/null +++ b/lib/accounts/transaction.dart @@ -0,0 +1,201 @@ +import "package:app/ops/update/editSpend.dart"; +import "package:flutter/material.dart"; +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter_slidable/flutter_slidable.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:realm/realm.dart"; + +class TransactionItem extends StatelessWidget { + const TransactionItem(this.spend, {super.key}); + + final Spend spend; + + void _showSpendEditForm(BuildContext context, Spend spend) { + Navigator.of(context) + .push(MaterialPageRoute(builder: (ctx) => EditSpendCard(spend))); + } + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + ), + child: Column(children: [ + Slidable( + // Specify a key if the Slidable is dismissible. + key: ValueKey(key), + + // The start action pane is the one at the left or the top side. + startActionPane: ActionPane( + // A motion is a widget used to control how the pane animates. + motion: const ScrollMotion(), + + // A pane can dismiss the Slidable. + dismissible: DismissiblePane(onDismissed: () { + deleteSpend(spend); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Transaction Deleted", + style: + TextStyle(color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + }), + + // All actions are defined in the children parameter. + children: [ + // A SlidableAction can have an icon and/or a label. + SlidableAction( + onPressed: (context) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Slide through to delete", + style: TextStyle( + color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); + }, + backgroundColor: const Color(0xFFFE4A49), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Delete', + ), + SlidableAction( + onPressed: (context) { + _showSpendEditForm(context, spend); + }, + backgroundColor: const Color.fromARGB(255, 96, 150, 249), + foregroundColor: Colors.white, + icon: Icons.edit, + label: 'Edit', + ), + ], + ), + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Color.fromARGB(255, 165, 204, 255), + child: FaIcon( + FontAwesomeIcons.featherPointed, + size: 20.0, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + title: Text( + spend.name, + style: const TextStyle( + fontSize: 20, + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("${spend.notes}"), + Row( + children: [ + // const FaIcon( + // FontAwesomeIcons.featherPointed, + // size: 14.0, + // color: Color.fromARGB(255, 5, 61, 135), + // ), + Text("category: ${spend.category?.name.toString()}"), + ], + ), + Row( + children: [ + // Text("${spend.date.weekday}, "), + Text("${spend.date.day} / "), + Text("${spend.date.month} / "), + Text("${spend.date.year}"), + ], + ), + Row( + children: [ + // const FaIcon( + // FontAwesomeIcons.featherPointed, + // size: 14.0, + // color: Color.fromARGB(255, 5, 61, 135), + // ), + Text("wallet: ${spend.wallet?.name.toString()}"), + ], + ), + ], + ), + trailing: Text( + spend.getAmount, + style: const TextStyle( + fontSize: 16, + ), + ), + ), + )), + const Divider( + height: 0, + color: Color.fromARGB(255, 227, 226, 226), + ), + ])); + } +} + +class Transactions extends StatefulWidget { + final Wallet wallet; + const Transactions(this.wallet, {super.key}); + + @override + TransactionState createState() => TransactionState(); +} + +class TransactionState extends State { + late Wallet wallet = getWallet(widget.wallet.id); + + late RealmResults spends = getSpendsByWallet(wallet.name); + + @override + Widget build(BuildContext context) { + return TransactionList(spends: spends); + } +} + +class TransactionList extends StatelessWidget { + const TransactionList({super.key, required this.spends}); + + final RealmResults spends; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), + child: ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: spends.length, + itemBuilder: (BuildContext context, int index) { + return TransactionItem(spends[index]); + }))), + ]); + } +} diff --git a/lib/accounts/transactions.dart b/lib/accounts/transactions.dart new file mode 100644 index 0000000..2d9c691 --- /dev/null +++ b/lib/accounts/transactions.dart @@ -0,0 +1,79 @@ +// import "package:app/home/spends.dart"; +import "package:app/accounts/transaction.dart"; +import "package:app/models/schemas.dart"; +// import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; + +class TransactionsPage extends StatefulWidget { + final Wallet wallet; + const TransactionsPage(this.wallet, {super.key}); + + @override + TransactionsPageState createState() => TransactionsPageState(); +} + +class TransactionsPageState extends State { + late Wallet wallet = getWallet(widget.wallet.id); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: CustomScrollView(slivers: [ + SliverAppBar( + pinned: true, + floating: true, + collapsedHeight: 160, + // actions: [], + flexibleSpace: FlexibleSpaceBar( + background: Container( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 50, + ), + Text( + "${wallet.name}", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + const Align( + alignment: Alignment.topLeft, + child: Text( + "Total Amount Spent", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ), + Text( + "GHS ${wallet.balance}", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + ], + ), + ), + ), + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 0), + child: SizedBox( + height: 5600, + child: Transactions(wallet), + ), + + ), + ) + ])); + } +} diff --git a/lib/cards/addCategory.dart b/lib/cards/addCategory.dart deleted file mode 100644 index 3001a34..0000000 --- a/lib/cards/addCategory.dart +++ /dev/null @@ -1,136 +0,0 @@ -import "package:app/models/schemas.dart"; -import "package:app/utility/schema/methods.dart"; -import "package:flutter/material.dart"; -import "package:realm/realm.dart"; - -class AddCategoryCard extends StatefulWidget { - const AddCategoryCard({super.key}); - - @override - AddCategoryCardState createState() => AddCategoryCardState(); -} - -class AddCategoryCardState extends State { - final _nameController = TextEditingController(); - - @override - void dispose() { - _nameController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.fromLTRB(30, 60, 30, 30), - child: Column( - children: [ - const Align( - alignment: Alignment.topLeft, - child: Text( - "Add Category", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - ), - const SizedBox( - height: 20, - ), - TextField( - controller: _nameController, - maxLength: 50, - keyboardType: TextInputType.text, - decoration: const InputDecoration(label: Text("Category Name")), - ), - - const SizedBox( - height: 40, - ), - - Row( - children: [ - FloatingActionButton.extended( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0)), - label: const Icon(Icons.close), - backgroundColor: const Color.fromARGB(255, 255, 231, 241), - foregroundColor: const Color.fromARGB(255, 163, 9, 71), - onPressed: () { - Navigator.pop(context); - }, - ), - const Spacer(), - FloatingActionButton.extended( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0)), - label: const Text( - " save ", - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w700, - ), - ), - foregroundColor: Colors.white, - backgroundColor: const Color.fromARGB(255, 5, 61, 135), - onPressed: () { - if (_nameController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 255, 231, 241), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "A Category must have a Name", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), - ), - Text( - "Please add a Name before saving.", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), - ), - ], - ), - )); - return; - } - createCategory(Category( - ObjectId(), - _nameController.text, - )); - _nameController.clear(); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 231, 255, 245), - content: Column( - children: [ - Text( - "Category successfully created.", - style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Happy categorizing your Spends! ", - style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), - ), - Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) - ], - ), - ], - ), - )); - }, - ), - ], - ), - ], - ) - ), - ); - } -} diff --git a/lib/cards/addSubscription.dart b/lib/cards/addSubscription.dart deleted file mode 100644 index 7e33594..0000000 --- a/lib/cards/addSubscription.dart +++ /dev/null @@ -1,201 +0,0 @@ -import 'package:app/models/schemas.dart'; -import "package:app/utility/schema/methods.dart"; -import 'package:app/models/schemas.dart' as subscription; -import "package:flutter/material.dart"; -import "package:realm/realm.dart"; - -class AddSubscriptionCard extends StatefulWidget { - const AddSubscriptionCard({super.key}); - - @override - AddSubscriptionCardState createState() => AddSubscriptionCardState(); -} - -class AddSubscriptionCardState extends State { - final _nameController = TextEditingController(); - final _amountController = TextEditingController(); - Duration _selectedDuration = duration.first; - Wallet _selectedWallet = wallets.first; - - @override - void dispose() { - _nameController.dispose(); - _amountController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Padding( - padding: const EdgeInsets.fromLTRB(30, 60, 30, 30), - child: Column( - children: [ - const Align( - alignment: Alignment.topLeft, - child: Text( - "Add Subscription", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - ), - TextField( - controller: _nameController, - maxLength: 50, - decoration: const InputDecoration(label: Text("Name")), - ), - TextField( - controller: _amountController, - maxLength: 5, - keyboardType: TextInputType.number, - decoration: const InputDecoration( - prefix: Text("GHS "), label: Text("Amount")), - ), - Row( - children: [ - DropdownButton( - value: _selectedWallet, - borderRadius: const BorderRadius.all(Radius.circular(20)), - icon: const Icon( - Icons.wallet_sharp, - size: 20, - color: Color.fromARGB(255, 17, 221, 163), - ), - items: wallets - .map((wallet) => DropdownMenuItem( - value: wallet, - child: Text(wallet.name), - )) - .toList(), - onChanged: (value) { - if (value == null) { - return; - } - setState(() { - _selectedWallet = value; - }); - }, - ), - const Spacer(), - DropdownButton( - value: _selectedDuration, - borderRadius: const BorderRadius.all(Radius.circular(20)), - icon: const Icon( - Icons.av_timer, - size: 20, - color: Color.fromARGB(255, 146, 2, 93), - ), - items: duration - .map((duration) => DropdownMenuItem( - value: duration, - child: Text(duration.name), - )) - .toList(), - onChanged: (value) { - if (value == null) { - return; - } - setState(() { - _selectedDuration = value; - }); - }, - ), - ], - ), - const SizedBox( - height: 35, - ), - Row( - children: [ - FloatingActionButton.extended( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0)), - label: const Icon(Icons.close), - backgroundColor: const Color.fromARGB(255, 255, 231, 241), - foregroundColor: const Color.fromARGB(255, 163, 9, 71), - onPressed: () { - Navigator.pop(context); - }, - ), - const Spacer(), - FloatingActionButton.extended( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0)), - label: const Text( - " record ", - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w700, - ), - ), - foregroundColor: Colors.white, - backgroundColor: const Color.fromARGB(255, 5, 61, 135), - onPressed: () { - if (_nameController.text.isEmpty || _amountController.text.isEmpty || _selectedDuration.name.isEmpty || _selectedWallet.name.isEmpty ) { - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 255, 231, 241), - content: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - "Subscription details incomplete", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Please add a name, amount, wallet and duration.", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), - ), - ], - ), - ], - ), - )); - return; - } - addSubscription(subscription.Subscription( - ObjectId(), - _nameController.text, - int.tryParse(_amountController.text) ?? 0, - wallet: _selectedWallet, - duration: _selectedDuration, - DateTime.now())); - _nameController.clear(); - _amountController.clear(); - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 231, 255, 245), - content: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Subscription successfully recorded your. yay! ", - style: TextStyle( - color: Color.fromARGB(255, 9, 163, 99)), - ), - Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) - ], - ), - ], - ), - )); - }, - ), - ], - ) - ], - ) - ), - ); - } -} diff --git a/lib/cards/balance.dart b/lib/cards/balance.dart index f48a9e5..ce7ab4e 100644 --- a/lib/cards/balance.dart +++ b/lib/cards/balance.dart @@ -6,12 +6,22 @@ class BalanceCard extends StatelessWidget { @override Widget build(BuildContext context) { - return Card( - color: const Color.fromARGB(255, 35, 206, 135), - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), + return Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + transform: GradientRotation(3.142 / 6), + colors: [ + Color.fromARGB(255, 19, 194, 110), + Color.fromARGB(255, 201, 249, 226), + ] + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Padding( - padding: const EdgeInsets.all(25), + padding: const EdgeInsets.all(20), child: Column( children: [ Row( @@ -21,46 +31,69 @@ class BalanceCard extends StatelessWidget { children: [ const Text( "Current Balance", - ), - Text("GHS $balance", - style: const TextStyle( - fontSize: 35.0, - fontWeight: FontWeight.w700, - color: Color.fromARGB(255, 5, 61, 135), - )), - ], - ) - ], - ), + style: TextStyle( + color: Color.fromARGB(255, 228, 255, 239), + ) + ), + Row( + children: [ + Text("GHS $balance", + style: const TextStyle( + fontSize: 35.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 255, 255, 255), + )), + ], + ), + ], + ) + ], + ), const SizedBox( - height: 20, + height: 15, ), - Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text("Income"), - Text("GHS ${income.balance}", - style: const TextStyle(fontWeight: FontWeight.w700, - color: Color.fromARGB(255, 5, 61, 135), - ), + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Income", + style: TextStyle(color: Color.fromARGB(255, 228, 255, 239), + ) + ), + Text( + "GHS ${income.balance}", + style: const TextStyle( + fontWeight: FontWeight.w700, + color: Color.fromARGB(255, 255, 255, 255), + ), + ) + ], + ), + const SizedBox( + width: 100, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Spend", + style: TextStyle(color: Color.fromARGB(255, 228, 255, 239), ) - ], - ), - const SizedBox( - width: 100, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text("Spend"), - Text("GHS ${totalSpend}", style: const TextStyle(fontWeight: FontWeight.w700, color: Color.fromARGB(255, 5, 61, 135),),) - ], - ) - ], - ) - ], - ))); + ), + Text( + "GHS ${totalSpend}", + style: const TextStyle( + fontWeight: FontWeight.w700, + color: Color.fromARGB(255, 255, 255, 255), + ), + ) + ], + ) + ], + ) + ], + ) + ), + ); } } diff --git a/lib/cards/newPage.dart b/lib/cards/newPage.dart new file mode 100644 index 0000000..3fae1da --- /dev/null +++ b/lib/cards/newPage.dart @@ -0,0 +1,35 @@ +import "package:flutter/material.dart"; + +class NewPageCard extends StatefulWidget { + const NewPageCard({super.key}); + + @override + NewPageCardState createState() => NewPageCardState(); +} + +class NewPageCardState extends State { + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: Padding( + padding: EdgeInsets.fromLTRB(30, 60, 30, 30), + child: Column( + children: [ + Align( + alignment: Alignment.topLeft, + child: Text( + "New Page", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + ), + ], + ) + ) + ); + } +} diff --git a/lib/cards/savings.dart b/lib/cards/savings.dart index 46c6ae9..17822fd 100644 --- a/lib/cards/savings.dart +++ b/lib/cards/savings.dart @@ -1,89 +1,73 @@ -import "package:avatar_glow/avatar_glow.dart"; import "package:flutter/material.dart"; +import "package:app/models/schemas.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; -class savingsCard extends StatelessWidget { - const savingsCard({super.key}); +class SelectedWallets extends StatelessWidget { + const SelectedWallets({required this.wallet, super.key}); + final Wallet wallet; @override Widget build(BuildContext context) { - return Card( - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)), - child: Padding( - padding: const EdgeInsets.all(25), - child: Column( - children: [ - const Text("Total Amount Saved"), - const Text("GHS 10,000", - style: TextStyle( - fontSize: 35.0, - fontWeight: FontWeight.w700, - color: Color.fromARGB(255, 5, 61, 135), - )), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - const SizedBox(height: 10,), - AvatarGlow( - glowColor: Color.fromARGB(255, 157, 255, 214), - curve: Curves.fastEaseInToSlowEaseOut, - child: FloatingActionButton( - shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)), - elevation: 3, - onPressed: () {}, - foregroundColor: const Color.fromARGB(255, 9, 163, 99), - backgroundColor: const Color.fromARGB(255, 231, 255, 245), - child: const Icon(Icons.add, - size: 35, - ), - ), - ), - const SizedBox(height: 10,), - const Text("Add Money") - ], + return Padding( + padding: const EdgeInsets.fromLTRB(0, 20, 0, 10), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + FloatingActionButton( + heroTag: "add", + mini: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50)), + elevation: 0, + onPressed: () {}, + backgroundColor: const Color.fromARGB(255, 204, 241, 228), + child: const Icon( + Icons.add, + size: 25, + color: Color.fromARGB(255, 48, 136, 6), ), - Column( - children: [ - const SizedBox(height: 10,), - FloatingActionButton( - shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)), - elevation: 3, - onPressed: () {}, - backgroundColor: const Color.fromARGB(255, 255, 231, 241), - foregroundColor: const Color.fromARGB(255, 163, 9, 71), - child: const Icon(Icons.remove, - size: 35, - ), - ), - const SizedBox(height: 10,), - const Text("Withdraw") - ], - ), - Column( - children: [ - const SizedBox(height: 10,), - FloatingActionButton( - shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)), - elevation: 3, - onPressed: () {}, - backgroundColor: const Color.fromARGB(255, 230, 243, 255), - foregroundColor: const Color.fromARGB(2255, 0, 128, 255), - child: const Icon(Icons.wallet, - size: 35, - ), - ), - const SizedBox(height: 10,), - const Text("Transfer") - ], - ), - - ], - ) - ], - ) - ) + ), + const Text("Wallets", + style: TextStyle( + fontSize: 25.0, + color: Color.fromARGB(255, 255, 255, 255), + )), + FloatingActionButton( + heroTag: "edit", + mini: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50)), + elevation: 0, + onPressed: () {}, + backgroundColor: const Color.fromARGB(255, 204, 241, 228), + child: const FaIcon(FontAwesomeIcons.penToSquare, + size: 20, color: Color.fromARGB(255, 48, 136, 6)), + ), + ], + ), + const SizedBox( + height: 12, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("${wallet.bal}", + style: const TextStyle( + fontSize: 35.0, + fontWeight: FontWeight.w700, + color: Color.fromARGB(255, 255, 255, 255), + )), + ], + ), + Text("${wallet.name}", + style: const TextStyle( + fontSize: 23.0, + color: Color.fromARGB(255, 255, 255, 255), + )), + ], + ) ); } } diff --git a/lib/cards/subscriptions.dart b/lib/cards/subscriptions.dart new file mode 100644 index 0000000..38b9960 --- /dev/null +++ b/lib/cards/subscriptions.dart @@ -0,0 +1,202 @@ +import "package:flutter/material.dart"; +import 'package:app/models/schemas.dart' as my; +import "package:app/utility/schema/methods.dart"; +import "package:app/ops/update/editSubscription.dart"; +import "package:flutter_slidable/flutter_slidable.dart"; +import "package:realm/realm.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +class SubscriptionItem extends StatelessWidget { + const SubscriptionItem(this.subscription, {super.key}); + + final my.Subscription subscription; + + void _showSubscriptionEditForm( + BuildContext context, my.Subscription subscription) { + Navigator.of(context).push(MaterialPageRoute( + builder: (ctx) => EditSubscriptionCard(subscription))); + } + + @override + Widget build(BuildContext context) { + return Slidable( + // Specify a key if the Slidable is dismissible. + key: ValueKey(key), + + // The start action pane is the one at the left or the top side. + startActionPane: ActionPane( + // A motion is a widget used to control how the pane animates. + motion: const ScrollMotion(), + + // A pane can dismiss the Slidable. + dismissible: DismissiblePane(onDismissed: () { + deleteSubscription(subscription); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Subscription Deleted.", + style: TextStyle(color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + }), + + // All actions are defined in the children parameter. + children: [ + // A SlidableAction can have an icon and/or a label. + SlidableAction( + onPressed: (context) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Please slide through to delete Subscription.", + style: TextStyle(color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); + }, + backgroundColor: const Color(0xFFFE4A49), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Delete', + ), + + SlidableAction( + onPressed: (context) { + _showSubscriptionEditForm(context, subscription); + }, + backgroundColor: const Color.fromARGB(255, 96, 150, 249), + foregroundColor: Colors.white, + icon: Icons.edit, + label: 'Edit', + ), + ], + ), + child: Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + child: Padding( + padding: const EdgeInsets.all(20), + child: Column(children: [ + Row( + children: [ + const CircleAvatar( + backgroundColor: Color.fromARGB(255, 215, 237, 253), + child: FaIcon( + FontAwesomeIcons.solidCreditCard, + size: 20, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const SizedBox( + width: 10, + ), + Text( + subscription.name, + style: const TextStyle( + fontSize: 20.0, + ), + ), + const Spacer(), + Text( + "- GHS ${subscription.getAmount}", + style: const TextStyle( + fontSize: 16, + color: Color.fromARGB(255, 163, 9, 71), + ), + ), + ], + ), + + const SizedBox( + height: 10, + ), + Row(children: [ + Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(10.0), + ), + child: const Text(" From ") + ), + const SizedBox( + width: 10, + ), + Text( + "${subscription.from}", + style: const TextStyle( + fontSize: 20.0, + ), + ), + const SizedBox( + width: 10, + ), + Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(10.0), + ), + child: const Text(" per ") + ), + const SizedBox( + width: 10, + ), + Text( + " ${subscription.period}", + style: const TextStyle( + color: Color.fromARGB(255, 148, 152, 158), + fontSize: 17.0, + ), + ), + + ],), + ]), + ) + ), + ); + } +} + +class SubscriptionsCard extends StatelessWidget { + const SubscriptionsCard({super.key}); + + @override + Widget build(BuildContext context) { + return SubscriptionList( + subscriptions: subscriptions, + ); + } +} + +class SubscriptionList extends StatelessWidget { + const SubscriptionList({super.key, required this.subscriptions}); + + final RealmResults subscriptions; + + @override + Widget build(BuildContext context) { + return ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: subscriptions.length, + itemBuilder: (BuildContext context, int index) { + return SubscriptionItem(subscriptions[index]); + }); + } +} diff --git a/lib/cards/subscriptionsBalanceCard.dart b/lib/cards/subscriptionsBalanceCard.dart new file mode 100644 index 0000000..ec3039c --- /dev/null +++ b/lib/cards/subscriptionsBalanceCard.dart @@ -0,0 +1,148 @@ +import "package:flutter/material.dart"; +import "package:app/utility/schema/methods.dart"; + +class SubscriptionsBalanceCard extends StatelessWidget { + const SubscriptionsBalanceCard({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + border: Border( + bottom: + BorderSide(width: 5.0, color: Color.fromARGB(255, 5, 61, 135)), + right: + BorderSide(width: 5.0, color: Color.fromARGB(255, 5, 61, 135)), + ), + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(20))), + child: Card( + color: Colors.white, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + child: Padding( + padding: const EdgeInsets.all(15), + child: Column( + children: [ + Column( + children: [ + const Text("Total Money Spent on Subscriptions", + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w500, + color: Color.fromARGB(255, 5, 61, 135), + )), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("GHS $subBalance", + style: const TextStyle( + fontSize: 35.0, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 5, 61, 135), + )), + const Text(".00", + style: TextStyle( + fontSize: 35.0, + color: Color.fromARGB(255, 202, 233, 255), + )), + ], + ), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 12.0, 0, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + "monthly", + style: TextStyle( + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + Row( + children: [ + Text( + "GHS $totalMonthlySubscriptionsBalance", + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const Text(".00", + style: TextStyle( + color: Color.fromARGB(255, 202, 233, 255), + )), + ], + ) + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + "yearly", + style: TextStyle( + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + Row( + children: [ + Text( + "GHS $totalYearlySubscriptionsBalance", + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const Text(".00", + style: TextStyle( + color: Color.fromARGB(255, 202, 233, 255), + )), + ], + ) + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + "one time", + style: TextStyle( + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + Row( + children: [ + Text( + "GHS $totalOneTimeSubscriptionsBalance", + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 17, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const Text(".00", + style: TextStyle( + color: Color.fromARGB(255, 202, 233, 255), + )), + ], + ) + ], + ), + ], + ), + ), + ], + ))), + ); + } +} diff --git a/lib/cards/transfer.dart b/lib/cards/transfer.dart new file mode 100644 index 0000000..7b17a94 --- /dev/null +++ b/lib/cards/transfer.dart @@ -0,0 +1,206 @@ +import "package:flutter/material.dart"; +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; + + + +class TransferCard extends StatefulWidget { + const TransferCard({super.key}); + + @override + TransferCardState createState() => TransferCardState(); +} + +class TransferCardState extends State { + Wallet _fromWallet = wallets.first; + Wallet _toWallet = wallets.last; + final _amountController = TextEditingController(); + + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.fromLTRB(30, 60, 30, 30), + child: Column( + children: [ + const Align( + alignment: Alignment.topLeft, + child: Text( + "Transfer", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + ), + Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 240, 240, 240), + borderRadius: BorderRadius.circular(8.0)), + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + "The amount you type below will be added to your Wallet's balance.", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + ), + ), + ) + ), + const SizedBox( + height: 20, + ), + TextField( + controller: _amountController, + maxLength: 10, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + prefix: Text("GHS "), + ), + ), + const Align( + alignment: Alignment.topLeft, + child: Text( + "From", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ), + DropdownButton( + value: _fromWallet, + hint: const Text("Wallet"), + icon: const Icon( + Icons.wallet_sharp, + color: Color.fromARGB(255, 151, 151, 151), + ), + isExpanded: true, + borderRadius: const BorderRadius.all(Radius.circular(20)), + items: wallets + .map((wallet) => DropdownMenuItem( + value: wallet, + child: Text(wallet.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _fromWallet = value; + }); + }, + ), + const Align( + alignment: Alignment.topLeft, + child: Text( + "To", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ), + DropdownButton( + value: _toWallet, + hint: const Text("Wallet"), + icon: const Icon( + Icons.wallet_sharp, + color: Color.fromARGB(255, 151, 151, 151), + ), + isExpanded: true, + borderRadius: const BorderRadius.all(Radius.circular(20)), + items: wallets + .map((wallet) => DropdownMenuItem( + value: wallet, + child: Text(wallet.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _toWallet = value; + }); + }, + ), + const SizedBox( + height: 20, + ), + FloatingActionButton.extended( + heroTag: "save", + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + // if (balance.isEmpty || name.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "A Wallet must have a Name and a Balance", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Text( + "Please add a Name and Balance before saving.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + return; + } + // updateWallet(Wallet( + // walletToEdit.id, + // name, + // int.parse(balance), + // )); + // ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + // backgroundColor: Color.fromARGB(255, 231, 255, 245), + // content: Column( + // children: [ + // Text( + // "Wallet successfully updated.", + // style: TextStyle( + // color: Color.fromARGB(255, 9, 163, 99)), + // ), + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text( + // "Happy tracking your Spends! ", + // style: TextStyle( + // color: Color.fromARGB(255, 9, 163, 99)), + // ), + // Icon(Icons.sentiment_very_satisfied, + // color: Color.fromARGB(255, 9, 163, 9)) + // ], + // ), + // ], + // ), + // )); + // }, + ), + ], + ) + ) + ); + } +} diff --git a/lib/cards/wallets.dart b/lib/cards/wallets.dart index b748077..5225d7c 100644 --- a/lib/cards/wallets.dart +++ b/lib/cards/wallets.dart @@ -1,7 +1,11 @@ +import "package:app/accounts/transactions.dart"; +import "package:app/ops/update/topUpWallet.dart"; import "package:flutter/material.dart"; import "package:app/models/schemas.dart"; +import "package:app/ops/update/editWallet.dart"; import "package:app/utility/schema/methods.dart"; import "package:flutter_slidable/flutter_slidable.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:realm/realm.dart"; class WalletItem extends StatelessWidget { @@ -9,8 +13,43 @@ class WalletItem extends StatelessWidget { final Wallet wallet; + void _showWalletEditForm(BuildContext context, Wallet wallet) { + Navigator.of(context) + .push(MaterialPageRoute(builder: (ctx) => EditWalletCard(wallet))); + } + + void _showTopUpWalletPage(BuildContext context, Wallet wallet) { + showModalBottomSheet( + showDragHandle: true, + context: context, + isScrollControlled: true, + builder: (ctx) => TopUpWalletCard(wallet), + ); + } + + void _showEditPage(BuildContext context, Wallet wallet) { + showModalBottomSheet( + showDragHandle: true, + context: context, + isScrollControlled: true, + builder: (ctx) => EditWalletCard(wallet), + ); + } + + void _showTransactionsPage(BuildContext context, Wallet wallet) { + showModalBottomSheet( + showDragHandle: true, + context: context, + isScrollControlled: true, + builder: (ctx) => TransactionsPage(wallet), + ); + } + @override Widget build(BuildContext context) { + + late int spendsCount = getSpendsByWallet(wallet.name).length; + return Slidable( // Specify a key if the Slidable is dismissible. key: ValueKey(key), @@ -23,19 +62,18 @@ class WalletItem extends StatelessWidget { // A pane can dismiss the Slidable. dismissible: DismissiblePane(onDismissed: () { deleteWallet(wallet); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 255, 231, 241), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Wallet Deleted", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), - ), - ], - ), - )); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Wallet Deleted", + style: TextStyle(color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); }), // All actions are defined in the children parameter. @@ -43,116 +81,156 @@ class WalletItem extends StatelessWidget { // A SlidableAction can have an icon and/or a label. SlidableAction( onPressed: (context) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 230, 243, 255), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Slide through to delete", - style: TextStyle( - color: Color.fromARGB(255, 0, 128, 255)), - ), - ], - ), - )); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Slide through to delete", + style: + TextStyle(color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); }, backgroundColor: const Color(0xFFFE4A49), foregroundColor: Colors.white, icon: Icons.delete, label: 'Delete', ), + SlidableAction( + onPressed: (context) { + _showWalletEditForm(context, wallet); + }, + backgroundColor: const Color.fromARGB(255, 96, 150, 249), + foregroundColor: Colors.white, + icon: Icons.edit, + label: 'Edit', + ), ], ), child: Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 20), - child: ExpansionTile( - shape: const Border(), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - wallet.name, - style: const TextStyle( - fontSize: 20.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(71, 47, 136, 6), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ExpansionTile( + collapsedBackgroundColor: Colors.white, + collapsedShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + ), + backgroundColor: Colors.white, + + leading: const CircleAvatar( + backgroundColor: Color.fromARGB(255, 204, 241, 228), + child: FaIcon( + FontAwesomeIcons.wallet, + size: 20, + color: Color.fromARGB(255, 48, 136, 6), ), ), - const SizedBox( - width: 30, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + wallet.name, + style: const TextStyle( + color: Color.fromARGB(255, 0, 0, 0), + ), + ), + ], ), - Text( + + subtitle: Text( wallet.bal, style: const TextStyle( - fontSize: 12.0, - color: Color.fromARGB(255, 95, 98, 103), - fontWeight: FontWeight.w700, + fontSize: 20.0, + color: Color.fromARGB(255, 48, 136, 6), + fontWeight: FontWeight.w600, ), ), - ], + + children: [ + Row( + children: [ + const Padding(padding: EdgeInsets.all(7)), + GestureDetector( + onTap: () { + _showTransactionsPage(context, wallet); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(7), + color: const Color.fromARGB(200, 109, 189, 255), + child: Text( + " $spendsCount transactions ", + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ))), + ), + const SizedBox( + width: 20, + ), + GestureDetector( + onTap: () { + _showEditPage(context, wallet); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(7), + color: const Color.fromARGB(199, 71, 34, 255), + child: const Text( + " edit ", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ))), + ), + const SizedBox( + width: 20, + ), + GestureDetector( + onTap: () { + _showTopUpWalletPage(context, wallet); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(5), + color: const Color.fromARGB(255, 23, 213, 110), + child: const Text( + " top up ", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ))), + ), + ]), + const SizedBox( + height: 20, + ), + ], + // remove the chevron up/down icon at the end of the ExpandedTIle Widget + // trailing: const SizedBox.shrink(), + ), ), - subtitle: const Row(children: []), - children: [ - Row(children: [ - const Padding(padding: EdgeInsets.all(7)), - ClipRRect( - borderRadius: BorderRadius.circular(5), - child: Container( - padding: const EdgeInsets.all(7), - color: const Color.fromARGB(200, 109, 189, 255), - child: const Text( - "transactions", - style: TextStyle(color: Colors.white), - ))), - const SizedBox(width: 10,), - ClipRRect( - borderRadius: BorderRadius.circular(7), - child: Container( - padding: const EdgeInsets.all(7), - color: const Color.fromARGB(199, 71, 34, 255), - child: const Text( - "edit", - style: TextStyle(color: Colors.white), - ))), - ]), - - const SizedBox(height: 10,), - - Row(children: [ - const Padding(padding: EdgeInsets.all(7)), - ClipRRect( - borderRadius: BorderRadius.circular(7), - child: Container( - padding: const EdgeInsets.all(7), - color: const Color.fromARGB(136, 12, 227, 123), - child: const Text( - "add", - style: TextStyle(color: Colors.white), - ))), - const SizedBox(width: 10,), - ClipRRect( - borderRadius: BorderRadius.circular(7), - child: Container( - padding: const EdgeInsets.all(7), - color: const Color.fromARGB(135, 255, 174, 0), - child: const Text( - "transfer", - style: TextStyle(color: Colors.white), - ))), - const SizedBox(width: 10,), - ClipRRect( - borderRadius: BorderRadius.circular(7), - child: Container( - padding: const EdgeInsets.all(7), - color: const Color.fromARGB(136, 255, 0, 174), - child: const Text( - "withdraw", - style: TextStyle(color: Colors.white), - ))), - ]), - const SizedBox(height: 10,), - ], ))); } } @@ -176,6 +254,8 @@ class WalletList extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), itemCount: wallets.length, itemBuilder: (BuildContext context, int index) { return WalletItem(wallets[index]); diff --git a/lib/home/home.dart b/lib/home/home.dart index 20d0e3b..6b33796 100644 --- a/lib/home/home.dart +++ b/lib/home/home.dart @@ -1,7 +1,6 @@ -import "package:app/home/spends.dart"; +import "package:app/home/insights.dart"; +import "package:app/home/spending.dart"; import "package:flutter/material.dart"; -import "package:app/cards/balance.dart"; -import "package:app/cards/addSpend.dart"; class Home extends StatefulWidget { const Home({super.key}); @@ -11,53 +10,48 @@ class Home extends StatefulWidget { } class HomeState extends State { - @override Widget build(BuildContext context) { - return MaterialApp( - title: "Home", - theme: ThemeData(fontFamily: 'Gilroy'), - home: Scaffold( + return DefaultTabController( + length: 2, + child: Scaffold( appBar: AppBar( - // actions: [ - // IconButton(onPressed: _addSpend, icon: const Icon(Icons.add)) - // ], - title: const Text("Home", style: TextStyle( - color: Colors.white - ),), + title: const Text( + "Ferndi", + style: TextStyle( + fontSize: 30, + color: Colors.white, + ), + ), backgroundColor: const Color.fromARGB(255, 5, 61, 135), ), - body: ListView( - padding: const EdgeInsets.all(15), - children: const [ - BalanceCard(), - SizedBox( - height: 10, - ), - AddSpendCard(), - SizedBox( - height: 20, - ), - Text( - "Spend History", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - // fontFamily: "WorkSans" - ), - ), - SizedBox( - height: 10, - ), - SizedBox( - //padding: EdgeInsets.fromLTRB(15, 10, 0, 0), - height: 650, - // height: double.infinity, - child: Spends(), + body: const Column( + children: [ + TabBar( + dividerColor: Color.fromARGB(255, 255, 255, 255), + indicatorColor: Color.fromARGB(255, 5, 61, 135), + indicatorWeight: 4, + splashBorderRadius: BorderRadius.all(Radius.circular(50)), + labelColor: Color.fromARGB(255, 5, 61, 135), + tabs: [ + Tab( + text: "Spending", + ), + Tab( + text: "Insights", + ), + ], ), - ], - /// [[ TODO ]] button to check past spends grouped in months - ))); + Expanded( + child: TabBarView( + children: [ + Spending(), + Insights(), + ] + ) + ) + ]) + ) + ); } } diff --git a/lib/home/insights.dart b/lib/home/insights.dart new file mode 100644 index 0000000..c90d271 --- /dev/null +++ b/lib/home/insights.dart @@ -0,0 +1,134 @@ +import "package:app/Insights/cards/delightful.dart"; +import 'package:app/Insights/cards/spendInfo.dart'; +import 'package:app/Insights/Categories.dart'; +import 'package:app/Insights/cards/spendsInfoCard.dart'; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; +// import "package:flutter_riverpod/flutter_riverpod.dart"; + +// Cards + +// Smart Card +// First Card gives you useful information + +// Buttons +// total categories +// Icon +// number +// button to see all categories +// button to add categories + +// total spends +// 4 in a row +// - this week +// - this month +// - all spends +// - since you joined +// Icon +// number +// button to add categories + +// category with the highest number of spends +// Icon +// number + +// wallet with the highest number of spends +// Icon +// number + +// Category with the most expensive spend +// Icon +// number +// button to add category + +// Wallet with the most expensive spend +// Icon +// number +// button to add categories + +// total wallets +// Icon +// number +// button to add wallet + +// Streak + +class Insights extends StatefulWidget { + const Insights({super.key}); + + @override + InsightsState createState() => InsightsState(); +} + +class InsightsState extends State { + @override + Widget build(BuildContext context) { + return ListView(padding: const EdgeInsets.all(15), children: [ + const DelightfulCard(), + const SizedBox( + height: 20, + ), + const SpendInfoCard2(), + const SizedBox( + height: 20, + ), + GestureDetector( + onTap: () => { + Navigator.push(context, + MaterialPageRoute(builder: (context) => const Categories())) + }, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + Row( + children: [ + const Text( + "All categories", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + const Spacer(), + Text( + " $categoriesCount ", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 151, 151, 151), + ), + ), + ], + ), + ], + ), + ), + ), + const SizedBox( + height: 20, + ), + const Row( + children: [ + SpendInfoCard(), + SizedBox( + width: 20, + ), + SpendInfoCard(), + SizedBox( + width: 20, + ), + SpendInfoCard(), + ], + ), + const SizedBox( + height: 20, + ), + ]); + } +} diff --git a/lib/home/spendHistory.dart b/lib/home/spendHistory.dart new file mode 100644 index 0000000..12d9663 --- /dev/null +++ b/lib/home/spendHistory.dart @@ -0,0 +1,129 @@ +import "package:app/home/spends.dart"; +// import "package:app/utility/schema/methods.dart"; +import "package:app/providers/spends_provider.dart"; +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +class SpendsPage extends ConsumerStatefulWidget { + const SpendsPage({super.key}); + + @override + SpendsPageState createState() => SpendsPageState(); +} + +class SpendsPageState extends ConsumerState { + @override + Widget build(BuildContext context) { + + final spendsCount = ref.watch(spendsCountProvider); + + return MaterialApp( + title: "Home", + theme: ThemeData(fontFamily: 'Gilroy'), + home: Scaffold( + appBar: AppBar( + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: const Padding( + padding: EdgeInsets.fromLTRB(20, 0, 0, 0), + child: FaIcon(FontAwesomeIcons.arrowLeft, + color: Color.fromARGB(255, 255, 255, 255)), + ), + ), + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + ), + body: ListView( + padding: const EdgeInsets.all(15), + children: [ + Container( + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + borderRadius: BorderRadius.circular(45.0), + ), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(10), + color: const Color.fromARGB(255, 5, 61, 135), + child: const Text( + " this week ", + style: TextStyle( + color: Colors.white, + fontSize: 17, + fontWeight: FontWeight.w600, + ), + ))), + const Spacer(), + ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(10), + color: const Color.fromARGB(198, 255, 255, 255), + child: const Text( + " this month ", + style: TextStyle( + color: Color.fromARGB(255, 5, 61, 135), + fontSize: 17, + fontWeight: FontWeight.w600, + ), + ))), + const Spacer(), + ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(10), + color: const Color.fromARGB(134, 255, 255, 255), + child: const Text( + " this year ", + style: TextStyle( + color: Color.fromARGB(255, 5, 61, 135), + fontSize: 17, + fontWeight: FontWeight.w600, + ), + ))), + ], + ), + ), + const SizedBox( + height: 15, + ), + Row( + children: [ + const Text( + "Spend History", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + const Spacer(), + const FaIcon(FontAwesomeIcons.arrowRightLong, + size: 23, color: Color.fromARGB(255, 151, 151, 151)), + Text( + " $spendsCount ", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + const SizedBox( + height: 5600, + child: Spends(), + ), + ], + ))); + } +} diff --git a/lib/home/spending.dart b/lib/home/spending.dart new file mode 100644 index 0000000..bde5b72 --- /dev/null +++ b/lib/home/spending.dart @@ -0,0 +1,74 @@ +import "package:app/home/spendHistory.dart"; +import "package:app/home/spends.dart"; +import "package:app/providers/spends_provider.dart"; +import "package:flutter/material.dart"; +import "package:app/cards/balance.dart"; +import "package:app/ops/create/addSpend.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +class Spending extends ConsumerStatefulWidget { + const Spending({super.key}); + + @override + HomeState createState() => HomeState(); +} + +class HomeState extends ConsumerState { + @override + Widget build(BuildContext context) { + final spendsCount = ref.watch(spendsCountProvider); + return ListView( + padding: const EdgeInsets.all(15), + children: [ + const BalanceCard(), + const SizedBox( + height: 10, + ), + const AddSpendCard(), + const SizedBox( + height: 20, + ), + GestureDetector( + onTap: () => { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SpendsPage())) + }, + child: Row( + children: [ + const Text( + "Spend History", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + const Spacer(), + const FaIcon(FontAwesomeIcons.arrowRightLong, + size: 23, color: Color.fromARGB(255, 151, 151, 151)), + Text( + " $spendsCount ", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ], + ), + ), + const SizedBox( + height: 10, + ), + const SizedBox( + //padding: EdgeInsets.fromLTRB(15, 10, 0, 0), + height: 2800, + // height: double.infinity, + child: Spends(), + ), + ]); + } +} \ No newline at end of file diff --git a/lib/home/spends.dart b/lib/home/spends.dart index c1b06d1..d83e747 100644 --- a/lib/home/spends.dart +++ b/lib/home/spends.dart @@ -1,104 +1,145 @@ import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:app/providers/spends_provider.dart"; import "package:app/models/schemas.dart"; import "package:app/utility/schema/methods.dart"; +import "package:app/ops/update/editSpend.dart"; import "package:flutter_slidable/flutter_slidable.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:realm/realm.dart"; -class SpendItem extends StatelessWidget { +class SpendItem extends ConsumerWidget { const SpendItem(this.spend, {super.key}); final Spend spend; + void _showSpendEditForm(BuildContext context, Spend spend) { + Navigator.of(context) + .push(MaterialPageRoute(builder: (ctx) => EditSpendCard(spend))); + } + @override - Widget build(BuildContext context) { - return Slidable( - // Specify a key if the Slidable is dismissible. - key: ValueKey(key), + Widget build(BuildContext context, WidgetRef ref) { + // ref.watch(spendsProvider); + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + Slidable( + // Specify a key if the Slidable is dismissible. + key: ValueKey(key), - // The start action pane is the one at the left or the top side. - startActionPane: ActionPane( - // A motion is a widget used to control how the pane animates. - motion: const ScrollMotion(), + // The start action pane is the one at the left or the top side. + startActionPane: ActionPane( + // A motion is a widget used to control how the pane animates. + motion: const ScrollMotion(), - // A pane can dismiss the Slidable. - dismissible: DismissiblePane(onDismissed: () { - deleteSpend(spend); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 255, 231, 241), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Spend Deleted", - style: TextStyle( - color: Color.fromARGB(255, 163, 9, 71)), + // A pane can dismiss the Slidable. + dismissible: DismissiblePane(onDismissed: () { + deleteSpend(spend); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Spend Deleted", + style: + TextStyle(color: Color.fromARGB(255, 163, 9, 71)), + ), + ], ), - ], - ), - )); - }), + )); + ref.read(spendsCountProvider.notifier).state--; + }), - // All actions are defined in the children parameter. - children: [ - // A SlidableAction can have an icon and/or a label. - SlidableAction( - onPressed: (context) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - backgroundColor: Color.fromARGB(255, 230, 243, 255), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Slide through to delete", - style: TextStyle( - color: Color.fromARGB(255, 0, 128, 255)), - ), - ], + // All actions are defined in the children parameter. + children: [ + // A SlidableAction can have an icon and/or a label. + SlidableAction( + onPressed: (context) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Slide through to delete", + style: TextStyle( + color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); + }, + backgroundColor: const Color(0xFFFE4A49), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Delete', + ), + SlidableAction( + onPressed: (context) { + _showSpendEditForm(context, spend); + }, + backgroundColor: const Color.fromARGB(255, 96, 150, 249), + foregroundColor: Colors.white, + icon: Icons.edit, + label: 'Edit', + ), + ], + ), + + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), + child: ListTile( + leading: CircleAvatar( + backgroundColor: Color.fromARGB(255, 205, 227, 255), + child: Text(spend.category!.emoji, style: const TextStyle( fontSize: 25),), + ), + title: Text( + spend.name, + style: const TextStyle( + fontSize: 20, + ), + ), + subtitle: Text("${spend.notes}"), + trailing: Text( + spend.getAmount, + style: const TextStyle( + fontSize: 16, + ), ), - )); - }, - backgroundColor: const Color(0xFFFE4A49), - foregroundColor: Colors.white, - icon: Icons.delete, - label: 'Delete', + ), + ), + ), + const Divider( + height: 0, + color: Color.fromARGB(255, 227, 226, 226), ), - // SlidableAction( - // onPressed: (context) {}, - // backgroundColor: Color.fromARGB(255, 96, 150, 249), - // // backgroundColor: Color(0xFF21B7CA), - // foregroundColor: Colors.white, - // icon: Icons.edit, - // label: 'Edit', - // ), ], ), - - child: ListTile( - leading: const FaIcon( - FontAwesomeIcons.featherPointed, - size: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - ), - title: Text(spend.name, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w500),), - subtitle: Text(spend.notes), - trailing: Text(spend.getAmount), - ), ); } } -class Spends extends StatefulWidget { +class Spends extends ConsumerStatefulWidget { const Spends({super.key}); @override SpendState createState() => SpendState(); } -class SpendState extends State { +class SpendState extends ConsumerState { + @override Widget build(BuildContext context) { - return SpendList(spends: spends); + final spendsFromProvider = ref.watch(spendsProvider); + return SpendList(spends: spendsFromProvider); } } @@ -112,11 +153,19 @@ class SpendList extends StatelessWidget { return Column( children: [ Expanded( + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 245, 245, 245), + borderRadius: BorderRadius.circular(20.0), + ), child: ListView.builder( - itemCount: spends.length, - itemBuilder: (BuildContext context, int index) { - return SpendItem(spends[index]); - })) + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: spends.length, + itemBuilder: (BuildContext context, int index) { + return SpendItem(spends[index]); + }), + )) ], ); } diff --git a/lib/main.dart b/lib/main.dart index 8f717d7..3d1cd60 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:app/onboarding/welcome.dart'; import "package:flutter/material.dart"; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'navigation.dart'; @@ -11,7 +12,11 @@ Future main() async { SharedPreferences preference = await SharedPreferences.getInstance(); onBoard = preference.getInt("onBoard"); await preference.setInt("onBoard", 1); - runApp(const MyApp()); + runApp( + const ProviderScope( + child: MyApp(), + ) + ); } class MyApp extends StatelessWidget { diff --git a/lib/models/schemas.dart b/lib/models/schemas.dart index 9c5cf8b..8c459b8 100644 --- a/lib/models/schemas.dart +++ b/lib/models/schemas.dart @@ -7,27 +7,24 @@ final config = Configuration.local([ Subscription.schema, Category.schema, Duration.schema, -], schemaVersion: 2, shouldDeleteIfMigrationNeeded: true); +], schemaVersion: 3, shouldDeleteIfMigrationNeeded: true); final realm = Realm(config); -final Categories = [ - Category(ObjectId(), "Health"), - Category(ObjectId(), "Food"), - Category(ObjectId(), "Electricity"), - Category(ObjectId(), "Groceries"), - Category(ObjectId(), "Transportation"), - Category(ObjectId(), "Miscellaneous"), +final List onboardWallets = [ + Wallet(ObjectId(), "Savings", 0), + Wallet(ObjectId(), "Debts", 0), + Wallet(ObjectId(), "Flexible", 0), + Wallet(ObjectId(), "Income", 0), ]; // Create a bunch of Durations when getting onboard -final Durations = [ +final durations = [ Duration(ObjectId(), "month"), Duration(ObjectId(), "year"), Duration(ObjectId(), "one time"), ]; - @RealmModel() class _Duration { @PrimaryKey() @@ -95,9 +92,32 @@ class _Category { @PrimaryKey() late ObjectId id; late String name; + late String emoji; + late String color; late List<_Spend> category; } +Wallet getWallet(ObjectId id) { + final walletToEdit = realm.query('id == \$0', [id]).first; + return walletToEdit; +} + +Category getCategory(ObjectId id) { + final categoryToEdit = realm.query('id == \$0', [id]).first; + return categoryToEdit; +} + +Spend getSpend(ObjectId id) { + final spendToEdit = realm.query('id == \$0', [id]).first; + return spendToEdit; +} + +Subscription getSubscription(ObjectId id) { + final subscriptionToEdit = realm.query('id == \$0', [id]).first; + return subscriptionToEdit; +} + + //============ TO SUPPORT OLD CODE // const WalletIcons = { diff --git a/lib/models/schemas.g.dart b/lib/models/schemas.g.dart index 631936b..4872ec4 100644 --- a/lib/models/schemas.g.dart +++ b/lib/models/schemas.g.dart @@ -319,11 +319,15 @@ class Category extends _Category with RealmEntity, RealmObjectBase, RealmObject { Category( ObjectId id, - String name, { + String name, + String emoji, + String color, { Iterable category = const [], }) { RealmObjectBase.set(this, 'id', id); RealmObjectBase.set(this, 'name', name); + RealmObjectBase.set(this, 'emoji', emoji); + RealmObjectBase.set(this, 'color', color); RealmObjectBase.set>( this, 'category', RealmList(category)); } @@ -340,6 +344,16 @@ class Category extends _Category @override set name(String value) => RealmObjectBase.set(this, 'name', value); + @override + String get emoji => RealmObjectBase.get(this, 'emoji') as String; + @override + set emoji(String value) => RealmObjectBase.set(this, 'emoji', value); + + @override + String get color => RealmObjectBase.get(this, 'color') as String; + @override + set color(String value) => RealmObjectBase.set(this, 'color', value); + @override RealmList get category => RealmObjectBase.get(this, 'category') as RealmList; @@ -361,6 +375,8 @@ class Category extends _Category return const SchemaObject(ObjectType.realmObject, Category, 'Category', [ SchemaProperty('id', RealmPropertyType.objectid, primaryKey: true), SchemaProperty('name', RealmPropertyType.string), + SchemaProperty('emoji', RealmPropertyType.string), + SchemaProperty('color', RealmPropertyType.string), SchemaProperty('category', RealmPropertyType.object, linkTarget: 'Spend', collectionType: RealmCollectionType.list), ]); diff --git a/lib/navigation.dart b/lib/navigation.dart index 2c683ce..222cad1 100644 --- a/lib/navigation.dart +++ b/lib/navigation.dart @@ -1,8 +1,8 @@ import "package:flutter/material.dart"; import "package:app/subscriptions/list.dart"; -// import "package:app/budgets/budgets.dart"; import 'package:app/accounts/accounts.dart'; import "package:app/home/home.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; class NavigationScreen extends StatefulWidget { const NavigationScreen({super.key}); @@ -27,8 +27,6 @@ class _NavigationScreenState extends State { Widget activePage = const Home(); switch (_selectedPageIndex) { - // case 1: - // activePage = const Budgets(); case 1: activePage = const Subscriptions(); case 2: @@ -36,28 +34,16 @@ class _NavigationScreenState extends State { } return MaterialApp( - // theme: theme, theme: ThemeData(fontFamily: 'Gilroy'), title: "ferndi - Budgeting App", home: Scaffold( - // appBar: AppBar( - // // Dynamically changed based on the screen loaded by - // // the navigation - // title: Text(activePageTitle), - // ), - // Dynamically loaded based on the screen selected from - // the bottom navigation body: activePage, bottomNavigationBar: BottomNavigationBar( items: const [ BottomNavigationBarItem( - icon: Icon(Icons.account_balance_wallet), + icon: FaIcon(FontAwesomeIcons.wallet), label: "Spending", ), - // BottomNavigationBarItem( - // icon: Icon(Icons.currency_bitcoin), - // label: "Budget", - // ), BottomNavigationBarItem( icon: Icon(Icons.card_membership_sharp), label: "Subscriptions", diff --git a/lib/onboarding/welcome.dart b/lib/onboarding/welcome.dart index 672711a..1bd1401 100644 --- a/lib/onboarding/welcome.dart +++ b/lib/onboarding/welcome.dart @@ -1,6 +1,6 @@ -import "package:app/cards/addSpend.dart"; -import "package:app/cards/addIncome.dart"; -import "package:app/cards/addCategories.dart"; +import "package:app/ops/create/addSpend.dart"; +import "package:app/ops/create/addIncome.dart"; +import "package:app/ops/create/addCategories.dart"; import "package:app/utility/schema/methods.dart"; import "package:app/navigation.dart"; import "package:flutter/material.dart"; @@ -12,260 +12,262 @@ class Onboarding extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: "ferndi", - theme: ThemeData(fontFamily: 'Gilroy'), - home: Scaffold( - appBar: AppBar( - title: const Text("Onboarding"), - ), - body: PageView( - children: [ - Container( - color: Colors.white, - child: const Column( - children: [ - SizedBox( - height: 12, - ), - Text( - "Welcome to ", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, + title: "ferndi", + theme: ThemeData(fontFamily: 'Gilroy'), + home: Scaffold( + appBar: AppBar( + title: const Text("Onboarding"), + ), + body: PageView(children: [ + Container( + color: Colors.white, + child: const Column( + children: [ + SizedBox( + height: 12, ), - ), - Text( - "Ferndi", - style: TextStyle( - fontSize: 50.0, - color: Color.fromARGB(255, 35, 206, 135), - fontWeight: FontWeight.w700, + Text( + "Welcome to ", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), ), - ), - Padding( - padding: EdgeInsets.fromLTRB(30, 20, 30, 0), - child: Column( - children: [ - ListTile( - leading: FaIcon( - FontAwesomeIcons.moneyBillTransfer, - size: 30.0, - color: Color.fromARGB(255, 16, 212, 173), + Text( + "Ferndi", + style: TextStyle( + fontSize: 50.0, + color: Color.fromARGB(255, 35, 206, 135), + fontWeight: FontWeight.w700, + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(30, 20, 30, 0), + child: Column( + children: [ + ListTile( + leading: FaIcon( + FontAwesomeIcons.moneyBillTransfer, + size: 30.0, + color: Color.fromARGB(255, 16, 212, 173), + ), + title: Text("TRACK YOUR SPENDS"), + subtitle: Text( + "Spend from your Wallets and record spends in real time like in real life."), ), - title: Text("TRACK YOUR SPENDS"), - subtitle: Text( - "Spend from your Wallets and record spends in real time like in real life."), - ), - ListTile( - leading: Icon( - Icons.subscriptions, - size: 30.0, - color: Color.fromARGB(255, 50, 163, 255), + ListTile( + leading: Icon( + Icons.subscriptions, + size: 30.0, + color: Color.fromARGB(255, 50, 163, 255), + ), + title: Text("TRACK YOUR SUBSCRIPTIONS"), + subtitle: Text( + "Know how much you spend on Subscriptions to empower your budgeting."), ), - title: Text("TRACK YOUR SUBSCRIPTIONS"), - subtitle: Text( - "Know how much you spend on Subscriptions to empower your budgeting."), - ), - ListTile( - leading: FaIcon( - Icons.savings, - size: 30.0, - color: Color.fromARGB(255, 222, 121, 255), + ListTile( + leading: FaIcon( + Icons.savings, + size: 30.0, + color: Color.fromARGB(255, 222, 121, 255), + ), + title: Text("SAVE AND GROW"), + subtitle: Text( + "A recommended savings Wallet to grow your wealth."), ), - title: Text("SAVE AND GROW"), - subtitle: Text( - "A recommended savings Wallet to grow your wealth."), - ), - SizedBox( - height: 70, - ), - Text("An opinionated way to manage your wealth."), - SizedBox( - height: 70, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.arrow_back), - Text(" swipe"), - ], - ), - ], + SizedBox( + height: 70, + ), + Text("An opinionated way to manage your wealth."), + SizedBox( + height: 70, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.arrow_back), + Text(" swipe"), + ], + ), + ], + ), ), - ), - ], + ], + ), ), - ), - Container( - color: Colors.white, - child: const Column( - children: [ - SizedBox( - height: 12, - ), - Text( - "Setup your first", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - Text( - "Wallet", - style: TextStyle( - fontSize: 50.0, - color: Color.fromARGB(255, 35, 206, 135), - fontWeight: FontWeight.w700, - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(30, 10, 30, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + ListView(children: [ + Container( + color: Colors.white, + child: const Column( children: [ - Text("Wallets are where you spend from."), - Text("You can add more Wallets later."), SizedBox( height: 12, ), - Text("In the Balance field, feel free to type in an estimate."), - Text("Don't worry, you can edit it later."), - SizedBox( - height: 24, + Text( + "Setup your first", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), ), - AddIncomeCard(), - SizedBox( - height: 70, + Text( + "Wallet", + style: TextStyle( + fontSize: 50.0, + color: Color.fromARGB(255, 35, 206, 135), + fontWeight: FontWeight.w700, + ), ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.arrow_back), - Text(" swipe"), - ], + Padding( + padding: EdgeInsets.fromLTRB(30, 10, 30, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text("Wallets are where you spend from."), + Text("You can add more Wallets later."), + SizedBox( + height: 12, + ), + Text( + "In the Balance field, feel free to type in an estimate."), + Text("Don't worry, you can edit it later."), + SizedBox( + height: 24, + ), + AddIncomeCard(), + SizedBox( + height: 70, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.arrow_back), + Text(" swipe"), + ], + ), + ], + ), ), ], - ), - ), - ], - ) - ), - Container( - color: Colors.white, - child: const Column( - children: [ - SizedBox( - height: 12, - ), - Text( - "Some good first ", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - Text( - "Categories", - style: TextStyle( - fontSize: 50.0, - color: Color.fromARGB(255, 35, 206, 135), - fontWeight: FontWeight.w700, - ), - ), - AddCategoriesCard(), - ], - ), - ), - Container( - color: Colors.white, - child: const Column( - children: [ - SizedBox( - height: 12, - ), - Text( - "Record your first", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), - ), - Text( - "Spend", - style: TextStyle( - fontSize: 50.0, - color: Color.fromARGB(255, 35, 206, 135), - fontWeight: FontWeight.w700, - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(30, 0, 30, 0), - child: Column( - children: [ - AddSpendCard(), - SizedBox( - height: 70, + )), + ]), + ListView(children: [ + Container( + color: Colors.white, + child: const Column( + children: [ + SizedBox( + height: 12, + ), + Text( + "Some good first ", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.arrow_back), - Text(" swipe"), - ], + ), + Text( + "Categories", + style: TextStyle( + fontSize: 50.0, + color: Color.fromARGB(255, 35, 206, 135), + fontWeight: FontWeight.w700, ), - ], - ) - ), - ], - ) - ), - Container( - color: Colors.white, - child: Column( - children: [ - const SizedBox( - height: 200, + ), + AddCategoriesCard(), + ], ), - Padding( - padding: const EdgeInsets.all(30.0), - child: Column( + ) + ]), + ListView(children: [ + Container( + color: Colors.white, + child: const Column( children: [ - const Text("A spending tracker that mimics real life."), - const SizedBox( - height: 200, + SizedBox( + height: 12, ), - FloatingActionButton.extended( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)), - label: const Text( - " Get Started ", - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w700, - ), + Text( + "Record your first", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, ), - foregroundColor: Colors.white, - backgroundColor: const Color.fromARGB(255, 5, 61, 135), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => const NavigationScreen())); - addDurations(); - }, ), + Text( + "Spend", + style: TextStyle( + fontSize: 50.0, + color: Color.fromARGB(255, 35, 206, 135), + fontWeight: FontWeight.w700, + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(30, 0, 30, 0), + child: Column( + children: [ + AddSpendCard(), + SizedBox( + height: 70, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.arrow_back), + Text(" swipe"), + ], + ), + ], + )), ], - ) - ), - ] - ) - ), - ] - ) - ) - ); + )), + ]), + Container( + color: Colors.white, + child: Column(children: [ + const SizedBox( + height: 200, + ), + Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + const Text( + "A spending tracker that mimics real life."), + const SizedBox( + height: 200, + ), + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " Get Started ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: + const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + const NavigationScreen())); + addDurations(); + addWallets(); + }, + ), + ], + )), + ])), + ]))); } -} +} \ No newline at end of file diff --git a/lib/cards/addCategories.dart b/lib/ops/create/addCategories.dart similarity index 73% rename from lib/cards/addCategories.dart rename to lib/ops/create/addCategories.dart index 87bd7c3..b8f2b82 100644 --- a/lib/cards/addCategories.dart +++ b/lib/ops/create/addCategories.dart @@ -21,9 +21,8 @@ class AddCategoriesCardState extends State { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.fromLTRB(30, 0, 30, 0), - child: Column( - children: [ + padding: const EdgeInsets.fromLTRB(30, 0, 30, 0), + child: Column(children: [ const ListTile( leading: FaIcon( FontAwesomeIcons.heartCircleCheck, @@ -76,7 +75,9 @@ class AddCategoriesCardState extends State { height: 35, ), FloatingActionButton.extended( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)), + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), label: const Text( " add all ", style: TextStyle( @@ -85,21 +86,25 @@ class AddCategoriesCardState extends State { ), ), foregroundColor: Colors.white, - backgroundColor: - const Color.fromARGB(255, 5, 61, 135), + backgroundColor: const Color.fromARGB(255, 5, 61, 135), onPressed: () { addCategories(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - backgroundColor: Color.fromARGB(255, 231, 255, 245), - content: Column( - children: [ - Text("Categories successfully created. You can add more later.", style: TextStyle(color:Color.fromARGB(255, 9, 163, 99)),), - Text("Swipe right to Record your first Spend.", style: TextStyle(color:Color.fromARGB(255, 9, 163, 99)),), - ], - ), - ) - ); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Text( + "Categories successfully created. You can add more later.", + style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), + ), + Text( + "Swipe right to Record your first Spend.", + style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), + ), + ], + ), + )); }, ), const SizedBox( @@ -112,8 +117,6 @@ class AddCategoriesCardState extends State { Text(" swipe"), ], ), - ] - ) - ); + ])); } } diff --git a/lib/ops/create/addCategory.dart b/lib/ops/create/addCategory.dart new file mode 100644 index 0000000..8dbb46e --- /dev/null +++ b/lib/ops/create/addCategory.dart @@ -0,0 +1,333 @@ +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; +import "package:realm/realm.dart"; + +class AddCategoryCard extends StatefulWidget { + const AddCategoryCard({super.key}); + + @override + AddCategoryCardState createState() => AddCategoryCardState(); +} + +class AddCategoryCardState extends State { + final _nameController = TextEditingController(); + final _emojiController = TextEditingController(); + + late String categoryEmoji = "πŸ’Έ"; + late Color categoryColor = const Color.fromARGB(255, 205, 227, 255); + + void _newEmoji(String selectedEmoji) { + setState(() { + categoryEmoji = selectedEmoji; + }); + } + + @override + void dispose() { + _nameController.dispose(); + _emojiController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Add Category"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column(children: [ + TextField( + controller: _nameController, + maxLength: 50, + keyboardType: TextInputType.text, + decoration: const InputDecoration(label: Text("Name")), + ), + const SizedBox( + height: 10, + ), + Row( + children: [ + Row( + children: [ + CircleAvatar( + backgroundColor: categoryColor, + child: Text( + categoryEmoji, + style: const TextStyle(fontSize: 27), + ), + ), + const SizedBox( + width: 30, + ), + ], + ), + Expanded( + child: TextFormField( + initialValue: categoryEmoji, + onChanged: _newEmoji, + maxLength: 1, + keyboardType: TextInputType.text, + decoration: const InputDecoration(label: Text("Emoji")), + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + SizedBox( + height: 40, + child: ListView(scrollDirection: Axis.horizontal, children: [ + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 194, 213, 252); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 194, 213, 252), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 250, 163); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 250, 163), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 200, 163); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color:const Color.fromARGB(255, 255, 200, 163), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 191, 236); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 191, 236), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 184, 255, 118); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 184, 255, 118), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 218, 255, 240); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 218, 255, 240), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 192, 255, 242); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color:const Color.fromARGB(255, 192, 255, 242), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 166, 168); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 166, 168), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 213, 168, 255); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 213, 168, 255), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 109, 255, 175); + }); + }, + child: ClipOval( + // borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 109, 255, 175), + )), + ), + const SizedBox( + width: 10, + ), + ]), + ), + const SizedBox( + height: 40, + ), + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (_nameController.text.isEmpty) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "A Category must have a Name", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Text( + "Please add a Name before saving.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + return; + } + createCategory(Category( + ObjectId(), + _nameController.text, + categoryEmoji, + "Color.fromARGB(255, 205, 227, 255)", + )); + _nameController.clear(); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Text( + "Category successfully created.", + style: + TextStyle(color: Color.fromARGB(255, 9, 163, 99)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Happy categorizing your Spends! ", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ]), + ), + )); + } +} diff --git a/lib/cards/addIncome.dart b/lib/ops/create/addIncome.dart similarity index 96% rename from lib/cards/addIncome.dart rename to lib/ops/create/addIncome.dart index 8488f45..76204c6 100644 --- a/lib/cards/addIncome.dart +++ b/lib/ops/create/addIncome.dart @@ -39,8 +39,9 @@ class AddIncomeCardState extends State { Text("Income"), ], ), - const Spacer(), - // Text("Income"), + const SizedBox( + width: 40, + ), Expanded( child: TextField( controller: _balanceController, @@ -61,6 +62,7 @@ class AddIncomeCardState extends State { height: 70, ), FloatingActionButton.extended( + elevation: 1, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50.0)), label: const Text( @@ -90,7 +92,7 @@ class AddIncomeCardState extends State { "Income Wallet successfully created. ", style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), ), - Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) + Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) ], ), Text( diff --git a/lib/cards/addSpend.dart b/lib/ops/create/addSpend.dart similarity index 69% rename from lib/cards/addSpend.dart rename to lib/ops/create/addSpend.dart index 5c009ba..3811a52 100644 --- a/lib/cards/addSpend.dart +++ b/lib/ops/create/addSpend.dart @@ -1,23 +1,28 @@ import "package:app/models/schemas.dart"; +import "package:app/providers/spends_provider.dart"; import "package:app/utility/schema/methods.dart"; import "package:flutter/material.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:realm/realm.dart"; -class AddSpendCard extends StatefulWidget { +class AddSpendCard extends ConsumerStatefulWidget { const AddSpendCard({super.key}); @override AddSpendCardState createState() => AddSpendCardState(); } -class AddSpendCardState extends State { +class AddSpendCardState extends ConsumerState { final _nameController = TextEditingController(); final _notesController = TextEditingController(); final _amountController = TextEditingController(); Category _selectedCategory = categories.first; Wallet _selectedWallet = wallets.first; + late int newBalance = + _selectedWallet.balance - int.parse(_amountController.text); + @override void dispose() { _nameController.dispose(); @@ -35,31 +40,65 @@ class AddSpendCardState extends State { padding: const EdgeInsets.fromLTRB(30, 0, 30, 20), child: Column( children: [ + const SizedBox( + height: 12, + ), TextField( controller: _nameController, decoration: const InputDecoration( - label: Text("What did you buy?"), + iconColor: Color.fromARGB(255, 151, 151, 151), + icon: FaIcon( + FontAwesomeIcons.penToSquare, + size: 24, + ), + border: InputBorder.none, + label: Text("What did spend on ?"), isDense: true, ), ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), TextField( controller: _notesController, decoration: const InputDecoration( + iconColor: Color.fromARGB(255, 151, 151, 151), + icon: FaIcon( + FontAwesomeIcons.noteSticky, + size: 24, + ), + border: InputBorder.none, label: Text("Notes"), isDense: true, ), ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), TextField( controller: _amountController, keyboardType: TextInputType.number, decoration: const InputDecoration( + iconColor: Color.fromARGB(255, 151, 151, 151), + icon: FaIcon( + FontAwesomeIcons.tags, + size: 24, + ), + border: InputBorder.none, prefix: Text("GHS "), label: Text("Amount"), isDense: true), ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), DropdownButton( value: _selectedCategory, - icon: const FaIcon(FontAwesomeIcons.boxOpen), + hint: const Text("Category"), + icon: const FaIcon( + FontAwesomeIcons.boxArchive, + color: Color.fromARGB(255, 151, 151, 151), + ), isExpanded: true, borderRadius: const BorderRadius.all(Radius.circular(20)), items: categories @@ -79,7 +118,11 @@ class AddSpendCardState extends State { ), DropdownButton( value: _selectedWallet, - icon: const Icon(Icons.wallet_sharp), + hint: const Text("Wallet"), + icon: const Icon( + Icons.wallet_sharp, + color: Color.fromARGB(255, 151, 151, 151), + ), isExpanded: true, borderRadius: const BorderRadius.all(Radius.circular(20)), items: wallets @@ -98,9 +141,10 @@ class AddSpendCardState extends State { }, ), const SizedBox( - height: 40, + height: 20, ), FloatingActionButton.extended( + elevation: 1, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50.0)), label: const Text( @@ -110,12 +154,16 @@ class AddSpendCardState extends State { fontWeight: FontWeight.w700, ), ), - foregroundColor: const Color.fromARGB(255, 5, 61, 135), + foregroundColor: const Color.fromARGB(255, 255, 255, 255), backgroundColor: const Color.fromARGB(255, 35, 206, 135), onPressed: () { - if (_nameController.text.isEmpty || _amountController.text.isEmpty || _selectedCategory.name.isEmpty || _selectedWallet.name.isEmpty ) { + if (_nameController.text.isEmpty || + _amountController.text.isEmpty || + _selectedCategory.name.isEmpty || + _selectedWallet.name.isEmpty) { + ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar( + .showSnackBar(const SnackBar( backgroundColor: Color.fromARGB(255, 255, 231, 241), content: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -139,9 +187,10 @@ class AddSpendCardState extends State { ), )); return; - } + } if (int.parse(_amountController.text) > _selectedWallet.balance) { + ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context) .showSnackBar(const SnackBar( backgroundColor: Color.fromARGB(255, 255, 231, 241), @@ -153,7 +202,7 @@ class AddSpendCardState extends State { color: Color.fromARGB(255, 163, 9, 71)), ), Text( - "Go to Accounts and add money first.", + "Go to Accounts and top up first.", style: TextStyle( color: Color.fromARGB(255, 163, 9, 71)), ), @@ -166,30 +215,38 @@ class AddSpendCardState extends State { _nameController.text, _notesController.text, int.parse(_amountController.text), + category: _selectedCategory, + wallet: _selectedWallet, DateTime.now())); - // print(_selectedWallet.balance - int.parse(_amountController.text)); + updateWallet(Wallet(_selectedWallet.id, + _selectedWallet.name, newBalance)); _nameController.clear(); _notesController.clear(); _amountController.clear(); + ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context) .showSnackBar(const SnackBar( backgroundColor: Color.fromARGB(255, 231, 255, 245), content: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "You have successfully recorded your Spend. Yay! ", style: TextStyle( - color: Color.fromARGB(255, 9, 163, 99)), + color: Color.fromARGB(255, 9, 163, 99)), ), - Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) ], ), ], ), )); } + ref.read(spendsCountProvider.notifier).state++; }), ], ))); diff --git a/lib/ops/create/addSubscription.dart b/lib/ops/create/addSubscription.dart new file mode 100644 index 0000000..e518db9 --- /dev/null +++ b/lib/ops/create/addSubscription.dart @@ -0,0 +1,218 @@ +import 'package:app/models/schemas.dart'; +import "package:app/utility/schema/methods.dart"; +import 'package:app/models/schemas.dart' as subscription; +import "package:flutter/material.dart"; +import "package:realm/realm.dart"; + +class AddSubscriptionCard extends StatefulWidget { + const AddSubscriptionCard({super.key}); + + @override + AddSubscriptionCardState createState() => AddSubscriptionCardState(); +} + +class AddSubscriptionCardState extends State { + final _nameController = TextEditingController(); + final _amountController = TextEditingController(); + Duration _selectedDuration = duration.first; + Wallet _selectedWallet = wallets.first; + + @override + void dispose() { + _nameController.dispose(); + _amountController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Add Subscription"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + TextField( + controller: _nameController, + maxLength: 50, + decoration: const InputDecoration( + label: Text("Name"), + isDense: true, + ), + ), + TextField( + controller: _amountController, + maxLength: 5, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + isDense: true, + prefix: Text("GHS "), + label: Text("Amount") + ), + ), + const SizedBox( height: 10,), + Row( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(15.0), + ), + child: DropdownButton( + underline: Container(), + value: _selectedWallet, + borderRadius: + const BorderRadius.all(Radius.circular(20)), + icon: const Icon( + Icons.wallet_sharp, + size: 30, + color: Color.fromARGB(255, 17, 221, 163), + ), + items: wallets + .map((wallet) => DropdownMenuItem( + value: wallet, + child: Text(wallet.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedWallet = value; + }); + }, + ), + ), + const Spacer(), + Container( + padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(15.0), + ), + child: DropdownButton( + underline: Container(), + value: _selectedDuration, + borderRadius: + const BorderRadius.all(Radius.circular(20)), + icon: const Icon( + Icons.av_timer, + size: 30, + color: Color.fromARGB(255, 146, 2, 93), + ), + items: duration + .map((duration) => DropdownMenuItem( + value: duration, + child: Text(duration.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedDuration = value; + }); + }, + ), + )], + ), + const SizedBox( + height: 35, + ), + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " record ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (_nameController.text.isEmpty || + _amountController.text.isEmpty || + _selectedDuration.name.isEmpty || + _selectedWallet.name.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Subscription details incomplete", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Please add a name, amount, wallet and duration.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + ], + ), + )); + return; + } + addSubscription(subscription.Subscription( + ObjectId(), + _nameController.text, + int.tryParse(_amountController.text) ?? 0, + wallet: _selectedWallet, + duration: _selectedDuration, + DateTime.now())); + _nameController.clear(); + _amountController.clear(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Subscription successfully recorded your. yay! ", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ], + ))), + ); + } +} diff --git a/lib/ops/create/addWallet.dart b/lib/ops/create/addWallet.dart new file mode 100644 index 0000000..5242642 --- /dev/null +++ b/lib/ops/create/addWallet.dart @@ -0,0 +1,139 @@ +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; +import "package:realm/realm.dart"; + +class AddWalletCard extends StatefulWidget { + const AddWalletCard({super.key}); + + @override + AddWalletCardState createState() => AddWalletCardState(); +} + +class AddWalletCardState extends State { + final _nameController = TextEditingController(); + final _balanceController = TextEditingController(); + + @override + void dispose() { + _nameController.dispose(); + _balanceController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Add Wallet"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + TextField( + controller: _nameController, + maxLength: 50, + keyboardType: TextInputType.text, + decoration: + const InputDecoration(label: Text("Wallet Name")), + ), + TextField( + controller: _balanceController, + maxLength: 10, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + prefix: Text("GHS "), label: Text("Balance")), + ), + const SizedBox( + height: 40, + ), + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save wallet ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (_balanceController.text.isEmpty || + _nameController.text.isEmpty) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: + Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "A Wallet must have a Name and a Balance", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Text( + "Please add a Name and Balance before saving.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + return; + } + createWallet(Wallet( + ObjectId(), + _nameController.text, + int.parse(_balanceController.text), + )); + _nameController.clear(); + _balanceController.clear(); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Text( + "Wallet successfully created.", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Happy tracking your Spends! ", + style: TextStyle( + color: + Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ], + ), + ))); + } +} diff --git a/lib/ops/update/editCategory.dart b/lib/ops/update/editCategory.dart new file mode 100644 index 0000000..2a20309 --- /dev/null +++ b/lib/ops/update/editCategory.dart @@ -0,0 +1,337 @@ +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; + +class EditCategoryCard extends StatefulWidget { + const EditCategoryCard({required this.category, super.key}); + + final Category category; + + @override + EditCategoryCardState createState() => EditCategoryCardState(); +} + +class EditCategoryCardState extends State { + + late Category categoryToEdit = getCategory(widget.category.id); + late String name = categoryToEdit.name; + late String categoryEmoji = categoryToEdit.emoji; + // late String categoryColor = categoryToEdit.color; + late Color categoryColor = const Color.fromARGB(255, 205, 227, 255); + // late Color defaultColor = const Color.fromARGB(255, 205, 227, 255); + + void _newEmoji(String selectedEmoji) { + setState(() { + categoryEmoji = selectedEmoji; + }); + } + + void _newName(String typedName) { + name = typedName; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Edit Category"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + TextFormField( + initialValue: name, + onChanged: _newName, + maxLength: 50, + keyboardType: TextInputType.text, + decoration: const InputDecoration(label: Text("Category Name")), + ), + const SizedBox( + height: 10, + ), + Row( + children: [ + Row( + children: [ + CircleAvatar( + backgroundColor: categoryColor, + child: Text( + categoryEmoji, + style: const TextStyle(fontSize: 27), + ), + ), + const SizedBox( + width: 30, + ), + ], + ), + Expanded( + child: TextFormField( + initialValue: categoryEmoji, + onChanged: _newEmoji, + maxLength: 1, + keyboardType: TextInputType.text, + decoration: const InputDecoration(label: Text("Emoji")), + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + SizedBox( + height: 40, + child: ListView(scrollDirection: Axis.horizontal, children: [ + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 194, 213, 252); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 194, 213, 252), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 250, 163); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 250, 163), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 200, 163); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color:const Color.fromARGB(255, 255, 200, 163), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 191, 236); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 191, 236), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 184, 255, 118); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 184, 255, 118), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 218, 255, 240); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 218, 255, 240), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 192, 255, 242); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color:const Color.fromARGB(255, 192, 255, 242), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 255, 166, 168); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 255, 166, 168), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 213, 168, 255); + }); + }, + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 213, 168, 255), + )), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () { + setState(() { + categoryColor = + const Color.fromARGB(255, 109, 255, 175); + }); + }, + child: ClipOval( + // borderRadius: BorderRadius.circular(50), + child: Container( + padding: const EdgeInsets.all(20), + color: const Color.fromARGB(255, 109, 255, 175), + )), + ), + const SizedBox( + width: 10, + ), + ]), + ), + const SizedBox( + height: 40, + ), + FloatingActionButton.extended( + heroTag: "save", + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (name.isEmpty) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "A Category must have a name", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Text( + "Please add a name before saving.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + return; + } + updateCategory(Category( + categoryToEdit.id, + name, + categoryEmoji, + "Color.fromARGB(255, 205, 227, 255)", + )); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Text( + "Category successfully updated.", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Enjoy Delightful Spending.", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ], + ), + ), + )); + } +} diff --git a/lib/ops/update/editSpend.dart b/lib/ops/update/editSpend.dart new file mode 100644 index 0000000..720bac7 --- /dev/null +++ b/lib/ops/update/editSpend.dart @@ -0,0 +1,263 @@ +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + +class EditSpendCard extends StatefulWidget { + final Spend spend; + const EditSpendCard(this.spend, {super.key}); + + @override + EditSpendCardState createState() => EditSpendCardState(); +} + +class EditSpendCardState extends State { + late Spend spendToEdit = getSpend(widget.spend.id); + + late String name = spendToEdit.name; + late String notes = spendToEdit.notes; + late String amount = spendToEdit.amount.toString(); + + void _newName(String typedName) { + name = typedName; + } + + void _newNotes(String typedNotes) { + notes = typedNotes; + } + + void _newAmount(String typedAmount) { + amount = typedAmount; + } + + late Category _selectedCategory = spendToEdit.category ??= categories.first; + late Wallet _selectedWallet = spendToEdit.wallet ??= wallets.first; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Card( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), + child: Padding( + padding: const EdgeInsets.fromLTRB(30, 0, 30, 20), + child: Column( + children: [ + const SizedBox( + height: 12, + ), + TextFormField( + initialValue: name, + onChanged: _newName, + decoration: InputDecoration( + iconColor: const Color.fromARGB(255, 151, 151, 151), + icon: const FaIcon( + FontAwesomeIcons.penToSquare, + size: 24, + ), + border: InputBorder.none, + label: const Text("What did spend on ?"), + hintText: "${spendToEdit.name}", + isDense: true, + ), + ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), + TextFormField( + initialValue: notes, + onChanged: _newNotes, + decoration: InputDecoration( + iconColor: const Color.fromARGB(255, 151, 151, 151), + icon: const FaIcon( + FontAwesomeIcons.noteSticky, + size: 24, + ), + border: InputBorder.none, + label: const Text("Notes"), + hintText: "${spendToEdit.notes}", + isDense: true, + ), + ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), + TextFormField( + initialValue: amount, + onChanged: _newAmount, + keyboardType: TextInputType.number, + decoration: InputDecoration( + iconColor: const Color.fromARGB(255, 151, 151, 151), + icon: const FaIcon( + FontAwesomeIcons.tags, + size: 24, + ), + border: InputBorder.none, + prefix: const Text("GHS "), + label: const Text("Amount"), + hintText: "${spendToEdit.amount}", + isDense: true), + ), + const Divider( + color: Color.fromARGB(255, 227, 226, 226), + ), + DropdownButton( + value: _selectedCategory, + hint: const Text("Category"), + icon: const FaIcon( + FontAwesomeIcons.boxArchive, + color: Color.fromARGB(255, 151, 151, 151), + ), + isExpanded: true, + borderRadius: const BorderRadius.all(Radius.circular(20)), + items: categories + .map((category) => DropdownMenuItem( + value: category, + child: Text(category.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedCategory = value; + }); + }, + ), + DropdownButton( + value: _selectedWallet, + hint: const Text("Wallet"), + icon: const Icon( + Icons.wallet_sharp, + color: Color.fromARGB(255, 151, 151, 151), + ), + isExpanded: true, + borderRadius: const BorderRadius.all(Radius.circular(20)), + items: wallets + .map((wallet) => DropdownMenuItem( + value: wallet, + child: Text(wallet.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedWallet = value; + }); + }, + ), + const SizedBox( + height: 20, + ), + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Color.fromARGB(255, 255, 255, 255), + backgroundColor: const Color.fromARGB(255, 35, 206, 135 + ), + onPressed: () { + if (name.isEmpty || + amount.isEmpty || + _selectedCategory.name.isEmpty || + _selectedWallet.name.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Spend details incomplete", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Please add name, amount, wallet and category.", + style: TextStyle( + color: + Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + ], + ), + )); + return; + } + if (int.parse(amount) > _selectedWallet.balance) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + children: [ + Text( + "You don't have enough money in the Wallet", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Text( + "Go to Accounts and top up first.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + )); + } else { + updateSpend(Spend( + spendToEdit.id, + name, + notes, + int.parse(amount.toString()), + category: _selectedCategory, + wallet: _selectedWallet, + DateTime.now() + )); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Spend edited and Saved successfully. ", + style: TextStyle( + color: + Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + } + Navigator.of(context).pop(); + } + ), + ], + ) + ) + ), + ); + } +} diff --git a/lib/ops/update/editSubscription.dart b/lib/ops/update/editSubscription.dart new file mode 100644 index 0000000..8406ca2 --- /dev/null +++ b/lib/ops/update/editSubscription.dart @@ -0,0 +1,220 @@ +import 'package:app/models/schemas.dart'; +import "package:app/utility/schema/methods.dart"; +import 'package:app/models/schemas.dart' as my; +import "package:flutter/material.dart"; + +class EditSubscriptionCard extends StatefulWidget { + final my.Subscription subscription; + const EditSubscriptionCard(this.subscription, {super.key}); + + @override + EditSubscriptionCardState createState() => EditSubscriptionCardState(); +} + +class EditSubscriptionCardState extends State { + + late my.Subscription subscriptionToEdit = + getSubscription(widget.subscription.id); + + late String name = subscriptionToEdit.name; + late String amount = subscriptionToEdit.amount.toString(); + + void _newName(String typedName) { + name = typedName; + } + + void _newAmount(String typedAmount) { + amount = typedAmount; + } + + late Duration _selectedDuration = subscriptionToEdit.duration ??= duration.first; + late Wallet _selectedWallet = subscriptionToEdit.wallet ??= wallets.first; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Add Subscription"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(20.0), + ), + child: Column( + children: [ + TextFormField( + initialValue: name, + onChanged: _newName, + maxLength: 50, + decoration: const InputDecoration(label: Text("Name")), + ), + TextFormField( + initialValue: amount, + onChanged: _newAmount, + maxLength: 5, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + prefix: Text("GHS "), label: Text("Amount")), + ), + const SizedBox( height: 10,), + Row( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(15.0), + ), + child: DropdownButton( + underline: Container(), + value: _selectedWallet, + borderRadius: const BorderRadius.all(Radius.circular(20)), + icon: const Icon( + Icons.wallet_sharp, + size: 30, + color: Color.fromARGB(255, 17, 221, 163), + ), + items: wallets + .map((wallet) => DropdownMenuItem( + value: wallet, + child: Text(wallet.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedWallet = value; + }); + }, + ),), + const Spacer(), + Container( + padding: const EdgeInsets.fromLTRB(20, 5, 20, 5), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), + ), + borderRadius: BorderRadius.circular(15.0), + ), + child: DropdownButton( + underline: Container(), + value: _selectedDuration, + borderRadius: const BorderRadius.all(Radius.circular(20)), + icon: const Icon( + Icons.av_timer, + size: 30, + color: Color.fromARGB(255, 146, 2, 93), + ), + items: duration + .map((duration) => DropdownMenuItem( + value: duration, + child: Text(duration.name), + )) + .toList(), + onChanged: (value) { + if (value == null) { + return; + } + setState(() { + _selectedDuration = value; + }); + }, + ), + )], + ), + const SizedBox( + height: 35, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FloatingActionButton.extended( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (name.isEmpty || + amount.isEmpty || + _selectedDuration.name.isEmpty || + _selectedWallet.name.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 255, 231, 241), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Subscription details incomplete", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Please add a name, amount, wallet and duration.", + style: TextStyle( + color: Color.fromARGB(255, 163, 9, 71)), + ), + ], + ), + ], + ), + )); + return; + } + updateSubscription(my.Subscription( + subscriptionToEdit.id, + name, + int.parse(amount), + wallet: _selectedWallet, + duration: _selectedDuration, + DateTime.now())); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Subscription successfully recorded your. yay! ", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ], + ) + ], + )), + )); + } +} diff --git a/lib/cards/addWallet.dart b/lib/ops/update/editWallet.dart similarity index 53% rename from lib/cards/addWallet.dart rename to lib/ops/update/editWallet.dart index a5bcf77..db34ca0 100644 --- a/lib/cards/addWallet.dart +++ b/lib/ops/update/editWallet.dart @@ -1,86 +1,75 @@ import "package:app/models/schemas.dart"; import "package:app/utility/schema/methods.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:flutter/material.dart"; -import "package:realm/realm.dart"; -class AddWalletCard extends StatefulWidget { - const AddWalletCard({super.key}); +class EditWalletCard extends StatefulWidget { + final Wallet wallet; + const EditWalletCard(this.wallet, {super.key}); @override - AddWalletCardState createState() => AddWalletCardState(); + EditWalletCardState createState() => EditWalletCardState(); } -class AddWalletCardState extends State { - final _nameController = TextEditingController(); - final _balanceController = TextEditingController(); +class EditWalletCardState extends State { + late Wallet walletToEdit = getWallet(widget.wallet.id); - @override - void dispose() { - _nameController.dispose(); - _balanceController.dispose(); - super.dispose(); + late String name = walletToEdit.name; + late String balance = walletToEdit.balance.toString(); + + void _newName(String typedName) { + name = typedName; + } + + void _newBalance(String typedBalance) { + balance = typedBalance; } @override Widget build(BuildContext context) { return Scaffold( - body: Padding( - padding: const EdgeInsets.fromLTRB(30, 60, 30, 30), - child: Column( - children: [ - const Align( - alignment: Alignment.topLeft, - child: Text( - "Add Wallet", - style: TextStyle( - fontSize: 30.0, - color: Color.fromARGB(255, 5, 61, 135), - fontWeight: FontWeight.w700, - ), + appBar: AppBar( + title: const Text("Edit Wallet"), + ), + body: Padding( + padding: const EdgeInsets.all(20), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all( + color: const Color.fromARGB(255, 227, 226, 226), ), + borderRadius: BorderRadius.circular(20.0), ), - const SizedBox( - height: 20, - ), - TextField( - controller: _nameController, + child: Column( + children: [ + TextFormField( + initialValue: name, + onChanged: _newName, maxLength: 50, keyboardType: TextInputType.text, decoration: const InputDecoration(label: Text("Wallet Name")), ), - TextField( - controller: _balanceController, + TextFormField( + initialValue: balance, + onChanged: _newBalance, maxLength: 10, keyboardType: TextInputType.number, decoration: const InputDecoration( - prefix: FaIcon( - FontAwesomeIcons.cediSign, - size: 14.0, - ), - label: Text("Balance")), + prefix: Text("GHS "), label: Text("Balance")), ), const SizedBox( height: 40, ), Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ FloatingActionButton.extended( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50.0)), - label: const Icon(Icons.close), - backgroundColor: const Color.fromARGB(255, 255, 231, 241), - foregroundColor: const Color.fromARGB(255, 163, 9, 71), - onPressed: () { - Navigator.pop(context); - }, - ), - const Spacer(), - FloatingActionButton.extended( + elevation: 1, + heroTag: "save", shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50.0)), label: const Text( - " save wallet ", + " save ", style: TextStyle( fontSize: 20.0, fontWeight: FontWeight.w700, @@ -89,8 +78,10 @@ class AddWalletCardState extends State { foregroundColor: Colors.white, backgroundColor: const Color.fromARGB(255, 5, 61, 135), onPressed: () { - if (_balanceController.text.isEmpty || _nameController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + if (balance.isEmpty || name.isEmpty) { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( backgroundColor: Color.fromARGB(255, 255, 231, 241), content: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -110,40 +101,43 @@ class AddWalletCardState extends State { )); return; } - createWallet(Wallet( - ObjectId(), - _nameController.text, - int.parse(_balanceController.text), + updateWallet(Wallet( + walletToEdit.id, + name, + int.parse(balance), )); - _nameController.clear(); - _balanceController.clear(); + ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar( backgroundColor: Color.fromARGB(255, 231, 255, 245), content: Column( children: [ Text( - "Wallet successfully created.", - style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), + "Wallet successfully updated.", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Happy tracking your Spends! ", - style: TextStyle(color: Color.fromARGB(255, 9, 163, 99)), + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), ), - Icon(Icons.sentiment_very_satisfied, color: Color.fromARGB(255, 9, 163, 9)) + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) ], ), ], ), )); + Navigator.of(context).pop(); }, ), ], ), ], )), - ); + )); } } diff --git a/lib/ops/update/topUpWallet.dart b/lib/ops/update/topUpWallet.dart new file mode 100644 index 0000000..dc0ab43 --- /dev/null +++ b/lib/ops/update/topUpWallet.dart @@ -0,0 +1,180 @@ +import "package:app/models/schemas.dart"; +import "package:app/utility/schema/methods.dart"; +import "package:flutter/material.dart"; + +class TopUpWalletCard extends StatefulWidget { + final Wallet wallet; + const TopUpWalletCard(this.wallet, {super.key}); + + @override + TopUpWalletCardState createState() => TopUpWalletCardState(); +} + +class TopUpWalletCardState extends State { + late Wallet walletToEdit = getWallet(widget.wallet.id); + + final _balanceController = TextEditingController(); + + late String name = walletToEdit.name; + late int balance = walletToEdit.balance; + + void _newBalance(String typedBalance) { + balance += int.parse(_balanceController.text); + } + + @override + void dispose() { + _balanceController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Padding( + padding: const EdgeInsets.fromLTRB(30, 60, 30, 30), + child: Column( + children: [ + Align( + alignment: Alignment.topLeft, + child: Text( + "Top up $name", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + ), + const Align( + alignment: Alignment.topLeft, + child: Text( + "Current Balance", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + fontWeight: FontWeight.w700, + ), + ), + ), + Align( + alignment: Alignment.topLeft, + child: Text( + "GHS ${walletToEdit.balance}", + style: const TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + fontWeight: FontWeight.w700, + ), + ), + ), + const SizedBox( + height: 20, + ), + const SizedBox( + height: 20, + ), + Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 240, 240, 240), + borderRadius: BorderRadius.circular(8.0)), + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + "The amount you type below will be added to your Wallet's balance.", + style: TextStyle( + color: Color.fromARGB(255, 151, 151, 151), + ), + ), + )), + const SizedBox( + height: 20, + ), + TextField( + controller: _balanceController, + maxLength: 10, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + prefix: Text("GHS "), + ), + ), + const SizedBox( + height: 40, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FloatingActionButton.extended( + elevation: 1, + heroTag: "save", + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.0)), + label: const Text( + " save ", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + foregroundColor: Colors.white, + backgroundColor: const Color.fromARGB(255, 5, 61, 135), + onPressed: () { + if (_balanceController.text.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 230, 243, 255), + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Nothing was added to your wallet", + style: TextStyle( + color: Color.fromARGB(255, 0, 128, 255)), + ), + ], + ), + )); + Navigator.of(context).pop(); + return; + } + _newBalance(_balanceController.text); + updateWallet(Wallet( + walletToEdit.id, + name, + balance, + )); + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + backgroundColor: Color.fromARGB(255, 231, 255, 245), + content: Column( + children: [ + Text( + "You have successfully topped up your Wallet.", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Happy tracking your Spends! ", + style: TextStyle( + color: Color.fromARGB(255, 9, 163, 99)), + ), + Icon(Icons.sentiment_very_satisfied, + color: Color.fromARGB(255, 9, 163, 9)) + ], + ), + ], + ), + )); + Navigator.of(context).pop(); + }, + ), + ], + ), + ], + )), + ); + } +} diff --git a/lib/providers/spends_provider.dart b/lib/providers/spends_provider.dart new file mode 100644 index 0000000..8044ccd --- /dev/null +++ b/lib/providers/spends_provider.dart @@ -0,0 +1,30 @@ +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:app/utility/schema/methods.dart"; +// import 'package:app/models/schemas.dart'; +// import "package:realm/realm.dart"; + +final spendsProvider = StateProvider((ref) { + return spends; +}); + +final spendsCountProvider = StateProvider((ref) { + return spendsCount; +}); + +// class spendsNotifier extends StateNotifier { //> { +// spendsNotifier() : super([]); + +// // Create a new spend record and persist to db +// void recordSpend(Spend spend) { +// realm.write(() { +// realm.add(spend); +// }); +// } + + // void updateSpend(Spend spend) { + // realm.write(() { + // realm.add(spend, update: true); + // }); + // } +// } + diff --git a/lib/subscriptions/list.dart b/lib/subscriptions/list.dart index cd91dc6..750a389 100644 --- a/lib/subscriptions/list.dart +++ b/lib/subscriptions/list.dart @@ -1,10 +1,7 @@ +import "package:app/cards/subscriptions.dart"; +import "package:app/cards/subscriptionsBalanceCard.dart"; import "package:flutter/material.dart"; -import 'package:app/models/schemas.dart'; -import "package:app/utility/schema/methods.dart"; -import "package:app/cards/addSubscription.dart"; -import "package:flutter_slidable/flutter_slidable.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; -import "package:google_fonts/google_fonts.dart"; +import "package:app/ops/create/addSubscription.dart"; class Subscriptions extends StatefulWidget { @@ -34,138 +31,51 @@ class SubscriptionsState extends State { actions: [ IconButton( color: Colors.white, - onPressed: _showSubscriptionForm, icon: const Icon(Icons.add)) + + onPressed: _showSubscriptionForm, icon: const Icon( + Icons.add, + size: 34, + color: Color.fromARGB(255, 5, 61, 135), + ) + ) + ], title: const Text("Subscriptions", style: TextStyle( - color: Colors.white + color: Color.fromARGB(255, 5, 61, 135) ),), - backgroundColor: const Color.fromARGB(255, 5, 61, 135), + backgroundColor: const Color.fromARGB(255, 202, 233, 255), ), body: Container( - padding: const EdgeInsets.all(15.0), - child: ListView.builder( - itemCount: subscriptions.length, - itemBuilder: (BuildContext context, int index) { - return _buildSubscriptionCard(subscriptions[index]); - } + color: const Color.fromARGB(255, 215, 237, 253), + child: ListView( + padding: const EdgeInsets.all(15), + children: const [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SubscriptionsBalanceCard(), + SizedBox( + height: 12, + ), + Text( + "Your Subscriptions", + style: TextStyle( + fontSize: 30.0, + color: Color.fromARGB(255, 5, 61, 135), + ), + ), + ], + ), + + SizedBox( + height: 2800, + child: + SubscriptionsCard() + ), + ] ), ), ) ); } } - -Widget _buildSubscriptionCard(Subscription subscriptionItem) { - return Slidable( - // Specify a key if the Slidable is dismissible. - key: ValueKey(subscriptionItem), - - // The start action pane is the one at the left or the top side. - startActionPane: ActionPane( - // A motion is a widget used to control how the pane animates. - motion: const ScrollMotion(), - - // A pane can dismiss the Slidable. - dismissible: DismissiblePane(onDismissed: () { - deleteSubscription(subscriptionItem); - print("subscription deleted from sliding through"); - }), - - // All actions are defined in the children parameter. - children: [ - // A SlidableAction can have an icon and/or a label. - SlidableAction( - onPressed: (context) { - deleteSubscription(subscriptionItem); - }, - backgroundColor: Color(0xFFFE4A49), - foregroundColor: Colors.white, - icon: Icons.delete, - label: 'Delete', - ), - ], - ), - child: Card ( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), - child: Padding( - padding: const EdgeInsets.all(10), - child: Column(children: [ - Row( - children: [ - const Icon( - Icons.wallet_sharp, - size: 20, - color: Color.fromARGB(255, 17, 221, 163), - ), - const SizedBox( - width: 10, - ), - Text( - "${subscriptionItem.from}", - style: const TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.w400, - ), - ), - ], - ), - Row( - children: [ - const Icon( - Icons.card_membership, - size: 20, - color: Color.fromARGB(255, 165, 64, 243), - ), - const SizedBox( - width: 10, - ), - Text( - subscriptionItem.name, - style: const TextStyle( - fontSize: 17.0, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - const Divider(), - Row( - children: [ - const Text("-", - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w700, - )), - const SizedBox( - width: 5, - ), - const FaIcon( - FontAwesomeIcons.cediSign, - size: 17.0, - ), - const SizedBox( - width: 3, - ), - Text( - subscriptionItem.getAmount, - style: GoogleFonts.hankenGrotesk( - // color: const Colo.fromARGB(255, 255, 140, 0), - fontSize: 25.0, - fontWeight: FontWeight.w900, - ), - ), - Text( - " / ${subscriptionItem.period}", - style: const TextStyle( - color: Color.fromARGB(255, 148, 152, 158), - fontSize: 17.0, - fontWeight: FontWeight.w500, - ), - ), - ], - ) - ]), - ) - ) - ); -} diff --git a/lib/utility/defaults/categories.dart b/lib/utility/defaults/categories.dart new file mode 100644 index 0000000..0970f09 --- /dev/null +++ b/lib/utility/defaults/categories.dart @@ -0,0 +1,39 @@ +import "package:realm/realm.dart"; +import 'package:app/models/schemas.dart'; + +const String categoryEmoji = "πŸ’Έ"; +const String categoryColor = "Color.fromARGB(255, 205, 227, 255)"; + +final onboardCategories = [ + Category(ObjectId(), "Health", "🩺", "Color.fromARGB(255, 255, 166, 168)"), + Category(ObjectId(), "Food", "πŸ•", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Electricity", "⚑️", "Color.fromARGB(255, 255, 166, 168)"), + Category(ObjectId(), "Groceries", "πŸ›’", "Color.fromARGB(255, 192, 255, 242)"), + Category(ObjectId(), "Transportation", "πŸš€", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Miscellaneous", "🧾", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Child Care", "πŸ’ž", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Lifestyle", "🧒", "Color.fromARGB(255, 255, 166, 168)"), + Category(ObjectId(), "Charity", "β€οΈβ€πŸ©Ή", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Banking", "🏦", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Clothes", "πŸ‘”", "Color.fromARGB(255, 192, 255, 242)"), + Category(ObjectId(), "Loan", "πŸ’΅", "Color.fromARGB(255, 255, 200, 163)"), + Category(ObjectId(), "Entertainment", "πŸ€ͺ", "Color.fromARGB(255, 109, 255, 175)"), + Category(ObjectId(), "Drinks", "πŸ₯‚", "Color.fromARGB(255, 192, 255, 242)"), + Category(ObjectId(), "Bills", "πŸ’Έ", "Color.fromARGB(255, 255, 191, 236)"), + Category(ObjectId(), "Home", "🏠", "Color.fromARGB(255, 255, 200, 163)"), + Category(ObjectId(), "Insurance", "πŸ–€", "Color.fromARGB(255, 213, 168, 255)"), + Category(ObjectId(), "Internet", "πŸ›œ", "Color.fromARGB(255, 184, 255, 118)"), + Category(ObjectId(), "Maintenance", "πŸ› οΈ", "Color.fromARGB(255, 255, 250, 163)"), + Category(ObjectId(), "Rent", "🏑", "Color.fromARGB(255, 255, 250, 163)"), + Category(ObjectId(), "Water", "🚿", "Color.fromARGB(255, 184, 255, 118)"), + Category(ObjectId(), "Phone", "πŸ“ž", "Color.fromARGB(255, 213, 168, 255)"), + Category(ObjectId(), "Education", "πŸ“š", "Color.fromARGB(255, 255, 250, 163)"), + Category(ObjectId(), "Gift", "πŸ’–", "Color.fromARGB(255, 184, 255, 118)"), + Category(ObjectId(), "Pharmacy", "πŸ’Š", "Color.fromARGB(255, 109, 255, 175)"), + Category(ObjectId(), "Work", "πŸ› οΈ", "Color.fromARGB(255, 255, 200, 163)"), + Category(ObjectId(), "Shopping", "πŸ›’", "Color.fromARGB(255, 213, 168, 255)"), + Category(ObjectId(), "Fuel", "⛽️", "Color.fromARGB(255, 109, 255, 175)"), +]; + + +// πŸ›’πŸš€πŸ‘ΆπŸ½πŸ‘”πŸ’—πŸ¦πŸ§’πŸ’ΈπŸ’΅πŸ€‘πŸ€ͺπŸ₯‚πŸ₯›πŸ§ΎπŸ‘🏠πŸͺ΄πŸ› οΈπŸ“šπŸ› οΈπŸ–€πŸ’˜πŸ’πŸ©·β€οΈβ€πŸ©ΉπŸ’’πŸ’–πŸ’žπŸ’šβ£οΈπŸ›œπŸ›–πŸšΏπŸ“žβ›½οΈ \ No newline at end of file diff --git a/lib/utility/schema/methods.dart b/lib/utility/schema/methods.dart index 2f00a69..e6d82c4 100644 --- a/lib/utility/schema/methods.dart +++ b/lib/utility/schema/methods.dart @@ -1,4 +1,5 @@ import 'package:app/models/schemas.dart'; +import 'package:app/utility/defaults/categories.dart'; final wallets = realm.all(); final spends = realm.all(); @@ -9,10 +10,51 @@ final subscriptions = realm.all(); // final budgets = realm.all; // Querying data for balance card -final num balance = wallets.map((wallet) => wallet.balance).toList().reduce((value, element) => value + element); +final balance = wallets + .map((wallet) => wallet.balance) + .toList() + .reduce((value, element) => value + element); final income = realm.query('name == \$0', ['Income']).first; -final totalSpend = spends.map((spend) => spend.amount).toList().reduce((value, element) => value + element); -final totalTransactions = spends.map((spend) => spend.amount).toList().length; + +// Querying data for selected wallets in accounts page wallets card +final savings = realm.query('name == \$0', ['Savings']).first; +final debts = realm.query('name == \$0', ['Debts']).first; +final flexible = realm.query('name == \$0', ['Flexible']).first; +final totalSpend = spends + .map((spend) => spend.amount) + .toList() + .reduce((value, element) => value + element); + +// final totalSpendByCategory = categories +// .map((category) => category.category +// .map((spend) => (spend.amount)) +// .reduce((value, element) => value + element)); + +final spendsCount = spends.length; +final categoriesCount = categories.length; +// Querying data for Subscriptions balance card +final num subBalance = subscriptions + .map((subscription) => subscription.amount) + .toList() + .reduce((value, element) => value + element); +final totalMonthlySubscriptionsBalance = realm + .query('duration.name == \$0', ['month']) + .toList() + .map((sub) => (sub.amount)) + .toList() + .reduce((value, element) => value + element); +final totalYearlySubscriptionsBalance = realm + .query('duration.name == \$0', ['year']) + .toList() + .map((sub) => (sub.amount)) + .toList() + .reduce((value, element) => value + element); +final totalOneTimeSubscriptionsBalance = realm + .query('duration.name == \$0', ['one time']) + .toList() + .map((sub) => (sub.amount)) + .toList() + .reduce((value, element) => value + element); // Create a new wallet and persist to db void createWallet(Wallet wallet) { @@ -34,6 +76,30 @@ void recordSpend(Spend spend) { }); } +void updateSpend(Spend spend) { + realm.write(() { + realm.add(spend, update: true); + }); +} + +void updateWallet(Wallet wallet) { + realm.write(() { + realm.add(wallet, update: true); + }); +} + +void updateCategory(Category category) { + realm.write(() { + realm.add(category, update: true); + }); +} + +void updateSubscription(Subscription subscription) { + realm.write(() { + realm.add(subscription, update: true); + }); +} + void deleteSpend(Spend spend) { realm.write(() { realm.delete(spend); @@ -63,13 +129,19 @@ void createCategory(Category category) { // Create a bunch of Categories when getting onboard void addCategories() { realm.write(() { - realm.addAll(Categories); + realm.addAll(onboardCategories); }); } void addDurations() { realm.write(() { - realm.addAll(Durations); + realm.addAll(durations); + }); +} + +void addWallets() { + realm.write(() { + realm.addAll(onboardWallets); }); } @@ -77,4 +149,15 @@ void deleteCategory(Category category) { realm.write(() { realm.delete(category); }); -} \ No newline at end of file +} + +getSpendsByWallet(String walletName) { + final spendsByWallet = realm.query("wallet.name == \$0", [walletName]); + return spendsByWallet; +} + +getSpendsByCategory(String categoryName) { + final spendsByCategory = + realm.query("category.name == \$0", [categoryName]); + return spendsByCategory; +} diff --git a/pubspec.lock b/pubspec.lock index 2bdad7e..96e82ac 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -246,6 +246,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: da9591d1f8d5881628ccd5c25c40e74fc3eef50ba45e40c3905a06e1712412d5 + url: "https://pub.dev" + source: hosted + version: "2.4.9" flutter_slidable: dependency: "direct main" description: @@ -400,6 +408,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" objectid: dependency: transitive description: @@ -496,6 +512,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + url: "https://pub.dev" + source: hosted + version: "6.1.1" pub_semver: dependency: transitive description: @@ -536,6 +560,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.6.1" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "942999ee48b899f8a46a860f1e13cee36f2f77609eb54c5b7a669bb20d550b11" + url: "https://pub.dev" + source: hosted + version: "2.4.9" sane_uuid: dependency: transitive description: @@ -653,6 +685,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" stream_channel: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c6f3a72..49fea0c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,8 @@ dependencies: flutter_slidable: shared_preferences: avatar_glow: + provider: + flutter_riverpod: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -85,7 +87,7 @@ flutter: fonts: # - asset: lib/assets/fonts/Gilroy-Black.ttf # - asset: lib/assets/fonts/Gilroy-BlackItalic.ttf - # - asset: lib/assets/fonts/Gilroy-Bold.ttf + - asset: lib/assets/fonts/Gilroy-Bold.ttf # - asset: lib/assets/fonts/Gilroy-BoldItalic.ttf # - asset: lib/assets/fonts/Gilroy-ExtraBold.ttf # - asset: lib/assets/fonts/Gilroy-ExtraBoldItalic.ttf