From dd5181af9465c8a47d139d1353ecaccbc695f37b Mon Sep 17 00:00:00 2001 From: jayesh Date: Mon, 10 Jun 2024 18:49:10 +0530 Subject: [PATCH] invest screen ui --- assets/images/invest_screen/svg/scanner.svg | 7 + .../images/invest_screen/svg/shield_done.svg | 3 + assets/images/invest_screen/svg/ticket.svg | 6 + .../images/invest_screen/svg/time_square.svg | 4 + assets/images/invest_screen/svg/wallet.svg | 6 + lib/core/routes/route_name.dart | 3 + lib/core/routes/routes.dart | 8 + lib/core/styles/app_color.dart | 7 + lib/core/styles/app_images.dart | 10 + lib/core/styles/app_text.dart | 15 ++ .../Invest/presentation/bloc/tab_bloc.dart | 25 +++ .../Invest/presentation/bloc/tab_event.dart | 12 ++ .../Invest/presentation/bloc/tab_state.dart | 24 +++ .../presentation/pages/investScreen.dart | 17 -- .../pages/invest_details_layout.dart | 59 ++++++ .../pages/invest_details_screen.dart | 40 ++++ .../presentation/pages/invest_layout.dart | 177 ++++++++++++++++++ .../presentation/pages/invest_screen.dart | 48 +++++ .../pages/invest_video_section.dart | 89 +++++++++ .../widgets/invest_details_section.dart | 155 +++++++++++++++ .../widgets/invest_image_carousel.dart | 149 +++++++++++++++ .../invest_included_documents_section.dart | 103 ++++++++++ .../widgets/key_investment_section.dart | 92 +++++++++ .../Invest/presentation/widgets/kyc_card.dart | 58 ++++++ lib/features/MainScreens/main_screen.dart | 2 +- lib/shared/components/text_widget.dart | 16 ++ pubspec.yaml | 2 + 27 files changed, 1119 insertions(+), 18 deletions(-) create mode 100644 assets/images/invest_screen/svg/scanner.svg create mode 100644 assets/images/invest_screen/svg/shield_done.svg create mode 100644 assets/images/invest_screen/svg/ticket.svg create mode 100644 assets/images/invest_screen/svg/time_square.svg create mode 100644 assets/images/invest_screen/svg/wallet.svg create mode 100644 lib/features/MainScreens/Invest/presentation/bloc/tab_bloc.dart create mode 100644 lib/features/MainScreens/Invest/presentation/bloc/tab_event.dart create mode 100644 lib/features/MainScreens/Invest/presentation/bloc/tab_state.dart delete mode 100644 lib/features/MainScreens/Invest/presentation/pages/investScreen.dart create mode 100644 lib/features/MainScreens/Invest/presentation/pages/invest_details_layout.dart create mode 100644 lib/features/MainScreens/Invest/presentation/pages/invest_details_screen.dart create mode 100644 lib/features/MainScreens/Invest/presentation/pages/invest_layout.dart create mode 100644 lib/features/MainScreens/Invest/presentation/pages/invest_screen.dart create mode 100644 lib/features/MainScreens/Invest/presentation/pages/invest_video_section.dart create mode 100644 lib/features/MainScreens/Invest/presentation/widgets/invest_details_section.dart create mode 100644 lib/features/MainScreens/Invest/presentation/widgets/invest_image_carousel.dart create mode 100644 lib/features/MainScreens/Invest/presentation/widgets/invest_included_documents_section.dart create mode 100644 lib/features/MainScreens/Invest/presentation/widgets/key_investment_section.dart create mode 100644 lib/features/MainScreens/Invest/presentation/widgets/kyc_card.dart diff --git a/assets/images/invest_screen/svg/scanner.svg b/assets/images/invest_screen/svg/scanner.svg new file mode 100644 index 0000000..e8062fd --- /dev/null +++ b/assets/images/invest_screen/svg/scanner.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/images/invest_screen/svg/shield_done.svg b/assets/images/invest_screen/svg/shield_done.svg new file mode 100644 index 0000000..b717469 --- /dev/null +++ b/assets/images/invest_screen/svg/shield_done.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/invest_screen/svg/ticket.svg b/assets/images/invest_screen/svg/ticket.svg new file mode 100644 index 0000000..9d29f0c --- /dev/null +++ b/assets/images/invest_screen/svg/ticket.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/invest_screen/svg/time_square.svg b/assets/images/invest_screen/svg/time_square.svg new file mode 100644 index 0000000..595e77c --- /dev/null +++ b/assets/images/invest_screen/svg/time_square.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/invest_screen/svg/wallet.svg b/assets/images/invest_screen/svg/wallet.svg new file mode 100644 index 0000000..003542b --- /dev/null +++ b/assets/images/invest_screen/svg/wallet.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/core/routes/route_name.dart b/lib/core/routes/route_name.dart index feb59b7..b17021c 100644 --- a/lib/core/routes/route_name.dart +++ b/lib/core/routes/route_name.dart @@ -61,4 +61,7 @@ class RouteName { //change password static const String changePasswordScreen = "changePasswordScreen"; + + //invest + static const String investDetailScreen = "investDetailScreen"; } diff --git a/lib/core/routes/routes.dart b/lib/core/routes/routes.dart index 73c2dc3..ed6891d 100644 --- a/lib/core/routes/routes.dart +++ b/lib/core/routes/routes.dart @@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart'; import 'package:tanami_app/core/routes/route_name.dart'; import 'package:tanami_app/features/MainScreens/Academy/presentation/pages/academy_details_screen.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/pages/invest_details_screen.dart'; import 'package:tanami_app/features/MainScreens/Portfolio/presentation/pages/portfolio_details_screen.dart'; import 'package:tanami_app/features/MainScreens/Wallet/presentation/pages/walletDetails.dart'; @@ -193,6 +194,13 @@ final goRouter = GoRouter( return const ChangePasswordScreen(); }, ), + GoRoute( + name: RouteName.investDetailScreen, + path: RouteName.investDetailScreen, + builder: (context, state) { + return const InvestDetailsScreen(); + }, + ), ], ), ], diff --git a/lib/core/styles/app_color.dart b/lib/core/styles/app_color.dart index 8a54af0..c75199a 100644 --- a/lib/core/styles/app_color.dart +++ b/lib/core/styles/app_color.dart @@ -83,4 +83,11 @@ class AppColor { //Delete Account Color static const Color descriptionText = Color(0xFFC6C6C6); + + //Invest Color + static const Color investKycCardColor = Color(0xFFEEF5FA); + static const Color investKycBorderColor = Color(0xFFB0D3EF); + static const Color investKycBoxShadow1Color = Color(0xFF90D4FF); + static const Color investKycBoxShadow2Color = Color(0xA0DAF0FF); + static const Color investTextColor = Color(0xFF066123); } diff --git a/lib/core/styles/app_images.dart b/lib/core/styles/app_images.dart index 4099df1..4e8f49c 100644 --- a/lib/core/styles/app_images.dart +++ b/lib/core/styles/app_images.dart @@ -102,4 +102,14 @@ class AppImages { //Language static const String infoIcon = 'assets/images/language_screen/png/info_icon.png'; + + //Invest + static const String investIcon = + 'assets/images/invest_screen/svg/shield_done.svg'; + static const String scannerIcon = + 'assets/images/invest_screen/svg/scanner.svg'; + static const String ticketIcon = 'assets/images/invest_screen/svg/ticket.svg'; + static const String walletIcon = 'assets/images/invest_screen/svg/wallet.svg'; + static const String timeSquareIcon = + 'assets/images/invest_screen/svg/time_square.svg'; } diff --git a/lib/core/styles/app_text.dart b/lib/core/styles/app_text.dart index 1959a24..d6be32b 100644 --- a/lib/core/styles/app_text.dart +++ b/lib/core/styles/app_text.dart @@ -189,4 +189,19 @@ class AppText { static const String theRequestWillBeProcessed = "The request will be processed within 72 hours"; static const closeText = "Close"; + + //Invest + static const String investText = "Invest"; + static const String availableText = "Available"; + static const String closedText = "Closed"; + static const String completeYourVerification = "Complete your verification"; + static const String verifyYourAccountInUnderMinutesToStartInvestingToday = + "Verify your account in under 10 minutes to start investing today!"; + static const String closingDateText = "Closing Date"; + static const String fundedText = "funded"; + static const String sponsorNameText = "Sponsor name"; + static const String estimatedReturnText = "Estimated return"; + static const String holdingPeriodText = "Holding period"; + static const String minimumInvestmentText = "Minimum investment"; + static const String keyMeritsIOfnvestmentText = "Key Merits of Investment"; } diff --git a/lib/features/MainScreens/Invest/presentation/bloc/tab_bloc.dart b/lib/features/MainScreens/Invest/presentation/bloc/tab_bloc.dart new file mode 100644 index 0000000..a953b48 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/bloc/tab_bloc.dart @@ -0,0 +1,25 @@ +import 'package:bloc/bloc.dart'; + +import 'tab_event.dart'; +import 'tab_state.dart'; + +class TabBloc extends Bloc { + TabBloc() : super(const TabState()) { + on(_onLoadAvailableItems); + on(_onLoadClosedItems); + } + + void _onLoadAvailableItems(LoadAvailableItems event, Emitter emit) { + // Simulate fetching available items + final availableItems = + List.generate(10, (index) => 'Available Item $index'); + emit(state.copyWith(availableItems: availableItems)); + } + + void _onLoadClosedItems(LoadClosedItems event, Emitter emit) { + // Simulate fetching closed items + final closedItems = + List.generate(10, (index) => 'Closed Item $index'); + emit(state.copyWith(closedItems: closedItems)); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/bloc/tab_event.dart b/lib/features/MainScreens/Invest/presentation/bloc/tab_event.dart new file mode 100644 index 0000000..427e302 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/bloc/tab_event.dart @@ -0,0 +1,12 @@ +import 'package:equatable/equatable.dart'; + +abstract class TabEvent extends Equatable { + const TabEvent(); + + @override + List get props => []; +} + +class LoadAvailableItems extends TabEvent {} + +class LoadClosedItems extends TabEvent {} diff --git a/lib/features/MainScreens/Invest/presentation/bloc/tab_state.dart b/lib/features/MainScreens/Invest/presentation/bloc/tab_state.dart new file mode 100644 index 0000000..b4e0d8e --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/bloc/tab_state.dart @@ -0,0 +1,24 @@ +import 'package:equatable/equatable.dart'; + +class TabState extends Equatable { + final List availableItems; + final List closedItems; + + const TabState({ + this.availableItems = const [], + this.closedItems = const [], + }); + + TabState copyWith({ + List? availableItems, + List? closedItems, + }) { + return TabState( + availableItems: availableItems ?? this.availableItems, + closedItems: closedItems ?? this.closedItems, + ); + } + + @override + List get props => [availableItems, closedItems]; +} diff --git a/lib/features/MainScreens/Invest/presentation/pages/investScreen.dart b/lib/features/MainScreens/Invest/presentation/pages/investScreen.dart deleted file mode 100644 index 36d8b2a..0000000 --- a/lib/features/MainScreens/Invest/presentation/pages/investScreen.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; - -class InvestScreen extends StatefulWidget { - const InvestScreen({super.key}); - - @override - State createState() => _InvestScreenState(); -} - -class _InvestScreenState extends State { - @override - Widget build(BuildContext context) { - return const Scaffold( - body: Text('Invest'), - ); - } -} diff --git a/lib/features/MainScreens/Invest/presentation/pages/invest_details_layout.dart b/lib/features/MainScreens/Invest/presentation/pages/invest_details_layout.dart new file mode 100644 index 0000000..6556012 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/pages/invest_details_layout.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/pages/invest_video_section.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/widgets/invest_details_section.dart'; + +import '../widgets/invest_image_carousel.dart'; +import '../widgets/invest_included_documents_section.dart'; +import '../widgets/key_investment_section.dart'; + +class InvestDetailsLayout extends StatelessWidget { + const InvestDetailsLayout({super.key}); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + color: AppColor.plainWhite, + borderRadius: const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: AppColor.plainBlack.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), + ), + ], + ), + child: Column( + children: [ + InvestCarouselView(), + const InvestDetailsSection(), + ], + ), + ), + Gap( + 20.h, + ), + const KeyInvestmentSection(), + Gap( + 20.h, + ), + const InvestIncludedDocumentsSection(), + Gap( + 20.h, + ), + const InvestVideoSection(), + ], + ), + ), + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/pages/invest_details_screen.dart b/lib/features/MainScreens/Invest/presentation/pages/invest_details_screen.dart new file mode 100644 index 0000000..d495009 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/pages/invest_details_screen.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/button_widget.dart'; +import '../../../../../shared/components/appbar_widget.dart'; +import '../../../Portfolio/presentation/bloc/carousel/carousel_bloc.dart'; +import 'invest_details_layout.dart'; + +class InvestDetailsScreen extends StatelessWidget { + const InvestDetailsScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + bottomNavigationBar: Container( + padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 26), + width: 1.sw, + height: 105.h, + child: ButtonWidget().elevatedBtn( + text: AppText.investText, + clr: AppColor.primaryColor2, + function: () {}), + ), + appBar: const AppBarWidget( + height: 45, + titleTxt: "", + ), + body: MultiBlocProvider( + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => CarouselBloc(), + ), + ], + child: const InvestDetailsLayout(), + )); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/pages/invest_layout.dart b/lib/features/MainScreens/Invest/presentation/pages/invest_layout.dart new file mode 100644 index 0000000..6ea294f --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/pages/invest_layout.dart @@ -0,0 +1,177 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:tanami_app/core/routes/route_name.dart'; +import 'package:tanami_app/core/routes/routes.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/widgets/kyc_card.dart'; + +import '../bloc/tab_bloc.dart'; +import '../bloc/tab_event.dart'; +import '../bloc/tab_state.dart'; +import '../widgets/invest_details_section.dart'; +import '../widgets/invest_image_carousel.dart'; + +class InvestLayout extends StatelessWidget { + const InvestLayout({super.key}); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Scaffold( + body: Column( + children: [ + TabBar( + tabs: const [ + Tab(text: AppText.availableText), + Tab(text: AppText.closedText), + ], + labelStyle: GoogleFonts.dmSans( + fontWeight: FontWeight.bold, + fontSize: 14.0, + ), + unselectedLabelStyle: GoogleFonts.dmSans( + fontWeight: FontWeight.normal, + fontSize: 14.0, + ), + labelColor: AppColor.plainBlack, + unselectedLabelColor: AppColor.charcoalColor, + indicatorColor: AppColor.plainBlack, + indicatorSize: TabBarIndicatorSize.tab, + indicatorWeight: 1.0, + indicatorPadding: const EdgeInsets.symmetric(horizontal: 16.0), + ), + const Expanded( + child: TabBarView( + children: [ + AvailableItemsScreen(), + ClosedItemsScreen(), + ], + ), + ), + ], + ), + ), + ); + } +} + +class AvailableItemsScreen extends StatelessWidget { + const AvailableItemsScreen({super.key}); + + @override + Widget build(BuildContext context) { + context.read().add(LoadAvailableItems()); + + return BlocBuilder( + builder: (context, state) { + if (state.availableItems.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } + return ListView.builder( + itemCount: state.availableItems.length, + itemBuilder: (context, index) { + return index == 0 + ? Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 18, + ), + child: kycCard()) + : InkWell( + onTap: () { + goRouter.pushNamed(RouteName.investDetailScreen); + }, + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 18, + ), + decoration: BoxDecoration( + color: AppColor.plainWhite, + borderRadius: + const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: AppColor.plainBlack.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), + ), + ], + ), + child: Column( + children: [ + InvestCarouselView(), + const InvestDetailsSection(), + ], + ), + ), + ); + }, + ); + }, + ); + } +} + +class ClosedItemsScreen extends StatelessWidget { + const ClosedItemsScreen({super.key}); + + @override + Widget build(BuildContext context) { + context.read().add(LoadClosedItems()); + + return BlocBuilder( + builder: (context, state) { + if (state.closedItems.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } + return ListView.builder( + itemCount: state.closedItems.length, + itemBuilder: (context, index) { + return index == 0 + ? Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 18, + ), + child: kycCard()) + : InkWell( + onTap: () { + goRouter.pushNamed(RouteName.investDetailScreen); + }, + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 18, + ), + decoration: BoxDecoration( + color: AppColor.plainWhite, + borderRadius: + const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: AppColor.plainBlack.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), + ), + ], + ), + child: Column( + children: [ + InvestCarouselView(), + const InvestDetailsSection(), + ], + ), + ), + ); + }, + ); + }, + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/pages/invest_screen.dart b/lib/features/MainScreens/Invest/presentation/pages/invest_screen.dart new file mode 100644 index 0000000..1023769 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/pages/invest_screen.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/bloc/tab_bloc.dart'; +import 'package:tanami_app/features/MainScreens/Portfolio/presentation/bloc/carousel/carousel_bloc.dart'; + +import '../../../../../core/styles/app_color.dart'; +import '../../../../../core/styles/app_text.dart'; +import '../../../../../shared/components/text_widget.dart'; +import 'invest_layout.dart'; + +class InvestScreen extends StatefulWidget { + const InvestScreen({super.key}); + + @override + State createState() => _InvestScreenState(); +} + +class _InvestScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + // backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + automaticallyImplyLeading: false, + title: TextWidget().text22W700( + AppText.investText, + clr: AppColor.charcoalColor, + ), + titleSpacing: 16, + ), + body: MultiBlocProvider( + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => TabBloc(), + ), + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => CarouselBloc(), + ), + ], + child: const InvestLayout(), + ), + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/pages/invest_video_section.dart b/lib/features/MainScreens/Invest/presentation/pages/invest_video_section.dart new file mode 100644 index 0000000..35b798e --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/pages/invest_video_section.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; + +import '../../../../../core/styles/app_text.dart'; + +class InvestVideoSection extends StatelessWidget { + const InvestVideoSection({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppText.videosTitle, + style: GoogleFonts.dmSans( + color: Colors.black, + fontSize: 15.sp, + fontWeight: FontWeight.w700, + ), + ), + SizedBox( + height: 12.h, + ), + ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: videos.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(18.0), + ), + child: Stack( + children: [ + Image.asset( + videos[index], + fit: BoxFit.cover, + height: 160.h, + width: 1.sw, + ), + Positioned( + bottom: 0.0, + child: Image.asset( + AppImages.academyCardOverlay, + ), + ), + Positioned.fill( + child: Image.asset( + AppImages.videoPlayIcon, + ), + ) + ], + ), + ), + ); + }, + ) + ], + ), + ), + ); + } +} + +List videos = [ + 'assets/images/academy_screen/vd_bg.jpg', + 'assets/images/academy_screen/vd_bg.jpg', + 'assets/images/academy_screen/vd_bg.jpg' +]; diff --git a/lib/features/MainScreens/Invest/presentation/widgets/invest_details_section.dart b/lib/features/MainScreens/Invest/presentation/widgets/invest_details_section.dart new file mode 100644 index 0000000..f80a133 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/widgets/invest_details_section.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import '../../../../../core/styles/app_text.dart'; +import '../../../../../shared/components/text_widget.dart'; + +class InvestDetailsSection extends StatelessWidget { + const InvestDetailsSection({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + color: AppColor.plainWhite, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text17W700( + 'Multi Family Residental', + clr: AppColor.plainBlack, + ), + Gap( + 10.h, + ), + TextWidget() + .text22W400("SAR 1,478,000", clr: AppColor.investTextColor), + const Gap(8.0), + LinearProgressIndicator( + value: 0.6, + borderRadius: BorderRadius.circular(2), + minHeight: 8.0, + backgroundColor: AppColor.txtBorderColor, + valueColor: const AlwaysStoppedAnimation( + AppColor.investTextColor), + ), + const Gap(8.0), + TextWidget().text11W700("60% ${AppText.fundedText}", + clr: AppColor.portoflioCardTextColor), + const Gap(8.0), + TextWidget().text14W400( + 'Forem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur tempus urna at turpis condimentum lobortis.', + clr: Colors.grey, + txtAlign: TextAlign.start, + ) + ], + ), + ), + ), + Container( + decoration: const BoxDecoration( + color: AppColor.portfolioCardBgColor, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20.0), + bottomRight: Radius.circular(20.0), + ), + ), + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20.0, vertical: 16.0), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 150.w, + child: TextWidget().text14W500( + "${AppText.sponsorNameText}:", + clr: AppColor.portoflioCardTextColor, + txtAlign: TextAlign.start, + ), + ), + TextWidget().text14W700( + 'Silverlake', + clr: AppColor.plainBlack, + txtAlign: TextAlign.end, + ) + ], + ), + SizedBox( + height: 8.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 150.w, + child: TextWidget().text14W500( + "${AppText.estimatedReturnText}:", + clr: AppColor.portoflioCardTextColor, + txtAlign: TextAlign.start, + ), + ), + TextWidget().text14W700( + '20.0%', + clr: AppColor.plainBlack, + txtAlign: TextAlign.end, + ), + ], + ), + SizedBox( + height: 8.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 150.w, + child: TextWidget().text14W500( + "${AppText.holdingPeriodText}:", + clr: AppColor.portoflioCardTextColor, + txtAlign: TextAlign.start, + ), + ), + TextWidget().text14W700( + '24 Months', + clr: AppColor.plainBlack, + txtAlign: TextAlign.end, + ), + ], + ), + SizedBox( + height: 8.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text14W500( + "${AppText.minimumInvestmentText}:", + clr: AppColor.portoflioCardTextColor, + txtAlign: TextAlign.start, + ), + TextWidget().text14W700( + 'SAR 1,000', + clr: AppColor.plainBlack, + txtAlign: TextAlign.end, + ), + ], + ) + ], + ), + ), + ) + ], + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/widgets/invest_image_carousel.dart b/lib/features/MainScreens/Invest/presentation/widgets/invest_image_carousel.dart new file mode 100644 index 0000000..8072eb8 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/widgets/invest_image_carousel.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +import '../../../Portfolio/presentation/bloc/carousel/carousel_bloc.dart'; +import '../../../Portfolio/presentation/bloc/carousel/carousel_event.dart'; +import '../../../Portfolio/presentation/bloc/carousel/carousel_state.dart'; + +final List imgList = [ + {'id': 1, 'img_path': 'assets/images/portfolio_screen/detailsbg.png'}, + {'id': 2, 'img_path': 'assets/images/portfolio_screen/detailsbg.png'}, + {'id': 3, 'img_path': 'assets/images/portfolio_screen/detailsbg.png'}, + {'id': 4, 'img_path': 'assets/images/portfolio_screen/detailsbg.png'}, + {'id': 5, 'img_path': 'assets/images/portfolio_screen/detailsbg.png'}, +]; + +class InvestCarouselView extends StatelessWidget { + final CarouselController _controller = CarouselController(); + + InvestCarouselView({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + height: 190.h, + decoration: const BoxDecoration( + color: AppColor.portfolioCardBgColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + ), + ), + child: Stack( + children: [ + ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + ), + child: CarouselSlider( + items: imgList + .map( + (item) => Image.asset( + item['img_path'], + fit: BoxFit.cover, + width: double.infinity, + alignment: Alignment.topCenter, + ), + ) + .toList(), + carouselController: _controller, + options: CarouselOptions( + scrollPhysics: const BouncingScrollPhysics(), + autoPlay: true, + aspectRatio: 2, + viewportFraction: 1, + onPageChanged: (index, reason) { + context.read().add(PageChanged(index)); + }), + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 17.0), + child: BlocBuilder( + builder: (context, state) { + int currentIndex = 0; + if (state is CarouselPageState) { + currentIndex = state.currentIndex; + } + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: imgList.asMap().entries.map((entry) { + return GestureDetector( + onTap: () => _controller.animateToPage(entry.key), + child: Container( + width: 20.w, + height: 7.h, + margin: const EdgeInsets.symmetric(horizontal: 3.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: (currentIndex == entry.key) + ? AppColor.plainWhite + : AppColor.smokeGrayColor, + ), + ), + ); + }).toList(), + ); + }, + ), + ), + ), + Positioned( + top: 20, + left: 20, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0), + decoration: BoxDecoration( + color: const Color(0xFFE4F5E9), + borderRadius: BorderRadius.circular(30.0), + ), + child: TextWidget().text12W700( + 'Asset Class', + clr: AppColor.selectedItemColor, + ), + ), + ), + Positioned( + top: 20, + right: 20, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30.0), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Image.asset( + AppImages.portfolioClock, + height: 15.h, + ), + Gap( + 5.w, + ), + TextWidget().text12W500( + '${AppText.closingDateText} Jul 10 2025', + clr: AppColor.plainBlack, + ), + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/widgets/invest_included_documents_section.dart b/lib/features/MainScreens/Invest/presentation/widgets/invest_included_documents_section.dart new file mode 100644 index 0000000..5239042 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/widgets/invest_included_documents_section.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +import '../../../../../core/styles/app_text.dart'; + +class InvestIncludedDocumentsSection extends StatelessWidget { + const InvestIncludedDocumentsSection({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.plainWhite, + borderRadius: const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: AppColor.plainBlack.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text15W700( + AppText.includeddocs, + clr: AppColor.plainBlack, + ), + Gap( + 16.h, + ), + GridView.count( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + childAspectRatio: 1.7, + mainAxisSpacing: 10.h, + crossAxisSpacing: 10.w, + crossAxisCount: 2, // Number of columns + children: List.generate( + 6, + (index) { + return Center( + child: Container( + decoration: const BoxDecoration( + color: AppColor.documentCardBgColor, + borderRadius: BorderRadius.all(Radius.circular(10.0)), + ), + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + Row( + children: [ + Image.asset( + AppImages.documentIcon, + height: 16.sp, + ), + Gap( + 7.w, + ), + TextWidget().text12W700("Filename.pdf", + clr: AppColor.plainBlack), + ], + ), + Gap( + 14.h, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextWidget().text12W700("512 Mb", + clr: AppColor.portoflioCardTextColor), + Gap( + 7.w, + ), + Image.asset( + AppImages.donwloadIcon, + height: 20.sp, + ), + ], + ), + ], + ), + ), + ); + }, + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/features/MainScreens/Invest/presentation/widgets/key_investment_section.dart b/lib/features/MainScreens/Invest/presentation/widgets/key_investment_section.dart new file mode 100644 index 0000000..1aed2e2 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/widgets/key_investment_section.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +import '../../../../../core/styles/app_text.dart'; + +class KeyInvestmentSection extends StatelessWidget { + const KeyInvestmentSection({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.plainWhite, + borderRadius: const BorderRadius.all(Radius.circular(20.0)), + boxShadow: [ + BoxShadow( + color: AppColor.plainBlack.withOpacity(0.15), + spreadRadius: 2, + blurRadius: 10, + offset: const Offset(0, 3), // changes position of shadow + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text15W700( + AppText.keyMeritsIOfnvestmentText, + clr: AppColor.plainBlack, + ), + Gap( + 16.h, + ), + ListView.builder( + itemCount: 4, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (ctx, index) { + return Container( + margin: const EdgeInsets.only( + bottom: 12, + ), + child: investmentSectionCardText( + AppImages.timeSquareIcon, + "Nunc vulputate libero et velit interdum", + "ac aliquet odio mattis.", + ), + ); + }) + ], + ), + ), + ); + } +} + +Widget investmentSectionCardText( + String icon, + String title, + String subtitle, +) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset(icon), + const Gap(8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text14W700( + title, + clr: AppColor.textLabelColor, + txtAlign: TextAlign.start, + ), + TextWidget().text14W400( + subtitle, + clr: AppColor.textLabelColor, + txtAlign: TextAlign.start, + ), + ], + ) + ], + ); +} diff --git a/lib/features/MainScreens/Invest/presentation/widgets/kyc_card.dart b/lib/features/MainScreens/Invest/presentation/widgets/kyc_card.dart new file mode 100644 index 0000000..c94c539 --- /dev/null +++ b/lib/features/MainScreens/Invest/presentation/widgets/kyc_card.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +Widget kycCard() { + return Container( + clipBehavior: Clip.antiAlias, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: ShapeDecoration( + color: AppColor.investKycCardColor, + shape: RoundedRectangleBorder( + side: const BorderSide(width: 1, color: AppColor.investKycBorderColor), + borderRadius: BorderRadius.circular(22), + ), + shadows: const [ + BoxShadow( + color: AppColor.investKycBoxShadow1Color, + blurRadius: 4, + offset: Offset(0, 1), + spreadRadius: 0, + ), + BoxShadow( + color: AppColor.investKycBoxShadow2Color, + blurRadius: 4, + offset: Offset(0, 8), + spreadRadius: 0, + ) + ], + ), + child: Row( + children: [ + SvgPicture.asset( + AppImages.investIcon, + ), + const Gap(8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget().text14W600( + AppText.completeYourVerification, + clr: AppColor.languageTextColor, + ), + TextWidget().text11W500( + AppText.verifyYourAccountInUnderMinutesToStartInvestingToday, + clr: AppColor.languageTextColor, + ), + ], + ), + ), + ], + ), + ); +} diff --git a/lib/features/MainScreens/main_screen.dart b/lib/features/MainScreens/main_screen.dart index 3189a75..ddfafcf 100644 --- a/lib/features/MainScreens/main_screen.dart +++ b/lib/features/MainScreens/main_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tanami_app/features/MainScreens/Academy/presentation/pages/academy_screen.dart'; -import 'package:tanami_app/features/MainScreens/Invest/presentation/pages/investScreen.dart'; +import 'package:tanami_app/features/MainScreens/Invest/presentation/pages/invest_screen.dart'; import 'package:tanami_app/features/MainScreens/Portfolio/presentation/pages/portfolio_screen.dart'; import 'package:tanami_app/features/MainScreens/Settings/presentation/pages/settings_Screen.dart'; import 'package:tanami_app/features/MainScreens/Wallet/presentation/pages/walletScreen.dart'; diff --git a/lib/shared/components/text_widget.dart b/lib/shared/components/text_widget.dart index 1398b21..12a2ea2 100644 --- a/lib/shared/components/text_widget.dart +++ b/lib/shared/components/text_widget.dart @@ -20,6 +20,14 @@ class TextWidget { color: clr ?? AppColor.plainWhite)); } + Widget text11W700(String text, {Color? clr}) { + return Text(text, + style: GoogleFonts.dmSans( + fontSize: 11, + fontWeight: FontWeight.w700, + color: clr ?? AppColor.plainWhite)); + } + //Text Size 12 Widget text12W400(String text, {Color? clr}) { return Text(text, @@ -213,6 +221,14 @@ class TextWidget { } //Text Size 22 + Widget text22W400(String text, {Color? clr}) { + return Text(text, + style: GoogleFonts.dmSans( + fontSize: 22, + fontWeight: FontWeight.w400, + color: clr ?? AppColor.plainWhite)); + } + Widget text22W700(String text, {Color? clr}) { return Text(text, style: GoogleFonts.dmSans( diff --git a/pubspec.yaml b/pubspec.yaml index a2a6ee1..4eb7165 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -118,3 +118,5 @@ flutter: - assets/images/settings_screen/svg/ - assets/images/language_screen/ - assets/images/language_screen/png/ + - assets/images/invest_screen/ + - assets/images/invest_screen/svg/