Merge pull request #8 from WDI-Ideas/jayeshjain25

Jayeshjain25
This commit is contained in:
Jayesh jain
2024-05-30 14:45:21 +05:30
committed by GitHub
57 changed files with 1349 additions and 103 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

View File

@@ -0,0 +1,10 @@
<svg width="49" height="45" viewBox="0 0 49 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.5" y="1" width="46" height="43" rx="21.5" stroke="url(#paint0_linear_868_47648)" stroke-width="2"/>
<path d="M23.48 29V18.1L21.08 18.68V16.56L24.62 15H26.28V29H23.48Z" fill="black"/>
<defs>
<linearGradient id="paint0_linear_868_47648" x1="9.5" y1="45" x2="45.5114" y2="-2.27648" gradientUnits="userSpaceOnUse">
<stop stop-color="#0FA44D"/>
<stop offset="1" stop-color="#0FA44D" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 537 B

View File

@@ -0,0 +1,10 @@
<svg width="49" height="45" viewBox="0 0 49 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.5" y="1" width="46" height="43" rx="21.5" stroke="url(#paint0_linear_868_47650)" stroke-width="2"/>
<path d="M19.5 29V27.02C20.34 26.34 21.16 25.66 21.96 24.98C22.76 24.3 23.48 23.6267 24.12 22.96C24.76 22.28 25.2667 21.62 25.64 20.98C26.0133 20.34 26.2 19.72 26.2 19.12C26.2 18.7467 26.1267 18.4067 25.98 18.1C25.8467 17.78 25.64 17.5267 25.36 17.34C25.08 17.14 24.7067 17.04 24.24 17.04C23.7867 17.04 23.4 17.1467 23.08 17.36C22.76 17.5733 22.52 17.86 22.36 18.22C22.2 18.5667 22.12 18.96 22.12 19.4H19.5C19.54 18.3733 19.7733 17.5133 20.2 16.82C20.6267 16.1267 21.2 15.6133 21.92 15.28C22.64 14.9333 23.44 14.76 24.32 14.76C25.3067 14.76 26.14 14.9467 26.82 15.32C27.5 15.68 28.0133 16.1733 28.36 16.8C28.72 17.4267 28.9 18.1467 28.9 18.96C28.9 19.5733 28.7867 20.1733 28.56 20.76C28.3333 21.3467 28.0267 21.92 27.64 22.48C27.2533 23.0267 26.8133 23.5533 26.32 24.06C25.8267 24.5667 25.3133 25.0533 24.78 25.52C24.26 25.9733 23.7467 26.4 23.24 26.8H29.22V29H19.5Z" fill="black"/>
<defs>
<linearGradient id="paint0_linear_868_47650" x1="9.5" y1="45" x2="45.5114" y2="-2.27648" gradientUnits="userSpaceOnUse">
<stop stop-color="#0FA44D"/>
<stop offset="1" stop-color="#0FA44D" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,10 @@
<svg width="49" height="45" viewBox="0 0 49 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.5" y="1" width="46" height="43" rx="21.5" stroke="url(#paint0_linear_868_47652)" stroke-width="2"/>
<path d="M24.46 29.24C23.5533 29.24 22.72 29.0733 21.96 28.74C21.2 28.4067 20.5933 27.9 20.14 27.22C19.6867 26.54 19.4467 25.68 19.42 24.64H22.08C22.0933 25.08 22.1933 25.48 22.38 25.84C22.5667 26.1867 22.8333 26.4667 23.18 26.68C23.54 26.88 23.9733 26.98 24.48 26.98C24.9467 26.98 25.34 26.8867 25.66 26.7C25.9933 26.5133 26.2467 26.2667 26.42 25.96C26.5933 25.6533 26.68 25.3 26.68 24.9C26.68 24.4333 26.5667 24.0467 26.34 23.74C26.1133 23.42 25.7933 23.18 25.38 23.02C24.98 22.8467 24.5133 22.76 23.98 22.76H22.94V20.54H23.98C24.6333 20.54 25.18 20.3867 25.62 20.08C26.0733 19.7733 26.3 19.32 26.3 18.72C26.3 18.2133 26.1333 17.8067 25.8 17.5C25.48 17.1933 25.0333 17.04 24.46 17.04C23.82 17.04 23.32 17.2267 22.96 17.6C22.6133 17.9733 22.42 18.4333 22.38 18.98H19.74C19.78 18.1 20 17.3467 20.4 16.72C20.8 16.08 21.3467 15.5933 22.04 15.26C22.7333 14.9267 23.54 14.76 24.46 14.76C25.4333 14.76 26.2533 14.9333 26.92 15.28C27.5867 15.6133 28.0933 16.0667 28.44 16.64C28.7867 17.2133 28.96 17.8333 28.96 18.5C28.96 19.0467 28.8533 19.5333 28.64 19.96C28.44 20.3733 28.1667 20.72 27.82 21C27.4867 21.28 27.1067 21.48 26.68 21.6C27.2133 21.7067 27.6733 21.9133 28.06 22.22C28.46 22.5267 28.7667 22.9133 28.98 23.38C29.2067 23.8467 29.32 24.3867 29.32 25C29.32 25.76 29.1333 26.4667 28.76 27.12C28.3867 27.76 27.84 28.2733 27.12 28.66C26.4 29.0467 25.5133 29.24 24.46 29.24Z" fill="black"/>
<defs>
<linearGradient id="paint0_linear_868_47652" x1="9.5" y1="45" x2="45.5114" y2="-2.27648" gradientUnits="userSpaceOnUse">
<stop stop-color="#0FA44D"/>
<stop offset="1" stop-color="#0FA44D" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,23 @@
<svg width="393" height="974" viewBox="0 0 393 974" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0H393V884C393 896.15 383.15 906 371 906H22C9.84975 906 0 896.15 0 884V0Z" fill="#002F0F"/>
<mask id="mask0_788_85561" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="151" y="57" width="242" height="917">
<path d="M151 57H393V952C393 964.15 383.15 974 371 974H151V57Z" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask0_788_85561)">
<g opacity="0.03">
<path d="M399.978 126.938C429.492 145.712 471.789 192.625 494.395 228.567C498.531 235.131 499.752 243.118 497.826 250.6L496.792 254.731C496.322 256.476 495.758 258.22 494.959 259.872C476.066 298.385 418.589 352.78 388.181 373.482C385.221 375.501 381.931 376.97 378.406 377.797L376.667 378.21C368.678 380.138 360.218 378.76 353.31 374.354C316.793 350.989 277.221 307.29 255.368 272.679C251.185 266.069 249.963 258.082 251.89 250.508L252.454 248.213C253.206 245.229 254.428 242.429 256.12 239.813C284.788 195.93 333.994 148.88 367.127 127.076C369.571 125.469 372.296 124.23 375.116 123.358C383.529 120.879 392.599 122.21 399.978 126.892" fill="#FBFBF6"/>
<path d="M475.173 94.8062C504.687 113.58 546.985 160.493 569.59 196.435C573.726 202.999 574.901 210.986 573.021 218.468L571.987 222.599C571.517 224.344 570.953 226.088 570.154 227.741C551.261 266.253 493.784 320.648 463.377 341.35C460.416 343.37 457.126 344.838 453.601 345.665L451.862 346.078C443.873 348.006 435.413 346.629 428.505 342.222C391.988 318.858 352.417 275.158 330.563 240.547C326.38 233.937 325.158 225.95 327.085 218.376L327.649 216.081C328.401 213.098 329.623 210.298 331.315 207.681C359.983 163.798 409.189 116.748 442.322 94.9439C444.766 93.3373 447.492 92.0979 450.311 91.2258C458.724 88.747 467.794 90.0782 475.173 94.7603" fill="black"/>
<path d="M441.581 405C434.673 405 427.811 403.072 421.936 399.308C382.318 374.015 342.417 327.929 322.115 295.797C317.086 287.856 315.535 278.033 317.838 268.944L318.402 266.649C319.342 262.931 320.846 259.534 322.867 256.458C352.898 210.51 403.42 163.138 435.66 141.885C438.62 139.911 441.91 138.396 445.341 137.387C455.492 134.403 466.443 135.964 475.419 141.655C507.565 162.082 550.473 211.336 571.763 245.212C576.745 253.107 578.249 262.839 575.946 271.927L574.912 276.059C574.301 278.354 573.596 280.419 572.656 282.347C553.575 321.319 496.38 376.173 463.811 398.298C460.239 400.731 456.244 402.521 451.968 403.531L450.229 403.944C447.362 404.632 444.448 405 441.534 405M455.727 148.174C453.471 148.174 451.216 148.495 449.007 149.138C446.751 149.78 444.636 150.79 442.709 152.03C411.456 172.594 362.579 218.497 333.488 263.022C332.219 264.996 331.232 267.2 330.621 269.586L330.057 271.882C328.553 277.803 329.54 284.184 332.83 289.371C352.428 320.401 390.824 364.789 428.798 389.071C434.203 392.514 440.923 393.616 447.221 392.101L448.96 391.688C451.733 390.999 454.317 389.852 456.667 388.291C487.356 367.405 543.424 313.699 561.377 277.069C561.941 275.921 562.411 274.59 562.787 273.121L563.821 268.99C565.325 263.068 564.338 256.78 561.142 251.638C537.502 214.09 496.004 169.381 468.605 151.938C464.704 149.459 460.239 148.174 455.727 148.174Z" fill="#747474"/>
</g>
</g>
<mask id="mask1_788_85561" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="57" width="151" height="849">
<path d="M151 57H0V884C0 896.15 9.84973 906 22 906H151V57Z" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask1_788_85561)">
<g opacity="0.03">
<path d="M2.02234 559.938C-27.4918 578.712 -69.7892 625.625 -92.3948 661.567C-96.5306 668.131 -97.7525 676.118 -95.8256 683.6L-94.7917 687.731C-94.3217 689.476 -93.7577 691.22 -92.9588 692.872C-74.0659 731.385 -16.5885 785.78 13.8186 806.482C16.7794 808.501 20.0692 809.97 23.594 810.797L25.3329 811.21C33.3224 813.138 41.7819 811.76 48.6905 807.354C85.2072 783.989 124.779 740.29 146.632 705.679C150.815 699.069 152.037 691.082 150.11 683.508L149.546 681.213C148.794 678.229 147.572 675.429 145.88 672.813C117.212 628.93 68.0063 581.88 34.8733 560.076C32.4295 558.469 29.7036 557.23 26.8838 556.358C18.4713 553.879 9.40088 555.21 2.02234 559.892" fill="#FBFBF6"/>
<path d="M-73.173 527.806C-102.687 546.58 -144.985 593.493 -167.59 629.435C-171.726 635.999 -172.901 643.986 -171.021 651.468L-169.987 655.599C-169.517 657.344 -168.953 659.088 -168.154 660.741C-149.261 699.253 -91.7838 753.648 -61.3767 774.35C-58.4159 776.37 -55.1261 777.838 -51.6013 778.665L-49.8624 779.078C-41.8729 781.006 -33.4134 779.629 -26.5048 775.222C10.0119 751.858 49.5834 708.158 71.4371 673.547C75.6198 666.937 76.8418 658.95 74.9149 651.376L74.3509 649.081C73.599 646.098 72.377 643.298 70.6851 640.681C42.0169 596.798 -7.18904 549.748 -40.322 527.944C-42.7658 526.337 -45.4917 525.098 -48.3115 524.226C-56.724 521.747 -65.7944 523.078 -73.173 527.76" fill="black"/>
<path d="M-39.5812 838C-32.6726 838 -25.8111 836.072 -19.9364 832.308C19.6821 807.015 59.5827 760.929 79.8854 728.797C84.9141 720.856 86.465 711.033 84.1621 701.944L83.5982 699.649C82.6582 695.931 81.1543 692.534 79.1335 689.458C49.1023 643.51 -1.41957 596.138 -33.6596 574.885C-36.6204 572.911 -39.9102 571.396 -43.341 570.387C-53.4923 567.403 -64.4427 568.964 -73.4191 574.655C-105.565 595.082 -148.473 644.336 -169.763 678.212C-174.745 686.107 -176.249 695.839 -173.946 704.927L-172.912 709.059C-172.301 711.354 -171.596 713.419 -170.656 715.347C-151.575 754.319 -94.3798 809.173 -61.8108 831.298C-58.2391 833.731 -54.2443 835.521 -49.9676 836.531L-48.2287 836.944C-45.3618 837.632 -42.448 838 -39.5342 838M-53.7273 581.174C-51.4715 581.174 -49.2156 581.495 -47.0067 582.138C-44.7509 582.78 -42.636 583.79 -40.7091 585.03C-9.45607 605.594 39.4209 651.497 68.5121 696.022C69.781 697.996 70.768 700.2 71.3789 702.586L71.9429 704.882C73.4468 710.803 72.4599 717.184 69.1701 722.371C49.5723 753.401 11.1757 797.789 -26.798 822.071C-32.2027 825.514 -38.9232 826.616 -45.2209 825.101L-46.9598 824.688C-49.7326 823.999 -52.3174 822.852 -54.6673 821.291C-85.3564 800.405 -141.424 746.699 -159.377 710.069C-159.941 708.921 -160.411 707.59 -160.787 706.121L-161.821 701.99C-163.325 696.068 -162.338 689.78 -159.142 684.638C-135.502 647.09 -94.0038 602.381 -66.6045 584.938C-62.7038 582.459 -58.2391 581.174 -53.7273 581.174Z" fill="#747474"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -1,9 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="24" height="24" rx="12" fill="url(#pattern0_868_22066)"/>
<defs>
<pattern id="pattern0_868_22066" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_868_22066" transform="translate(-0.137256) scale(0.00628931)"/>
</pattern>
<image id="image0_868_22066" width="318" height="159" xlink:href="data:image/png;base64,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"/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 110 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.331 2.0215C13.7102 2.0215 15.6521 3.89543 15.7611 6.24774L15.766 6.4565V7.3895C15.766 7.80371 15.4302 8.1395 15.016 8.1395C14.6363 8.1395 14.3225 7.85735 14.2728 7.49127L14.266 7.3895V6.4565C14.266 4.8936 13.044 3.61576 11.5034 3.52648L11.331 3.5215H6.45597C4.89392 3.5215 3.61623 4.74363 3.52696 6.28408L3.52197 6.4565V17.5865C3.52197 19.1493 4.74388 20.4272 6.28363 20.5165L6.45597 20.5215H11.341C12.8983 20.5215 14.172 19.3039 14.261 17.7693L14.266 17.5975V16.6545C14.266 16.2403 14.6018 15.9045 15.016 15.9045C15.3957 15.9045 15.7095 16.1867 15.7591 16.5527L15.766 16.6545V17.5975C15.766 19.9687 13.8992 21.9046 11.5553 22.0164L11.341 22.0215H6.45597C4.07753 22.0215 2.13581 20.1474 2.0268 17.7952L2.02197 17.5865V6.4565C2.02197 4.07744 3.89573 2.13536 6.24728 2.02633L6.45597 2.0215H11.331ZM22.3282 11.4797C22.4707 11.6162 22.5595 11.8084 22.5595 12.0214C22.5595 12.2365 22.4689 12.4304 22.3239 12.5672L19.4104 15.4687C19.1169 15.761 18.642 15.76 18.3498 15.4665C18.084 15.1997 18.0607 14.783 18.2791 14.4899L18.3519 14.4059L19.992 12.7714H9.76847C9.35426 12.7714 9.01847 12.4356 9.01847 12.0214C9.01847 11.6417 9.30063 11.3279 9.6667 11.2782L9.76847 11.2714H19.9937L18.352 9.63781C18.0852 9.37213 18.06 8.95553 18.2772 8.66143L18.3497 8.57715C18.6153 8.31029 19.0319 8.28516 19.326 8.50236L19.4103 8.57479L22.3282 11.4797Z" fill="#363636"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -9,6 +9,10 @@ class RouteName {
//Login
static const String loginScreen = 'loginScreen';
//Register
static const String registerStepScreen = 'registerStepScreen';
static const String registerScreen = 'registerScreen';
//No Internet
static const String noInternetScreen = 'noInternet';
@@ -20,4 +24,10 @@ class RouteName {
//
static const String mainScreen = 'mainScreen';
//Biometric
static const String biometricScreen = 'biometricScreen';
//Biometric
static const String otpScreen = 'otpScreen';
}

View File

@@ -3,7 +3,11 @@
import 'package:go_router/go_router.dart';
import 'package:tanami_app/core/routes/route_name.dart';
import 'package:tanami_app/features/MainScreens/MainScreen.dart';
import 'package:tanami_app/features/biometric/presentation/pages/biometric_screen.dart';
import 'package:tanami_app/features/countrySelection/presentation/pages/choose_country_screen.dart';
import 'package:tanami_app/features/otpVerification/presentation/pages/otp_screen.dart';
import 'package:tanami_app/features/register/presentation/pages/register_screen.dart';
import 'package:tanami_app/features/register/presentation/pages/register_step_screen.dart';
import 'package:tanami_app/features/welcome/presentation/pages/weclome_screen.dart';
import '../../features/login/presentation/pages/login_screen.dart';
@@ -24,18 +28,23 @@ final goRouter = GoRouter(
builder: (context, state) {
return const SplashScreen();
},
// redirect: (context, state) {
// if (true) {
// return "/login";
// }
// return "/";
// },
routes: [
GoRoute(
name: RouteName.loginScreen,
path: RouteName.loginScreen,
path: "${RouteName.loginScreen}/:fromScreen",
builder: (context, state) {
return const LoginScreen();
return LoginScreen(
fromScreen: state.pathParameters["fromScreen"]!,
);
},
),
GoRoute(
name: RouteName.registerStepScreen,
path: "${RouteName.registerStepScreen}/:fromScreentype",
builder: (context, state) {
return RegisterStepScreen(
fromScreen: state.pathParameters["fromScreentype"]!,
);
},
),
GoRoute(
@@ -59,6 +68,27 @@ final goRouter = GoRouter(
return const MainScreen();
},
),
GoRoute(
name: RouteName.biometricScreen,
path: RouteName.biometricScreen,
builder: (context, state) {
return const BiometricScreen();
},
),
GoRoute(
name: RouteName.registerScreen,
path: RouteName.registerScreen,
builder: (context, state) {
return const RegisterScreen();
},
),
GoRoute(
name: RouteName.otpScreen,
path: RouteName.otpScreen,
builder: (context, state) {
return const OtpScreen();
},
),
]),
// GoRoute(

View File

@@ -36,4 +36,9 @@ class AppColor {
//Radio Color
static const Color radioActiveColor = Color(0xFF0B8933);
//Otp Color
static const Color strokeColor = Color(0xFFB4B4B4);
static const Color otpTextColor = Color(0xFF191B1E);
static const Color fillColor = Color(0xFFF6F6F6);
}

View File

@@ -22,6 +22,16 @@ class AppImages {
"assets/images/auth_screen/svg/hide_password.svg";
static const String showPassword =
"assets/images/auth_screen/svg/show_password.svg";
static const String step1Image =
"assets/images/auth_screen/svg/first_step.svg";
static const String step2Image =
"assets/images/auth_screen/svg/second_step.svg";
static const String step3Image =
"assets/images/auth_screen/svg/third_step.svg";
static const String stage1Image =
"assets/images/auth_screen/png/stage_one.png";
static const String stage2Image =
"assets/images/auth_screen/png/stage_two.png";
//Country Flag
static const String bahrainFlag =
@@ -35,4 +45,15 @@ class AppImages {
"assets/images/country_flag/png/saudi_arabia_flag.png";
static const String unitedArabEmiratesFlag =
"assets/images/country_flag/png/uae_flag.png";
//Biometric Screen
static const String biometricBg =
"assets/images/biometric_screen/svg/biometric_bg.svg";
static const String biometricFingerprint =
"assets/images/biometric_screen/png/biometric_fingerprint.png";
static const String biometricFace =
"assets/images/biometric_screen/png/biomertric_face.png";
//Dialog
static const String exitAppIcon = "assets/images/dialog/svg/exit_icon.svg";
}

View File

@@ -29,6 +29,26 @@ class AppText {
static const String invalidPassword = "Invalid Password";
static const String forgorPassword = "Forgot Password";
//Register
static const String getStartedToday = "Get started today";
static const String setupYourTanamiAccountToBegin =
"Setup your Tanami account to begin investing in a few simple steps";
static const String step1 = "Step 1";
static const String step2 = "Step 2";
static const String step3 = "Step 3";
static const String enterYourCountryOfResidence =
"Enter your country of residence and mobile number";
static const String enterNameEmailPassword =
"Enter your name, email and password";
static const String enableBiometricAuthentication =
"Enable biometric authentication and select a unique pin code for easy access";
static const String getStarted = "Get started";
static const String welcome = "Welcome!";
static const String selectYourCountryOfResidence =
"Select your country of residence and enter your mobile number";
static const String nextText = "Next";
static const String backText = "Back";
//Country Name
static const String bahrainCountryText = "Bahrain";
static const String kuwaitCountryText = "Kuwait";
@@ -36,6 +56,17 @@ class AppText {
static const String qatarCountryText = "Qatar";
static const String saudiArabiaCountryText = "Saudi Arabia";
static const String uaeCountryText = "United Arab Emirates";
static const String confirmSelectionText = "Confirm selection";
//Dialog
static const String exitText = "Exit";
static const String cancelText = "Cancel";
static const String areYouSureYouWantToExitText =
"Are you sure you want to Exit?";
//OTP
static const String checkYourMessages = "Check your messages";
static const String referToSameOtpMessage =
"Please refer to the same OTP message shown below";
static const String resendSms = "Resend SMS";
}

View File

@@ -0,0 +1,20 @@
import 'package:tanami_app/core/styles/app_images.dart';
import 'package:tanami_app/core/styles/app_text.dart';
List<String> title = [
AppText.step1,
AppText.step2,
AppText.step3,
];
List<String> description = [
AppText.enterYourCountryOfResidence,
AppText.enterNameEmailPassword,
AppText.enableBiometricAuthentication,
];
List<String> stepImage = [
AppImages.step1Image,
AppImages.step2Image,
AppImages.step3Image,
];

View File

@@ -0,0 +1,49 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../../../../core/styles/app_images.dart';
class BiometricLayout extends StatelessWidget {
const BiometricLayout({super.key});
@override
Widget build(BuildContext context) {
String biometricImage = "";
if (Platform.isIOS) {
biometricImage = AppImages.biometricFace;
} else {
biometricImage = AppImages.biometricFingerprint;
}
return Scaffold(
body: SizedBox(
width: 1.sw,
height: 1.sh,
child: Stack(
children: [
Positioned.fill(
child: SvgPicture.asset(
height: 1.sh,
width: 1.sw,
AppImages.biometricBg,
fit: BoxFit.cover,
),
),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Image.asset(
biometricImage,
width: 133,
height: 155,
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
import 'package:tanami_app/features/biometric/presentation/pages/biometric_layout.dart';
class BiometricScreen extends StatelessWidget {
const BiometricScreen({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
// resizeToAvoidBottomInset: true,
body: BiometricLayout(),
);
}
}

View File

@@ -6,12 +6,22 @@ import 'choose_country_state.dart';
class RadioBloc extends Bloc<RadioEvent, RadioState> {
RadioBloc() : super(RadioInitial()) {
on<RadioSelected>(_onRadioSelected);
on<ResetRadioSelection>(_onResetRadioSelection);
}
void _onRadioSelected(RadioSelected event, Emitter<RadioState> emit) {
emit(RadioSelectionChanged(event.selectedIndex));
}
void _onResetRadioSelection(
ResetRadioSelection event, Emitter<RadioState> emit) {
emit(RadioInitial());
}
void resetSelection() {
add(ResetRadioSelection());
}
int get selectedCountry {
if (state is RadioSelectionChanged) {
return (state as RadioSelectionChanged).selectedIndex;

View File

@@ -10,8 +10,10 @@ abstract class RadioEvent extends Equatable {
class RadioSelected extends RadioEvent {
final int selectedIndex;
const RadioSelected(this.selectedIndex);
const RadioSelected([this.selectedIndex = 0]);
@override
List<Object> get props => [selectedIndex];
}
class ResetRadioSelection extends RadioEvent {}

View File

@@ -24,7 +24,6 @@ class ChooseCountryLayout extends StatelessWidget {
child: ButtonWidget().elevatedBtn(
txtClr: AppColor.plainWhite,
function: () {
// radioBloc.add(const BackPressed(true));
goRouter.pop();
},
text: AppText.confirmSelectionText,

View File

@@ -17,7 +17,7 @@ class CountrySelectionList extends StatelessWidget {
final radioBloc = context.read<RadioBloc>();
return BlocBuilder<RadioBloc, RadioState>(
builder: (context, state) {
int selectedIndex = 0;
int selectedIndex = -1;
if (state is RadioSelectionChanged) {
selectedIndex = state.selectedIndex;
}

View File

@@ -56,13 +56,20 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
emit(LoginFieldsState(areFieldsFilled));
}
// Method to reset text fields
void resetFields() {
phoneNumberTextField.clear();
passwordTextField.clear();
countrySelectionTextField.clear();
}
// Mock API function, replace with actual API call
Future<bool> _mockLoginApi(
String email,
String phoneNumber,
String password,
String countryResidence,
) async {
return email == "1234567891" && password == "123456";
return phoneNumber == "1234567891" && password == "123456";
}
@override

View File

@@ -1,29 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../shared/components/bloc/password_field/password_visibility_bloc.dart';
import '../../../../shared/components/exit_app_dialog.dart';
import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart';
import '../bloc/login_bloc.dart';
import 'login_layout.dart';
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
final String fromScreen;
const LoginScreen({super.key, required this.fromScreen});
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
body: MultiBlocProvider(
// Define the providers for the OnboardingBloc and other blocs
providers: [
BlocProvider(
// Create an instance of the OnboardingBloc
create: (context) => LoginBloc(),
),
BlocProvider(
create: (context) => PasswordVisibilityBloc(),
),
],
child: const LoginLayout(),
final radioBloc = context.read<RadioBloc>();
return WillPopScope(
onWillPop: () async {
if (fromScreen == "welcome" || fromScreen == "registerStep") {
exitAppDialog(context);
return false;
} else {
radioBloc.resetSelection();
return true;
}
},
child: Scaffold(
resizeToAvoidBottomInset: true,
body: MultiBlocProvider(
// Define the providers for the OnboardingBloc and other blocs
providers: [
BlocProvider(
// Create an instance of the OnboardingBloc
create: (context) => LoginBloc(),
),
],
child: const LoginLayout(),
),
),
);
}

View File

@@ -11,6 +11,7 @@ import '../../../../core/styles/app_color.dart';
import '../../../../core/styles/app_text.dart';
import '../../../../shared/components/button_widget.dart';
import '../../../../shared/components/text_widget.dart';
import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart';
import '../bloc/login_bloc.dart';
import '../bloc/login_event.dart';
import '../bloc/login_state.dart';
@@ -20,6 +21,7 @@ class BottomSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final radioBloc = context.read<RadioBloc>();
return Column(
children: [
const Gap(12),
@@ -39,9 +41,11 @@ class BottomSection extends StatelessWidget {
if (state is LoginLoading) {
Loader.loader(context);
} else if (state is LoginSuccess) {
goRouter.pop();
goRouter.goNamed('mainScreen');
successToastMessage(context, "login successful !");
goRouter.pop();
goRouter.goNamed(RouteName.biometricScreen);
} else if (state is LoginFailure) {
goRouter.pop();
errorToastMessage(
@@ -94,7 +98,10 @@ class BottomSection extends StatelessWidget {
const Gap(5),
ButtonWidget().textBtn(
function: () {
goRouter.goNamed(RouteName.loginScreen);
radioBloc.resetSelection();
goRouter.pushNamed(RouteName.registerStepScreen, pathParameters: {
"fromScreentype": "login",
});
},
text: TextWidget().tex14W700(AppText.signUpText,
clr: AppColor.textLabelColor,

View File

@@ -16,6 +16,9 @@ class LoginForm extends StatelessWidget {
Widget build(BuildContext context) {
final loginBloc = context.read<LoginBloc>();
// Reset fields when the screen is built
loginBloc.resetFields();
return BlocConsumer<RadioBloc, RadioState>(listener: (context, state) {
int selectedCountry = -1;
if (state is RadioSelectionChanged) {

View File

@@ -0,0 +1,53 @@
// otp_bloc.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'otp_event.dart';
import 'otp_state.dart';
class OtpBloc extends Bloc<OtpEvent, OtpState> {
final TextEditingController otpController = TextEditingController();
OtpBloc() : super(OtpInitial()) {
on<StartListeningForOtp>(_onStartListeningForOtp);
on<OtpCodeChanged>(_onOtpCodeChanged);
on<OtpSubmit>(_onOtpSubmit);
}
void _onStartListeningForOtp(
StartListeningForOtp event, Emitter<OtpState> emit) {
_startListening();
}
void _onOtpCodeChanged(OtpCodeChanged event, Emitter<OtpState> emit) {
emit(OtpCodeReceived(event.code));
if (event.code.length == 6) {
add(OtpSubmit(event.code));
}
}
void _onOtpSubmit(OtpSubmit event, Emitter<OtpState> emit) async {
emit(OtpSubmitting());
try {
// Add your OTP verification logic here
await Future.delayed(const Duration(seconds: 2));
if (otpController.text == "123456") {
emit(OtpSubmissionSuccess());
} else {
emit(const OtpSubmissionFailure("Otp Invalid !"));
} // Simulate network call
} catch (e) {
emit(OtpSubmissionFailure(e.toString()));
}
}
void _startListening() {
SmsAutoFill().listenForCode(); // Correctly call listenForCode
}
@override
Future<void> close() {
otpController.dispose();
SmsAutoFill().unregisterListener();
return super.close();
}
}

View File

@@ -0,0 +1,29 @@
// otp_event.dart
import 'package:equatable/equatable.dart';
abstract class OtpEvent extends Equatable {
const OtpEvent();
@override
List<Object> get props => [];
}
class OtpCodeChanged extends OtpEvent {
final String code;
const OtpCodeChanged(this.code);
@override
List<Object> get props => [code];
}
class OtpSubmit extends OtpEvent {
final String code;
const OtpSubmit(this.code);
@override
List<Object> get props => [code];
}
class StartListeningForOtp extends OtpEvent {}

View File

@@ -0,0 +1,33 @@
// otp_state.dart
import 'package:equatable/equatable.dart';
abstract class OtpState extends Equatable {
const OtpState();
@override
List<Object> get props => [];
}
class OtpInitial extends OtpState {}
class OtpCodeReceived extends OtpState {
final String code;
const OtpCodeReceived(this.code);
@override
List<Object> get props => [code];
}
class OtpSubmitting extends OtpState {}
class OtpSubmissionSuccess extends OtpState {}
class OtpSubmissionFailure extends OtpState {
final String error;
const OtpSubmissionFailure(this.error);
@override
List<Object> get props => [error];
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:tanami_app/features/otpVerification/presentation/widgets/otp_fill_section.dart';
import '../widgets/otp_top_section.dart';
class OtpLayout extends StatelessWidget {
const OtpLayout({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: const [
OtpTopSection(),
OtpFillSection(),
],
));
}
}

View File

@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:tanami_app/features/otpVerification/presentation/bloc/otp_bloc.dart';
import 'package:tanami_app/features/otpVerification/presentation/pages/otp_layout.dart';
import '../bloc/otp_event.dart';
class OtpScreen extends StatelessWidget {
const OtpScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
body: MultiBlocProvider(
providers: [
BlocProvider(
// Create an instance of the OnboardingBloc
create: (context) => OtpBloc()..add(StartListeningForOtp()),
),
],
child: const OtpLayout(),
),
);
}
}

View File

@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'package:tanami_app/core/routes/routes.dart';
import 'package:tanami_app/core/styles/app_color.dart';
import 'package:tanami_app/shared/components/loader.dart';
import 'package:tanami_app/shared/components/toast_message.dart';
import '../bloc/otp_bloc.dart';
import '../bloc/otp_event.dart';
import '../bloc/otp_state.dart';
class OtpFillSection extends StatelessWidget {
const OtpFillSection({super.key});
@override
Widget build(BuildContext context) {
return BlocConsumer<OtpBloc, OtpState>(
listener: (context, state) {
if (state is OtpSubmitting) {
Loader.loader(context);
} else if (state is OtpSubmissionSuccess) {
goRouter.pop();
successToastMessage(context, 'OTP Verified Successfully!');
} else if (state is OtpSubmissionFailure) {
goRouter.pop();
errorToastMessage(context, 'OTP Verification Failed: ${state.error}');
}
},
builder: (context, state) {
final otpBloc = context.read<OtpBloc>();
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
PinFieldAutoFill(
controller: otpBloc.otpController,
currentCode: otpBloc.otpController.text,
decoration: BoxLooseDecoration(
textStyle: GoogleFonts.dmSans(
fontSize: 22,
color: AppColor.otpTextColor,
fontWeight: FontWeight.w700,
),
bgColorBuilder: const FixedColorBuilder(AppColor.fillColor),
radius: const Radius.circular(12),
strokeColorBuilder: const FixedColorBuilder(
AppColor.strokeColor,
)),
codeLength: 6,
onCodeChanged: (code) {
if (code != null) {
otpBloc.otpController.text = code;
otpBloc.add(OtpCodeChanged(code));
}
},
autoFocus: true,
),
],
),
);
},
);
}
}

View File

@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gap/gap.dart';
import '../../../../core/styles/app_color.dart';
import '../../../../core/styles/app_images.dart';
import '../../../../core/styles/app_text.dart';
import '../../../../shared/components/text_widget.dart';
class OtpTopSection extends StatelessWidget {
const OtpTopSection({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Gap(85),
Center(
child: SvgPicture.asset(
AppImages.weclomeLogo,
),
),
const Gap(125),
TextWidget().tex20W700(
AppText.checkYourMessages,
clr: AppColor.charcoalColor,
),
const Gap(25),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 35),
child: TextWidget().tex14W500(
AppText.referToSameOtpMessage,
clr: AppColor.smokeGrayColor,
),
),
],
);
}
}

View File

@@ -0,0 +1,74 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'register_event.dart';
import 'register_state.dart';
class RegisterBloc extends Bloc<RegisterEvent, RegisterState> {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
final TextEditingController countrySelectionTextField =
TextEditingController();
final TextEditingController phoneNumberTextField = TextEditingController();
final TextEditingController passwordTextField = TextEditingController();
GlobalKey<FormState> getFormKey() {
return formKey;
}
RegisterBloc() : super(RegisterInitial()) {
phoneNumberTextField.addListener(_onFormFieldChanged);
passwordTextField.addListener(_onFormFieldChanged);
countrySelectionTextField.addListener(_onFormFieldChanged);
on<RegisterFormChanged>(_onLoginFormChanged);
on<RegisterSubmitted>((event, emit) async {
if (!formKey.currentState!.validate()) {
return;
}
emit(RegisterLoading());
try {
// Simulate API call
await Future.delayed(const Duration(seconds: 2));
// Replace the next line with actual API call
final isSuccess = await _mockLoginApi(
event.phoneNumber, event.password, event.countryResidence);
if (isSuccess) {
emit(RegisterSuccess());
} else {
emit(const RegisterFailure(
"Register failed. Please check your credentials."));
}
} catch (e) {
emit(RegisterFailure(e.toString()));
}
});
}
void _onFormFieldChanged() {
add(RegisterFormChanged(
phoneNumberTextField.text,
countrySelectionTextField.text,
));
}
void _onLoginFormChanged(
RegisterFormChanged event, Emitter<RegisterState> emit) {
final areFieldsFilled =
event.phoneNumber.isNotEmpty && event.country.isNotEmpty;
emit(RegisterFieldsState(areFieldsFilled));
}
// Mock API function, replace with actual API call
Future<bool> _mockLoginApi(
String phoneNumber,
String password,
String countryResidence,
) async {
return true;
}
@override
Future<void> close() {
phoneNumberTextField.dispose();
passwordTextField.dispose();
countrySelectionTextField.dispose();
return super.close();
}
}

View File

@@ -0,0 +1,33 @@
import 'package:equatable/equatable.dart';
abstract class RegisterEvent extends Equatable {
const RegisterEvent();
@override
List<Object> get props => [];
}
class RegisterSubmitted extends RegisterEvent {
final String phoneNumber;
final String password;
final String countryResidence;
const RegisterSubmitted(
this.phoneNumber,
this.password,
this.countryResidence,
);
@override
List<Object> get props => [phoneNumber, password, countryResidence];
}
class RegisterFormChanged extends RegisterEvent {
final String phoneNumber;
final String country;
const RegisterFormChanged(this.phoneNumber, this.country);
@override
List<Object> get props => [phoneNumber, country];
}

View File

@@ -0,0 +1,32 @@
import 'package:equatable/equatable.dart';
abstract class RegisterState extends Equatable {
const RegisterState();
@override
List<Object> get props => [];
}
class RegisterInitial extends RegisterState {}
class RegisterLoading extends RegisterState {}
class RegisterSuccess extends RegisterState {}
class RegisterFailure extends RegisterState {
final String error;
const RegisterFailure(this.error);
@override
List<Object> get props => [error];
}
class RegisterFieldsState extends RegisterState {
final bool areFieldsFilled;
const RegisterFieldsState(this.areFieldsFilled);
@override
List<Object> get props => [areFieldsFilled];
}

View File

@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:tanami_app/features/register/presentation/widgets/register_bottom_section.dart';
import 'package:tanami_app/features/register/presentation/widgets/register_form.dart';
import 'package:tanami_app/features/register/presentation/widgets/register_top_section.dart';
class RegisterLayout extends StatelessWidget {
const RegisterLayout({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
//
children: const [
RegisterTopSection(),
RegisterForm(),
RegisterBottomSection(),
],
));
}
}

View File

@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:tanami_app/features/register/presentation/bloc/register_bloc.dart';
import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart';
import 'register_layout.dart';
class RegisterScreen extends StatelessWidget {
const RegisterScreen({super.key});
@override
Widget build(BuildContext context) {
final radioBloc = context.read<RadioBloc>();
return WillPopScope(
onWillPop: () async {
radioBloc.resetSelection();
return true; // Allow the pop to happen
},
child: Scaffold(
resizeToAvoidBottomInset: true,
body: MultiBlocProvider(
providers: [
BlocProvider(
// Create an instance of the OnboardingBloc
create: (context) => RegisterBloc(),
),
],
child: const RegisterLayout(),
),
),
);
}
}

View File

@@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:tanami_app/features/register/presentation/widgets/register_step_count.dart';
import '../widgets/register_step_bottom_section.dart';
import '../widgets/register_step_top_section.dart';
class RegisterStepLayout extends StatelessWidget {
const RegisterStepLayout({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: const [
RegisterStepTopSection(),
Gap(20),
RegisterStepCount(),
RegisterStepBottomSection(),
],
));
}
}

View File

@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../../../../shared/components/exit_app_dialog.dart';
import 'register_step_layout.dart';
class RegisterStepScreen extends StatelessWidget {
final String fromScreen;
const RegisterStepScreen({
super.key,
required this.fromScreen,
});
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (fromScreen == "welcome" || fromScreen == "login") {
exitAppDialog(context);
return false;
} else {
return true;
}
},
child: const Scaffold(
resizeToAvoidBottomInset: true,
body: RegisterStepLayout(),
),
);
}
}

View File

@@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gap/gap.dart';
import 'package:tanami_app/core/styles/app_images.dart';
import 'package:tanami_app/shared/components/loader.dart';
import 'package:tanami_app/shared/components/toast_message.dart';
import '../../../../core/routes/route_name.dart';
import '../../../../core/routes/routes.dart';
import '../../../../core/styles/app_color.dart';
import '../../../../core/styles/app_text.dart';
import '../../../../shared/components/button_widget.dart';
import '../../../../shared/components/text_widget.dart';
import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart';
import '../bloc/register_bloc.dart';
import '../bloc/register_event.dart';
import '../bloc/register_state.dart';
class RegisterBottomSection extends StatelessWidget {
const RegisterBottomSection({super.key});
@override
Widget build(BuildContext context) {
final radioBloc = context.read<RadioBloc>();
return Column(
children: [
const Gap(90),
Image.asset(
AppImages.stage1Image,
width: 75,
height: 12,
),
const Gap(36),
BlocConsumer<RegisterBloc, RegisterState>(
listener: (context, state) {
if (state is RegisterLoading) {
Loader.loader(context);
} else if (state is RegisterSuccess) {
successToastMessage(context, "successful !");
goRouter.pop();
goRouter.pushNamed(RouteName.otpScreen);
} else if (state is RegisterFailure) {
goRouter.pop();
errorToastMessage(
context,
state.error,
);
}
},
builder: (context, state) {
bool isButtonEnabled = false;
if (state is RegisterFieldsState) {
isButtonEnabled = state.areFieldsFilled;
} else if (state is RegisterSuccess || state is RegisterFailure) {
isButtonEnabled = true;
}
return Container(
margin: const EdgeInsets.symmetric(
horizontal: 16,
),
width: 1.sw,
height: 56.h,
child: ButtonWidget().elevatedBtn(
txtClr: isButtonEnabled
? AppColor.plainWhite
: AppColor.inactiveBtnTxtColor,
function: () {
isButtonEnabled
? context.read<RegisterBloc>().add(
RegisterSubmitted(
context
.read<RegisterBloc>()
.phoneNumberTextField
.text,
context
.read<RegisterBloc>()
.passwordTextField
.text,
""),
)
: null;
},
text: AppText.nextText,
clr: isButtonEnabled
? AppColor.primaryColor2
: AppColor.inactiveBtnColor,
),
);
},
),
const Gap(5),
ButtonWidget().textBtn(
function: () {
radioBloc.resetSelection();
goRouter.pop();
},
text: TextWidget().tex14W700(AppText.backText,
clr: AppColor.textLabelColor,
textDecoration: TextDecoration.underline)),
],
);
}
}

View File

@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:tanami_app/core/styles/app_text.dart';
import 'package:tanami_app/core/utils/constant/country_flag_data.dart';
import '../../../../shared/components/form_label_textfield.dart';
import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart';
import '../../../countrySelection/presentation/bloc/choose_country_state.dart';
import '../bloc/register_bloc.dart';
class RegisterForm extends StatelessWidget {
const RegisterForm({super.key});
@override
Widget build(BuildContext context) {
final loginBloc = context.read<RegisterBloc>();
int selectedCountry = -1;
return BlocConsumer<RadioBloc, RadioState>(listener: (context, state) {
if (state is RadioSelectionChanged) {
selectedCountry = state.selectedIndex;
loginBloc.countrySelectionTextField.text = countryName[selectedCountry];
}
}, builder: (context, state) {
if (state is RadioSelectionChanged) {
selectedCountry = state.selectedIndex;
} else {
selectedCountry = -1;
}
return Form(
key: loginBloc.formKey,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 14,
),
child: Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Gap(50),
FormLabelTextField(
prefixWidget: selectedCountry == -1
? null
: Image.asset(
countryFlag[selectedCountry],
width: 20,
height: 20,
),
hintText: AppText.chooseCountry,
title: AppText.countryOfResidence,
type: "country selection",
textEditingController: loginBloc.countrySelectionTextField,
),
const Gap(20),
FormLabelTextField(
prefixWidget: selectedCountry == -1
? null
: Image.asset(
countryFlag[selectedCountry],
width: 20,
height: 20,
),
hintText: "+0 (000) 000 00 00",
title: AppText.phoneNumber,
type: "phone number",
textEditingController: loginBloc.phoneNumberTextField,
),
],
),
),
),
);
});
}
}

View File

@@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gap/gap.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/shared/components/button_widget.dart';
import '../../../../core/styles/app_text.dart';
import '../../../../shared/components/text_widget.dart';
class RegisterStepBottomSection extends StatelessWidget {
const RegisterStepBottomSection({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 40.0),
child: Column(
children: [
Container(
margin: const EdgeInsets.symmetric(
horizontal: 16,
),
width: 1.sw,
height: 56.h,
child: ButtonWidget().elevatedBtn(
function: () {
goRouter.pushNamed(
RouteName.registerScreen,
);
},
text: AppText.getStarted,
txtClr: AppColor.plainWhite,
clr: AppColor.primaryColor2,
),
),
const Gap(16),
ButtonWidget().textBtn(
function: () {
goRouter.goNamed(RouteName.loginScreen, pathParameters: {
"fromScreen": "registerStep",
});
},
text: TextWidget().tex14W700(
AppText.loginText,
clr: AppColor.darkGreyColor,
textDecoration: TextDecoration.underline,
))
],
),
);
}
}

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tanami_app/core/styles/app_color.dart';
import 'package:tanami_app/core/utils/constant/register_step_data.dart';
import 'package:tanami_app/shared/components/text_widget.dart';
class RegisterStepCount extends StatelessWidget {
const RegisterStepCount({super.key});
@override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.symmetric(
horizontal: 27,
vertical: 5,
),
child: ListTile(
isThreeLine: true,
leading: SvgPicture.asset(stepImage[index]),
title: TextWidget().tex14W700(
title[index],
clr: AppColor.textLabelColor,
txtAlign: TextAlign.start,
),
subtitle: TextWidget().tex14W500(
description[index],
clr: AppColor.textLabelColor,
txtAlign: TextAlign.start,
),
),
);
},
);
}
}

View File

@@ -0,0 +1,39 @@
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';
class RegisterStepTopSection extends StatelessWidget {
const RegisterStepTopSection({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Gap(85),
Center(
child: SvgPicture.asset(
AppImages.weclomeLogo,
),
),
const Gap(30),
TextWidget().tex20W700(
AppText.getStarted,
clr: AppColor.charcoalColor,
),
const Gap(10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 75),
child: TextWidget().tex14W500(
AppText.setupYourTanamiAccountToBegin,
clr: AppColor.smokeGrayColor,
),
),
],
);
}
}

View File

@@ -0,0 +1,39 @@
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';
class RegisterTopSection extends StatelessWidget {
const RegisterTopSection({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Gap(85),
Center(
child: SvgPicture.asset(
AppImages.weclomeLogo,
),
),
const Gap(60),
TextWidget().tex20W700(
AppText.welcome,
clr: AppColor.charcoalColor,
),
const Gap(10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 75),
child: TextWidget().tex14W500(
AppText.selectYourCountryOfResidence,
clr: AppColor.smokeGrayColor,
),
),
],
);
}
}

View File

@@ -25,7 +25,11 @@ class LoginSignUpButton extends StatelessWidget {
width: 1.sw,
height: 56.h,
child: ButtonWidget().elevatedBtn(
function: () {},
function: () {
goRouter.goNamed(RouteName.registerStepScreen, pathParameters: {
"fromScreentype": "welcome",
});
},
text: AppText.signUpText,
txtClr: AppColor.plainWhite,
clr: AppColor.primaryColor,
@@ -34,11 +38,15 @@ class LoginSignUpButton extends StatelessWidget {
const Gap(16),
ButtonWidget().textBtn(
function: () {
goRouter.goNamed(RouteName.loginScreen);
goRouter.goNamed(RouteName.loginScreen, pathParameters: {
"fromScreen": "welcome",
});
},
text: TextWidget().tex14W700(AppText.loginText,
clr: AppColor.darkGreyColor,
textDecoration: TextDecoration.underline))
text: TextWidget().tex14W700(
AppText.loginText,
clr: AppColor.darkGreyColor,
textDecoration: TextDecoration.underline,
))
],
),
);

View File

@@ -6,6 +6,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'core/routes/routes.dart';
import 'core/utils/connectivity/network_connectivity.dart';
import 'features/countrySelection/presentation/bloc/choose_country_bloc.dart';
import 'shared/components/bloc/password_field/password_visibility_bloc.dart';
/* CREATED BY - JAYESH JAIN
DATE - 24-05-2024
@@ -53,7 +54,10 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
providers: [
BlocProvider(
create: (context) => RadioBloc(),
)
),
BlocProvider(
create: (context) => PasswordVisibilityBloc(),
),
],
child: ScreenUtilInit(
builder: (BuildContext context, Widget? child) => MaterialApp.router(

View File

@@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.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/core/styles/app_text.dart';
exitAppDialog(
context,
) {
return showDialog(
context: context,
builder: (context) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AlertDialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 16),
backgroundColor: const Color(0XFFFFFFFF),
//contentPadding: EdgeInsets.fromLTRB(96, 32, 96, 28),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
side: BorderSide(color: Color(0XFFFFFFFF)),
),
content: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//sizedBoxHeight(32.h),
Align(
alignment: Alignment.center,
child: CircleAvatar(
radius: 25,
backgroundColor: AppColor.inactiveBtnColor,
child: Center(
child: SvgPicture.asset(
AppImages.exitAppIcon,
width: 30,
height: 30,
fit: BoxFit.contain,
color: AppColor.primaryColor,
),
),
),
),
SizedBox(
height: 22.h,
),
Align(
alignment: Alignment.center,
child: Text(
AppText.areYouSureYouWantToExitText,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 22.sp,
//fontWeight: FontWeight.w600,
),
),
),
Gap(21.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Container(
height: 48.h,
width: 140.w,
decoration: BoxDecoration(
border: Border.all(
color: AppColor.primaryColor,
),
borderRadius: BorderRadius.circular(10.h),
color: AppColor.plainWhite,
),
child: Center(
child: Text(
AppText.cancelText,
style: TextStyle(
color: AppColor.primaryColor, fontSize: 18.sp),
),
),
),
),
Gap(15.w),
InkWell(
onTap: () {
SystemNavigator.pop();
Navigator.pop(context);
},
child: Container(
height: 48.h,
width: 140.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.h),
color: AppColor.primaryColor),
child: Center(
child: Text(
AppText.exitText,
style: TextStyle(
color: AppColor.plainWhite, fontSize: 18.sp),
),
),
),
),
],
),
],
),
),
],
),
);
}

View File

@@ -13,23 +13,15 @@ class TextWidget {
}
//Text Size 14
Widget tex14W700(String text, {Color? clr, TextDecoration? textDecoration}) {
return Text(text,
textAlign: TextAlign.center,
style: GoogleFonts.dmSans(
fontSize: 14,
fontWeight: FontWeight.w700,
decoration: textDecoration ?? TextDecoration.none,
color: clr ?? AppColor.plainWhite));
}
Widget tex14W500(
String text, {
Color? clr,
TextDecoration? textDecoration,
TextAlign? txtAlign,
}) {
return Text(text,
textAlign: TextAlign.center,
textAlign: txtAlign ?? TextAlign.center,
style: GoogleFonts.dmSans(
fontSize: 14,
fontWeight: FontWeight.w500,
@@ -37,6 +29,17 @@ class TextWidget {
color: clr ?? AppColor.plainWhite));
}
Widget tex14W700(String text,
{Color? clr, TextDecoration? textDecoration, TextAlign? txtAlign}) {
return Text(text,
textAlign: txtAlign ?? TextAlign.center,
style: GoogleFonts.dmSans(
fontSize: 14,
fontWeight: FontWeight.w700,
decoration: textDecoration ?? TextDecoration.none,
color: clr ?? AppColor.plainWhite));
}
//Text Size 15
Widget tex15W500(
String text, {

View File

@@ -808,6 +808,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.2"
pin_input_text_field:
dependency: transitive
description:
name: pin_input_text_field
sha256: "8d6fc670aa673a4df5976086f0e8039972a5b2bcb783c8db8dd3b9b4b072ca90"
url: "https://pub.dev"
source: hosted
version: "4.5.1"
platform:
dependency: transitive
description:
@@ -941,6 +949,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
sms_autofill:
dependency: "direct main"
description:
name: sms_autofill
sha256: "43139a175fb3c57ff103ac4b82f2aa70b6c45cf93539d7974c2556810f355363"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
source_gen:
dependency: transitive
description:

View File

@@ -74,6 +74,9 @@ dependencies:
#Style
control_style: ^0.1.0
#OTP Autofill
sms_autofill: ^2.3.1
dev_dependencies:
flutter_test:
sdk: flutter
@@ -90,8 +93,13 @@ flutter:
- assets/images/welcome_screen/png/
- assets/images/auth_screen/
- assets/images/auth_screen/svg/
- assets/images/auth_screen/png/
- assets/images/country_flag/
- assets/images/country_flag/svg/
- assets/images/country_flag/png/
- assets/images/bottom_bar/active/
- assets/images/bottom_bar/inactive/
- assets/images/biometric_screen/
- assets/images/biometric_screen/png/
- assets/images/biometric_screen/svg/
- assets/images/dialog/
- assets/images/dialog/svg/