Compare commits
7 Commits
db6e4d543d
...
d86820ec98
Author | SHA1 | Date | |
---|---|---|---|
d86820ec98 | |||
ececa5e541 | |||
b0de8c255e | |||
6977c8166d | |||
7a1cddee03 | |||
59e6e82d13 | |||
9475767021 |
|
@ -12,6 +12,12 @@ if (localPropertiesFile.exists()) {
|
|||
}
|
||||
}
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
|
@ -51,11 +57,21 @@ android {
|
|||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
// signingConfig signingConfigs.debug
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
BIN
assets/icons/icon-balance.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/icons/icon-coins.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/icons/icon-money-receive.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
assets/icons/icon-strongbox.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/images/img-business-failure.png
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
assets/images/img-cat.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
assets/images/img-data-analysis.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
assets/images/img-data-report.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
assets/images/img-deer.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/img-growing.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
assets/images/img-leader.png
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
assets/images/img-lion.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
assets/images/img-money-income.png
Normal file
After Width: | Height: | Size: 60 KiB |
|
@ -10,14 +10,10 @@ class PathAssets {
|
|||
static const String iconGoogle = 'assets/icons/icon-google.png';
|
||||
static const String icon1 = 'assets/icons/icon-1.png';
|
||||
static const String iconConnect = 'assets/icons/icon-connect.png';
|
||||
static const String iconPortofolioBonds =
|
||||
'assets/icons/icon-portofolio-bonds.png';
|
||||
static const String iconPortofolioShares =
|
||||
'assets/icons/icon-portofolio-shares.png';
|
||||
static const String iconPortofolioSharia =
|
||||
'assets/icons/icon-portofolio-sharia.png';
|
||||
static const String iconPortofolioMoneyMarket =
|
||||
'assets/icons/icon-portofolio-moneymarket.png';
|
||||
static const String iconPortofolioBonds = 'assets/icons/icon-portofolio-bonds.png';
|
||||
static const String iconPortofolioShares = 'assets/icons/icon-portofolio-shares.png';
|
||||
static const String iconPortofolioSharia = 'assets/icons/icon-portofolio-sharia.png';
|
||||
static const String iconPortofolioMoneyMarket = 'assets/icons/icon-portofolio-moneymarket.png';
|
||||
static const String iconShield = 'assets/icons/icon-shield.png';
|
||||
static const String iconFlag = 'assets/icons/icon-flag.png';
|
||||
static const String iconKtp1 = 'assets/icons/icon-ktp1.png';
|
||||
|
@ -28,6 +24,10 @@ class PathAssets {
|
|||
static const String iconSelfie2 = 'assets/icons/icon-selfie2.png';
|
||||
static const String iconSelfie3 = 'assets/icons/icon-selfie3.png';
|
||||
static const String iconSelfie4 = 'assets/icons/icon-selfie4.png';
|
||||
static const String iconStrongBox = 'assets/icons/icon-strongbox.png';
|
||||
static const String iconBalance = 'assets/icons/icon-balance.png';
|
||||
static const String iconMoneyReceive = 'assets/icons/icon-money-receive.png';
|
||||
static const String iconCoins = 'assets/icons/icon-coins.png';
|
||||
|
||||
/// IMAGE
|
||||
static const String imgSplashLogo = 'assets/images/splash-logo.png';
|
||||
|
@ -40,12 +40,20 @@ class PathAssets {
|
|||
static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png';
|
||||
static const String imgKtpClear = 'assets/images/img-ktp-clear.png';
|
||||
static const String imgKtpBlur = 'assets/images/img-ktp-blur.png';
|
||||
static const String imgDashboardAccount =
|
||||
'assets/images/img-dashboard-account.png';
|
||||
static const String imgDashboardAccount = 'assets/images/img-dashboard-account.png';
|
||||
static const String imgCarousel = 'assets/images/img-carousel.png';
|
||||
static const String imgArticles = 'assets/images/img-articles.png';
|
||||
static const String imgProduct = 'assets/images/img-product.png';
|
||||
static const String imgSuccessSignup = 'assets/images/img-success-signup.png';
|
||||
static const String imgBgKtp = 'assets/images/img-bg-photo-ktp.png';
|
||||
static const String imgBgSelfie = 'assets/images/img-bg-photo-selfie.png';
|
||||
static const String imgDataReport = 'assets/images/img-data-report.png';
|
||||
static const String imgDataAnalysis = 'assets/images/img-data-analysis.png';
|
||||
static const String imgBusinessFailure = 'assets/images/img-business-failure.png';
|
||||
static const String imgLeader = 'assets/images/img-leader.png';
|
||||
static const String imgMoneyIncome = 'assets/images/img-money-income.png';
|
||||
static const String imgGrowing = 'assets/images/img-growing.png';
|
||||
static const String imgCat = 'assets/images/img-cat.png';
|
||||
static const String imgDeer = 'assets/images/img-deer.png';
|
||||
static const String imgLion = 'assets/images/img-lion.png';
|
||||
}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ButtonBack extends StatelessWidget {
|
||||
const ButtonBack({super.key});
|
||||
final EdgeInsets? margin;
|
||||
final void Function()? onPress;
|
||||
const ButtonBack({super.key, this.margin, this.onPress});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
return Container(
|
||||
margin: margin ?? EdgeInsets.all(0),
|
||||
width: SizeConfig.width * 0.1,
|
||||
child: IconButton(
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
shape: const CircleBorder()
|
||||
shape: const CircleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200)
|
||||
)
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
onPressed: onPress ?? () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.arrow_back)
|
||||
),
|
||||
);
|
||||
|
|
|
@ -33,6 +33,7 @@ class TextFormView extends StatelessWidget {
|
|||
final Color? disabledborderColor;
|
||||
final bool? enableInteractiveSelection;
|
||||
final Color? fontColorDisabled;
|
||||
final EdgeInsets? contentPadding;
|
||||
final FocusNode? focusNode;
|
||||
|
||||
// ignore: prefer_const_constructors_in_immutables
|
||||
|
@ -189,10 +190,11 @@ class TextFormView extends StatelessWidget {
|
|||
suffixIconConstraints: suffixIconConstraints,
|
||||
prefixIconConstraints: preffixIconConstraints,
|
||||
prefix: prefix,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
contentPadding: contentPadding ?? const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 16.0,
|
||||
)),
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
@ -73,13 +73,13 @@ class ColorPalette {
|
|||
static const Color chathamsBlue = Color(0xFF285BB9);
|
||||
static const Color background = Color(0xFFDADADA);
|
||||
static const Color backgroundBlueLight = Color(0xFFEBF3FD);
|
||||
static const Color slate500 = Color(0xFF64748B);
|
||||
static const Color blue50 = Color(0xFFEFF6FF);
|
||||
static const Color blue200 = Color(0xFFBFDBFE);
|
||||
static const Color slate50 = Color(0xFFF8FAFC);
|
||||
static const Color slate200 = Color(0xFFE2E8F0);
|
||||
static const Color slate300 = Color(0xFFCBD5E1);
|
||||
static const Color slate400 = Color(0xFF94A3B8);
|
||||
static const Color slate500 = Color(0xFF64748B);
|
||||
static const Color slate800 = Color(0xFF1E293B);
|
||||
static const Color purple100 = Color(0xFFEDE9FE);
|
||||
static const Color purple500 = Color(0xFF8B5CF6);
|
||||
|
|
96
lib/features/auth/login/view/login_view.dart
Normal file
|
@ -0,0 +1,96 @@
|
|||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
|
||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/login/view/password_view.dart';
|
||||
import 'package:cims_apps/features/auth/login/view/phone_number_view.dart';
|
||||
import 'package:cims_apps/features/auth/login/view_model/login_view_model.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/risk_profile_view.dart';
|
||||
import 'package:cims_apps/features/bottom_navigation_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LoginView extends StatefulWidget {
|
||||
const LoginView({super.key});
|
||||
|
||||
@override
|
||||
State<LoginView> createState() => _LoginViewState();
|
||||
}
|
||||
|
||||
class _LoginViewState extends State<LoginView> {
|
||||
int currentPage = 0;
|
||||
PageController pageController = PageController(initialPage: 0);
|
||||
TextEditingController phoneNumberController = TextEditingController();
|
||||
TextEditingController passwordController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
pageController.dispose();
|
||||
phoneNumberController.dispose();
|
||||
passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => LoginViewModel(),
|
||||
child: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if(currentPage == 1){
|
||||
currentPage--;
|
||||
pageController.jumpToPage(0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 70,
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white,
|
||||
automaticallyImplyLeading: false,
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ButtonBack(),
|
||||
const Text('Sign In'),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1,
|
||||
)
|
||||
],
|
||||
),
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200)
|
||||
),
|
||||
),
|
||||
body: PageView(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
controller: pageController,
|
||||
children: [
|
||||
PhoneNumberView(nextStep: nextStep, controller: phoneNumberController),
|
||||
PasswordView(nextStep: nextStep, controller: passwordController)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void nextStep() {
|
||||
if(pageController.page == 0){
|
||||
currentPage++;
|
||||
pageController.jumpToPage(1);
|
||||
}else{
|
||||
routePush(context, page: RiskProfileView());
|
||||
}
|
||||
}
|
||||
}
|
78
lib/features/auth/login/view/password_view.dart
Normal file
|
@ -0,0 +1,78 @@
|
|||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
|
||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/login/view_model/login_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PasswordView extends StatelessWidget {
|
||||
final void Function() nextStep;
|
||||
final TextEditingController controller;
|
||||
const PasswordView({super.key, required this.nextStep, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<LoginViewModel>(
|
||||
builder: (context, provider, child) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextTitle(title: 'Enter your password', fontSize: 24),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Password',
|
||||
ctrl: controller,
|
||||
obscureText: !provider.showPassword,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
provider.changeShowPassword();
|
||||
},
|
||||
child: Icon(
|
||||
provider.showPassword
|
||||
? Icons.visibility_outlined
|
||||
: Icons.visibility_off_outlined,
|
||||
color: ColorPalette.greyDarker,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.all(0)
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
child: Text(
|
||||
'Forget the password?',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
),
|
||||
)
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Confirm',
|
||||
heightWrapContent: true,
|
||||
width: SizeConfig.width,
|
||||
marginVertical: 0,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
onPressed: nextStep,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
116
lib/features/auth/login/view/phone_number_view.dart
Normal file
|
@ -0,0 +1,116 @@
|
|||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
|
||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/registration_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class PhoneNumberView extends StatelessWidget {
|
||||
final void Function() nextStep;
|
||||
final TextEditingController controller;
|
||||
const PhoneNumberView({super.key, required this.nextStep, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextTitle(title: 'Enter your phone number', fontSize: 24),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Phone Number',
|
||||
keyboardType: TextInputType.number,
|
||||
ctrl: controller,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.deny(RegExp(r'^0'))
|
||||
],
|
||||
prefixIcon: Container(
|
||||
width: SizeConfig.width * .23,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
margin: const EdgeInsets.only(right: 16),
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorPalette.grey,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
bottomLeft: Radius.circular(8),
|
||||
)),
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ImageView(
|
||||
image: PathAssets.iconFlag,
|
||||
fit: BoxFit.contain,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
'+62',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.slate800,
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Phone number must be filled';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
height: 32,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Next',
|
||||
heightWrapContent: true,
|
||||
width: SizeConfig.width,
|
||||
marginVertical: 0,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
onPressed: nextStep,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Don't have an account yet?",
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
routePush(context, page: RegistrationView());
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.all(0)
|
||||
),
|
||||
child: Text(
|
||||
'Sign Up',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.primary
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
10
lib/features/auth/login/view_model/login_view_model.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class LoginViewModel extends ChangeNotifier {
|
||||
bool showPassword = false;
|
||||
|
||||
void changeShowPassword() {
|
||||
showPassword = !showPassword;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/results_view.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/risk_profile_view.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/risk_profile_view_model/risk_profile_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class QuestionView extends StatefulWidget {
|
||||
const QuestionView({super.key});
|
||||
|
||||
@override
|
||||
State<QuestionView> createState() => _QuestionViewState();
|
||||
}
|
||||
|
||||
class _QuestionViewState extends State<QuestionView> {
|
||||
int currentPage = 0;
|
||||
PageController pageController = PageController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => RiskProfileViewModel(),
|
||||
child: Consumer<RiskProfileViewModel>(
|
||||
builder: (context, provider, child) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 70,
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white,
|
||||
automaticallyImplyLeading: false,
|
||||
centerTitle: true,
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ButtonBack(),
|
||||
const Text('Risk Profile', textAlign: TextAlign.center),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1
|
||||
)
|
||||
],
|
||||
),
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200)
|
||||
),
|
||||
),
|
||||
body: PageView(
|
||||
controller: pageController,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: provider.listRiskProfileQuestion.asMap().entries.map((e) {
|
||||
return containerQuestion(
|
||||
e.value,
|
||||
e.key,
|
||||
(index, score) => provider.selectedAnswer(index, score)
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
bottomNavigationBar: SizedBox(
|
||||
height: 84,
|
||||
child: ButtonView(
|
||||
name: 'Next',
|
||||
marginVertical: 16,
|
||||
onPressed: () {
|
||||
if(currentPage > 3){
|
||||
int totalScore = provider.listScore.reduce((value, element) => value + element);
|
||||
provider.setTypeResult(totalScore);
|
||||
routePush(context, page: ResultsView(totalScore: totalScore.toString(), typeResult: provider.typeResult));
|
||||
}else{
|
||||
setState(() {
|
||||
currentPage += 1;
|
||||
});
|
||||
pageController.nextPage(duration: Duration(milliseconds: 300), curve: Curves.ease);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget containerQuestion(RiskProfileQuestion data, int index, void Function(int index, int score) onTapAnswers) {
|
||||
return SizedBox(
|
||||
height: SizeConfig.height,
|
||||
width: SizeConfig.width,
|
||||
child: ListView(
|
||||
padding: EdgeInsets.all(24),
|
||||
children: [
|
||||
ImageView(
|
||||
image: data.img,
|
||||
fit: BoxFit.fitWidth,
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
'${index + 1} of 5 question',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ColorPalette.primary
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
data.question,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: ColorPalette.slate800
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Column(
|
||||
children: data.answers.asMap().entries.map((e) {
|
||||
bool selected = data.selectedScore == e.value.score;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
onTapAnswers(index, e.value.score);
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
margin: EdgeInsets.only(top: 12),
|
||||
padding: EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: selected ? ColorPalette.primary : ColorPalette.slate200),
|
||||
borderRadius: BorderRadius.circular(8)
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
e.value.title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: selected ? ColorPalette.primary : ColorPalette.slate500,
|
||||
fontWeight: FontWeight.w500
|
||||
),
|
||||
),
|
||||
),
|
||||
if(selected)...[
|
||||
Icon(Icons.check_circle_rounded, color: ColorPalette.primary)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/registration_password_view.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/risk_profile_view_model/risk_profile_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ResultsView extends StatelessWidget {
|
||||
final String totalScore;
|
||||
final RiskProfileResult typeResult;
|
||||
const ResultsView({super.key, required this.typeResult, required this.totalScore});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 70,
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white,
|
||||
automaticallyImplyLeading: false,
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ButtonBack(),
|
||||
const Text('Risk Profile', textAlign: TextAlign.center),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1
|
||||
)
|
||||
],
|
||||
),
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200)
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: typeResult.color,
|
||||
image: DecorationImage(image: AssetImage(typeResult.img), alignment: Alignment.centerRight)
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
typeResult.type,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: ColorPalette.white
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16,),
|
||||
Text('Total Score :',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: ColorPalette.white
|
||||
),
|
||||
),
|
||||
Text(totalScore,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 28,
|
||||
color: ColorPalette.white
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
typeResult.desc,
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500,
|
||||
fontSize: 16
|
||||
)
|
||||
),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
'Suitable Product',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate800,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 16,
|
||||
children: typeResult.suitableProduct.map((e) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: ColorPalette.slate200),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: typeResult.color.withOpacity(0.1)
|
||||
),
|
||||
child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: typeResult.color)
|
||||
),
|
||||
SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(e['desc'],
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ColorPalette.slate800
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
SizedBox(
|
||||
height: 32,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Re-test',
|
||||
onPressed: () {
|
||||
},
|
||||
marginVertical: 0,
|
||||
backgroundColor: ColorPalette.white,
|
||||
textColor: ColorPalette.primary,
|
||||
borderColor: ColorPalette.primary,
|
||||
isOutlined: true,
|
||||
textSize: 16,
|
||||
heightWrapContent: true,
|
||||
contentPadding: EdgeInsets.all(16),
|
||||
width: SizeConfig.width,
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Confirm',
|
||||
onPressed: () {
|
||||
routePush(context, page: DialogSuccess());
|
||||
},
|
||||
marginVertical: 0,
|
||||
textSize: 16,
|
||||
heightWrapContent: true,
|
||||
contentPadding: EdgeInsets.all(16),
|
||||
width: SizeConfig.width,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/risk_profile/question_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RiskProfileView extends StatelessWidget {
|
||||
const RiskProfileView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 70,
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white,
|
||||
automaticallyImplyLeading: false,
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ButtonBack(),
|
||||
const Text('Risk Profile', textAlign: TextAlign.center),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1
|
||||
)
|
||||
],
|
||||
),
|
||||
shape: const RoundedRectangleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200)
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
ImageView(image: PathAssets.imgDataReport),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
'Know Your Risk Profile',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate800,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
'We will provide recommendations that match your profile and risk tolerance level.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ImageView(
|
||||
image: PathAssets.iconShield,
|
||||
width: 20,
|
||||
height: 22,
|
||||
),
|
||||
SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Text(
|
||||
'Your data is secure and encrypted',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.primary,
|
||||
fontSize: 16
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
ButtonView(
|
||||
name: "Let's Start",
|
||||
onPressed: () {
|
||||
routePush(context, page: QuestionView());
|
||||
},
|
||||
marginVertical: 0,
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RiskProfileQuestion {
|
||||
String img;
|
||||
int selectedScore;
|
||||
String question;
|
||||
List<Answer> answers;
|
||||
|
||||
RiskProfileQuestion(this.img, this.question, this.selectedScore, this.answers);
|
||||
}
|
||||
|
||||
class RiskProfileResult {
|
||||
String type;
|
||||
String img;
|
||||
String desc;
|
||||
Color color;
|
||||
List<dynamic> suitableProduct;
|
||||
|
||||
RiskProfileResult(this.type, this.img, this.color, this.desc, this.suitableProduct);
|
||||
}
|
||||
|
||||
class Answer {
|
||||
int score;
|
||||
String title;
|
||||
|
||||
Answer(this.score, this.title);
|
||||
}
|
||||
|
||||
class RiskProfileViewModel extends ChangeNotifier {
|
||||
List<int> listScore = [0,0,0,0,0];
|
||||
RiskProfileResult typeResult = RiskProfileResult('', '', Colors.transparent, '', []);
|
||||
|
||||
List<RiskProfileQuestion> listRiskProfileQuestion = [
|
||||
RiskProfileQuestion(
|
||||
PathAssets.imgGrowing, 'How long is your planned investment horizon?', 0,
|
||||
[
|
||||
Answer(2, '<1 year'),
|
||||
Answer(4, '1-3 year'),
|
||||
Answer(6, '3-5 year'),
|
||||
Answer(8, '>5 year')
|
||||
]
|
||||
),
|
||||
RiskProfileQuestion(
|
||||
PathAssets.imgLeader, 'Investment objectives of mutualfund investors?', 0,
|
||||
[
|
||||
Answer(2, 'Security of Investment Funds'),
|
||||
Answer(4, 'Investment Income and Security'),
|
||||
Answer(6, 'Revenue and growth over the long term'),
|
||||
Answer(8, 'Growth')
|
||||
]
|
||||
),
|
||||
RiskProfileQuestion(
|
||||
PathAssets.imgBusinessFailure, 'How much can I afford to lose on my investment (Risk level you can afford)?', 0,
|
||||
[
|
||||
Answer(2, '0%'),
|
||||
Answer(4, '<25%'),
|
||||
Answer(6, '26-50%'),
|
||||
Answer(8, '>50%')
|
||||
]
|
||||
),
|
||||
RiskProfileQuestion(
|
||||
PathAssets.imgMoneyIncome, 'I am willing to use .... % of my income for investment (financial circumstances of the financier)?', 0,
|
||||
[
|
||||
Answer(2, '0%'),
|
||||
Answer(4, '<25%'),
|
||||
Answer(6, '26-50%'),
|
||||
Answer(8, '>50%')
|
||||
]
|
||||
),
|
||||
RiskProfileQuestion(
|
||||
PathAssets.imgDataAnalysis, 'Mutual Fund Investment Knowledge Level?', 0,
|
||||
[
|
||||
Answer(2, 'Low'),
|
||||
Answer(4, 'Medium'),
|
||||
Answer(6, 'High'),
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
List<RiskProfileResult> listRiskProfileResult = [
|
||||
RiskProfileResult(
|
||||
'Conservative',
|
||||
PathAssets.imgCat,
|
||||
ColorPalette.green500,
|
||||
'Investors with a conservative risk profile are risk-averse or do not want to experience large losses. Therefore, mutual fund products that are suitable for conservative investors are products that have low risk and stable returns.',
|
||||
[
|
||||
{'desc': 'Money Market Mutual Fund', 'icon': PathAssets.iconStrongBox},
|
||||
{'desc': 'Fixed Income Mutual Fund', 'icon': PathAssets.iconMoneyReceive},
|
||||
{'desc': 'Balanced Mutual Fund', 'icon': PathAssets.iconBalance},
|
||||
]
|
||||
),
|
||||
RiskProfileResult(
|
||||
'Moderate',
|
||||
PathAssets.imgDeer,
|
||||
ColorPalette.orange500,
|
||||
'Investors with a moderate risk profile are investors who are ready to accept moderate risk to get higher returns than conservative mutual fund products. Therefore, mutual fund products that are suitable for moderate investors are products that have moderate risk and higher returns than conservative mutual fund products.',
|
||||
[
|
||||
{'desc': 'Fixed Income Mutual Fund', 'icon': PathAssets.iconMoneyReceive},
|
||||
{'desc': 'Balanced Mutual Fund', 'icon': PathAssets.iconBalance},
|
||||
]
|
||||
),
|
||||
RiskProfileResult(
|
||||
'Aggressive',
|
||||
PathAssets.imgLion,
|
||||
ColorPalette.purple500,
|
||||
'Investors with an aggressive risk profile are investors who are ready to accept high risks to get high returns. Therefore, mutual fund products that are suitable for aggressive investors are products that have high risk and high returns.',
|
||||
[
|
||||
{'desc': 'Equity Mutual Fund', 'icon': PathAssets.iconCoins},
|
||||
{'desc': 'Aggressive Balanced Fund', 'icon': PathAssets.iconBalance},
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
void selectedAnswer(int index, int score) {
|
||||
listScore[index] = score;
|
||||
listRiskProfileQuestion[index].selectedScore = score;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setTypeResult(int totalScore) {
|
||||
if(totalScore <= 25){
|
||||
typeResult = listRiskProfileResult[0];
|
||||
}else if(totalScore <= 50){
|
||||
typeResult = listRiskProfileResult[1];
|
||||
}else{
|
||||
typeResult = listRiskProfileResult[2];
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/registration_view.dart';
|
||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -47,7 +50,7 @@ class _HomeViewState extends State<HomeView> {
|
|||
InvestType('Sharia', PathAssets.iconPortofolioSharia)
|
||||
];
|
||||
|
||||
StepVerification listStepVerification = StepVerification(1, [
|
||||
StepVerification listStepVerification = StepVerification(0, [
|
||||
'Registration', 'Verification', 'Complete'
|
||||
]);
|
||||
|
||||
|
@ -268,6 +271,7 @@ class _HomeViewState extends State<HomeView> {
|
|||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
if(listStepVerification.currentStep == 1)...[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
@ -368,6 +372,38 @@ class _HomeViewState extends State<HomeView> {
|
|||
],
|
||||
),
|
||||
)
|
||||
]else if(listStepVerification.currentStep == 0)...[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorPalette.blue50,
|
||||
borderRadius: BorderRadius.circular(12)
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia",
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Registration',
|
||||
width: SizeConfig.width,
|
||||
marginVertical: 0,
|
||||
heightWrapContent: true,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
onPressed: () {
|
||||
routePush(context, page: InitialRegistrationStep());
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -515,9 +551,15 @@ class _HomeViewState extends State<HomeView> {
|
|||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: ColorPalette.colorSwitchButtonActive
|
||||
color: ColorPalette.green100
|
||||
),
|
||||
child: Text(
|
||||
article.type,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.green500
|
||||
),
|
||||
),
|
||||
child: Text(article.type),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
|
@ -5,11 +7,12 @@ import 'package:cims_apps/core/utils/size_config.dart';
|
|||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CategoryPortofolio {
|
||||
class InvestmentType {
|
||||
String name;
|
||||
int value;
|
||||
int mutualFunds;
|
||||
|
||||
CategoryPortofolio(this.value, this.name);
|
||||
InvestmentType(this.value, this.name, this.mutualFunds);
|
||||
}
|
||||
|
||||
class PortofolioView extends StatefulWidget {
|
||||
|
@ -36,11 +39,11 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
bool seePortofolioValue = false;
|
||||
int touchedIndex = -1;
|
||||
|
||||
List<CategoryPortofolio> listCategoryPortofolio = [
|
||||
CategoryPortofolio(20, 'Money Market'),
|
||||
CategoryPortofolio(15, 'Shares'),
|
||||
CategoryPortofolio(8, 'Bonds'),
|
||||
CategoryPortofolio(50, 'Sharia'),
|
||||
List<InvestmentType> listInvestmentType = [
|
||||
InvestmentType(20, 'Money Market', 2),
|
||||
InvestmentType(15, 'Shares', 5),
|
||||
InvestmentType(8, 'Bonds', 3),
|
||||
InvestmentType(50, 'Sharia', 4),
|
||||
];
|
||||
|
||||
List<String> assetsImage = [
|
||||
|
@ -91,7 +94,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
topRight: Radius.circular(24)),
|
||||
),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
children: [
|
||||
Stack(alignment: Alignment.center, children: [
|
||||
AspectRatio(
|
||||
|
@ -117,16 +120,25 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
show: true,
|
||||
),
|
||||
sectionsSpace: 20,
|
||||
centerSpaceRadius: 100,
|
||||
centerSpaceRadius: 110,
|
||||
sections: sectionsDataPortofolio())),
|
||||
),
|
||||
const Column(
|
||||
Column(
|
||||
children: [
|
||||
Text('Total Mutual Fund'),
|
||||
Text('10',
|
||||
const Text('Total Mutual Fund',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate400
|
||||
),
|
||||
),
|
||||
Text(listInvestmentType.map((e) => e.mutualFunds).reduce((value, element) => value + element).toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 44,
|
||||
fontWeight: FontWeight.w700)),
|
||||
fontWeight: FontWeight.w700
|
||||
)
|
||||
)
|
||||
,
|
||||
],
|
||||
)
|
||||
]),
|
||||
|
@ -138,9 +150,6 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
height: 24,
|
||||
),
|
||||
...listColumnPortofolio(),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -223,7 +232,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
}
|
||||
|
||||
List<PieChartSectionData> sectionsDataPortofolio() {
|
||||
return listCategoryPortofolio.asMap().entries.map((e) {
|
||||
return listInvestmentType.asMap().entries.map((e) {
|
||||
final isTouched = e.key == touchedIndex;
|
||||
final radius = isTouched ? 40.0 : 30.0;
|
||||
return PieChartSectionData(
|
||||
|
@ -256,7 +265,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12,
|
||||
children: listCategoryPortofolio.asMap().entries.map((e) {
|
||||
children: listInvestmentType.asMap().entries.map((e) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
width: SizeConfig.width * 0.18,
|
||||
|
@ -294,7 +303,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
}
|
||||
|
||||
List<Widget> listColumnPortofolio() {
|
||||
return listCategoryPortofolio.asMap().entries.map((e) {
|
||||
return listInvestmentType.asMap().entries.map((e) {
|
||||
return Column(
|
||||
children: [
|
||||
if (e.key > 0) ...[
|
||||
|
@ -316,7 +325,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
subtitle: Text(
|
||||
e.value.name,
|
||||
'${e.value.mutualFunds} Mutual Funds',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600, color: Color(0xff94A3B8)),
|
||||
),
|
||||
|
|
|
@ -124,22 +124,13 @@ class _ProductChartViewState extends State<ProductChartView> {
|
|||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 48),
|
||||
padding: const EdgeInsets.only(top: 48, bottom: 24),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 2.5,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return LineChart(
|
||||
LineChartData(
|
||||
// showingTooltipIndicators: showingTooltipOnSpots.map((index) {
|
||||
// return ShowingTooltipIndicators([
|
||||
// LineBarSpot(
|
||||
// tooltipsOnBar,
|
||||
// lineBarsData.indexOf(tooltipsOnBar),
|
||||
// tooltipsOnBar.spots[index],
|
||||
// ),
|
||||
// ]);
|
||||
// }).toList(),
|
||||
extraLinesData: ExtraLinesData(
|
||||
verticalLines: [
|
||||
VerticalLine(
|
||||
|
|
|
@ -99,8 +99,6 @@ class _ProductViewState extends State<ProductView> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SizedBox(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
child: Stack(
|
||||
children: [
|
||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||
|
@ -141,7 +139,8 @@ class _ProductViewState extends State<ProductView> {
|
|||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Padding(
|
||||
bottomNavigationBar: Container(
|
||||
height: SizeConfig.height * .1,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: ButtonView(
|
||||
name: 'Buy',
|
||||
|
@ -275,7 +274,7 @@ class _ProductViewState extends State<ProductView> {
|
|||
),
|
||||
cardInformation('Time Machine', timeMachine()),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
height: 32,
|
||||
),
|
||||
topFiveHoldings(),
|
||||
const SizedBox(
|
||||
|
@ -498,6 +497,9 @@ class _ProductViewState extends State<ProductView> {
|
|||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
@ -523,11 +525,12 @@ class _ProductViewState extends State<ProductView> {
|
|||
onPressed: () {
|
||||
|
||||
},
|
||||
prefixIcon: Icon(Icons.space_dashboard_sharp),
|
||||
prefixIcon: Icon(Icons.calendar_month_rounded),
|
||||
backgroundColor: ColorPalette.blue50,
|
||||
sizeBorderRadius: 8,
|
||||
isSecondaryColor: false,
|
||||
width: SizeConfig.width * .5,
|
||||
marginVertical: 0,
|
||||
heightWrapContent: true,
|
||||
isOutlined: true,
|
||||
widthPrefix: 10,
|
||||
|
@ -552,6 +555,7 @@ class _ProductViewState extends State<ProductView> {
|
|||
heightWrapContent: true,
|
||||
backgroundColor: ColorPalette.orange50,
|
||||
sizeBorderRadius: 8,
|
||||
marginVertical: 0,
|
||||
isOutlined: true,
|
||||
borderColor: ColorPalette.orange500,
|
||||
textSize: 14,
|
||||
|
@ -590,6 +594,8 @@ class _ProductViewState extends State<ProductView> {
|
|||
TextFormView(
|
||||
name: '',
|
||||
ctrl: machineController,
|
||||
keyboardType: TextInputType.number,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
onChanged: (value) {
|
||||
value = value.replaceAll('Rp ', '').replaceAll('.', '');
|
||||
double parseValue = double.parse(value);
|
||||
|
@ -600,7 +606,6 @@ class _ProductViewState extends State<ProductView> {
|
|||
}
|
||||
setEstimatedValue();
|
||||
},
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:cims_apps/application/component/image/image_view.dart';
|
|||
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||
import 'package:cims_apps/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/auth/login/view/login_view.dart';
|
||||
import 'package:cims_apps/features/auth/registration/view/registration_view.dart';
|
||||
import 'package:cims_apps/features/bottom_navigation_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -70,7 +71,7 @@ class DashboardPublicView extends StatelessWidget {
|
|||
width: SizeConfig.width * .43,
|
||||
height: SizeConfig.height * .06,
|
||||
onPressed: () {
|
||||
routePush(context, page: const BottomNavigationView());
|
||||
routePush(context, page: const LoginView());
|
||||
},
|
||||
),
|
||||
ButtonView(
|
||||
|
|
|
@ -17,7 +17,7 @@ class _SplashScreenState extends State<SplashScreen> {
|
|||
@override
|
||||
void initState() {
|
||||
Future.delayed(const Duration(seconds: 3)).then(
|
||||
(value) => routePush(context, page: const DashboardPublicView()),
|
||||
(value) => routePush(context, page: const DashboardPublicView(), routeType: RouteType.pushRemove),
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ class MyApp extends StatelessWidget {
|
|||
titleTextStyle: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontFamily: 'Manrope',
|
||||
color: ColorPalette.slate800,
|
||||
)),
|
||||
fontFamily: 'Manrope',
|
||||
|
|