diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..9a75488 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/msys64/mingw64/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3df4c00 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "c:/pocket_pal", + "program": "c:/pocket_pal/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ddf6b2..5a88be7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,60 @@ { - "cmake.ignoreCMakeListsMissing": true + "cmake.ignoreCMakeListsMissing": true, + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index dd25078..828ccd0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:pocket_pal/pages/dash.dart'; import 'package:pocket_pal/pages/sign_in.dart'; import 'package:flutter/services.dart'; @@ -13,6 +14,6 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack); - return MaterialApp(debugShowCheckedModeBanner: false, home: SignInScreen()); + return MaterialApp(debugShowCheckedModeBanner: false, home: DashBoardPage()); } } diff --git a/lib/pages/dash.dart b/lib/pages/dash.dart index a1df63c..aa040a1 100644 --- a/lib/pages/dash.dart +++ b/lib/pages/dash.dart @@ -2,12 +2,8 @@ import 'package:flutter/material.dart'; import 'package:pocket_pal/widgets/bottom_navigation_bar.dart'; import 'package:pocket_pal/widgets/horizontal_cards.dart'; import 'package:pocket_pal/widgets/profile_section.dart'; -<<<<<<< HEAD -import 'package:pocket_pal/widgets/radial_chart.dart'; -import 'package:rive/rive.dart'; -======= import 'package:pocket_pal/widgets/pi_chart.dart'; ->>>>>>> 6daba8125d6946b50523811e219e6703666d7260 +import 'package:rive/rive.dart'; class DashBoardPage extends StatefulWidget { const DashBoardPage({super.key}); @@ -20,11 +16,6 @@ class _DashBoardPageState extends State { int _selectedIndex = 0; bool _isProfileVisible = true; -<<<<<<< HEAD - - -======= ->>>>>>> 6daba8125d6946b50523811e219e6703666d7260 void _onItemTapped(int index) { setState(() { _selectedIndex = index; @@ -79,7 +70,7 @@ class _DashBoardPageState extends State { children: [ SizedBox( height: MediaQuery.of(context).size.height * 0.03), - HorizontalCards(), + const HorizontalCards(isSubscriptionPage: false), SizedBox( height: MediaQuery.of(context).size.height * 0.03), PieChartWidget(data: getPieChartData()), diff --git a/lib/pages/sign_in.dart b/lib/pages/sign_in.dart index 7682251..e6f7026 100644 --- a/lib/pages/sign_in.dart +++ b/lib/pages/sign_in.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:pocket_pal/pages/dash.dart'; class SignInScreen extends StatefulWidget { - const SignInScreen({Key? key}) : super(key: key); + const SignInScreen({super.key}); @override State createState() => _SignInScreenState(); diff --git a/lib/pages/subscription_page.dart b/lib/pages/subscription_page.dart new file mode 100644 index 0000000..d3badae --- /dev/null +++ b/lib/pages/subscription_page.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:pocket_pal/widgets/horizontal_cards.dart'; +import 'package:rive/rive.dart'; // Add this import + +class SubscriptionPage extends StatelessWidget { + const SubscriptionPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + + resizeToAvoidBottomInset: false, + appBar: AppBar( + title: const Text('Subscription Tracker', + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.bold, + fontFamily: 'Arcade', + color: Colors.white, + )), + backgroundColor: const Color.fromARGB(255, 49, 2, 65), + //remove back button + automaticallyImplyLeading: false, + ), + body: Stack( + children: [ + const Positioned.fill( + child: RiveAnimation.asset( + 'assets/animations/cosmos.riv', + fit: BoxFit.cover, + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + // Search Bar + TextField( + decoration: InputDecoration( + hintText: 'Search', + hintStyle: const TextStyle(color: Colors.white70), + prefixIcon: const Icon(Icons.search, color: Colors.white70), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Colors.purple.shade100), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Colors.purple), + ), + fillColor: const Color.fromARGB(70, 168, 140, 215), + filled: true, + ), + ), + const SizedBox(height: 20), + + // Active/Expired Cards + const HorizontalCards(isSubscriptionPage: true), + const SizedBox(height: 20), + + // Spending Insights + const Text( + 'Spending Insights', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, + color: Colors.white), + ), + Expanded( + child: Container( + margin: const EdgeInsets.only(top: 10), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color.fromARGB(45, 86, 33, 131), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color.fromARGB(255, 0, 0, 0)), + + ), + child: const Center( + child: Text('Display list of subscriptions here', + style: TextStyle( + fontSize: 16, + color: Colors.white70, + )), + ), + ), + ), + ], + ), + ), + ], + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + // TODO: Implement add subscription functionality + }, + backgroundColor: const Color.fromARGB(255, 49, 2, 65), + child: const Icon(Icons.add, color: Colors.white), + ), + ); + } +} diff --git a/lib/widgets/bottom_navigation_bar.dart b/lib/widgets/bottom_navigation_bar.dart index 6037ad4..bdddded 100644 --- a/lib/widgets/bottom_navigation_bar.dart +++ b/lib/widgets/bottom_navigation_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:pocket_pal/pages/subscription_page.dart'; class PocketPalBottomNavigationBar extends StatelessWidget { const PocketPalBottomNavigationBar({ @@ -37,7 +38,16 @@ class PocketPalBottomNavigationBar extends StatelessWidget { ], currentIndex: selectedIndex, selectedItemColor: Colors.white, - onTap: (index) => onItemTapped(index), + onTap: (index) { + if (index == 2) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SubscriptionPage()), + ); + } else { + onItemTapped(index); + } + }, ); } } diff --git a/lib/widgets/cosmos.dart b/lib/widgets/cosmos.dart new file mode 100644 index 0000000..d4e9afc --- /dev/null +++ b/lib/widgets/cosmos.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +class CosmosBackground extends StatelessWidget { + const CosmosBackground({super.key}); + + @override + Widget build(BuildContext context) { + return const Positioned.fill( + child: RiveAnimation.asset( + 'assets/animations/cosmos.riv', + fit: BoxFit.cover, + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/horizontal_cards.dart b/lib/widgets/horizontal_cards.dart index 494bb0e..97e8a6e 100644 --- a/lib/widgets/horizontal_cards.dart +++ b/lib/widgets/horizontal_cards.dart @@ -1,116 +1,88 @@ import 'package:flutter/material.dart'; class HorizontalCards extends StatelessWidget { - const HorizontalCards({super.key}); + final List? cardDataList; + final bool isSubscriptionPage; + + const HorizontalCards({ + super.key, + this.cardDataList, + this.isSubscriptionPage = false, + }); + + List get _defaultSubscriptionCards => [ + CardData('Active', 10, 0, Colors.green, isCount: true), + CardData('Expired', 2, 0, Colors.red, isCount: true), + CardData('Upcoming', 5, 0, Colors.orange, isCount: true), + ]; + + List get _defaultDashboardCards => [ + CardData( + 'Expenses', + 800.0, + 2000.0, + const Color.fromARGB(138, 244, 67, 54), + showProgress: true, + ), + CardData( + 'Savings', + 1200.0, + 5000.0, + const Color.fromARGB(255, 21, 162, 92), + showProgress: true, + ), + CardData( + 'Income', + 2000.0, + 3000.0, + const Color.fromARGB(128, 33, 149, 243), + showProgress: true, + ), + ]; @override Widget build(BuildContext context) { - final cardWidth = MediaQuery.of(context).size.width * 1; - final cardHeight = MediaQuery.of(context).size.height * 1; - - final List cardDataList = [ - CardData( - 'Expenses', 800.0, 2000.0, const Color.fromARGB(138, 244, 67, 54)), - CardData('Savings', 1200.0, 5000, const Color.fromARGB(255, 21, 162, 92)), - CardData('Income', 2000.0, 0, const Color.fromARGB(128, 33, 149, 243)), - ]; + final cards = cardDataList ?? + (isSubscriptionPage + ? _defaultSubscriptionCards + : _defaultDashboardCards); return SizedBox( - height: 150, + height: isSubscriptionPage ? 120 : 150, child: ListView.builder( scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), - itemCount: cardDataList.length, + itemCount: cards.length, itemBuilder: (context, index) { - return Container( - width: cardWidth, - height: cardHeight, - padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 10), + final card = cards[index]; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), child: Card( elevation: 10, - shadowColor: cardDataList[index].color.withAlpha(100), + + shadowColor: card.color.withAlpha(100), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: Container( + //set the width of the card + width: 340, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - cardDataList[index].color.withAlpha(255), - cardDataList[index].color.withAlpha(150), + card.color.withAlpha(255), + card.color.withAlpha(150), ], ), ), - child: Stack( - alignment: Alignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - cardDataList[index].title, - style: const TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Text( - '₹${cardDataList[index].progress.toStringAsFixed(2)} / ${cardDataList[index].value.toStringAsFixed(2)}', - style: const TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: - cardDataList[index].color.withAlpha(204), - spreadRadius: 2, - blurRadius: 10, - offset: const Offset(0, 0), - ), - ], - ), - child: SizedBox( - width: 60, - height: 60, - child: CircularProgressIndicator( - value: cardDataList[index].value != 0 - ? cardDataList[index].progress / - cardDataList[index].value - : 0, - backgroundColor: - const Color.fromARGB(255, 159, 158, 158), - valueColor: const AlwaysStoppedAnimation( - Colors.white), - strokeWidth: 8, - ), - ), - ), - ], - ), - ), - ], + child: Padding( + padding: const EdgeInsets.all(16.0), + child: card.showProgress + ? _buildProgressCard(card) + : _buildCountCard(card), ), ), ), @@ -119,6 +91,87 @@ class HorizontalCards extends StatelessWidget { ), ); } + + Widget _buildProgressCard(CardData card) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + card.title, + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + '₹${card.progress.toStringAsFixed(2)} / ${card.value.toStringAsFixed(2)}', + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + _buildProgressIndicator(card), + ], + ); + } + + Widget _buildCountCard(CardData card) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + card.title, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + card.progress.toInt().toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], + ); + } + + Widget _buildProgressIndicator(CardData card) { + return Container( + width: 90, + height: 80, + padding: const EdgeInsets.fromLTRB(15,0,0,0), + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: card.color.withAlpha(204), + spreadRadius: 2, + blurRadius: 10, + ), + ], + ), + child: CircularProgressIndicator( + value: card.value != 0 ? card.progress / card.value : 0, + backgroundColor: const Color.fromARGB(255, 159, 158, 158), + valueColor: const AlwaysStoppedAnimation(Colors.white), + strokeWidth: 8, + ), + ); + } } class CardData { @@ -126,6 +179,15 @@ class CardData { final double progress; final double value; final Color color; + final bool isCount; + final bool showProgress; - CardData(this.title, this.progress, this.value, this.color); + CardData( + this.title, + this.progress, + this.value, + this.color, { + this.isCount = false, + this.showProgress = false, + }); } diff --git a/lib/widgets/pi_chart.dart b/lib/widgets/pi_chart.dart index af3ddaf..d13a87f 100644 --- a/lib/widgets/pi_chart.dart +++ b/lib/widgets/pi_chart.dart @@ -4,7 +4,7 @@ import 'package:syncfusion_flutter_charts/charts.dart'; class PieChartWidget extends StatelessWidget { final List data; - const PieChartWidget({Key? key, required this.data}) : super(key: key); + const PieChartWidget({super.key, required this.data}); @override Widget build(BuildContext context) { diff --git a/pubspec.yaml b/pubspec.yaml index 3b5eb27..64bf90b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,10 +27,10 @@ dev_dependencies: flutter: assets: - assets/123.jpg + - assets/animations/cosmos.riv uses-material-design: true fonts: - family: Arcade fonts: - asset: fonts/ARCADECLASSIC.TTF - assets: - - assets/animations/cosmos.riv \ No newline at end of file + \ No newline at end of file