Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a594b1e68a | |||
| 4409aef9e2 | |||
| a9389070bf | |||
| 485aa7a46f | |||
| a54e734d46 |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
|
@ -1,24 +0,0 @@
|
||||||
<svg width="524" height="173" viewBox="0 0 524 173" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g clip-path="url(#clip0_23_9019)">
|
|
||||||
<path d="M194.31 28.74L206.48 51L219.27 28.76H232.21L212.29 62.86V83H200.67V62.84L180.75 28.74H194.31Z" fill="#9E2891"/>
|
|
||||||
<path d="M247.79 32.69C247.809 33.51 247.661 34.3252 247.353 35.0855C247.045 35.8457 246.584 36.5347 246 37.11C245.412 37.6962 244.71 38.1564 243.938 38.4625C243.166 38.7685 242.34 38.914 241.51 38.89C240.677 38.907 239.85 38.7584 239.076 38.4528C238.302 38.1472 237.596 37.6908 237 37.11C236.41 36.5373 235.944 35.8494 235.631 35.0891C235.317 34.3287 235.164 33.5121 235.18 32.69C235.159 31.8731 235.31 31.0608 235.623 30.3062C235.937 29.5515 236.406 28.8714 237 28.31C237.604 27.735 238.317 27.2853 239.096 26.9867C239.875 26.6881 240.706 26.5465 241.54 26.57C242.362 26.5477 243.18 26.6902 243.946 26.989C244.712 27.2878 245.41 27.737 246 28.31C246.586 28.8755 247.048 29.5571 247.356 30.3113C247.665 31.0655 247.812 31.8756 247.79 32.69ZM246.93 43.15V83H236V43.15H246.93Z" fill="#9E2891"/>
|
|
||||||
<path d="M316.92 61.13V83.07H306V60.74C306 54.7 303.7 51.68 299.1 51.68C298.017 51.6409 296.939 51.8473 295.947 52.2837C294.954 52.7201 294.074 53.3752 293.37 54.2C291.819 56.1914 291.048 58.6803 291.2 61.2V83.07H280.26V60.74C280.26 54.7 277.927 51.68 273.26 51.68C272.176 51.6412 271.098 51.855 270.11 52.3045C269.123 52.754 268.253 53.4268 267.57 54.27C266.061 56.2815 265.304 58.7583 265.43 61.27V83.07H254.53V43.15H264.06L265.06 48.15C266.341 46.4745 267.981 45.1076 269.86 44.15C272.055 43.1452 274.447 42.643 276.86 42.68C282.54 42.68 286.494 44.9267 288.72 49.42C290.134 47.2728 292.099 45.5457 294.41 44.42C296.907 43.2298 299.645 42.6342 302.41 42.68C304.364 42.6151 306.308 42.9667 308.115 43.7116C309.922 44.4564 311.55 45.5774 312.89 47C315.57 49.8067 316.914 54.5167 316.92 61.13Z" fill="#9E2891"/>
|
|
||||||
<path d="M363 83H357.42C352.4 83 349.944 80.83 350.05 76.49C348.731 78.6384 346.895 80.4226 344.71 81.68C342.347 82.9271 339.701 83.5403 337.03 83.46C332.59 83.46 329.014 82.44 326.3 80.4C324.968 79.4019 323.9 78.0925 323.19 76.5864C322.481 75.0802 322.151 73.4231 322.23 71.76C322.153 69.8652 322.549 67.9809 323.382 66.2771C324.214 64.5733 325.458 63.1034 327 62C330.12 59.7 334.654 58.55 340.6 58.55H348.51V56.56C348.542 55.736 348.377 54.9164 348.029 54.1687C347.681 53.4211 347.161 52.7668 346.51 52.26C344.913 51.1085 342.966 50.5465 341 50.67C339.238 50.5873 337.492 51.0481 336 51.99C335.383 52.3861 334.857 52.9079 334.455 53.5213C334.054 54.1348 333.786 54.8261 333.67 55.55H323.19C323.3 53.6561 323.848 51.8134 324.79 50.1668C325.732 48.5201 327.043 47.1144 328.62 46.06C331.874 43.8133 336.187 42.69 341.56 42.69C347.187 42.69 351.54 43.93 354.62 46.41C357.7 48.89 359.237 52.48 359.23 57.18V71.18C359.19 71.5381 359.224 71.9007 359.331 72.2449C359.438 72.5891 359.614 72.9075 359.85 73.18C360.408 73.5936 361.098 73.7892 361.79 73.73H363V83ZM340.47 65.78C338.602 65.6742 336.747 66.1493 335.16 67.14C334.544 67.5708 334.048 68.1509 333.717 68.8261C333.386 69.5012 333.233 70.2492 333.27 71C333.247 71.6411 333.379 72.2783 333.654 72.8578C333.929 73.4374 334.339 73.9423 334.85 74.33C336.106 75.2174 337.625 75.6544 339.16 75.57C340.39 75.6344 341.62 75.4517 342.777 75.0326C343.935 74.6135 344.997 73.9666 345.9 73.13C346.741 72.2633 347.401 71.2376 347.84 70.1129C348.28 68.9882 348.49 67.7872 348.46 66.58V65.8L340.47 65.78Z" fill="#9E2891"/>
|
|
||||||
<path d="M391.54 53.07H387.2C384.1 53.07 381.827 54 380.38 55.86C378.827 58.0793 378.063 60.7553 378.21 63.46V83H367.29V43.15H377.21L378.21 49.15C379.277 47.3096 380.799 45.7739 382.63 44.69C384.812 43.5902 387.239 43.0702 389.68 43.18H391.54V53.07Z" fill="#9E2891"/>
|
|
||||||
<path d="M433.94 83H424.25L423.25 78.19C421.853 79.9282 420.065 81.3117 418.032 82.2275C415.999 83.1434 413.778 83.5657 411.55 83.46C409.459 83.5413 407.373 83.2027 405.415 82.4641C403.457 81.7256 401.667 80.6021 400.15 79.16C397.21 76.2867 395.74 71.4967 395.74 64.79V43.15H406.66V63.46C406.66 67.08 407.3 69.8 408.56 71.63C409.218 72.552 410.101 73.2899 411.125 73.7731C412.149 74.2564 413.28 74.4687 414.41 74.39C415.642 74.4479 416.869 74.1975 417.979 73.6614C419.09 73.1253 420.049 72.3205 420.77 71.32C422.257 69.28 423 66.4267 423 62.76V43.15H433.93L433.94 83Z" fill="#9E2891"/>
|
|
||||||
<path d="M200.9 89.43H214.85L234.54 143.68H222.06L217.87 131.82H197.26L193.07 143.68H181.07L200.9 89.43ZM214.7 122.43L207.49 101.82L200.36 122.43H214.7Z" fill="#9E2891"/>
|
|
||||||
<path d="M255.77 144.15C251.999 144.235 248.268 143.369 244.92 141.63C241.873 140.003 239.377 137.507 237.75 134.46C236.09 131.132 235.226 127.464 235.226 123.745C235.226 120.026 236.09 116.358 237.75 113.03C239.403 109.984 241.927 107.501 245 105.9C248.362 104.162 252.107 103.296 255.89 103.38C261.224 103.38 265.557 104.737 268.89 107.45C272.315 110.281 274.532 114.312 275.09 118.72H263.75C263.384 116.884 262.417 115.223 261 114C259.536 112.814 257.693 112.197 255.81 112.26C254.504 112.217 253.205 112.482 252.02 113.035C250.835 113.587 249.797 114.411 248.99 115.44C247.323 117.885 246.431 120.776 246.431 123.735C246.431 126.694 247.323 129.585 248.99 132.03C249.799 133.056 250.838 133.877 252.023 134.427C253.207 134.978 254.505 135.243 255.81 135.2C257.737 135.266 259.623 134.634 261.12 133.42C262.579 132.164 263.552 130.438 263.87 128.54H275.11C274.597 133.016 272.376 137.121 268.91 140C265.517 142.76 261.137 144.143 255.77 144.15Z" fill="#9E2891"/>
|
|
||||||
<path d="M320.17 143.68H314.59C309.583 143.68 307.13 141.51 307.23 137.17C305.907 139.319 304.068 141.103 301.88 142.36C299.521 143.609 296.878 144.226 294.21 144.15C289.76 144.15 286.21 143.15 283.47 141.08C282.137 140.082 281.069 138.773 280.36 137.266C279.65 135.76 279.321 134.103 279.4 132.44C279.31 130.546 279.691 128.659 280.51 126.949C281.328 125.239 282.558 123.758 284.09 122.64C287.223 120.34 291.76 119.19 297.7 119.19H305.6V117.25C305.632 116.426 305.467 115.606 305.119 114.858C304.772 114.11 304.251 113.456 303.6 112.95C302.059 111.957 300.275 111.407 298.442 111.359C296.61 111.312 294.8 111.768 293.21 112.68C292.595 113.078 292.071 113.6 291.671 114.213C291.271 114.827 291.005 115.517 290.89 116.24H280.33C280.442 114.347 280.99 112.505 281.932 110.858C282.874 109.212 284.184 107.806 285.76 106.75C289.013 104.503 293.326 103.38 298.7 103.38C304.34 103.38 308.693 104.62 311.76 107.1C314.826 109.58 316.363 113.17 316.37 117.87V131.87C316.332 132.228 316.367 132.59 316.474 132.934C316.58 133.278 316.756 133.596 316.99 133.87C317.552 134.274 318.239 134.466 318.93 134.41H320.17V143.68ZM297.62 126.47C295.751 126.36 293.895 126.836 292.31 127.83C291.694 128.257 291.197 128.833 290.865 129.505C290.532 130.177 290.376 130.921 290.41 131.67C290.388 132.312 290.521 132.95 290.798 133.529C291.074 134.109 291.487 134.613 292 135C293.252 135.887 294.767 136.324 296.3 136.24C297.523 136.301 298.746 136.117 299.897 135.698C301.047 135.279 302.102 134.634 303 133.8C303.844 132.936 304.506 131.911 304.946 130.785C305.386 129.66 305.594 128.458 305.56 127.25V126.47H297.62Z" fill="#9E2891"/>
|
|
||||||
<path d="M364.27 143.68H354.73L353.65 138.18C352.225 140.111 350.352 141.666 348.191 142.712C346.031 143.757 343.649 144.261 341.25 144.18C337.925 144.23 334.65 143.358 331.79 141.66C328.968 139.944 326.695 137.456 325.24 134.49C323.61 131.134 322.802 127.44 322.88 123.71C322.795 120.002 323.604 116.329 325.24 113C326.711 110.043 328.998 107.569 331.83 105.87C334.706 104.174 337.992 103.302 341.33 103.35C346.49 103.35 350.49 105.157 353.33 108.77V89.43H364.26L364.27 143.68ZM353.5 123.84C353.645 120.825 352.708 117.857 350.86 115.47C350.01 114.432 348.931 113.605 347.708 113.054C346.485 112.502 345.151 112.241 343.81 112.29C342.464 112.241 341.124 112.503 339.895 113.054C338.665 113.605 337.579 114.432 336.72 115.47C334.978 117.885 334.041 120.787 334.041 123.765C334.041 126.743 334.978 129.645 336.72 132.06C337.581 133.095 338.668 133.919 339.897 134.468C341.126 135.018 342.465 135.278 343.81 135.23C345.147 135.283 346.479 135.027 347.701 134.482C348.924 133.938 350.005 133.119 350.86 132.09C352.705 129.748 353.642 126.818 353.5 123.84Z" fill="#9E2891"/>
|
|
||||||
<path d="M379.88 105.9C383.105 104.169 386.722 103.301 390.38 103.38C394.058 103.311 397.698 104.12 401 105.74C403.986 107.237 406.486 109.55 408.21 112.41C410.559 116.613 411.392 121.496 410.57 126.24H381.7V126.55C381.805 129.079 382.792 131.492 384.49 133.37C385.356 134.219 386.389 134.878 387.524 135.305C388.658 135.732 389.87 135.917 391.08 135.85C393.027 135.923 394.952 135.426 396.62 134.42C398.103 133.446 399.147 131.932 399.53 130.2H410.3C409.913 132.787 408.881 135.236 407.3 137.32C405.634 139.494 403.446 141.214 400.94 142.32C398.09 143.585 394.998 144.21 391.88 144.15C387.901 144.251 383.955 143.401 380.37 141.67C377.234 140.103 374.642 137.629 372.93 134.57C371.14 131.282 370.243 127.582 370.33 123.84C370.23 120.073 371.09 116.342 372.83 113C374.447 110.003 376.895 107.538 379.88 105.9ZM397 113.49C395.244 112.124 393.064 111.416 390.84 111.49C388.664 111.409 386.532 112.119 384.84 113.49C383.196 114.894 382.157 116.879 381.94 119.03H400C399.746 116.868 398.672 114.885 397 113.49Z" fill="#9E2891"/>
|
|
||||||
<path d="M479.28 121.82V143.76H468.35V121.44C468.35 115.393 466.05 112.37 461.45 112.37C460.366 112.329 459.288 112.535 458.295 112.972C457.303 113.408 456.422 114.064 455.72 114.89C454.167 116.881 453.392 119.369 453.54 121.89V143.75H442.62V121.44C442.62 115.393 440.286 112.37 435.62 112.37C434.534 112.33 433.453 112.543 432.464 112.992C431.475 113.442 430.604 114.115 429.92 114.96C428.413 116.973 427.659 119.449 427.79 121.96V143.74H416.89V103.84H426.42L427.42 108.84C428.7 107.164 430.341 105.798 432.22 104.84C434.415 103.835 436.806 103.333 439.22 103.37C444.9 103.37 448.85 105.617 451.07 110.11C452.49 107.965 454.458 106.238 456.77 105.11C459.266 103.92 462.004 103.324 464.77 103.37C466.717 103.299 468.657 103.642 470.462 104.376C472.267 105.111 473.895 106.22 475.24 107.63C477.926 110.477 479.273 115.207 479.28 121.82Z" fill="#9E2891"/>
|
|
||||||
<path d="M502.21 132.44L511.67 103.84H523.37L505.7 149.34C504.985 151.312 504.102 153.219 503.06 155.04C502.312 156.331 501.231 157.398 499.93 158.13C498.401 158.889 496.706 159.25 495 159.18H484.39V150H490.39C491.439 150.081 492.486 149.836 493.39 149.3C494.197 148.556 494.808 147.625 495.17 146.59L496.17 143.95L480.9 103.84H492.52L502.21 132.44Z" fill="#9E2891"/>
|
|
||||||
<path d="M121.07 26.53L98.76 39.42L76.03 52.54L53.26 39.39L53.24 39.38L30.96 26.52L31.41 25.76L53.24 13.15L53.26 13.13L76.02 0L98.76 13.12L120.6 25.74L121.07 26.53Z" fill="#9E2891"/>
|
|
||||||
<path d="M53.26 172.41H98.76V110.9L121.51 97.78L137.93 88.29L152.02 80.15L129.27 40.75L98.76 58.36L92.43 62.02L76 71.49L59.6 62.03L53.26 58.37L53.24 58.36L22.75 40.75L0 80.16L14.09 88.3L30.5 97.78L53.24 110.9L53.26 110.91V137.18V172.41Z" fill="#9E2891"/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id="clip0_23_9019">
|
|
||||||
<rect width="523.37" height="172.42" fill="white"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
BIN
assets/images/landing_1.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
BIN
assets/images/landing_2.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
BIN
assets/images/landing_3.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 2.2 MiB |
BIN
assets/images/loading.png
Normal file
|
After Width: | Height: | Size: 448 KiB |
|
|
@ -9,12 +9,14 @@
|
||||||
"cont": "ቀጥል",
|
"cont": "ቀጥል",
|
||||||
"register": "ይመዝገቡ",
|
"register": "ይመዝገቡ",
|
||||||
"login_with_google": "በጉግል ይግቡ",
|
"login_with_google": "በጉግል ይግቡ",
|
||||||
|
"login_with_apple": "በአፕል ይግቡ",
|
||||||
"or": "ወይም",
|
"or": "ወይም",
|
||||||
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
||||||
"create_account": "አዲስ መለያ ይፍጠሩ",
|
"create_account": "አዲስ መለያ ይፍጠሩ",
|
||||||
"already_have_account": "መለያ አለዎት?",
|
"already_have_account": "መለያ አለዎት?",
|
||||||
"login": " ይግቡ ",
|
"login": " ይግቡ ",
|
||||||
"register_with_google": "በጉግል ይመዝገቡ",
|
"register_with_google": "በጉግል ይመዝገቡ",
|
||||||
|
"register_with_apple": "በአፕል ይመዝገቡ",
|
||||||
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
||||||
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
||||||
"login_with_email": "በኢሜይል ይግቡ",
|
"login_with_email": "በኢሜይል ይግቡ",
|
||||||
|
|
@ -193,8 +195,7 @@
|
||||||
"keep_momentum":"በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
"keep_momentum":"በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
||||||
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
||||||
"total_practices": "ጠቅላላ ልምምዶች",
|
"total_practices": "ጠቅላላ ልምምዶች",
|
||||||
"progress_percentage": "የእድገት መቶኛ",
|
"progress_percentage": "የእድገት መቶኛ"
|
||||||
"notifications": "ማሳወቂያዎች"
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@
|
||||||
"cont": "Continue",
|
"cont": "Continue",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"login_with_google": "Login with Google",
|
"login_with_google": "Login with Google",
|
||||||
|
"login_with_apple": "Login with Apple",
|
||||||
"or": "Or",
|
"or": "Or",
|
||||||
"login_with_phone": "Login with phone number",
|
"login_with_phone": "Login with phone number",
|
||||||
"create_account": "Create an account",
|
"create_account": "Create an account",
|
||||||
"already_have_account": "Already have an account?",
|
"already_have_account": "Already have an account?",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register_with_google": "Register with Google",
|
"register_with_google": "Register with Google",
|
||||||
|
"register_with_apple": "Register with Apple",
|
||||||
"register_with_phone": "Register with phone number",
|
"register_with_phone": "Register with phone number",
|
||||||
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
||||||
"login_with_email": "Login with email",
|
"login_with_email": "Login with email",
|
||||||
|
|
@ -190,9 +192,8 @@
|
||||||
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
|
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
|
||||||
"track_journey": "Track your learning journey and see your growth over time.",
|
"track_journey": "Track your learning journey and see your growth over time.",
|
||||||
"learn_english": "Learn English",
|
"learn_english": "Learn English",
|
||||||
"keep_momentum":"Great job! Keep the momentum.",
|
"keep_momentum": "Great job! Keep the momentum.",
|
||||||
"completed_practices": "Completed Practices",
|
"completed_practices": "Completed Practices",
|
||||||
"total_practices": "Total Practices",
|
"total_practices": "Total Practices",
|
||||||
"progress_percentage": "Progress Percentage",
|
"progress_percentage": "Progress Percentage"
|
||||||
"notifications": "Notifications"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,5 @@
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
|
||||||
<string>13.0</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
||||||
46
ios/Podfile
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Uncomment this line to define a global platform for your project
|
||||||
|
platform :ios, '15.0'
|
||||||
|
|
||||||
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
|
project 'Runner', {
|
||||||
|
'Debug' => :debug,
|
||||||
|
'Profile' => :release,
|
||||||
|
'Release' => :release,
|
||||||
|
}
|
||||||
|
|
||||||
|
def flutter_root
|
||||||
|
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||||
|
unless File.exist?(generated_xcode_build_settings_path)
|
||||||
|
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||||
|
end
|
||||||
|
|
||||||
|
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||||
|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||||
|
return matches[1].strip if matches
|
||||||
|
end
|
||||||
|
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||||
|
end
|
||||||
|
|
||||||
|
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||||
|
|
||||||
|
flutter_ios_podfile_setup
|
||||||
|
|
||||||
|
target 'Runner' do
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
target 'RunnerTests' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
flutter_additional_ios_build_settings(target)
|
||||||
|
target.build_configurations.each do |config|
|
||||||
|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
28
ios/Podfile.lock
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
PODS:
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- flutter_phone_direct_caller (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- permission_handler_apple (9.3.0):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_phone_direct_caller (from `.symlinks/plugins/flutter_phone_direct_caller/ios`)
|
||||||
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
flutter_phone_direct_caller:
|
||||||
|
:path: ".symlinks/plugins/flutter_phone_direct_caller/ios"
|
||||||
|
permission_handler_apple:
|
||||||
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
|
flutter_phone_direct_caller: 7d5d72794577b96f12b4b6da13a9ef90ba438665
|
||||||
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 4b015915ec662986b54bf30ab778da63f7dda016
|
||||||
|
|
||||||
|
COCOAPODS: 1.16.2
|
||||||
|
|
@ -11,9 +11,13 @@
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||||
|
896DC9E666DF8098D827C010 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9793345F00B89E38C23EBB8 /* Pods_RunnerTests.framework */; };
|
||||||
|
8E1B3E4A2C540A0B00F51C11 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8E1B3E492C540A0B00F51C11 /* GoogleService-Info.plist */; };
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
99CE3BFD23F69C6D49568DE0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93B517F10FA92BB14B3CDC5A /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
|
@ -42,12 +46,19 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
18336A33563E3B5B5B9974CC /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
20E44080F42EAC6B045A6D89 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
69301B8842E33A5CD16999A8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
74C1B93B8C9E9562FD058B56 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
8E1B3E492C540A0B00F51C11 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
|
93B517F10FA92BB14B3CDC5A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -55,13 +66,27 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
ACEEA7C32CFC6E9900D60211 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
|
A8C2A6C7D1D99F7BA12EAF94 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
F1F6AAAC52D909E27AEDEFC0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
F9793345F00B89E38C23EBB8 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
932D3841F05A890DB5B188A4 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
896DC9E666DF8098D827C010 /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||||
|
99CE3BFD23F69C6D49568DE0 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -76,9 +101,32 @@
|
||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
633D6DCBF46C9B68DCD511FE /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
93B517F10FA92BB14B3CDC5A /* Pods_Runner.framework */,
|
||||||
|
F9793345F00B89E38C23EBB8 /* Pods_RunnerTests.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
8096B886696A019BCD318B6B /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
74C1B93B8C9E9562FD058B56 /* Pods-Runner.debug.xcconfig */,
|
||||||
|
69301B8842E33A5CD16999A8 /* Pods-Runner.release.xcconfig */,
|
||||||
|
F1F6AAAC52D909E27AEDEFC0 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
20E44080F42EAC6B045A6D89 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
18336A33563E3B5B5B9974CC /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
A8C2A6C7D1D99F7BA12EAF94 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
|
@ -94,6 +142,8 @@
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
|
8096B886696A019BCD318B6B /* Pods */,
|
||||||
|
633D6DCBF46C9B68DCD511FE /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
@ -113,6 +163,8 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
8E1B3E492C540A0B00F51C11 /* GoogleService-Info.plist */,
|
||||||
|
ACEEA7C32CFC6E9900D60211 /* Runner.entitlements */,
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
|
@ -128,8 +180,10 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
94F71B9A2AE7A340918A2B71 /* [CP] Check Pods Manifest.lock */,
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
932D3841F05A890DB5B188A4 /* Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
|
@ -145,18 +199,24 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
EDCDA15227D1D12483183F4E /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
DE13979F911D29D4A95BCE2F /* [CP] Embed Pods Frameworks */,
|
||||||
|
E684A37538F596FB5432DE3F /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = Runner;
|
name = Runner;
|
||||||
|
packageProductDependencies = (
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
);
|
||||||
productName = Runner;
|
productName = Runner;
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
|
|
@ -178,6 +238,11 @@
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1100;
|
||||||
|
SystemCapabilities = {
|
||||||
|
com.apple.SignInWithApple = {
|
||||||
|
enabled = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -190,6 +255,9 @@
|
||||||
Base,
|
Base,
|
||||||
);
|
);
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
packageReferences = (
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
||||||
|
);
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
|
|
@ -215,6 +283,7 @@
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
8E1B3E4A2C540A0B00F51C11 /* GoogleService-Info.plist in Resources */,
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -238,6 +307,28 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
|
94F71B9A2AE7A340918A2B71 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
|
|
@ -253,6 +344,62 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
|
DE13979F911D29D4A95BCE2F /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
E684A37538F596FB5432DE3F /* [CP] Copy Pods Resources */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Copy Pods Resources";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
EDCDA15227D1D12483183F4E /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
|
@ -346,7 +493,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|
@ -361,15 +508,23 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K73ZX6D43Q;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Yimaru LMS TestApp App Store Profile";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|
@ -378,13 +533,14 @@
|
||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 20E44080F42EAC6B045A6D89 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
|
@ -395,13 +551,14 @@
|
||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 18336A33563E3B5B5B9974CC /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
|
@ -410,13 +567,14 @@
|
||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = A8C2A6C7D1D99F7BA12EAF94 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
|
@ -472,7 +630,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
|
@ -523,7 +681,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|
@ -540,15 +698,23 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K73ZX6D43Q;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Yimaru LMS TestApp App Store Profile";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
@ -562,15 +728,23 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K73ZX6D43Q;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.yimaru.lms.testapp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Yimaru LMS TestApp App Store Profile";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|
@ -611,6 +785,20 @@
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "abseil-cpp-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||||
|
"version" : "1.2024072200.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "app-check",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/app-check.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
|
||||||
|
"version" : "11.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "appauth-ios",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/openid/AppAuth-iOS.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "145104f5ea9d58ae21b60add007c33c1cc0c948e",
|
||||||
|
"version" : "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "firebase-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "8d5b4189f1f482df8d5c58c9985ea70491ef5382",
|
||||||
|
"version" : "12.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "flutterfire",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/flutterfire",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "05731e3fb091093546db363e379bff166f7286a3",
|
||||||
|
"version" : "4.4.0-firebase-core-swift"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9bfcc6cf435b2e7c5562c1900b8680c594fa9a64",
|
||||||
|
"version" : "3.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleappmeasurement",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "219e564a8510e983e675c94f77f7f7c50049f22d",
|
||||||
|
"version" : "12.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googledatatransport",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
|
||||||
|
"version" : "10.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googlesignin-ios",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleSignIn-iOS.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "913b4005ea26aebe1c97d54e35ad82a515924c71",
|
||||||
|
"version" : "9.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleutilities",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
|
||||||
|
"version" : "8.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "grpc-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
|
||||||
|
"version" : "1.69.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtm-session-fetcher",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a2ab612cb980066ee56d90d60d8462992c07f24b",
|
||||||
|
"version" : "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtmappauth",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GTMAppAuth.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "56e0ccf09a6dd29dc7e68bdf729598240ca8aa16",
|
||||||
|
"version" : "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "interop-ios-for-google-sdks",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||||
|
"version" : "101.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "leveldb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/leveldb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||||
|
"version" : "1.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nanopb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/nanopb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
|
||||||
|
"version" : "2.30910.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "promises",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/promises.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
|
||||||
|
"version" : "2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-collections",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-collections.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fea17c02d767f46b23070fdfdacc28a03a39232a",
|
||||||
|
"version" : "1.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,24 @@
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Prepare Flutter Framework Script"
|
||||||
|
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||||
|
<EnvironmentBuildable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</EnvironmentBuildable>
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
|
|
|
||||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
|
|
@ -4,4 +4,7 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
|
||||||
167
ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "abseil-cpp-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||||
|
"version" : "1.2024072200.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "app-check",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/app-check.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
|
||||||
|
"version" : "11.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "appauth-ios",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/openid/AppAuth-iOS.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "145104f5ea9d58ae21b60add007c33c1cc0c948e",
|
||||||
|
"version" : "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "firebase-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "8d5b4189f1f482df8d5c58c9985ea70491ef5382",
|
||||||
|
"version" : "12.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "flutterfire",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/flutterfire",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "05731e3fb091093546db363e379bff166f7286a3",
|
||||||
|
"version" : "4.4.0-firebase-core-swift"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9bfcc6cf435b2e7c5562c1900b8680c594fa9a64",
|
||||||
|
"version" : "3.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleappmeasurement",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "219e564a8510e983e675c94f77f7f7c50049f22d",
|
||||||
|
"version" : "12.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googledatatransport",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
|
||||||
|
"version" : "10.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googlesignin-ios",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleSignIn-iOS.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "913b4005ea26aebe1c97d54e35ad82a515924c71",
|
||||||
|
"version" : "9.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleutilities",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
|
||||||
|
"version" : "8.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "grpc-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
|
||||||
|
"version" : "1.69.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtm-session-fetcher",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a2ab612cb980066ee56d90d60d8462992c07f24b",
|
||||||
|
"version" : "3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtmappauth",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GTMAppAuth.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "56e0ccf09a6dd29dc7e68bdf729598240ca8aa16",
|
||||||
|
"version" : "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "interop-ios-for-google-sdks",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||||
|
"version" : "101.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "leveldb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/leveldb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||||
|
"version" : "1.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nanopb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/nanopb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
|
||||||
|
"version" : "2.30910.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "promises",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/promises.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
|
||||||
|
"version" : "2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-collections",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-collections.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fea17c02d767f46b23070fdfdacc28a03a39232a",
|
||||||
|
"version" : "1.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,15 @@ import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||||
|
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
ios/Runner/GoogleService-Info.plist
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CLIENT_ID</key>
|
||||||
|
<string>900714037062-3qqf7urii8vg99id91nmmuvom3fm5c1u.apps.googleusercontent.com</string>
|
||||||
|
<key>REVERSED_CLIENT_ID</key>
|
||||||
|
<string>com.googleusercontent.apps.900714037062-3qqf7urii8vg99id91nmmuvom3fm5c1u</string>
|
||||||
|
<key>ANDROID_CLIENT_ID</key>
|
||||||
|
<string>900714037062-4trqu7ln6en4kcm6gadk0uo01qijn1mk.apps.googleusercontent.com</string>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyDbaGD47oUJOyn9n3b0pbH6ozmbGyIlOKk</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>900714037062</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.yimaru.lms.testapp</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>yimaru-academy-5e7e2</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>yimaru-academy-5e7e2.firebasestorage.app</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:900714037062:ios:45b484d79222c3ab4e6f47</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -1,51 +1,83 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Yimaru App</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>yimaru_app</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>com.googleusercontent.apps.900714037062-3qqf7urii8vg99id91nmmuvom3fm5c1u</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Yimaru App</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>yimaru_app</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
|
||||||
<true/>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<key>UIMainStoryboardFile</key>
|
|
||||||
<string>Main</string>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIStatusBarHidden</key>
|
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneClassName</key>
|
||||||
|
<string>UIWindowScene</string>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>flutter</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>FlutterSceneDelegate</string>
|
||||||
|
<key>UISceneStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIStatusBarHidden</key>
|
||||||
|
<false/>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
10
ios/Runner/Runner.entitlements
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.developer.applesignin</key>
|
||||||
|
<array>
|
||||||
|
<string>Default</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -35,6 +35,7 @@ import 'package:yimaru_app/ui/views/learn_practice/learn_practice_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart';
|
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/failure/failure_view.dart';
|
import 'package:yimaru_app/ui/views/failure/failure_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart';
|
import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart';
|
||||||
|
import 'package:yimaru_app/services/notification_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart';
|
import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart';
|
||||||
import 'package:yimaru_app/services/smart_auth_service.dart';
|
import 'package:yimaru_app/services/smart_auth_service.dart';
|
||||||
import 'package:yimaru_app/services/course_service.dart';
|
import 'package:yimaru_app/services/course_service.dart';
|
||||||
|
|
@ -55,11 +56,9 @@ import 'package:yimaru_app/services/localization_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
||||||
import 'package:yimaru_app/services/onboarding_service.dart';
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
|
import 'package:yimaru_app/services/apple_auth_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
|
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/payment/payment_view.dart';
|
import 'package:yimaru_app/ui/views/payment/payment_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/notification/notification_view.dart';
|
|
||||||
import 'package:yimaru_app/services/in_app_notification_service.dart';
|
|
||||||
import 'package:yimaru_app/services/push_notification_service.dart';
|
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
@StackedApp(
|
@StackedApp(
|
||||||
|
|
@ -99,7 +98,6 @@ import 'package:yimaru_app/services/push_notification_service.dart';
|
||||||
MaterialRoute(page: CourseModuleView),
|
MaterialRoute(page: CourseModuleView),
|
||||||
MaterialRoute(page: LearnCourseView),
|
MaterialRoute(page: LearnCourseView),
|
||||||
MaterialRoute(page: PaymentView),
|
MaterialRoute(page: PaymentView),
|
||||||
MaterialRoute(page: NotificationView),
|
|
||||||
// @stacked-route
|
// @stacked-route
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
|
@ -115,6 +113,7 @@ import 'package:yimaru_app/services/push_notification_service.dart';
|
||||||
LazySingleton(classType: ImagePickerService),
|
LazySingleton(classType: ImagePickerService),
|
||||||
LazySingleton(classType: GoogleAuthService),
|
LazySingleton(classType: GoogleAuthService),
|
||||||
LazySingleton(classType: ImageDownloaderService),
|
LazySingleton(classType: ImageDownloaderService),
|
||||||
|
LazySingleton(classType: NotificationService),
|
||||||
LazySingleton(classType: SmartAuthService),
|
LazySingleton(classType: SmartAuthService),
|
||||||
LazySingleton(classType: CourseService),
|
LazySingleton(classType: CourseService),
|
||||||
LazySingleton(classType: AudioPlayerService),
|
LazySingleton(classType: AudioPlayerService),
|
||||||
|
|
@ -126,8 +125,7 @@ import 'package:yimaru_app/services/push_notification_service.dart';
|
||||||
LazySingleton(classType: LearnService),
|
LazySingleton(classType: LearnService),
|
||||||
LazySingleton(classType: LocalizationService),
|
LazySingleton(classType: LocalizationService),
|
||||||
LazySingleton(classType: OnboardingService),
|
LazySingleton(classType: OnboardingService),
|
||||||
LazySingleton(classType: InAppNotificationService),
|
LazySingleton(classType: AppleAuthService),
|
||||||
LazySingleton(classType: PushNotificationService),
|
|
||||||
// @stacked-service
|
// @stacked-service
|
||||||
],
|
],
|
||||||
bottomsheets: [
|
bottomsheets: [
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import 'package:stacked_services/src/navigation/navigation_service.dart';
|
||||||
import 'package:stacked_shared/stacked_shared.dart';
|
import 'package:stacked_shared/stacked_shared.dart';
|
||||||
|
|
||||||
import '../services/api_service.dart';
|
import '../services/api_service.dart';
|
||||||
|
import '../services/apple_auth_service.dart';
|
||||||
import '../services/audio_player_service.dart';
|
import '../services/audio_player_service.dart';
|
||||||
import '../services/authentication_service.dart';
|
import '../services/authentication_service.dart';
|
||||||
import '../services/course_service.dart';
|
import '../services/course_service.dart';
|
||||||
|
|
@ -20,14 +21,13 @@ import '../services/dio_service.dart';
|
||||||
import '../services/google_auth_service.dart';
|
import '../services/google_auth_service.dart';
|
||||||
import '../services/image_downloader_service.dart';
|
import '../services/image_downloader_service.dart';
|
||||||
import '../services/image_picker_service.dart';
|
import '../services/image_picker_service.dart';
|
||||||
import '../services/in_app_notification_service.dart';
|
|
||||||
import '../services/in_app_update_service.dart';
|
import '../services/in_app_update_service.dart';
|
||||||
import '../services/learn_service.dart';
|
import '../services/learn_service.dart';
|
||||||
import '../services/localization_service.dart';
|
import '../services/localization_service.dart';
|
||||||
|
import '../services/notification_service.dart';
|
||||||
import '../services/onboarding_service.dart';
|
import '../services/onboarding_service.dart';
|
||||||
import '../services/permission_handler_service.dart';
|
import '../services/permission_handler_service.dart';
|
||||||
import '../services/phone_caller_service.dart';
|
import '../services/phone_caller_service.dart';
|
||||||
import '../services/push_notification_service.dart';
|
|
||||||
import '../services/secure_storage_service.dart';
|
import '../services/secure_storage_service.dart';
|
||||||
import '../services/smart_auth_service.dart';
|
import '../services/smart_auth_service.dart';
|
||||||
import '../services/status_checker_service.dart';
|
import '../services/status_checker_service.dart';
|
||||||
|
|
@ -56,6 +56,7 @@ Future<void> setupLocator(
|
||||||
locator.registerLazySingleton(() => ImagePickerService());
|
locator.registerLazySingleton(() => ImagePickerService());
|
||||||
locator.registerLazySingleton(() => GoogleAuthService());
|
locator.registerLazySingleton(() => GoogleAuthService());
|
||||||
locator.registerLazySingleton(() => ImageDownloaderService());
|
locator.registerLazySingleton(() => ImageDownloaderService());
|
||||||
|
locator.registerLazySingleton(() => NotificationService());
|
||||||
locator.registerLazySingleton(() => SmartAuthService());
|
locator.registerLazySingleton(() => SmartAuthService());
|
||||||
locator.registerLazySingleton(() => CourseService());
|
locator.registerLazySingleton(() => CourseService());
|
||||||
locator.registerLazySingleton(() => AudioPlayerService());
|
locator.registerLazySingleton(() => AudioPlayerService());
|
||||||
|
|
@ -67,6 +68,5 @@ Future<void> setupLocator(
|
||||||
locator.registerLazySingleton(() => LearnService());
|
locator.registerLazySingleton(() => LearnService());
|
||||||
locator.registerLazySingleton(() => LocalizationService());
|
locator.registerLazySingleton(() => LocalizationService());
|
||||||
locator.registerLazySingleton(() => OnboardingService());
|
locator.registerLazySingleton(() => OnboardingService());
|
||||||
locator.registerLazySingleton(() => InAppNotificationService());
|
locator.registerLazySingleton(() => AppleAuthService());
|
||||||
locator.registerLazySingleton(() => PushNotificationService());
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,14 @@ class DefaultFirebaseOptions {
|
||||||
|
|
||||||
static const FirebaseOptions ios = FirebaseOptions(
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
apiKey: 'AIzaSyDbaGD47oUJOyn9n3b0pbH6ozmbGyIlOKk',
|
apiKey: 'AIzaSyDbaGD47oUJOyn9n3b0pbH6ozmbGyIlOKk',
|
||||||
appId: '1:900714037062:ios:1caf8f24a4333b8e4e6f47',
|
appId: '1:900714037062:ios:45b484d79222c3ab4e6f47',
|
||||||
messagingSenderId: '900714037062',
|
messagingSenderId: '900714037062',
|
||||||
projectId: 'yimaru-academy-5e7e2',
|
projectId: 'yimaru-academy-5e7e2',
|
||||||
storageBucket: 'yimaru-academy-5e7e2.firebasestorage.app',
|
storageBucket: 'yimaru-academy-5e7e2.firebasestorage.app',
|
||||||
androidClientId:
|
androidClientId:
|
||||||
'900714037062-4trqu7ln6en4kcm6gadk0uo01qijn1mk.apps.googleusercontent.com',
|
'900714037062-4trqu7ln6en4kcm6gadk0uo01qijn1mk.apps.googleusercontent.com',
|
||||||
iosClientId:
|
iosClientId:
|
||||||
'900714037062-35bg0hsou56hg37mbcbpiar9uti7tcku.apps.googleusercontent.com',
|
'900714037062-3qqf7urii8vg99id91nmmuvom3fm5c1u.apps.googleusercontent.com',
|
||||||
iosBundleId: 'com.yimaru.lms.app',
|
iosBundleId: 'com.yimaru.lms.testapp',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import 'package:yimaru_app/app/app.dialogs.dart';
|
||||||
import 'package:yimaru_app/app/app.locator.dart';
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
import 'package:yimaru_app/services/notification_service.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:yimaru_app/services/push_notification_service.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/translations/codegen_loader.g.dart';
|
import 'package:yimaru_app/ui/common/translations/codegen_loader.g.dart';
|
||||||
import 'firebase_options.dart';
|
import 'firebase_options.dart';
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ Future<void> main() async {
|
||||||
|
|
||||||
await setupLocator();
|
await setupLocator();
|
||||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
await locator<PushNotificationService>().initialize();
|
await locator<NotificationService>().initialize();
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
setupDialogUi();
|
setupDialogUi();
|
||||||
setupBottomSheetUi();
|
setupBottomSheetUi();
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:yimaru_app/models/notification_payload.dart';
|
|
||||||
|
|
||||||
part 'in_app_notification.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class InAppNotification {
|
|
||||||
final String? id;
|
|
||||||
|
|
||||||
final String? type;
|
|
||||||
|
|
||||||
final String? level;
|
|
||||||
|
|
||||||
final String? image;
|
|
||||||
|
|
||||||
final NotificationPayload? payload;
|
|
||||||
|
|
||||||
@JsonKey(name: 'is_read')
|
|
||||||
final bool? isRead;
|
|
||||||
|
|
||||||
@JsonKey(name: 'reciever')
|
|
||||||
final String? receiver;
|
|
||||||
|
|
||||||
@JsonKey(name: 'recipient_id')
|
|
||||||
final int? recipientId;
|
|
||||||
|
|
||||||
@JsonKey(name: 'receiver_type')
|
|
||||||
final String? receiverType;
|
|
||||||
|
|
||||||
@JsonKey(name: 'error_severity')
|
|
||||||
final String? errorSeverity;
|
|
||||||
|
|
||||||
@JsonKey(name: 'delivery_status')
|
|
||||||
final String? deliveryStatus;
|
|
||||||
|
|
||||||
@JsonKey(name: 'delivery_channel')
|
|
||||||
final String? deliveryChannel;
|
|
||||||
|
|
||||||
const InAppNotification(
|
|
||||||
{this.id,
|
|
||||||
this.type,
|
|
||||||
this.image,
|
|
||||||
this.level,
|
|
||||||
this.isRead,
|
|
||||||
this.payload,
|
|
||||||
this.receiver,
|
|
||||||
this.recipientId,
|
|
||||||
this.receiverType,
|
|
||||||
this.errorSeverity,
|
|
||||||
this.deliveryStatus,
|
|
||||||
this.deliveryChannel});
|
|
||||||
|
|
||||||
factory InAppNotification.fromJson(Map<String, dynamic> json) =>
|
|
||||||
_$InAppNotificationFromJson(json);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$InAppNotificationToJson(this);
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'in_app_notification.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
InAppNotification _$InAppNotificationFromJson(Map<String, dynamic> json) =>
|
|
||||||
InAppNotification(
|
|
||||||
id: json['id'] as String?,
|
|
||||||
type: json['type'] as String?,
|
|
||||||
image: json['image'] as String?,
|
|
||||||
level: json['level'] as String?,
|
|
||||||
isRead: json['is_read'] as bool?,
|
|
||||||
payload: json['payload'] == null
|
|
||||||
? null
|
|
||||||
: NotificationPayload.fromJson(
|
|
||||||
json['payload'] as Map<String, dynamic>),
|
|
||||||
receiver: json['reciever'] as String?,
|
|
||||||
recipientId: (json['recipient_id'] as num?)?.toInt(),
|
|
||||||
receiverType: json['receiver_type'] as String?,
|
|
||||||
errorSeverity: json['error_severity'] as String?,
|
|
||||||
deliveryStatus: json['delivery_status'] as String?,
|
|
||||||
deliveryChannel: json['delivery_channel'] as String?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$InAppNotificationToJson(InAppNotification instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': instance.id,
|
|
||||||
'type': instance.type,
|
|
||||||
'level': instance.level,
|
|
||||||
'image': instance.image,
|
|
||||||
'payload': instance.payload,
|
|
||||||
'is_read': instance.isRead,
|
|
||||||
'reciever': instance.receiver,
|
|
||||||
'recipient_id': instance.recipientId,
|
|
||||||
'receiver_type': instance.receiverType,
|
|
||||||
'error_severity': instance.errorSeverity,
|
|
||||||
'delivery_status': instance.deliveryStatus,
|
|
||||||
'delivery_channel': instance.deliveryChannel,
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
part 'notification_payload.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class NotificationPayload {
|
|
||||||
final String? message;
|
|
||||||
|
|
||||||
final String? headline;
|
|
||||||
|
|
||||||
const NotificationPayload({this.message, this.headline});
|
|
||||||
|
|
||||||
factory NotificationPayload.fromJson(Map<String, dynamic> json) =>
|
|
||||||
_$NotificationPayloadFromJson(json);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$NotificationPayloadToJson(this);
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'notification_payload.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
NotificationPayload _$NotificationPayloadFromJson(Map<String, dynamic> json) =>
|
|
||||||
NotificationPayload(
|
|
||||||
message: json['message'] as String?,
|
|
||||||
headline: json['headline'] as String?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$NotificationPayloadToJson(
|
|
||||||
NotificationPayload instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'message': instance.message,
|
|
||||||
'headline': instance.headline,
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:yimaru_app/models/app_update.dart';
|
import 'package:yimaru_app/models/app_update.dart';
|
||||||
import 'package:yimaru_app/models/in_app_notification.dart';
|
|
||||||
import 'package:yimaru_app/models/learn_lesson.dart';
|
import 'package:yimaru_app/models/learn_lesson.dart';
|
||||||
import 'package:yimaru_app/models/learn_practice.dart';
|
import 'package:yimaru_app/models/learn_practice.dart';
|
||||||
import 'package:yimaru_app/models/learn_program.dart';
|
import 'package:yimaru_app/models/learn_program.dart';
|
||||||
|
|
@ -113,6 +112,34 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apple auth
|
||||||
|
Future<Map<String, dynamic>> appleAuth(Map<String, dynamic> data) async {
|
||||||
|
try {
|
||||||
|
Response response = await _service.dio.post(
|
||||||
|
'$kBaseUrl/$kAppleAuthUrl',
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.success,
|
||||||
|
'message': 'Logged in successfully',
|
||||||
|
'data': User.fromJson(response.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
'message': '${response.data['message']}, ${response.data['error']}'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
'message': e.response?.data.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify otp
|
// Verify otp
|
||||||
Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic> data) async {
|
||||||
try {
|
try {
|
||||||
|
|
@ -356,55 +383,6 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark notifications
|
|
||||||
Future<void> markNotificationsRead() async {
|
|
||||||
try {
|
|
||||||
await _service.dio.post(
|
|
||||||
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kNotificationsUrl/$kMarkNotificationRead');
|
|
||||||
} catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get unread notifications
|
|
||||||
Future<int> getUnreadNotifications() async {
|
|
||||||
try {
|
|
||||||
final Response response = await _service.dio.get(
|
|
||||||
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kNotificationsUrl/$kUnreadUrl');
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
return response.data['unread'];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} catch (e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get notifications
|
|
||||||
Future<List<InAppNotification>> getAllNotifications() async {
|
|
||||||
try {
|
|
||||||
List<InAppNotification> notifications = [];
|
|
||||||
|
|
||||||
final Response response = await _service.dio
|
|
||||||
.get('$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kNotificationsUrl');
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
var data = response.data;
|
|
||||||
var decodedData = data['notifications'] as List;
|
|
||||||
notifications = decodedData.map(
|
|
||||||
(e) {
|
|
||||||
return InAppNotification.fromJson(e);
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
return notifications;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
} catch (e) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get assessment question sets
|
// Get assessment question sets
|
||||||
Future<List<Assessment>> getAssessments() async {
|
Future<List<Assessment>> getAssessments() async {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
36
lib/services/apple_auth_service.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
class AppleAuthService with ListenableServiceMixin {
|
||||||
|
AuthorizationCredentialAppleID? _appleCredential;
|
||||||
|
|
||||||
|
AuthorizationCredentialAppleID? get appleCredential => _appleCredential;
|
||||||
|
|
||||||
|
AppleAuthService() {
|
||||||
|
listenToReactiveValues([_appleCredential]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isSupported => Platform.isIOS;
|
||||||
|
|
||||||
|
Future<void> appleAuth() async {
|
||||||
|
if (!isSupported) {
|
||||||
|
throw UnsupportedError('Apple Sign-In is only available on iOS.');
|
||||||
|
}
|
||||||
|
|
||||||
|
_appleCredential = await SignInWithApple.getAppleIDCredential(
|
||||||
|
scopes: [
|
||||||
|
AppleIDAuthorizationScopes.email,
|
||||||
|
AppleIDAuthorizationScopes.fullName,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void logout() {
|
||||||
|
_appleCredential = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
AuthenticationService() {
|
AuthenticationService() {
|
||||||
listenToReactiveValues([_user, _state, _localizationService]);
|
listenToReactiveValues([_user,_state, _localizationService]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout state
|
// Logout state
|
||||||
|
|
@ -31,6 +31,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
|
|
||||||
StateObjects get state => _state;
|
StateObjects get state => _state;
|
||||||
|
|
||||||
|
|
||||||
// Check user logged in
|
// Check user logged in
|
||||||
Future<bool> userLoggedIn() async {
|
Future<bool> userLoggedIn() async {
|
||||||
if (await _secureService.getString('userId') != null) {
|
if (await _secureService.getString('userId') != null) {
|
||||||
|
|
@ -201,6 +202,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
await setFirstTimeInstall(firstTimeInstall);
|
await setFirstTimeInstall(firstTimeInstall);
|
||||||
await _secureService.setString('language', language);
|
await _secureService.setString('language', language);
|
||||||
|
|
||||||
|
|
||||||
_state = StateObjects.none;
|
_state = StateObjects.none;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ class GoogleAuthService with ListenableServiceMixin {
|
||||||
|
|
||||||
_googleUser ??=
|
_googleUser ??=
|
||||||
await _signIn.authenticate(scopeHint: ['email', 'profile']);
|
await _signIn.authenticate(scopeHint: ['email', 'profile']);
|
||||||
|
|
||||||
});
|
});
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/models/in_app_notification.dart';
|
|
||||||
|
|
||||||
import '../app/app.locator.dart';
|
|
||||||
import 'api_service.dart';
|
|
||||||
|
|
||||||
class InAppNotificationService with ListenableServiceMixin {
|
|
||||||
// Dependency injection
|
|
||||||
final _apiService = locator<ApiService>();
|
|
||||||
|
|
||||||
// Initialization
|
|
||||||
learnService() {
|
|
||||||
listenToReactiveValues([_unreadCount, _notifications]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unread count
|
|
||||||
int _unreadCount = 0;
|
|
||||||
|
|
||||||
int get unreadCount => _unreadCount;
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
List<InAppNotification> _notifications = [];
|
|
||||||
|
|
||||||
List<InAppNotification> get notifications => _notifications;
|
|
||||||
|
|
||||||
// Unread notifications
|
|
||||||
Future<void> markNotificationRead() async {
|
|
||||||
await _apiService.markNotificationsRead();
|
|
||||||
_unreadCount = await _apiService.getUnreadNotifications();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// All notifications
|
|
||||||
Future<void> getAllNotifications() async {
|
|
||||||
_notifications = await _apiService.getAllNotifications();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unread notifications
|
|
||||||
Future<void> getUnreadNotifications() async {
|
|
||||||
_unreadCount = await _apiService.getUnreadNotifications();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -58,6 +58,8 @@ class LearnService with ListenableServiceMixin {
|
||||||
|
|
||||||
List<LearnLesson> get lessons => _lessons;
|
List<LearnLesson> get lessons => _lessons;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Learn programs
|
// Learn programs
|
||||||
Future<String?> refreshObject(String url) async {
|
Future<String?> refreshObject(String url) async {
|
||||||
Map<String, dynamic> data = {'reference': url};
|
Map<String, dynamic> data = {'reference': url};
|
||||||
|
|
|
||||||
138
lib/services/notification_service.dart
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
|
await locator<NotificationService>().setupFlutterNotifications();
|
||||||
|
await locator<NotificationService>().showNotification(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotificationService {
|
||||||
|
final _messaging = FirebaseMessaging.instance;
|
||||||
|
|
||||||
|
bool _isFlutterLocalNotificationInitialized = false;
|
||||||
|
|
||||||
|
final _localNotifications = FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
Future<void> initialize() async {
|
||||||
|
// Initialize FCM token
|
||||||
|
await updateFCMToken();
|
||||||
|
|
||||||
|
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||||
|
|
||||||
|
// Request permission
|
||||||
|
await _requestPermission();
|
||||||
|
|
||||||
|
// setup message handle
|
||||||
|
await _setupMessageHandler();
|
||||||
|
|
||||||
|
// Subscribe to all devices
|
||||||
|
subscribeToTopic('yimaru');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _requestPermission() async {
|
||||||
|
await _messaging.requestPermission(
|
||||||
|
alert: true,
|
||||||
|
badge: true,
|
||||||
|
sound: true,
|
||||||
|
carPlay: false,
|
||||||
|
provisional: false,
|
||||||
|
announcement: false,
|
||||||
|
criticalAlert: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setupFlutterNotifications() async {
|
||||||
|
if (_isFlutterLocalNotificationInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android setup
|
||||||
|
const channel = AndroidNotificationChannel(
|
||||||
|
'yimaru', // id
|
||||||
|
'Yimaru', // title
|
||||||
|
importance: Importance.high,
|
||||||
|
);
|
||||||
|
|
||||||
|
await _localNotifications
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
AndroidFlutterLocalNotificationsPlugin>()
|
||||||
|
?.createNotificationChannel(channel);
|
||||||
|
|
||||||
|
const initializationSettingsAndroid =
|
||||||
|
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||||
|
|
||||||
|
// IOS setup
|
||||||
|
const initializationSettingsDarwin = DarwinInitializationSettings();
|
||||||
|
|
||||||
|
const initializationSettings = InitializationSettings(
|
||||||
|
android: initializationSettingsAndroid,
|
||||||
|
iOS: initializationSettingsDarwin);
|
||||||
|
|
||||||
|
// Flutter notification setup
|
||||||
|
await _localNotifications.initialize(
|
||||||
|
settings: initializationSettings,
|
||||||
|
onDidReceiveNotificationResponse: (NotificationResponse response) {
|
||||||
|
if (response.payload == 'Page') {
|
||||||
|
// navigatorKey.currentState?.pushNamed('RouteName');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
_isFlutterLocalNotificationInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showNotification(RemoteMessage message) async {
|
||||||
|
RemoteNotification? notification = message.notification;
|
||||||
|
AndroidNotification? android = message.notification?.android;
|
||||||
|
|
||||||
|
if (notification != null && android != null) {
|
||||||
|
await _localNotifications.show(
|
||||||
|
id: notification.hashCode,
|
||||||
|
title: notification.title,
|
||||||
|
body: notification.body,
|
||||||
|
notificationDetails: const NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails('yimaru', 'Yimaru',
|
||||||
|
enableVibration: true,
|
||||||
|
priority: Priority.high,
|
||||||
|
icon: '@mipmap/ic_launcher',
|
||||||
|
importance: Importance.high),
|
||||||
|
iOS: DarwinNotificationDetails(
|
||||||
|
presentAlert: true, presentBadge: true, presentSound: true)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setupMessageHandler() async {
|
||||||
|
// Foreground message
|
||||||
|
FirebaseMessaging.onMessage
|
||||||
|
.listen((RemoteMessage message) => showNotification(message));
|
||||||
|
|
||||||
|
// Background message
|
||||||
|
FirebaseMessaging.onMessageOpenedApp.listen(_handleBackgroundMessage);
|
||||||
|
|
||||||
|
// Opened app
|
||||||
|
final initialMessage = await _messaging.getInitialMessage();
|
||||||
|
|
||||||
|
if (initialMessage != null) {
|
||||||
|
_handleBackgroundMessage(initialMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleBackgroundMessage(RemoteMessage message) {
|
||||||
|
if (message.data['type'] == 'Page') {
|
||||||
|
// navigatorKey.currentState?.pushNamed('RouteName');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> subscribeToTopic(String topic) async {
|
||||||
|
await FirebaseMessaging.instance.subscribeToTopic(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateFCMToken() async {
|
||||||
|
// print('DEVICE TOKEN: ${await _messaging.getToken()}');
|
||||||
|
_messaging.onTokenRefresh.listen((newToken) {
|
||||||
|
// updateTokenOnServer(newToken);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
||||||
import 'package:yimaru_app/app/app.locator.dart';
|
|
||||||
|
|
||||||
@pragma('vm:entry-point')
|
|
||||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
|
||||||
await locator<PushNotificationService>().setupFlutterNotifications();
|
|
||||||
await locator<PushNotificationService>().showNotification(message);
|
|
||||||
}
|
|
||||||
class PushNotificationService { final _messaging = FirebaseMessaging.instance;
|
|
||||||
|
|
||||||
bool _isFlutterLocalNotificationInitialized = false;
|
|
||||||
|
|
||||||
final _localNotifications = FlutterLocalNotificationsPlugin();
|
|
||||||
|
|
||||||
Future<void> initialize() async {
|
|
||||||
// Initialize FCM token
|
|
||||||
await updateFCMToken();
|
|
||||||
|
|
||||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
|
||||||
|
|
||||||
// Request permission
|
|
||||||
await _requestPermission();
|
|
||||||
|
|
||||||
// setup message handle
|
|
||||||
await _setupMessageHandler();
|
|
||||||
|
|
||||||
// Subscribe to all devices
|
|
||||||
subscribeToTopic('yimaru');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _requestPermission() async {
|
|
||||||
await _messaging.requestPermission(
|
|
||||||
alert: true,
|
|
||||||
badge: true,
|
|
||||||
sound: true,
|
|
||||||
carPlay: false,
|
|
||||||
provisional: false,
|
|
||||||
announcement: false,
|
|
||||||
criticalAlert: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setupFlutterNotifications() async {
|
|
||||||
if (_isFlutterLocalNotificationInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Android setup
|
|
||||||
const channel = AndroidNotificationChannel(
|
|
||||||
'yimaru', // id
|
|
||||||
'Yimaru', // title
|
|
||||||
importance: Importance.high,
|
|
||||||
);
|
|
||||||
|
|
||||||
await _localNotifications
|
|
||||||
.resolvePlatformSpecificImplementation<
|
|
||||||
AndroidFlutterLocalNotificationsPlugin>()
|
|
||||||
?.createNotificationChannel(channel);
|
|
||||||
|
|
||||||
const initializationSettingsAndroid =
|
|
||||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
|
||||||
|
|
||||||
// IOS setup
|
|
||||||
const initializationSettingsDarwin = DarwinInitializationSettings();
|
|
||||||
|
|
||||||
const initializationSettings = InitializationSettings(
|
|
||||||
android: initializationSettingsAndroid,
|
|
||||||
iOS: initializationSettingsDarwin);
|
|
||||||
|
|
||||||
// Flutter notification setup
|
|
||||||
await _localNotifications.initialize(
|
|
||||||
settings: initializationSettings,
|
|
||||||
onDidReceiveNotificationResponse: (NotificationResponse response) {
|
|
||||||
if (response.payload == 'Page') {
|
|
||||||
// navigatorKey.currentState?.pushNamed('RouteName');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
_isFlutterLocalNotificationInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showNotification(RemoteMessage message) async {
|
|
||||||
RemoteNotification? notification = message.notification;
|
|
||||||
AndroidNotification? android = message.notification?.android;
|
|
||||||
|
|
||||||
if (notification != null && android != null) {
|
|
||||||
await _localNotifications.show(
|
|
||||||
id: notification.hashCode,
|
|
||||||
title: notification.title,
|
|
||||||
body: notification.body,
|
|
||||||
notificationDetails: const NotificationDetails(
|
|
||||||
android: AndroidNotificationDetails('yimaru', 'Yimaru',
|
|
||||||
enableVibration: true,
|
|
||||||
priority: Priority.high,
|
|
||||||
icon: '@mipmap/ic_launcher',
|
|
||||||
importance: Importance.high),
|
|
||||||
iOS: DarwinNotificationDetails(
|
|
||||||
presentAlert: true, presentBadge: true, presentSound: true)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setupMessageHandler() async {
|
|
||||||
// Foreground message
|
|
||||||
FirebaseMessaging.onMessage
|
|
||||||
.listen((RemoteMessage message) => showNotification(message));
|
|
||||||
|
|
||||||
// Background message
|
|
||||||
FirebaseMessaging.onMessageOpenedApp.listen(_handleBackgroundMessage);
|
|
||||||
|
|
||||||
// Opened app
|
|
||||||
final initialMessage = await _messaging.getInitialMessage();
|
|
||||||
|
|
||||||
if (initialMessage != null) {
|
|
||||||
_handleBackgroundMessage(initialMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleBackgroundMessage(RemoteMessage message) {
|
|
||||||
if (message.data['type'] == 'Page') {
|
|
||||||
// navigatorKey.currentState?.pushNamed('RouteName');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> subscribeToTopic(String topic) async {
|
|
||||||
await FirebaseMessaging.instance.subscribeToTopic(topic);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> updateFCMToken() async {
|
|
||||||
// print('DEVICE TOKEN: ${await _messaging.getToken()}');
|
|
||||||
_messaging.onTokenRefresh.listen((newToken) {
|
|
||||||
// updateTokenOnServer(newToken);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -13,15 +13,12 @@ String kCheckUrl = 'check';
|
||||||
|
|
||||||
String kFilesUrl = 'files';
|
String kFilesUrl = 'files';
|
||||||
|
|
||||||
String kUnreadUrl = 'unread';
|
|
||||||
|
|
||||||
String kApiVersionUrl = 'v1';
|
String kApiVersionUrl = 'v1';
|
||||||
|
|
||||||
String kLevelsUrl = 'levels';
|
String kLevelsUrl = 'levels';
|
||||||
|
|
||||||
String kCoursesUrl = 'courses';
|
String kCoursesUrl = 'courses';
|
||||||
|
|
||||||
|
|
||||||
String kModulesUrl = 'modules';
|
String kModulesUrl = 'modules';
|
||||||
|
|
||||||
String kLessonsUrl = 'lessons';
|
String kLessonsUrl = 'lessons';
|
||||||
|
|
@ -72,8 +69,6 @@ String kQuestionSetsUrl = 'question-sets';
|
||||||
|
|
||||||
String kRequestResetCode = 'sendResetCode';
|
String kRequestResetCode = 'sendResetCode';
|
||||||
|
|
||||||
String kNotificationsUrl = 'notifications';
|
|
||||||
|
|
||||||
String kSubcategoriesUrl = 'sub-categories';
|
String kSubcategoriesUrl = 'sub-categories';
|
||||||
|
|
||||||
String kProgressSummary = 'progress-summary';
|
String kProgressSummary = 'progress-summary';
|
||||||
|
|
@ -84,8 +79,6 @@ String kCoursePracticeQuestions = 'questions';
|
||||||
|
|
||||||
String kCatalogCoursesUrl = 'catalog-courses';
|
String kCatalogCoursesUrl = 'catalog-courses';
|
||||||
|
|
||||||
String kMarkNotificationRead = 'mark-all-read';
|
|
||||||
|
|
||||||
String kUpdateProfileImage = 'profile-picture';
|
String kUpdateProfileImage = 'profile-picture';
|
||||||
|
|
||||||
String kSubscriptionsUrl = 'subscription-plans';
|
String kSubscriptionsUrl = 'subscription-plans';
|
||||||
|
|
@ -108,6 +101,8 @@ String kLessonProgressUrl = 'api/v1/progress/videos';
|
||||||
|
|
||||||
String kGoogleAuthUrl = 'api/v1/auth/google/android';
|
String kGoogleAuthUrl = 'api/v1/auth/google/android';
|
||||||
|
|
||||||
|
String kAppleAuthUrl = 'api/v1/auth/apple';
|
||||||
|
|
||||||
String kCourseProgressUrl = 'api/v1/progress/courses';
|
String kCourseProgressUrl = 'api/v1/progress/courses';
|
||||||
|
|
||||||
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ enum Voice { sample, recorded }
|
||||||
enum ResponseStatus { success, failure }
|
enum ResponseStatus { success, failure }
|
||||||
|
|
||||||
// Login method
|
// Login method
|
||||||
enum LoginMethod { phone, email, google }
|
enum LoginMethod { phone, email, google, apple }
|
||||||
|
|
||||||
// Sign-up method
|
// Sign-up method
|
||||||
enum SignUpMethod { phone, email, google }
|
enum SignUpMethod { phone, email, google, apple }
|
||||||
|
|
||||||
// Learn practice
|
// Learn practice
|
||||||
enum LearnPractices { course, module, lesson }
|
enum LearnPractices { course, module, lesson }
|
||||||
|
|
@ -50,7 +50,6 @@ enum StateObjects {
|
||||||
profileUpdate,
|
profileUpdate,
|
||||||
resetPassword,
|
resetPassword,
|
||||||
learnPractice,
|
learnPractice,
|
||||||
notifications,
|
|
||||||
courseCatalogs,
|
courseCatalogs,
|
||||||
loginWithEmail,
|
loginWithEmail,
|
||||||
coursePractice,
|
coursePractice,
|
||||||
|
|
@ -62,7 +61,9 @@ enum StateObjects {
|
||||||
profileCompletion,
|
profileCompletion,
|
||||||
learnSubscription,
|
learnSubscription,
|
||||||
learnSubscriptions,
|
learnSubscriptions,
|
||||||
|
loginWithApple,
|
||||||
registerWithGoogle,
|
registerWithGoogle,
|
||||||
|
registerWithApple,
|
||||||
learnPracticeSample,
|
learnPracticeSample,
|
||||||
learnPracticeAnswer,
|
learnPracticeAnswer,
|
||||||
loginWithPhoneNumber,
|
loginWithPhoneNumber,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import 'dart:ui';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart' show AssetLoader;
|
import 'package:easy_localization/easy_localization.dart' show AssetLoader;
|
||||||
|
|
||||||
class CodegenLoader extends AssetLoader {
|
class CodegenLoader extends AssetLoader{
|
||||||
const CodegenLoader();
|
const CodegenLoader();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -14,431 +14,403 @@ class CodegenLoader extends AssetLoader {
|
||||||
return Future.value(mapLocales[locale.toString()]);
|
return Future.value(mapLocales[locale.toString()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Map<String, dynamic> _am = {
|
static const Map<String,dynamic> _en = {
|
||||||
"loading": "በመጫን ላይ",
|
"loading": "Loading",
|
||||||
"welcome_back": "እንኳን በደህና ተመለሱ",
|
"welcome_back": "Welcome back",
|
||||||
"checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ",
|
"checking_user_info": "Checking user info",
|
||||||
"dont_have_account": "መለያ የለዎትም?",
|
"dont_have_account": "Don't have an account?",
|
||||||
"email": "ኢሜይል",
|
"email": "Email",
|
||||||
"password": "የይለፍ ቃል",
|
"password": "Password",
|
||||||
"forgot_password": "የይለፍ ቃል ረሱ?",
|
"forgot_password": "Forgot password?",
|
||||||
"cont": "ቀጥል",
|
"cont": "Continue",
|
||||||
"register": "ይመዝገቡ",
|
"register": "Register",
|
||||||
"login_with_google": "በጉግል ይግቡ",
|
"login_with_google": "Login with Google",
|
||||||
"or": "ወይም",
|
"login_with_apple": "Login with Apple",
|
||||||
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
"or": "Or",
|
||||||
"create_account": "አዲስ መለያ ይፍጠሩ",
|
"login_with_phone": "Login with phone number",
|
||||||
"already_have_account": "መለያ አለዎት?",
|
"create_account": "Create an account",
|
||||||
"login": " ይግቡ ",
|
"already_have_account": "Already have an account?",
|
||||||
"register_with_google": "በጉግል ይመዝገቡ",
|
"login": "Login",
|
||||||
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
"register_with_google": "Register with Google",
|
||||||
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
"register_with_apple": "Register with Apple",
|
||||||
"login_with_email": "በኢሜይል ይግቡ",
|
"register_with_phone": "Register with phone number",
|
||||||
"create_password": "የይለፍ ቃል ይፍጠሩ",
|
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
||||||
"confirm_password": "የይለፍ ቃል ያረጋግጡ",
|
"login_with_email": "Login with email",
|
||||||
"eight_character_minimum": "ቢያንስ 8 ፊደላት",
|
"create_password": "Create password",
|
||||||
"password_match": "የይለፍ ቃሉ ተመሳስሏል",
|
"confirm_password": "Confirm password",
|
||||||
"sign_up_agreement":
|
"eight_character_minimum": "8 characters minimum",
|
||||||
"‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
|
"password_match": "password match",
|
||||||
"terms_of_services": "የአገልግሎት ውሎች",
|
"sign_up_agreement": "By clicking ‘Sign Up’, you agree to our ‘Terms of Service’ and ‘Privacy Policy’",
|
||||||
"and": "እና",
|
"terms_of_services": "Terms of Service",
|
||||||
"privacy_policy": "የግላዊነት ፖሊሲ",
|
"and": "and",
|
||||||
"register_with_email": "በኢሜል ይመዝገቡ",
|
"privacy_policy": "Privacy Policy",
|
||||||
"verification_code": "የማረጋገጫ ኮድ",
|
"register_with_email": "Register with email",
|
||||||
"resend_code": "ኮዱን እንደገና ላክ",
|
"verification_code": "Verification Code",
|
||||||
"code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል",
|
"resend_code": "Resend Code",
|
||||||
"code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል",
|
"code_sent_to_phone": "Code sent to your number",
|
||||||
"resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ",
|
"code_sent_to_email": "Code sent to your email",
|
||||||
"reset_password": " የይለፍ ቃልን ይቀይሩ",
|
"resend_code_in": "Resend code in",
|
||||||
"enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።",
|
"reset_password": "Reset Password",
|
||||||
"please_wait": "እባክዎ ይጠብቁ",
|
"enter_email_reset_code": "Enter your email. We will send you a reset code.",
|
||||||
"reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል",
|
"please_wait": "Please wait",
|
||||||
"reset_code": " የመቀየሪያ ኮድ ",
|
"reset_code_sent": "Reset code sent successfully",
|
||||||
"new_password": "አዲስ የይለፍ ቃል",
|
"reset_code": "Reset code",
|
||||||
"logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል",
|
"new_password": "New password",
|
||||||
"view_course": " ኮርሱን ይመልከቱ",
|
"logged_in_successfully": "Logged in successfully",
|
||||||
"continue_learning": "መማርን ይቀጥሉ",
|
"continue_learning": "Continue Learning",
|
||||||
"start_learning": "ትምህርትን ይጀምሩ",
|
"start_learning": "Start Learning",
|
||||||
"completed": "ተጠናቋል",
|
"completed": "Completed",
|
||||||
"take_practice": "ልምምድ ያድርጉ",
|
"view_course": "View course",
|
||||||
"your_current_level": "የአሁኑ ደረጃዎ",
|
"take_practice": "Take practice",
|
||||||
"overall_progress": "አጠቃላይ እድገት",
|
"your_current_level": "Your current level",
|
||||||
"great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው",
|
"overall_progress": "Overall progress",
|
||||||
"view_module": "ሞጁሉን ይመልከቱ",
|
"great_work": "Keep up the great work! You're doing amazing",
|
||||||
"progress": "እድገት",
|
"view_module": "View module",
|
||||||
"keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ",
|
"progress": "Progress",
|
||||||
"lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ",
|
"keep_going": "Let's keep going - you're more than half there",
|
||||||
"practice": "ልምምድ",
|
"lessons_in_module": "Lessons in this module",
|
||||||
"start": "ጀምር",
|
"practice": "Practice",
|
||||||
"in_progress": "በሂደት ላይ",
|
"start": "Start",
|
||||||
"hello": "ሰላም",
|
"in_progress": "In Progress",
|
||||||
"ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ",
|
"hello": "Hello",
|
||||||
"learn": "ይማሩ ",
|
"ready_to_learn": "Ready to keep learning English today",
|
||||||
"course": "ኮርስ",
|
"learn": "Learn",
|
||||||
"profile": " ፕሮፋይል ",
|
"course": "Course",
|
||||||
"speaking_partner": "የንግግር ጓደኛ",
|
"profile": "Profile",
|
||||||
"practice_what_you_learned": "አሁን የተማሩትን እንለማመድ",
|
"speaking_partner": "Speaking partner",
|
||||||
"practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ",
|
"practice_what_you_learned": "Let's practice what you just learnt",
|
||||||
"start_practice": "ልምምድ ጀምር",
|
"practice_questions": "I will ask you a few questions and you can respond",
|
||||||
"almost_there": "ሊጨርሱ ተቃርበዋል",
|
"start_practice": "Start practice",
|
||||||
"finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ",
|
"almost_there": "You're almost there",
|
||||||
"continue_practice": "ልምምዱን ይቀጥሉ",
|
"finish_session": "Finish the session to see your progress",
|
||||||
"end_session": "ክፍለ ጊዜውን ያብቁ ",
|
"continue_practice": "Continue practice",
|
||||||
"tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ",
|
"end_session": "End session",
|
||||||
"practice_speaking": "ንግግርን ይለማመዱ",
|
"tap_start_to_listen": "Tap the start button to listen",
|
||||||
"tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ",
|
"practice_speaking": "Practice speaking",
|
||||||
"reply": "እንደገና አዳምጥ",
|
"tap_microphone": "Tap the microphone to speak",
|
||||||
"cancel": "ይቅር",
|
"reply": "Reply",
|
||||||
"you_are_speaking": "እየተናገሩ ነው",
|
"cancel": "Cancel",
|
||||||
"practice_completed": "ልምምዱ ተጠናቅቋል",
|
"you_are_speaking": "You're speaking",
|
||||||
"great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው",
|
"practice_completed": "Practice completed!",
|
||||||
"practice_again": "እንደገና ይለማመዱ",
|
"great_improvement": "You sound more confident this time, great improvement",
|
||||||
"conversation_review": "የንግግር ግምገማ",
|
"practice_again": "Practice again",
|
||||||
"result": "ውጤት",
|
"conversation_review": "Conversation review",
|
||||||
"quick_tip": "ጠቃሚ ምክር",
|
"result": "Result",
|
||||||
"retry": "እንደገና ይሞክሩ",
|
"quick_tip": "Quick tip",
|
||||||
"completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል",
|
"retry": "Retry",
|
||||||
"analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው",
|
"completed_a1": "Yay, you've completed A1",
|
||||||
"view_profile": "ፕሮፋይሎን ይመልከቱ ",
|
"analyzing_speaking": "We're now analyzing your speaking skill",
|
||||||
"hi": "ሰላም",
|
"view_profile": "View profile",
|
||||||
"edit_profile": "መገለጫ ያስተካክሉ",
|
"hi": "Hi",
|
||||||
"first_name": "የመጀመሪያ ስም",
|
"edit_profile": "Edit profile",
|
||||||
"last_name": "የአባት ስም",
|
"first_name": "First name",
|
||||||
"gender": "ፆታ",
|
"last_name": "Last name",
|
||||||
"male": "ወንድ",
|
"gender": "Gender",
|
||||||
"female": "ሴት",
|
"male": "Male",
|
||||||
"phone_number": "የስልክ ቁጥር",
|
"female": "Female",
|
||||||
"country": "ሀገር",
|
"phone_number": "Phone number",
|
||||||
"region": "ክልል",
|
"country": "Country",
|
||||||
"select_region": "ክልል ይምረጡ",
|
"region": "Region",
|
||||||
"enter_your_city": "ከተማዎን ያስገቡ",
|
"select_region": "Select region",
|
||||||
"occupation": "የስራ መስክ",
|
"enter_your_city": "Enter your city",
|
||||||
"select_occupation": "ሙያዎን ይምረጡ",
|
"occupation": "Occupation",
|
||||||
"save_changes": "ለውጦችን ያስቀምጡ",
|
"select_occupation": "Select occupation",
|
||||||
"my_progress": "የእኔ እድገት",
|
"save_changes": "Save changes",
|
||||||
"track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ",
|
"my_progress": "My progress",
|
||||||
"account_and_privacy": "መለያ እና ግላዊነት",
|
"track_your_achievement": "Track your achievements and learning streak",
|
||||||
"manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ",
|
"account_and_privacy": "Account & Privacy",
|
||||||
"support": "ድጋፍ",
|
"manage_settings": "Manage settings and app preference",
|
||||||
"get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ",
|
"support": "Support",
|
||||||
"logout": "ውጣ",
|
"get_help": "Get help through phone or Telegram",
|
||||||
"app_settings": "የመተግበሪያ ቅንብሮች",
|
"logout": "Logout",
|
||||||
"legal_and_information": "ሕጋዊ እና መረጃ",
|
"app_settings": "App settings",
|
||||||
"change_language": "ቋንቋ ቀይር",
|
"legal_and_information": "Legal & Information",
|
||||||
"terms_and_conditions": "ውሎች እና ሁኔታዎች",
|
"change_language": "Change language",
|
||||||
"delete_account": "መለያ ሰርዝ",
|
"terms_and_conditions": "Terms & Conditions",
|
||||||
"language_preference": "የቋንቋ ምርጫ",
|
"delete_account": "Delete account",
|
||||||
"choose_your_language": "ለውጦችን አስቀምጥ",
|
"language_preference": "Language preference",
|
||||||
"switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ",
|
"choose_your_language": "Choose your language",
|
||||||
"need_help": "እገዛ ይፈልጋሉ?",
|
"switch_language_anytime": "You can switch languages anytime",
|
||||||
"call_support": "የስልክ ድጋፍ",
|
"need_help": "Need help?",
|
||||||
"talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ",
|
"call_support": "Call support",
|
||||||
"telegram_support": "የቴሌግራም ድጋፍ",
|
"talk_with_support": "Talk with our support team directly",
|
||||||
"chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ",
|
"telegram_support": "Telegram support",
|
||||||
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
|
"chat_via_telegram": "Chat instantly via Telegram",
|
||||||
"tap_to_call": "ለመደወል ይንኩ",
|
"call_our_support": "Call our support team between 9 AM - 6 PM",
|
||||||
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
|
"tap_to_call": "Tap to call",
|
||||||
"connect_with_support_team":
|
"join_telegram": "Join Yimaru Academy on Telegram",
|
||||||
"ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
|
"connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates",
|
||||||
"open_in_telegram": "በቴሌግራም ይክፈቱ",
|
"open_in_telegram": "Open in Telegram",
|
||||||
"search_for": "ፈልጉት",
|
"search_for": "Search for",
|
||||||
"current_level": "የአሁኑ ደረጃ",
|
"current_level": "Current Level",
|
||||||
"keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።",
|
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
|
||||||
"no_practice_available": "ምንም ልምምድ አልተገኘም!",
|
"no_practice_available": "No practice available!",
|
||||||
"begin_module_practice": "የሞጁሉን ልምምድ ጀምር",
|
"begin_module_practice": "Begin Module Practice",
|
||||||
"lets_practice_lesson": "እንለማመድ",
|
"lets_practice_lesson": "Let’s Practice",
|
||||||
"lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!",
|
"lets_quickly_review": "Let’s quickly review what you’ve learned in this module!",
|
||||||
"lets_practice_module": "አሁን የተማርከውን እንለማመድ!",
|
"lets_practice_module": "Let's practice what you just learnt!",
|
||||||
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
"ask_you_few_actions": "I’ll ask you a few questions, and you can respond naturally.",
|
||||||
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
"begin_level_practice": "Begin Level Practice",
|
||||||
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
"lets_practice_course": "Let’s Practice Course",
|
||||||
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
"lets_quick_review": "Let’s quickly review what you’ve learned in this level!",
|
||||||
"speaking": "እየተናገረ ነው",
|
"speaking": "is speaking...",
|
||||||
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
"you_have_finished_practice": "You have finished your practice",
|
||||||
"view_results": "ውጤቶቼን እይ",
|
"view_results": "View My Results",
|
||||||
"sample_answer": "ናሙና መልስ",
|
"sample_answer": "Sample Answer",
|
||||||
"your_answer": "መልስህ",
|
"your_answer": "Your Answer",
|
||||||
"sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!",
|
"sound_confident": "You sound more confident this time - great improvement!",
|
||||||
"you_have_completed": "አያይ! አጠናቀቅህ",
|
"you_have_completed": "Yay, you’ve completed",
|
||||||
"yes": "አዎ",
|
"yes": "Yes",
|
||||||
"no": "አይ",
|
"no": "No",
|
||||||
"want_to_quit": "ለመውጣት እርግጠኛ ነህ?",
|
"want_to_quit": "Are you sure you want to quit?",
|
||||||
"required_field": "ይህ መስክ ያስፈልጋል",
|
"required_field": "The field is required",
|
||||||
"enter_full_name": "ሙሉ ስምህን አስገባ",
|
"enter_full_name": "Enter your full name",
|
||||||
"invalid_email": "የማይሰራ የኢሜይል ቅርጸት",
|
"invalid_email": "Invalid email format",
|
||||||
"phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት",
|
"phone_must_start_with": "Phone number must start with 251",
|
||||||
"phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት",
|
"phone_must_be": "Phone number must be 12 digits",
|
||||||
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
"what_should_we_call_you": "What should we call you?",
|
||||||
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
"name_for_personalization": "We’ll use your name to personalize your learning journey.",
|
||||||
"choose_your_gender": "ጾታህን ምረጥ",
|
"choose_your_gender": "Choose your gender?",
|
||||||
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
"gender_for_personalization": "We’ll personalize your learning experience based on your gender.",
|
||||||
"age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?",
|
"age_range": "Which age range are you in?",
|
||||||
"age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
"age_for_personalization": "We’ll personalize your learning experience based on your age.",
|
||||||
"educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?",
|
"educational_background": "What’s your current educational level?",
|
||||||
"education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።",
|
"education_for_personalization": "This helps us tailor your lessons to your experience.",
|
||||||
"your_occupation": "ስራህ ምንድን ነው?",
|
"your_occupation": "What’s your occupation?",
|
||||||
"occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
"occupation_for_personalization": "We’ll personalize your learning experience based on your occupation.",
|
||||||
"location": "ከየት ነህ?",
|
"location": "Where are you from?",
|
||||||
"select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ",
|
"select_country_region": "Select your country and region from the dropdown",
|
||||||
"select_country": "አገር ምረጥ",
|
"select_country": "Select country",
|
||||||
"learning_goal": "የመማር ዓላማህን ምረጥ",
|
"learning_goal": "Choose your learning goal.",
|
||||||
"language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?",
|
"language_goal": "What’s your main goal for improving your English?",
|
||||||
"your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።",
|
"your_goal": "Your goal helps us tailor your learning journey.",
|
||||||
"write_your_goal": "ዓላማህን ጻፍ…",
|
"write_your_goal": "Write your goal…",
|
||||||
"challenge_you_face": "What challenge do you face most with English?",
|
"challenge_you_face": "What challenge do you face most with English?",
|
||||||
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
|
"evey_one_has_strugle": "Everyone has struggles, let’s start fixing yours",
|
||||||
"write_your_challenge": "ችግርህን ጻፍ…",
|
"write_your_challenge": "Write your challenge…",
|
||||||
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
|
"topic_interest": "Which topics interest you most?",
|
||||||
"favourite_topic":
|
"favourite_topic": "Your favorite topics help us create fun, relatable lessons.",
|
||||||
"የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
|
"your_interest": "Write your interest…",
|
||||||
"your_interest": "ፍላጎትህን ጻፍ…",
|
"want_quick_assessment": "Want a quick assessment to know your English level?",
|
||||||
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
|
"answer_quick_questions": "Answer a few quick questions to help us understand your English proficiency.",
|
||||||
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
|
"skip": "Skip",
|
||||||
"skip": "ዝለል",
|
"finish_level": "Finish Level",
|
||||||
"finish_level": "ደረጃውን አጠናቅቅ",
|
"likely_speaker": "You’re likely speaker of",
|
||||||
"likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ",
|
"great_job": "Great Job! Here’s your next step to keep improving.",
|
||||||
"great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።",
|
"lets_start_practice": "Let's start your practice",
|
||||||
"lets_start_practice": "ልምምድህን እንጀምር",
|
"welcome_abroad": "Welcome aboard",
|
||||||
"welcome_abroad": "እንኳን ደህና መጣህ",
|
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
||||||
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
"finish": "Finish",
|
||||||
"finish": "አጠናቅቅ",
|
"finish_all_practice_lesson": "Finish the previous lesson practice to take this practice",
|
||||||
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
|
"finish_all_practice_module": "Finish the lesson practices to take the Module Practice",
|
||||||
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
|
"finish_all_practice_course": "Finish the Module practices to take the Course practice",
|
||||||
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
|
"finish_all_practice_previouse_module": "Finish the previous Module practice to take this practice",
|
||||||
"finish_all_practice_previouse_module":
|
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
|
||||||
"ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
|
"track_journey": "Track your learning journey and see your growth over time.",
|
||||||
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
|
"learn_english": "Learn English",
|
||||||
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
|
"keep_momentum": "Great job! Keep the momentum.",
|
||||||
"learn_english": "እንግሊዝኛ ይማሩ",
|
"completed_practices": "Completed Practices",
|
||||||
"keep_momentum": "በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
"total_practices": "Total Practices",
|
||||||
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
"progress_percentage": "Progress Percentage"
|
||||||
"total_practices": "ጠቅላላ ልምምዶች",
|
};
|
||||||
"progress_percentage": "የእድገት መቶኛ",
|
static const Map<String,dynamic> _am = {
|
||||||
"notifications": "ማሳወቂያዎች"
|
"loading": "በመጫን ላይ",
|
||||||
};
|
"welcome_back": "እንኳን በደህና ተመለሱ",
|
||||||
static const Map<String, dynamic> _en = {
|
"checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ",
|
||||||
"loading": "Loading",
|
"dont_have_account": "መለያ የለዎትም?",
|
||||||
"welcome_back": "Welcome back",
|
"email": "ኢሜይል",
|
||||||
"checking_user_info": "Checking user info",
|
"password": "የይለፍ ቃል",
|
||||||
"dont_have_account": "Don't have an account?",
|
"forgot_password": "የይለፍ ቃል ረሱ?",
|
||||||
"email": "Email",
|
"cont": "ቀጥል",
|
||||||
"password": "Password",
|
"register": "ይመዝገቡ",
|
||||||
"forgot_password": "Forgot password?",
|
"login_with_google": "በጉግል ይግቡ",
|
||||||
"cont": "Continue",
|
"login_with_apple": "በአፕል ይግቡ",
|
||||||
"register": "Register",
|
"or": "ወይም",
|
||||||
"login_with_google": "Login with Google",
|
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
||||||
"or": "Or",
|
"create_account": "አዲስ መለያ ይፍጠሩ",
|
||||||
"login_with_phone": "Login with phone number",
|
"already_have_account": "መለያ አለዎት?",
|
||||||
"create_account": "Create an account",
|
"login": " ይግቡ ",
|
||||||
"already_have_account": "Already have an account?",
|
"register_with_google": "በጉግል ይመዝገቡ",
|
||||||
"login": "Login",
|
"register_with_apple": "በአፕል ይመዝገቡ",
|
||||||
"register_with_google": "Register with Google",
|
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
||||||
"register_with_phone": "Register with phone number",
|
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
||||||
"enter_phone_number":
|
"login_with_email": "በኢሜይል ይግቡ",
|
||||||
"Enter your phone number. We will send you a confirmation code there.",
|
"create_password": "የይለፍ ቃል ይፍጠሩ",
|
||||||
"login_with_email": "Login with email",
|
"confirm_password": "የይለፍ ቃል ያረጋግጡ",
|
||||||
"create_password": "Create password",
|
"eight_character_minimum": "ቢያንስ 8 ፊደላት",
|
||||||
"confirm_password": "Confirm password",
|
"password_match": "የይለፍ ቃሉ ተመሳስሏል",
|
||||||
"eight_character_minimum": "8 characters minimum",
|
"sign_up_agreement": "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
|
||||||
"password_match": "password match",
|
"terms_of_services": "የአገልግሎት ውሎች",
|
||||||
"sign_up_agreement":
|
"and": "እና",
|
||||||
"By clicking ‘Sign Up’, you agree to our ‘Terms of Service’ and ‘Privacy Policy’",
|
"privacy_policy": "የግላዊነት ፖሊሲ",
|
||||||
"terms_of_services": "Terms of Service",
|
"register_with_email": "በኢሜል ይመዝገቡ",
|
||||||
"and": "and",
|
"verification_code": "የማረጋገጫ ኮድ",
|
||||||
"privacy_policy": "Privacy Policy",
|
"resend_code": "ኮዱን እንደገና ላክ",
|
||||||
"register_with_email": "Register with email",
|
"code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል",
|
||||||
"verification_code": "Verification Code",
|
"code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል",
|
||||||
"resend_code": "Resend Code",
|
"resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ",
|
||||||
"code_sent_to_phone": "Code sent to your number",
|
"reset_password": " የይለፍ ቃልን ይቀይሩ",
|
||||||
"code_sent_to_email": "Code sent to your email",
|
"enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።",
|
||||||
"resend_code_in": "Resend code in",
|
"please_wait": "እባክዎ ይጠብቁ",
|
||||||
"reset_password": "Reset Password",
|
"reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል",
|
||||||
"enter_email_reset_code":
|
"reset_code": " የመቀየሪያ ኮድ ",
|
||||||
"Enter your email. We will send you a reset code.",
|
"new_password": "አዲስ የይለፍ ቃል",
|
||||||
"please_wait": "Please wait",
|
"logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል",
|
||||||
"reset_code_sent": "Reset code sent successfully",
|
"view_course": " ኮርሱን ይመልከቱ",
|
||||||
"reset_code": "Reset code",
|
"continue_learning": "መማርን ይቀጥሉ",
|
||||||
"new_password": "New password",
|
"start_learning": "ትምህርትን ይጀምሩ",
|
||||||
"logged_in_successfully": "Logged in successfully",
|
"completed": "ተጠናቋል",
|
||||||
"continue_learning": "Continue Learning",
|
"take_practice": "ልምምድ ያድርጉ",
|
||||||
"start_learning": "Start Learning",
|
"your_current_level": "የአሁኑ ደረጃዎ",
|
||||||
"completed": "Completed",
|
"overall_progress": "አጠቃላይ እድገት",
|
||||||
"view_course": "View course",
|
"great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው",
|
||||||
"take_practice": "Take practice",
|
"view_module": "ሞጁሉን ይመልከቱ",
|
||||||
"your_current_level": "Your current level",
|
"progress": "እድገት",
|
||||||
"overall_progress": "Overall progress",
|
"keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ",
|
||||||
"great_work": "Keep up the great work! You're doing amazing",
|
"lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ",
|
||||||
"view_module": "View module",
|
"practice": "ልምምድ",
|
||||||
"progress": "Progress",
|
"start": "ጀምር",
|
||||||
"keep_going": "Let's keep going - you're more than half there",
|
"in_progress": "በሂደት ላይ",
|
||||||
"lessons_in_module": "Lessons in this module",
|
"hello": "ሰላም",
|
||||||
"practice": "Practice",
|
"ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ",
|
||||||
"start": "Start",
|
"learn": "ይማሩ ",
|
||||||
"in_progress": "In Progress",
|
"course": "ኮርስ",
|
||||||
"hello": "Hello",
|
"profile": " ፕሮፋይል ",
|
||||||
"ready_to_learn": "Ready to keep learning English today",
|
"speaking_partner": "የንግግር ጓደኛ",
|
||||||
"learn": "Learn",
|
"practice_what_you_learned": "አሁን የተማሩትን እንለማመድ",
|
||||||
"course": "Course",
|
"practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ",
|
||||||
"profile": "Profile",
|
"start_practice": "ልምምድ ጀምር",
|
||||||
"speaking_partner": "Speaking partner",
|
"almost_there": "ሊጨርሱ ተቃርበዋል",
|
||||||
"practice_what_you_learned": "Let's practice what you just learnt",
|
"finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ",
|
||||||
"practice_questions": "I will ask you a few questions and you can respond",
|
"continue_practice": "ልምምዱን ይቀጥሉ",
|
||||||
"start_practice": "Start practice",
|
"end_session": "ክፍለ ጊዜውን ያብቁ ",
|
||||||
"almost_there": "You're almost there",
|
"tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ",
|
||||||
"finish_session": "Finish the session to see your progress",
|
"practice_speaking": "ንግግርን ይለማመዱ",
|
||||||
"continue_practice": "Continue practice",
|
"tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ",
|
||||||
"end_session": "End session",
|
"reply": "እንደገና አዳምጥ",
|
||||||
"tap_start_to_listen": "Tap the start button to listen",
|
"cancel": "ይቅር",
|
||||||
"practice_speaking": "Practice speaking",
|
"you_are_speaking": "እየተናገሩ ነው",
|
||||||
"tap_microphone": "Tap the microphone to speak",
|
"practice_completed": "ልምምዱ ተጠናቅቋል",
|
||||||
"reply": "Reply",
|
"great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው",
|
||||||
"cancel": "Cancel",
|
"practice_again": "እንደገና ይለማመዱ",
|
||||||
"you_are_speaking": "You're speaking",
|
"conversation_review": "የንግግር ግምገማ",
|
||||||
"practice_completed": "Practice completed!",
|
"result": "ውጤት",
|
||||||
"great_improvement":
|
"quick_tip": "ጠቃሚ ምክር",
|
||||||
"You sound more confident this time, great improvement",
|
"retry": "እንደገና ይሞክሩ",
|
||||||
"practice_again": "Practice again",
|
"completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል",
|
||||||
"conversation_review": "Conversation review",
|
"analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው",
|
||||||
"result": "Result",
|
"view_profile": "ፕሮፋይሎን ይመልከቱ ",
|
||||||
"quick_tip": "Quick tip",
|
"hi": "ሰላም",
|
||||||
"retry": "Retry",
|
"edit_profile": "መገለጫ ያስተካክሉ",
|
||||||
"completed_a1": "Yay, you've completed A1",
|
"first_name": "የመጀመሪያ ስም",
|
||||||
"analyzing_speaking": "We're now analyzing your speaking skill",
|
"last_name": "የአባት ስም",
|
||||||
"view_profile": "View profile",
|
"gender": "ፆታ",
|
||||||
"hi": "Hi",
|
"male": "ወንድ",
|
||||||
"edit_profile": "Edit profile",
|
"female": "ሴት",
|
||||||
"first_name": "First name",
|
"phone_number": "የስልክ ቁጥር",
|
||||||
"last_name": "Last name",
|
"country": "ሀገር",
|
||||||
"gender": "Gender",
|
"region": "ክልል",
|
||||||
"male": "Male",
|
"select_region": "ክልል ይምረጡ",
|
||||||
"female": "Female",
|
"enter_your_city": "ከተማዎን ያስገቡ",
|
||||||
"phone_number": "Phone number",
|
"occupation": "የስራ መስክ",
|
||||||
"country": "Country",
|
"select_occupation": "ሙያዎን ይምረጡ",
|
||||||
"region": "Region",
|
"save_changes": "ለውጦችን ያስቀምጡ",
|
||||||
"select_region": "Select region",
|
"my_progress": "የእኔ እድገት",
|
||||||
"enter_your_city": "Enter your city",
|
"track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ",
|
||||||
"occupation": "Occupation",
|
"account_and_privacy": "መለያ እና ግላዊነት",
|
||||||
"select_occupation": "Select occupation",
|
"manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ",
|
||||||
"save_changes": "Save changes",
|
"support": "ድጋፍ",
|
||||||
"my_progress": "My progress",
|
"get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ",
|
||||||
"track_your_achievement": "Track your achievements and learning streak",
|
"logout": "ውጣ",
|
||||||
"account_and_privacy": "Account & Privacy",
|
"app_settings": "የመተግበሪያ ቅንብሮች",
|
||||||
"manage_settings": "Manage settings and app preference",
|
"legal_and_information": "ሕጋዊ እና መረጃ",
|
||||||
"support": "Support",
|
"change_language": "ቋንቋ ቀይር",
|
||||||
"get_help": "Get help through phone or Telegram",
|
"terms_and_conditions": "ውሎች እና ሁኔታዎች",
|
||||||
"logout": "Logout",
|
"delete_account": "መለያ ሰርዝ",
|
||||||
"app_settings": "App settings",
|
"language_preference": "የቋንቋ ምርጫ",
|
||||||
"legal_and_information": "Legal & Information",
|
"choose_your_language": "ለውጦችን አስቀምጥ",
|
||||||
"change_language": "Change language",
|
"switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ",
|
||||||
"terms_and_conditions": "Terms & Conditions",
|
"need_help": "እገዛ ይፈልጋሉ?",
|
||||||
"delete_account": "Delete account",
|
"call_support": "የስልክ ድጋፍ",
|
||||||
"language_preference": "Language preference",
|
"talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ",
|
||||||
"choose_your_language": "Choose your language",
|
"telegram_support": "የቴሌግራም ድጋፍ",
|
||||||
"switch_language_anytime": "You can switch languages anytime",
|
"chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ",
|
||||||
"need_help": "Need help?",
|
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
|
||||||
"call_support": "Call support",
|
"tap_to_call": "ለመደወል ይንኩ",
|
||||||
"talk_with_support": "Talk with our support team directly",
|
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
|
||||||
"telegram_support": "Telegram support",
|
"connect_with_support_team": "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
|
||||||
"chat_via_telegram": "Chat instantly via Telegram",
|
"open_in_telegram": "በቴሌግራም ይክፈቱ",
|
||||||
"call_our_support": "Call our support team between 9 AM - 6 PM",
|
"search_for": "ፈልጉት",
|
||||||
"tap_to_call": "Tap to call",
|
"current_level": "የአሁኑ ደረጃ",
|
||||||
"join_telegram": "Join Yimaru Academy on Telegram",
|
"keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።",
|
||||||
"connect_with_support_team":
|
"no_practice_available": "ምንም ልምምድ አልተገኘም!",
|
||||||
"Connect with our support team instantly on Telegram for quick assistance and community updates",
|
"begin_module_practice": "የሞጁሉን ልምምድ ጀምር",
|
||||||
"open_in_telegram": "Open in Telegram",
|
"lets_practice_lesson": "እንለማመድ",
|
||||||
"search_for": "Search for",
|
"lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
"current_level": "Current Level",
|
"lets_practice_module": "አሁን የተማርከውን እንለማመድ!",
|
||||||
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
|
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
||||||
"no_practice_available": "No practice available!",
|
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
||||||
"begin_module_practice": "Begin Module Practice",
|
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
||||||
"lets_practice_lesson": "Let’s Practice",
|
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
"lets_quickly_review":
|
"speaking": "እየተናገረ ነው",
|
||||||
"Let’s quickly review what you’ve learned in this module!",
|
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
||||||
"lets_practice_module": "Let's practice what you just learnt!",
|
"view_results": "ውጤቶቼን እይ",
|
||||||
"ask_you_few_actions":
|
"sample_answer": "ናሙና መልስ",
|
||||||
"I’ll ask you a few questions, and you can respond naturally.",
|
"your_answer": "መልስህ",
|
||||||
"begin_level_practice": "Begin Level Practice",
|
"sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!",
|
||||||
"lets_practice_course": "Let’s Practice Course",
|
"you_have_completed": "አያይ! አጠናቀቅህ",
|
||||||
"lets_quick_review":
|
"yes": "አዎ",
|
||||||
"Let’s quickly review what you’ve learned in this level!",
|
"no": "አይ",
|
||||||
"speaking": "is speaking...",
|
"want_to_quit": "ለመውጣት እርግጠኛ ነህ?",
|
||||||
"you_have_finished_practice": "You have finished your practice",
|
"required_field": "ይህ መስክ ያስፈልጋል",
|
||||||
"view_results": "View My Results",
|
"enter_full_name": "ሙሉ ስምህን አስገባ",
|
||||||
"sample_answer": "Sample Answer",
|
"invalid_email": "የማይሰራ የኢሜይል ቅርጸት",
|
||||||
"your_answer": "Your Answer",
|
"phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት",
|
||||||
"sound_confident":
|
"phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት",
|
||||||
"You sound more confident this time - great improvement!",
|
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
||||||
"you_have_completed": "Yay, you’ve completed",
|
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
||||||
"yes": "Yes",
|
"choose_your_gender": "ጾታህን ምረጥ",
|
||||||
"no": "No",
|
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
"want_to_quit": "Are you sure you want to quit?",
|
"age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?",
|
||||||
"required_field": "The field is required",
|
"age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
"enter_full_name": "Enter your full name",
|
"educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?",
|
||||||
"invalid_email": "Invalid email format",
|
"education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።",
|
||||||
"phone_must_start_with": "Phone number must start with 251",
|
"your_occupation": "ስራህ ምንድን ነው?",
|
||||||
"phone_must_be": "Phone number must be 12 digits",
|
"occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
"what_should_we_call_you": "What should we call you?",
|
"location": "ከየት ነህ?",
|
||||||
"name_for_personalization":
|
"select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ",
|
||||||
"We’ll use your name to personalize your learning journey.",
|
"select_country": "አገር ምረጥ",
|
||||||
"choose_your_gender": "Choose your gender?",
|
"learning_goal": "የመማር ዓላማህን ምረጥ",
|
||||||
"gender_for_personalization":
|
"language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?",
|
||||||
"We’ll personalize your learning experience based on your gender.",
|
"your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።",
|
||||||
"age_range": "Which age range are you in?",
|
"write_your_goal": "ዓላማህን ጻፍ…",
|
||||||
"age_for_personalization":
|
"challenge_you_face": "What challenge do you face most with English?",
|
||||||
"We’ll personalize your learning experience based on your age.",
|
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
|
||||||
"educational_background": "What’s your current educational level?",
|
"write_your_challenge": "ችግርህን ጻፍ…",
|
||||||
"education_for_personalization":
|
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
|
||||||
"This helps us tailor your lessons to your experience.",
|
"favourite_topic": "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
|
||||||
"your_occupation": "What’s your occupation?",
|
"your_interest": "ፍላጎትህን ጻፍ…",
|
||||||
"occupation_for_personalization":
|
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
|
||||||
"We’ll personalize your learning experience based on your occupation.",
|
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
|
||||||
"location": "Where are you from?",
|
"skip": "ዝለል",
|
||||||
"select_country_region": "Select your country and region from the dropdown",
|
"finish_level": "ደረጃውን አጠናቅቅ",
|
||||||
"select_country": "Select country",
|
"likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ",
|
||||||
"learning_goal": "Choose your learning goal.",
|
"great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።",
|
||||||
"language_goal": "What’s your main goal for improving your English?",
|
"lets_start_practice": "ልምምድህን እንጀምር",
|
||||||
"your_goal": "Your goal helps us tailor your learning journey.",
|
"welcome_abroad": "እንኳን ደህና መጣህ",
|
||||||
"write_your_goal": "Write your goal…",
|
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
||||||
"challenge_you_face": "What challenge do you face most with English?",
|
"finish": "አጠናቅቅ",
|
||||||
"evey_one_has_strugle": "Everyone has struggles, let’s start fixing yours",
|
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
|
||||||
"write_your_challenge": "Write your challenge…",
|
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
|
||||||
"topic_interest": "Which topics interest you most?",
|
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
|
||||||
"favourite_topic":
|
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
|
||||||
"Your favorite topics help us create fun, relatable lessons.",
|
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
|
||||||
"your_interest": "Write your interest…",
|
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
|
||||||
"want_quick_assessment":
|
"learn_english": "እንግሊዝኛ ይማሩ",
|
||||||
"Want a quick assessment to know your English level?",
|
"keep_momentum": "በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
||||||
"answer_quick_questions":
|
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
||||||
"Answer a few quick questions to help us understand your English proficiency.",
|
"total_practices": "ጠቅላላ ልምምዶች",
|
||||||
"skip": "Skip",
|
"progress_percentage": "የእድገት መቶኛ"
|
||||||
"finish_level": "Finish Level",
|
};
|
||||||
"likely_speaker": "You’re likely speaker of",
|
static const Map<String, Map<String,dynamic>> mapLocales = {"en": _en, "am": _am};
|
||||||
"great_job": "Great Job! Here’s your next step to keep improving.",
|
|
||||||
"lets_start_practice": "Let's start your practice",
|
|
||||||
"welcome_abroad": "Welcome aboard",
|
|
||||||
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
|
||||||
"finish": "Finish",
|
|
||||||
"finish_all_practice_lesson":
|
|
||||||
"Finish the previous lesson practice to take this practice",
|
|
||||||
"finish_all_practice_module":
|
|
||||||
"Finish the lesson practices to take the Module Practice",
|
|
||||||
"finish_all_practice_course":
|
|
||||||
"Finish the Module practices to take the Course practice",
|
|
||||||
"finish_all_practice_previouse_module":
|
|
||||||
"Finish the previous Module practice to take this practice",
|
|
||||||
"finish_all_practice_previouse_course":
|
|
||||||
"Finish the previous course practice to take this",
|
|
||||||
"track_journey":
|
|
||||||
"Track your learning journey and see your growth over time.",
|
|
||||||
"learn_english": "Learn English",
|
|
||||||
"keep_momentum": "Great job! Keep the momentum.",
|
|
||||||
"completed_practices": "Completed Practices",
|
|
||||||
"total_practices": "Total Practices",
|
|
||||||
"progress_percentage": "Progress Percentage",
|
|
||||||
"notifications": "Notifications"
|
|
||||||
};
|
|
||||||
static const Map<String, Map<String, dynamic>> mapLocales = {
|
|
||||||
"am": _am,
|
|
||||||
"en": _en
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
// ignore_for_file: constant_identifier_names
|
// ignore_for_file: constant_identifier_names
|
||||||
|
|
||||||
abstract class LocaleKeys {
|
abstract class LocaleKeys {
|
||||||
static const loading = 'loading';
|
static const loading = 'loading';
|
||||||
static const welcome_back = 'welcome_back';
|
static const welcome_back = 'welcome_back';
|
||||||
static const checking_user_info = 'checking_user_info';
|
static const checking_user_info = 'checking_user_info';
|
||||||
|
|
@ -13,12 +13,14 @@ abstract class LocaleKeys {
|
||||||
static const cont = 'cont';
|
static const cont = 'cont';
|
||||||
static const register = 'register';
|
static const register = 'register';
|
||||||
static const login_with_google = 'login_with_google';
|
static const login_with_google = 'login_with_google';
|
||||||
|
static const login_with_apple = 'login_with_apple';
|
||||||
static const or = 'or';
|
static const or = 'or';
|
||||||
static const login_with_phone = 'login_with_phone';
|
static const login_with_phone = 'login_with_phone';
|
||||||
static const create_account = 'create_account';
|
static const create_account = 'create_account';
|
||||||
static const already_have_account = 'already_have_account';
|
static const already_have_account = 'already_have_account';
|
||||||
static const login = 'login';
|
static const login = 'login';
|
||||||
static const register_with_google = 'register_with_google';
|
static const register_with_google = 'register_with_google';
|
||||||
|
static const register_with_apple = 'register_with_apple';
|
||||||
static const register_with_phone = 'register_with_phone';
|
static const register_with_phone = 'register_with_phone';
|
||||||
static const enter_phone_number = 'enter_phone_number';
|
static const enter_phone_number = 'enter_phone_number';
|
||||||
static const login_with_email = 'login_with_email';
|
static const login_with_email = 'login_with_email';
|
||||||
|
|
@ -43,10 +45,10 @@ abstract class LocaleKeys {
|
||||||
static const reset_code = 'reset_code';
|
static const reset_code = 'reset_code';
|
||||||
static const new_password = 'new_password';
|
static const new_password = 'new_password';
|
||||||
static const logged_in_successfully = 'logged_in_successfully';
|
static const logged_in_successfully = 'logged_in_successfully';
|
||||||
static const view_course = 'view_course';
|
|
||||||
static const continue_learning = 'continue_learning';
|
static const continue_learning = 'continue_learning';
|
||||||
static const start_learning = 'start_learning';
|
static const start_learning = 'start_learning';
|
||||||
static const completed = 'completed';
|
static const completed = 'completed';
|
||||||
|
static const view_course = 'view_course';
|
||||||
static const take_practice = 'take_practice';
|
static const take_practice = 'take_practice';
|
||||||
static const your_current_level = 'your_current_level';
|
static const your_current_level = 'your_current_level';
|
||||||
static const overall_progress = 'overall_progress';
|
static const overall_progress = 'overall_progress';
|
||||||
|
|
@ -161,8 +163,7 @@ abstract class LocaleKeys {
|
||||||
static const educational_background = 'educational_background';
|
static const educational_background = 'educational_background';
|
||||||
static const education_for_personalization = 'education_for_personalization';
|
static const education_for_personalization = 'education_for_personalization';
|
||||||
static const your_occupation = 'your_occupation';
|
static const your_occupation = 'your_occupation';
|
||||||
static const occupation_for_personalization =
|
static const occupation_for_personalization = 'occupation_for_personalization';
|
||||||
'occupation_for_personalization';
|
|
||||||
static const location = 'location';
|
static const location = 'location';
|
||||||
static const select_country_region = 'select_country_region';
|
static const select_country_region = 'select_country_region';
|
||||||
static const select_country = 'select_country';
|
static const select_country = 'select_country';
|
||||||
|
|
@ -189,15 +190,13 @@ abstract class LocaleKeys {
|
||||||
static const finish_all_practice_lesson = 'finish_all_practice_lesson';
|
static const finish_all_practice_lesson = 'finish_all_practice_lesson';
|
||||||
static const finish_all_practice_module = 'finish_all_practice_module';
|
static const finish_all_practice_module = 'finish_all_practice_module';
|
||||||
static const finish_all_practice_course = 'finish_all_practice_course';
|
static const finish_all_practice_course = 'finish_all_practice_course';
|
||||||
static const finish_all_practice_previouse_module =
|
static const finish_all_practice_previouse_module = 'finish_all_practice_previouse_module';
|
||||||
'finish_all_practice_previouse_module';
|
static const finish_all_practice_previouse_course = 'finish_all_practice_previouse_course';
|
||||||
static const finish_all_practice_previouse_course =
|
|
||||||
'finish_all_practice_previouse_course';
|
|
||||||
static const track_journey = 'track_journey';
|
static const track_journey = 'track_journey';
|
||||||
static const learn_english = 'learn_english';
|
static const learn_english = 'learn_english';
|
||||||
static const keep_momentum = 'keep_momentum';
|
static const keep_momentum = 'keep_momentum';
|
||||||
static const completed_practices = 'completed_practices';
|
static const completed_practices = 'completed_practices';
|
||||||
static const total_practices = 'total_practices';
|
static const total_practices = 'total_practices';
|
||||||
static const progress_percentage = 'progress_percentage';
|
static const progress_percentage = 'progress_percentage';
|
||||||
static const notifications = 'notifications';
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -333,12 +333,6 @@ TextStyle style14LG400 = const TextStyle(
|
||||||
color: kcLightGrey,
|
color: kcLightGrey,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style12W600 = const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: kcWhite,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style14MG400 = const TextStyle(
|
TextStyle style14MG400 = const TextStyle(
|
||||||
color: kcMediumGrey,
|
color: kcMediumGrey,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,6 @@ class CourseView extends StackedView<CourseViewModel> {
|
||||||
Widget _buildAppBar(CourseViewModel viewModel) => ProfileAppBar(
|
Widget _buildAppBar(CourseViewModel viewModel) => ProfileAppBar(
|
||||||
name: viewModel.user?.firstName,
|
name: viewModel.user?.firstName,
|
||||||
profileImage: viewModel.user?.profilePicture,
|
profileImage: viewModel.user?.profilePicture,
|
||||||
unreadCount: viewModel.unreadCount.toString(),
|
|
||||||
onTap: () async => await viewModel.navigateToNotification(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildCategoryColumnWrapper(CourseViewModel viewModel) =>
|
Widget _buildCategoryColumnWrapper(CourseViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import '../../../app/app.locator.dart';
|
||||||
import '../../../app/app.router.dart';
|
import '../../../app/app.router.dart';
|
||||||
import '../../../models/user.dart';
|
import '../../../models/user.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
|
|
||||||
class CourseViewModel extends ReactiveViewModel {
|
class CourseViewModel extends ReactiveViewModel {
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
|
|
@ -14,23 +13,15 @@ class CourseViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final _inAppNotificationService = locator<InAppNotificationService>();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_authenticationService,_inAppNotificationService];
|
[_authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
User? get _user => _authenticationService.user;
|
User? get _user => _authenticationService.user;
|
||||||
|
|
||||||
User? get user => _user;
|
User? get user => _user;
|
||||||
|
|
||||||
// Notification count
|
|
||||||
int get _unreadCount => _inAppNotificationService.unreadCount;
|
|
||||||
|
|
||||||
int get unreadCount => _unreadCount;
|
|
||||||
|
|
||||||
// Course
|
// Course
|
||||||
final List<Map<String, dynamic>> _courses = [
|
final List<Map<String, dynamic>> _courses = [
|
||||||
{
|
{
|
||||||
|
|
@ -50,11 +41,6 @@ class CourseViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToNotification() async =>
|
|
||||||
await _navigationService.navigateToNotificationView();
|
|
||||||
|
|
||||||
Future<void> navigateToCourseCatalog() async =>
|
Future<void> navigateToCourseCatalog() async =>
|
||||||
await _navigationService.navigateToCourseCatalogView();
|
await _navigationService.navigateToCourseCatalogView();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_carousel_widget/flutter_carousel_widget.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/views/failure/screens/first_failure_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/failure/screens/second_failure_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/failure/screens/third_failure_screen.dart';
|
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
import '../../common/app_colors.dart';
|
||||||
import '../../common/ui_helpers.dart';
|
import '../../common/ui_helpers.dart';
|
||||||
|
|
@ -30,38 +26,94 @@ class FailureView extends StackedView<FailureViewModel> {
|
||||||
_buildScaffoldWrapper();
|
_buildScaffoldWrapper();
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper() => Scaffold(
|
Widget _buildScaffoldWrapper() => Scaffold(
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildStartupScreens(),
|
body: _buildScaffold(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildStartupScreens() => FlutterCarousel(
|
Widget _buildScaffold() => Stack(
|
||||||
options: FlutterCarouselOptions(
|
children: _buildScaffoldChildren(),
|
||||||
autoPlay: true,
|
|
||||||
viewportFraction: 1,
|
|
||||||
showIndicator: false,
|
|
||||||
height: double.maxFinite,
|
|
||||||
),
|
|
||||||
items: _buildScreens(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScaffoldChildren() => [
|
||||||
_buildFirstFailure(),
|
_buildBackground(),
|
||||||
_buildSecondFailure(),
|
_buildColumn(),
|
||||||
_buildThirdFailure(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildFirstFailure() => FirstFailureScreen(
|
Widget _buildBackground() => Image.asset(
|
||||||
label: label,
|
'assets/images/loading.png',
|
||||||
onTap: onTap,
|
fit: BoxFit.fill,
|
||||||
|
width: double.maxFinite,
|
||||||
|
height: double.maxFinite,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSecondFailure() => SecondFailureScreen(
|
Widget _buildColumn() => Column(
|
||||||
label: label,
|
mainAxisSize: MainAxisSize.max,
|
||||||
onTap: onTap,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildThirdFailure() => ThirdFailureScreen(
|
List<Widget> _buildColumnChildren() =>
|
||||||
label: label,
|
[_buildIconWrapper(), _buildSafeWrapper()];
|
||||||
|
|
||||||
|
Widget _buildIconWrapper() => Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 100),
|
||||||
|
child: _buildIcon(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildIcon() => SvgPicture.asset('assets/icons/logo.svg', height: 50);
|
||||||
|
|
||||||
|
Widget _buildSafeWrapper() => SafeArea(child: _buildBottomSectionWrapper());
|
||||||
|
|
||||||
|
Widget _buildBottomSectionWrapper() => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
|
child: _buildBottomSectionColumn(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildBottomSectionColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: _buildBottomSectionChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildBottomSectionChildren() => [
|
||||||
|
_buildLoadingTextWrapper(),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
_buildRetryButtonWrapper()
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildLoadingTextWrapper() => Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: _buildLoadingTextChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildLoadingTextChildren() => [
|
||||||
|
_buildLoadingText(),
|
||||||
|
horizontalSpaceSmall,
|
||||||
|
_buildIndicatorWrapper(),
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildLoadingText() =>
|
||||||
|
Text('$label ...', style: const TextStyle(color: kcWhite, fontSize: 16));
|
||||||
|
|
||||||
|
Widget _buildIndicatorWrapper() => SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: _buildIndicator(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildIndicator() =>
|
||||||
|
const CustomCircularProgressIndicator(color: kcWhite);
|
||||||
|
|
||||||
|
Widget _buildRetryButtonWrapper() => GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
child: _buildRetryButton(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildRetryButton() => Text(
|
||||||
|
'Retry',
|
||||||
|
style: style16W600.copyWith(
|
||||||
|
fontStyle: FontStyle.italic, decoration: TextDecoration.underline),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,165 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/failure/failure_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/startup/startup_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
|
|
||||||
class FirstFailureScreen extends ViewModelWidget<FailureViewModel> {
|
|
||||||
final String label;
|
|
||||||
final GestureTapCallback onTap;
|
|
||||||
|
|
||||||
const FirstFailureScreen({super.key,required this.onTap,required this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, FailureViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( ) => Scaffold(
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
Widget _buildScaffoldPadding( ) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( ) =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_white.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper( ) => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren( ) => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25W600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25W400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' ሰዓት ',
|
|
||||||
style: style25W600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25W400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_1.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper( ) =>
|
|
||||||
SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper( ) => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildRetryButtonWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
|
||||||
Text('$label...', style: style16W600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcWhite);
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildRetryButtonWrapper() => GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: _buildRetryButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildRetryButton() => Text(
|
|
||||||
'Retry',
|
|
||||||
style: style16W600.copyWith(
|
|
||||||
fontStyle: FontStyle.italic, decoration: TextDecoration.underline),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/failure/failure_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
|
|
||||||
class SecondFailureScreen extends ViewModelWidget<FailureViewModel> {
|
|
||||||
final String label;
|
|
||||||
final GestureTapCallback onTap;
|
|
||||||
|
|
||||||
const SecondFailureScreen(
|
|
||||||
{super.key, required this.onTap, required this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, FailureViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper() => Scaffold(
|
|
||||||
backgroundColor: Colors.amber,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffoldPadding() => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren() =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_purple.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper() => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren() => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25P600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' እድሜ ',
|
|
||||||
style: style25P600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_2.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper() => SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper() => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildRetryButtonWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() => Text('$label...', style: style16P600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcPrimaryColor);
|
|
||||||
|
|
||||||
Widget _buildRetryButtonWrapper() => GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: _buildRetryButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildRetryButton() => Text(
|
|
||||||
'Retry',
|
|
||||||
style: style16P600.copyWith(
|
|
||||||
fontStyle: FontStyle.italic, decoration: TextDecoration.underline),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,165 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/failure/failure_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
|
|
||||||
class ThirdFailureScreen extends ViewModelWidget<FailureViewModel> {
|
|
||||||
final String label;
|
|
||||||
final GestureTapCallback onTap;
|
|
||||||
|
|
||||||
const ThirdFailureScreen(
|
|
||||||
{super.key, required this.onTap, required this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, FailureViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( ) => Scaffold(
|
|
||||||
backgroundColor:kcWhite,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
Widget _buildScaffoldPadding( ) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( ) =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_purple.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper( ) => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren( ) => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25P600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' ቦታ ',
|
|
||||||
style: style25P600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_3.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper( ) =>
|
|
||||||
SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper( ) => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
horizontalSpaceSmall,_buildRetryButtonWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
|
||||||
Text('$label...', style: style16P600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcPrimaryColor);
|
|
||||||
|
|
||||||
Widget _buildRetryButtonWrapper() => GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: _buildRetryButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildRetryButton() => Text(
|
|
||||||
'Retry',
|
|
||||||
style: style16P600.copyWith(
|
|
||||||
fontStyle: FontStyle.italic, decoration: TextDecoration.underline),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -4,8 +4,6 @@ import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/views/course/course_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart';
|
import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
|
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
|
||||||
|
|
@ -19,8 +17,6 @@ class HomeView extends StackedView<HomeViewModel> {
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(HomeViewModel viewModel) async {
|
void onViewModelReady(HomeViewModel viewModel) async {
|
||||||
await viewModel.inAppUpdate();
|
await viewModel.inAppUpdate();
|
||||||
await viewModel.getUnreadNotifications();
|
|
||||||
|
|
||||||
super.onViewModelReady(viewModel);
|
super.onViewModelReady(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +80,7 @@ class HomeView extends StackedView<HomeViewModel> {
|
||||||
case 0:
|
case 0:
|
||||||
return const LearnProgramView();
|
return const LearnProgramView();
|
||||||
case 1:
|
case 1:
|
||||||
return const CourseView();
|
return const ComingSoon();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return const ProfileView();
|
return const ProfileView();
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
|
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
import '../../../services/in_app_update_service.dart';
|
import '../../../services/in_app_update_service.dart';
|
||||||
|
|
||||||
class HomeViewModel extends ReactiveViewModel {
|
class HomeViewModel extends ReactiveViewModel {
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
final _statusChecker = locator<StatusCheckerService>();
|
final _statusChecker = locator<StatusCheckerService>();
|
||||||
|
|
||||||
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
final _bottomSheetService = locator<BottomSheetService>();
|
final _bottomSheetService = locator<BottomSheetService>();
|
||||||
|
|
||||||
|
|
@ -22,11 +22,9 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final _inAppNotificationService = locator<InAppNotificationService>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_authenticationService,_inAppNotificationService];
|
[_authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
User? get _user => _authenticationService.user;
|
User? get _user => _authenticationService.user;
|
||||||
|
|
@ -57,6 +55,8 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
// In-app update
|
// In-app update
|
||||||
|
|
@ -65,12 +65,4 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
await _inAppUpdateService.checkForUpdate();
|
await _inAppUpdateService.checkForUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Unread notifications
|
|
||||||
Future<void> getUnreadNotifications() async {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
|
||||||
await _inAppNotificationService.getUnreadNotifications();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_carousel_widget/flutter_carousel_widget.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/screens/first_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/first_landing_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/landing/screens/fourth_landing_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/screens/second_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/second_landing_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/screens/third_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/third_landing_screen.dart';
|
||||||
|
|
||||||
|
|
@ -43,15 +44,17 @@ class LandingView extends StackedView<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScreens() => [
|
||||||
_buildFirstLanding(),
|
_buildFirstWelcome(),
|
||||||
_buildSecondLanding(),
|
_buildSecondWelcome(),
|
||||||
_buildThirdLanding(),
|
_buildThirdWelcome(),
|
||||||
|
_buildFourthWelcome()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildFirstLanding() => const FirstLandingScreen();
|
Widget _buildFirstWelcome() => const FirstLandingScreen();
|
||||||
|
|
||||||
Widget _buildSecondLanding() => const SecondLandingScreen();
|
Widget _buildSecondWelcome() => const SecondLandingScreen();
|
||||||
|
|
||||||
Widget _buildThirdLanding() => const ThirdLandingScreen();
|
Widget _buildThirdWelcome() => const ThirdLandingScreen();
|
||||||
|
|
||||||
|
Widget _buildFourthWelcome() => const FourthLandingScreen();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class FirstLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
'assets/icons/logo_white.svg',
|
'assets/icons/logo.svg',
|
||||||
height: 25,
|
height: 25,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -100,7 +100,7 @@ class FirstLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
Widget _buildImage() => Image.asset(
|
||||||
'assets/images/landing_1.png',
|
'assets/images/landing_1.jpg',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -126,10 +126,10 @@ class FirstLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
lib/ui/views/landing/screens/fourth_landing_screen.dart
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
|
|
||||||
|
import '../../../widgets/custom_circular_progress_indicator.dart';
|
||||||
|
import '../landing_viewmodel.dart';
|
||||||
|
|
||||||
|
class FourthLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
|
const FourthLandingScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, LandingViewModel viewModel) =>
|
||||||
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
|
Widget _buildScaffoldWrapper(LandingViewModel viewModel) => Scaffold(
|
||||||
|
backgroundColor: Colors.amber,
|
||||||
|
body: _buildScaffoldPadding(viewModel),
|
||||||
|
);
|
||||||
|
Widget _buildScaffoldPadding(LandingViewModel viewModel) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
child: _buildScaffold(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildScaffold(LandingViewModel viewModel) => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: _buildScaffoldChildren(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildScaffoldChildren(LandingViewModel viewModel) =>
|
||||||
|
[_buildUpperColumn(), _buildLowerColumnWrapper(viewModel)];
|
||||||
|
|
||||||
|
Widget _buildUpperColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: _buildUpperColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildUpperColumnChildren() =>
|
||||||
|
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
||||||
|
|
||||||
|
Widget _buildIconWrapper() => Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: _buildIcon(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
|
'assets/icons/logo.svg',
|
||||||
|
color: kcPrimaryColor,
|
||||||
|
height: 25,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildLowerColumnWrapper(LandingViewModel viewModel) => Expanded(
|
||||||
|
child: _buildLowerColumn(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildLowerColumn(LandingViewModel viewModel) => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: _buildLowerColumnChildren(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildLowerColumnChildren(LandingViewModel viewModel) => [
|
||||||
|
_buildTitle(),
|
||||||
|
verticalSpaceMedium,
|
||||||
|
_buildImageWrapper(),
|
||||||
|
verticalSpaceMedium,
|
||||||
|
_buildSafeWrapper(viewModel)
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildTitle() => Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: 'እንግሊዝኛ\n',
|
||||||
|
style: style25P600,
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: 'በማንኛውም',
|
||||||
|
style: style25P400,
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: ' እድሜ ',
|
||||||
|
style: style25P600,
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: 'ይማሩ!',
|
||||||
|
style: style25P400,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
||||||
|
|
||||||
|
Widget _buildImageClipper() => ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
child: _buildImage(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildImage() => Image.asset(
|
||||||
|
'assets/images/landing_2.jpg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildSafeWrapper(LandingViewModel viewModel) =>
|
||||||
|
SafeArea(child: _buildContinueButtonWrapper(viewModel));
|
||||||
|
|
||||||
|
Widget _buildContinueButtonWrapper(LandingViewModel viewModel) => Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: _buildButtonContainer(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildButtonContainer(LandingViewModel viewModel) => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
|
child: _buildContinueButtonState(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildContinueButtonState(LandingViewModel viewModel) =>
|
||||||
|
viewModel.isBusy ? _buildIndicator() : _buildContinueButton(viewModel);
|
||||||
|
|
||||||
|
Widget _buildIndicator() =>
|
||||||
|
const CustomCircularProgressIndicator(color: kcWhite);
|
||||||
|
|
||||||
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 25,
|
||||||
|
text: 'Get Started',
|
||||||
|
foregroundColor: kcWhite,
|
||||||
|
backgroundColor: kcPrimaryColor,
|
||||||
|
onTap: () async => await viewModel.setFirstTimeInstall(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ class SecondLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
'assets/icons/logo_purple.svg',
|
'assets/icons/logo.svg',
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
height: 25,
|
height: 25,
|
||||||
);
|
);
|
||||||
|
|
@ -101,7 +101,7 @@ class SecondLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
Widget _buildImage() => Image.asset(
|
||||||
'assets/images/landing_2.png',
|
'assets/images/landing_2.jpg',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -127,10 +127,10 @@ class SecondLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class ThirdLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
'assets/icons/logo_purple.svg',
|
'assets/icons/logo.svg',
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
height: 25,
|
height: 25,
|
||||||
);
|
);
|
||||||
|
|
@ -101,7 +101,7 @@ class ThirdLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
Widget _buildImage() => Image.asset(
|
||||||
'assets/images/landing_3.png',
|
'assets/images/landing_3.jpg',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -127,10 +127,10 @@ class ThirdLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,14 @@ class LanguageViewModel extends ReactiveViewModel {
|
||||||
_localizationService.isSelectedLanguage(title);
|
_localizationService.isSelectedLanguage(title);
|
||||||
|
|
||||||
Future<void> setSelectedLanguage(
|
Future<void> setSelectedLanguage(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
required Map<String, dynamic> title}) async {
|
required Map<String, dynamic> title}) async {
|
||||||
await _localizationService.setSelectedLanguage(
|
await _localizationService.setSelectedLanguage(
|
||||||
context: context, title: title);
|
context: context, title: title);
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,14 @@ import 'learn_course_viewmodel.dart';
|
||||||
|
|
||||||
class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
final int id;
|
final int id;
|
||||||
final bool first;
|
|
||||||
|
|
||||||
const LearnCourseView({Key? key, required this.id, required this.first})
|
const LearnCourseView({Key? key, required this.id}) : super(key: key);
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
Future<void> _onPractice(
|
Future<void> _onPractice(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
required LearnCourse course,
|
required LearnCourse course,
|
||||||
required LearnCourseViewModel viewModel}) async {
|
required LearnCourseViewModel viewModel}) async {
|
||||||
if (course.access?.isCompleted ?? false) {
|
if (course.access?.completedCount == course.access?.totalCount) {
|
||||||
await viewModel.navigateToLearnPractice(
|
await viewModel.navigateToLearnPractice(
|
||||||
id: course.id ?? 0, level: course.name ?? '');
|
id: course.id ?? 0, level: course.name ?? '');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -152,8 +150,8 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
context: context,
|
context: context,
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
course: viewModel.courses[index]),
|
course: viewModel.courses[index]),
|
||||||
onViewTap: () async => await viewModel.navigateToLearnModule(
|
onViewTap: () async =>
|
||||||
first: first && index == 0, course: viewModel.courses[index]),
|
await viewModel.navigateToLearnModule(viewModel.courses[index]),
|
||||||
),
|
),
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,8 @@ class LearnCourseViewModel extends ReactiveViewModel {
|
||||||
Future<void> navigateToLearnSubscription() async =>
|
Future<void> navigateToLearnSubscription() async =>
|
||||||
await _navigationService.navigateToLearnSubscriptionView();
|
await _navigationService.navigateToLearnSubscriptionView();
|
||||||
|
|
||||||
Future<void> navigateToLearnModule(
|
Future<void> navigateToLearnModule(LearnCourse course) async =>
|
||||||
{required bool first, required LearnCourse course}) async =>
|
_navigationService.navigateToLearnModuleView(course: course);
|
||||||
_navigationService.navigateToLearnModuleView(
|
|
||||||
first: first, course: course);
|
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice(
|
Future<void> navigateToLearnPractice(
|
||||||
{required int id, required String level}) async =>
|
{required int id, required String level}) async =>
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,32 @@ import '../../widgets/small_app_bar.dart';
|
||||||
import 'learn_lesson_viewmodel.dart';
|
import 'learn_lesson_viewmodel.dart';
|
||||||
|
|
||||||
class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
final bool first;
|
|
||||||
final LearnModule module;
|
final LearnModule module;
|
||||||
|
|
||||||
const LearnLessonView({Key? key, required this.first, required this.module})
|
const LearnLessonView({Key? key, required this.module}) : super(key: key);
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
Future<void> _onPractice(
|
Future<void> _onPractice(
|
||||||
{required int index,
|
{required int index,
|
||||||
required LearnLesson lesson,
|
required LearnLesson lesson,
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required LearnLessonViewModel viewModel}) async {
|
required LearnLessonViewModel viewModel}) async {
|
||||||
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
|
/* if (lesson.access?.isAccessible ?? false) {
|
||||||
if (lesson.access?.isAccessible ?? false) {
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
} else {
|
||||||
|
await _showSheet(context: context, viewModel: viewModel);
|
||||||
|
}*/
|
||||||
|
if (index > 1) {
|
||||||
|
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
|
||||||
|
if (lesson.access?.isAccessible ?? false) {
|
||||||
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
|
} else {
|
||||||
|
await _showSheet(context: context, viewModel: viewModel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await _showSheet(context: context, viewModel: viewModel);
|
await viewModel.navigateToLearnSubscription();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (first && index < 3) {
|
if (lesson.access?.isAccessible ?? false) {
|
||||||
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
} else {
|
} else {
|
||||||
await _showSheet(context: context, viewModel: viewModel);
|
await _showSheet(context: context, viewModel: viewModel);
|
||||||
|
|
@ -217,7 +224,6 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildTile(
|
itemBuilder: (context, index) => _buildTile(
|
||||||
index: index,
|
index: index,
|
||||||
first: first && index < 3,
|
|
||||||
lesson: viewModel.lessons[index],
|
lesson: viewModel.lessons[index],
|
||||||
last: index == viewModel.lessons.length - 1,
|
last: index == viewModel.lessons.length - 1,
|
||||||
onPracticeTap: () async => await _onPractice(
|
onPracticeTap: () async => await _onPractice(
|
||||||
|
|
@ -238,14 +244,12 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
Widget _buildTile({
|
Widget _buildTile({
|
||||||
required bool last,
|
required bool last,
|
||||||
required int index,
|
required int index,
|
||||||
required bool first,
|
|
||||||
required LearnLesson lesson,
|
required LearnLesson lesson,
|
||||||
required GestureTapCallback? onLessonTap,
|
required GestureTapCallback? onLessonTap,
|
||||||
required GestureTapCallback? onPracticeTap,
|
required GestureTapCallback? onPracticeTap,
|
||||||
}) =>
|
}) =>
|
||||||
LearnLessonTile(
|
LearnLessonTile(
|
||||||
last: last,
|
last: last,
|
||||||
first: first,
|
|
||||||
index: index,
|
index: index,
|
||||||
lesson: lesson,
|
lesson: lesson,
|
||||||
onLessonTap: onLessonTap,
|
onLessonTap: onLessonTap,
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,21 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
Future<void> _onPractice(
|
Future<void> _onPractice(
|
||||||
{required LearnLesson lesson,
|
{required LearnLesson lesson,
|
||||||
required LearnLessonDetailViewModel viewModel}) async {
|
required LearnLessonDetailViewModel viewModel}) async {
|
||||||
await viewModel.pause();
|
/* await viewModel.pause();
|
||||||
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
|
*/
|
||||||
|
if (index > 1) {
|
||||||
|
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
|
||||||
|
await viewModel.pause();
|
||||||
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
|
} else {
|
||||||
|
await viewModel.pause();
|
||||||
|
await viewModel.navigateToLearnSubscription();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await viewModel.pause();
|
||||||
|
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,27 @@ import '../../widgets/small_app_bar.dart';
|
||||||
import 'learn_module_viewmodel.dart';
|
import 'learn_module_viewmodel.dart';
|
||||||
|
|
||||||
class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
final bool first;
|
|
||||||
final LearnCourse course;
|
final LearnCourse course;
|
||||||
|
|
||||||
const LearnModuleView({Key? key, required this.first, required this.course})
|
const LearnModuleView({Key? key, required this.course}) : super(key: key);
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
Future<void> _onPractice(
|
Future<void> _onPractice(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
required LearnModule module,
|
required LearnModule module,
|
||||||
required LearnModuleViewModel viewModel}) async {
|
required LearnModuleViewModel viewModel}) async {
|
||||||
if (module.access?.isCompleted ?? false ) {
|
if (module.access?.completedCount == module.access?.totalCount) {
|
||||||
await viewModel.navigateToLearnPractice(
|
await viewModel.navigateToLearnPractice(
|
||||||
id: module.id ?? 0, module: module.name ?? '');
|
id: module.id ?? 0, module: module.name ?? '');
|
||||||
} else {
|
} else {
|
||||||
if (module.access?.isAccessible ?? false) {
|
if (module.access?.isAccessible ?? false) {
|
||||||
|
print('Accessible');
|
||||||
await _showSheet(
|
await _showSheet(
|
||||||
context: context,
|
context: context,
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
practice: PracticeReason.module);
|
practice: PracticeReason.module);
|
||||||
} else {
|
} else {
|
||||||
|
print('Inaccessible');
|
||||||
|
|
||||||
await _showSheet(
|
await _showSheet(
|
||||||
context: context,
|
context: context,
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
|
|
@ -200,8 +201,8 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
viewModel: viewModel,
|
viewModel: viewModel,
|
||||||
module: viewModel.modules[index],
|
module: viewModel.modules[index],
|
||||||
),
|
),
|
||||||
onModuleTap: () async => await viewModel.navigateToLearnLesson(
|
onModuleTap: () async =>
|
||||||
first: first && index == 0, module: viewModel.modules[index]),
|
await viewModel.navigateToLearnLesson(viewModel.modules[index]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,8 @@ class LearnModuleViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnLesson(
|
Future<void> navigateToLearnLesson(LearnModule module) async =>
|
||||||
{required bool first, required LearnModule module}) async =>
|
await _navigationService.navigateToLearnLessonView(module: module);
|
||||||
await _navigationService.navigateToLearnLessonView(
|
|
||||||
first: first, module: module);
|
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice(
|
Future<void> navigateToLearnPractice(
|
||||||
{required int id, required String module}) async =>
|
{required int id, required String module}) async =>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import 'package:yimaru_app/services/voice_recorder_service.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../app/app.router.dart';
|
|
||||||
import '../../../models/learn_question.dart';
|
import '../../../models/learn_question.dart';
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/audio_player_service.dart';
|
import '../../../services/audio_player_service.dart';
|
||||||
|
|
@ -265,9 +264,6 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnSubscription() async =>
|
|
||||||
await _navigationService.navigateToLearnSubscriptionView();
|
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
// Refresh url
|
// Refresh url
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,6 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
required this.subtitle,
|
required this.subtitle,
|
||||||
required this.practice});
|
required this.practice});
|
||||||
|
|
||||||
Future<void> _practice(LearnPracticeViewModel viewModel) async {
|
|
||||||
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
|
|
||||||
viewModel.goTo(1);
|
|
||||||
} else {
|
|
||||||
await viewModel.navigateToLearnSubscription();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||||
await viewModel.stopRecording();
|
await viewModel.stopRecording();
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
|
|
@ -215,7 +207,7 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
text: label,
|
text: label,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
onTap: () => viewModel.goTo(1),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await _practice(viewModel),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,6 @@ class LearnProgramView extends StackedView<LearnProgramViewModel> {
|
||||||
Widget _buildAppBar(LearnProgramViewModel viewModel) => ProfileAppBar(
|
Widget _buildAppBar(LearnProgramViewModel viewModel) => ProfileAppBar(
|
||||||
name: viewModel.user?.firstName,
|
name: viewModel.user?.firstName,
|
||||||
profileImage: viewModel.user?.profilePicture,
|
profileImage: viewModel.user?.profilePicture,
|
||||||
unreadCount: viewModel.unreadCount.toString(),
|
|
||||||
onTap: () async => await viewModel.navigateToNotification(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildProgramsColumnWrapper(LearnProgramViewModel viewModel) =>
|
Widget _buildProgramsColumnWrapper(LearnProgramViewModel viewModel) =>
|
||||||
|
|
@ -89,8 +87,8 @@ class LearnProgramView extends StackedView<LearnProgramViewModel> {
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
itemBuilder: (context, index) => _buildTile(
|
itemBuilder: (context, index) => _buildTile(
|
||||||
program: viewModel.learnPrograms[index],
|
program: viewModel.learnPrograms[index],
|
||||||
onTap: () async => await viewModel.navigateToLearnCourse(
|
onTap: () async => await viewModel
|
||||||
first: index == 0, id: viewModel.learnPrograms[index].id ?? 0),
|
.navigateToLearnCourse(viewModel.learnPrograms[index].id ?? 0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import 'package:yimaru_app/models/learn_program.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/user.dart';
|
import '../../../models/user.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
import '../../../services/learn_service.dart';
|
import '../../../services/learn_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
|
|
@ -22,34 +21,23 @@ class LearnProgramViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final _inAppNotificationService = locator<InAppNotificationService>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_learnService, _authenticationService,_inAppNotificationService];
|
[_learnService, _authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
User? get _user => _authenticationService.user;
|
User? get _user => _authenticationService.user;
|
||||||
|
|
||||||
User? get user => _user;
|
User? get user => _user;
|
||||||
|
|
||||||
// Notification count
|
|
||||||
int get _unreadCount => _inAppNotificationService.unreadCount;
|
|
||||||
|
|
||||||
int get unreadCount => _unreadCount;
|
|
||||||
|
|
||||||
// Learn programs
|
// Learn programs
|
||||||
List<LearnProgram> get _learnPrograms => _learnService.programs;
|
List<LearnProgram> get _learnPrograms => _learnService.programs;
|
||||||
|
|
||||||
List<LearnProgram> get learnPrograms => _learnPrograms;
|
List<LearnProgram> get learnPrograms => _learnPrograms;
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
Future<void> navigateToNotification() async =>
|
Future<void> navigateToLearnCourse(int id) async =>
|
||||||
await _navigationService.navigateToNotificationView();
|
_navigationService.navigateToLearnCourseView(id: id);
|
||||||
|
|
||||||
Future<void> navigateToLearnCourse(
|
|
||||||
{required int id, required bool first}) async =>
|
|
||||||
_navigationService.navigateToLearnCourseView(id: id, first: first);
|
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:yimaru_app/app/app.router.dart';
|
||||||
import 'package:yimaru_app/models/user.dart';
|
import 'package:yimaru_app/models/user.dart';
|
||||||
|
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
|
import '../../../services/apple_auth_service.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
|
|
@ -25,19 +26,23 @@ class LoginViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
final _appleAuthService = locator<AppleAuthService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_googleAuthService, _localizationService];
|
[_googleAuthService, _appleAuthService, _localizationService];
|
||||||
|
|
||||||
// Google user
|
// Google user
|
||||||
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
||||||
|
|
||||||
GoogleSignInAccount? get googleUser => _googleUser;
|
GoogleSignInAccount? get googleUser => _googleUser;
|
||||||
|
|
||||||
|
bool get isAppleSignInAvailable => _appleAuthService.isSupported;
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
Map<String, dynamic> get _selectedLanguage =>
|
||||||
_localizationService.selectedLanguage;
|
_localizationService.selectedLanguage;
|
||||||
|
|
@ -235,6 +240,50 @@ class LoginViewModel extends ReactiveViewModel
|
||||||
Future<void> signInWithGoogle() async => await runBusyFuture(_googleAuth(),
|
Future<void> signInWithGoogle() async => await runBusyFuture(_googleAuth(),
|
||||||
busyObject: StateObjects.loginWithGoogle);
|
busyObject: StateObjects.loginWithGoogle);
|
||||||
|
|
||||||
|
// Sign-in with Apple
|
||||||
|
Future<void> _appleAuth() async {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
await _appleAuthService.appleAuth();
|
||||||
|
|
||||||
|
final credential = _appleAuthService.appleCredential;
|
||||||
|
final identityToken = credential?.identityToken;
|
||||||
|
|
||||||
|
if (identityToken == null || identityToken.isEmpty) {
|
||||||
|
showErrorToast('Apple login failed. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'id_token': identityToken,
|
||||||
|
'email': credential?.email,
|
||||||
|
'first_name': credential?.givenName,
|
||||||
|
'last_name': credential?.familyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
data.removeWhere((_, value) => value == null || value == '');
|
||||||
|
|
||||||
|
Map<String, dynamic> response = await _apiService.appleAuth(data);
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success) {
|
||||||
|
User user = response['data'] as User;
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'userId': user.userId,
|
||||||
|
'accessToken': user.accessToken,
|
||||||
|
'refreshToken': user.refreshToken
|
||||||
|
};
|
||||||
|
await _authenticationService.saveUserCredential(data);
|
||||||
|
clearUserData();
|
||||||
|
await replaceWithStartUp();
|
||||||
|
showSuccessToast(response['message']);
|
||||||
|
} else {
|
||||||
|
showErrorToast(response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signInWithApple() async => await runBusyFuture(_appleAuth(),
|
||||||
|
busyObject: StateObjects.loginWithApple);
|
||||||
|
|
||||||
// Login with phone
|
// Login with phone
|
||||||
Future<void> loginWithPhoneNumber() async =>
|
Future<void> loginWithPhoneNumber() async =>
|
||||||
await runBusyFuture(_loginWithPhoneNumber(),
|
await runBusyFuture(_loginWithPhoneNumber(),
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
Stack(children: [
|
Stack(children: [
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildLoginWithEmailState(viewModel),
|
_buildLoginWithEmailState(viewModel),
|
||||||
_buildLoginWithGoogleState(viewModel)
|
_buildLoginWithGoogleState(viewModel),
|
||||||
|
_buildLoginWithAppleState(viewModel)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold(
|
||||||
|
|
@ -232,6 +233,8 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
List<Widget> _buildLowerColumnChildren(LoginViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(LoginViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
_buildLoginWithGoogleButton(viewModel),
|
_buildLoginWithGoogleButton(viewModel),
|
||||||
|
if (viewModel.isAppleSignInAvailable)
|
||||||
|
_buildLoginWithAppleButton(viewModel),
|
||||||
_buildOptionTextDivider(),
|
_buildOptionTextDivider(),
|
||||||
_buildLoginWithPhoneButton(viewModel),
|
_buildLoginWithPhoneButton(viewModel),
|
||||||
verticalSpaceMedium
|
verticalSpaceMedium
|
||||||
|
|
@ -265,6 +268,18 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
onTap: () async => await viewModel.signInWithGoogle(),
|
onTap: () async => await viewModel.signInWithGoogle(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildLoginWithAppleButton(LoginViewModel viewModel) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: kcWhite,
|
||||||
|
borderColor: kcPrimaryColor,
|
||||||
|
foregroundColor: kcPrimaryColor,
|
||||||
|
text: LocaleKeys.login_with_apple.tr(),
|
||||||
|
leadingIcon: Icons.apple,
|
||||||
|
onTap: () async => await viewModel.signInWithApple(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
||||||
Widget _buildLoginWithPhoneButton(LoginViewModel viewModel) =>
|
Widget _buildLoginWithPhoneButton(LoginViewModel viewModel) =>
|
||||||
|
|
@ -287,4 +302,9 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
viewModel.busy(StateObjects.loginWithGoogle)
|
viewModel.busy(StateObjects.loginWithGoogle)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildLoginWithAppleState(LoginViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.loginWithApple)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/notification_card.dart';
|
|
||||||
|
|
||||||
import '../../../models/in_app_notification.dart';
|
|
||||||
import '../../common/app_colors.dart';
|
|
||||||
import '../../common/enmus.dart';
|
|
||||||
import '../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
import '../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
import '../../widgets/small_app_bar.dart';
|
|
||||||
import 'notification_viewmodel.dart';
|
|
||||||
|
|
||||||
class NotificationView extends StackedView<NotificationViewModel> {
|
|
||||||
const NotificationView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onViewModelReady(NotificationViewModel viewModel) async {
|
|
||||||
await viewModel.getAllNotifications();
|
|
||||||
await viewModel.markNotificationsRead();
|
|
||||||
super.onViewModelReady(viewModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
NotificationViewModel viewModelBuilder(BuildContext context) =>
|
|
||||||
NotificationViewModel();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget builder(
|
|
||||||
BuildContext context,
|
|
||||||
NotificationViewModel viewModel,
|
|
||||||
Widget? child,
|
|
||||||
) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(NotificationViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffoldContainer(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffoldContainer(NotificationViewModel viewModel) => Container(
|
|
||||||
decoration: bgDecoration,
|
|
||||||
child: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(NotificationViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBodyWrapper(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBodyWrapper(NotificationViewModel viewModel) =>
|
|
||||||
_buildBody(viewModel);
|
|
||||||
|
|
||||||
Widget _buildBody(NotificationViewModel viewModel) => _buildColumn(viewModel);
|
|
||||||
|
|
||||||
Widget _buildColumn(NotificationViewModel viewModel) => Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren(NotificationViewModel viewModel) => [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBarWrapper(viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildNotificationsColumnWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBarWrapper(NotificationViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildAppbar(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppbar(NotificationViewModel viewModel) => SmallAppBar(
|
|
||||||
showBackButton: true,
|
|
||||||
onPop: viewModel.pop,
|
|
||||||
title: LocaleKeys.notifications.tr(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildNotificationsColumnWrapper(NotificationViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildNotificationsColumnScrollView(viewModel));
|
|
||||||
|
|
||||||
Widget _buildNotificationsColumnScrollView(NotificationViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildListViewBuilder(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildListViewBuilder(NotificationViewModel viewModel) =>
|
|
||||||
viewModel.busy(StateObjects.notifications)
|
|
||||||
? _buildProgressIndicator()
|
|
||||||
: _buildListView(viewModel);
|
|
||||||
|
|
||||||
Widget _buildProgressIndicator() => const Center(
|
|
||||||
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildListView(NotificationViewModel viewModel) => ListView.separated(
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: viewModel.notifications.length,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
|
||||||
itemBuilder: (context, index) => _buildCard(
|
|
||||||
notification: viewModel.notifications[index],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCard({
|
|
||||||
required InAppNotification notification,
|
|
||||||
}) =>
|
|
||||||
NotificationCard(notification: notification);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
|
||||||
import '../../../models/in_app_notification.dart';
|
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
import '../../../services/localization_service.dart';
|
|
||||||
import '../../../services/status_checker_service.dart';
|
|
||||||
import '../../common/enmus.dart';
|
|
||||||
|
|
||||||
class NotificationViewModel extends ReactiveViewModel {
|
|
||||||
// Dependency injection
|
|
||||||
final _statusChecker = locator<StatusCheckerService>();
|
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
|
||||||
|
|
||||||
final _inAppNotificationService = locator<InAppNotificationService>();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
|
||||||
[_localizationService, _inAppNotificationService];
|
|
||||||
|
|
||||||
// Languages
|
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
|
||||||
_localizationService.selectedLanguage;
|
|
||||||
|
|
||||||
Map<String, dynamic> get selectedLanguage => _selectedLanguage;
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
List<InAppNotification> get _notifications =>
|
|
||||||
_inAppNotificationService.notifications;
|
|
||||||
|
|
||||||
List<InAppNotification> get notifications => _notifications;
|
|
||||||
|
|
||||||
// Notification count
|
|
||||||
int get _unreadCount => _inAppNotificationService.unreadCount;
|
|
||||||
|
|
||||||
int get unreadCount => _unreadCount;
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
|
||||||
|
|
||||||
// Remote api call
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
Future<void> getAllNotifications() async =>
|
|
||||||
await runBusyFuture(_getAllNotifications(),
|
|
||||||
busyObject: StateObjects.notifications);
|
|
||||||
|
|
||||||
Future<void> _getAllNotifications() async {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
|
||||||
await _inAppNotificationService.getAllNotifications();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> getUnreadNotifications() async =>
|
|
||||||
await runBusyFuture(_getUnreadNotifications());
|
|
||||||
|
|
||||||
Future<void> _getUnreadNotifications() async {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
|
||||||
await _inAppNotificationService.getUnreadNotifications();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> markNotificationsRead() async {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
|
||||||
await _inAppNotificationService.markNotificationRead();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -205,8 +205,8 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
_selectedCountry = value;
|
_selectedCountry = value;
|
||||||
if (value?.code?.toLowerCase().trim() == 'et') {
|
if (value?.code?.toLowerCase().trim() == 'et') {
|
||||||
_dropdownRegion = true;
|
_dropdownRegion = true;
|
||||||
_selectedRegion = _regions.firstWhere(
|
_selectedRegion = _regions
|
||||||
(e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
|
.firstWhere((e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
|
||||||
} else {
|
} else {
|
||||||
_dropdownRegion = false;
|
_dropdownRegion = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,7 @@ class PaymentView extends StackedView<PaymentViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(PaymentViewModel viewModel) async {
|
void onViewModelReady(PaymentViewModel viewModel) async {
|
||||||
await viewModel.createLearnSubscriptionRequest(
|
await viewModel.createLearnSubscriptionRequest(phone: phone,subscription: subscription);
|
||||||
phone: phone, subscription: subscription);
|
|
||||||
super.onViewModelReady(viewModel);
|
super.onViewModelReady(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,22 +45,18 @@ class PaymentViewModel extends ReactiveViewModel {
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
// Learn subscription
|
// Learn subscription
|
||||||
Future<void> createLearnSubscriptionRequest(
|
Future<void> createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async =>
|
||||||
{required String phone,
|
await runBusyFuture(_createLearnSubscriptionRequest(phone: phone,subscription: subscription),
|
||||||
required LearnSubscription subscription}) async =>
|
|
||||||
await runBusyFuture(
|
|
||||||
_createLearnSubscriptionRequest(
|
|
||||||
phone: phone, subscription: subscription),
|
|
||||||
busyObject: StateObjects.learnSubscription);
|
busyObject: StateObjects.learnSubscription);
|
||||||
|
|
||||||
Future<void> _createLearnSubscriptionRequest(
|
Future<void> _createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async {
|
||||||
{required String phone, required LearnSubscription subscription}) async {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
if (await _statusChecker.checkConnection()) {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'provider': 'CHAPA',
|
'provider': 'CHAPA',
|
||||||
'phone': '251$phone',
|
'phone': '251$phone',
|
||||||
'email': 'test@gmail.com',
|
'email': 'test@gmail.com',
|
||||||
'plan_id': subscription.id,
|
'plan_id': subscription.id,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> response =
|
Map<String, dynamic> response =
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/notification_icon.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/profile_card.dart';
|
import 'package:yimaru_app/ui/widgets/profile_card.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/profile_image.dart';
|
import 'package:yimaru_app/ui/widgets/profile_image.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/view_profile_button.dart';
|
import 'package:yimaru_app/ui/widgets/view_profile_button.dart';
|
||||||
|
|
@ -90,9 +89,8 @@ class ProfileView extends StackedView<ProfileViewModel> {
|
||||||
required ProfileViewModel viewModel}) =>
|
required ProfileViewModel viewModel}) =>
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceSmall,
|
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildNotificationIconWrapper(viewModel),
|
_buildNotificationIconWrapper(),
|
||||||
_buildProfileSection(context: context, viewModel: viewModel),
|
_buildProfileSection(context: context, viewModel: viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildViewProfileButton(viewModel),
|
_buildViewProfileButton(viewModel),
|
||||||
|
|
@ -104,10 +102,12 @@ class ProfileView extends StackedView<ProfileViewModel> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildNotificationIconWrapper(ProfileViewModel viewModel) =>
|
Widget _buildNotificationIconWrapper() =>
|
||||||
NotificationIcon(
|
Align(alignment: Alignment.bottomRight, child: _buildNotificationIcon());
|
||||||
count: viewModel.unreadCount.toString(),
|
|
||||||
onTap: () async => await viewModel.navigateToNotification(),
|
Widget _buildNotificationIcon() => const Icon(
|
||||||
|
Icons.notifications_none,
|
||||||
|
color: kcDarkGrey,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildProfileSection(
|
Widget _buildProfileSection(
|
||||||
|
|
@ -166,7 +166,7 @@ class ProfileView extends StackedView<ProfileViewModel> {
|
||||||
|
|
||||||
List<Widget> _buildSettingsChildren(ProfileViewModel viewModel) => [
|
List<Widget> _buildSettingsChildren(ProfileViewModel viewModel) => [
|
||||||
// _buildDownloadsCard(viewModel),
|
// _buildDownloadsCard(viewModel),
|
||||||
_buildProgressCard(viewModel),
|
_buildProgressCard(viewModel),
|
||||||
_buildAccountCard(viewModel),
|
_buildAccountCard(viewModel),
|
||||||
_buildSupportCard(viewModel)
|
_buildSupportCard(viewModel)
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import '../../../models/user.dart';
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/app_colors.dart';
|
import '../../common/app_colors.dart';
|
||||||
|
|
||||||
|
|
@ -24,26 +23,21 @@ class ProfileViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
final _imagePickerService = locator<ImagePickerService>();
|
final _imagePickerService = locator<ImagePickerService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final _inAppNotificationService = locator<InAppNotificationService>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_authenticationService,_inAppNotificationService];
|
[_authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
User? get _user => _authenticationService.user;
|
User? get _user => _authenticationService.user;
|
||||||
|
|
||||||
User? get user => _user;
|
User? get user => _user;
|
||||||
|
|
||||||
// Notification count
|
|
||||||
int get _unreadCount => _inAppNotificationService.unreadCount;
|
|
||||||
|
|
||||||
int get unreadCount => _unreadCount;
|
|
||||||
|
|
||||||
// Image picker
|
// Image picker
|
||||||
Future<void> openCamera() async =>
|
Future<void> openCamera() async =>
|
||||||
runBusyFuture(_openCamera(), busyObject: StateObjects.profileImage);
|
runBusyFuture(_openCamera(), busyObject: StateObjects.profileImage);
|
||||||
|
|
@ -86,24 +80,21 @@ class ProfileViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToSupport() async =>
|
Future<void> navigateToProfileDetail() async =>
|
||||||
await _navigationService.navigateToSupportView();
|
await _navigationService.navigateToProfileDetailView();
|
||||||
|
|
||||||
Future<void> navigateToProgress() async =>
|
|
||||||
await _navigationService.navigateToProgressView();
|
|
||||||
|
|
||||||
Future<void> navigateToDownloads() async =>
|
Future<void> navigateToDownloads() async =>
|
||||||
await _navigationService.navigateToDownloadsView();
|
await _navigationService.navigateToDownloadsView();
|
||||||
|
|
||||||
Future<void> navigateToNotification() async =>
|
Future<void> navigateToProgress() async =>
|
||||||
await _navigationService.navigateToNotificationView();
|
await _navigationService.navigateToProgressView();
|
||||||
|
|
||||||
Future<void> navigateToProfileDetail() async =>
|
|
||||||
await _navigationService.navigateToProfileDetailView();
|
|
||||||
|
|
||||||
Future<void> navigateToAccountPrivacy() async =>
|
Future<void> navigateToAccountPrivacy() async =>
|
||||||
await _navigationService.navigateToAccountPrivacyView();
|
await _navigationService.navigateToAccountPrivacyView();
|
||||||
|
|
||||||
|
Future<void> navigateToSupport() async =>
|
||||||
|
await _navigationService.navigateToSupportView();
|
||||||
|
|
||||||
Future<void> navigateToLogin() async =>
|
Future<void> navigateToLogin() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.loginView);
|
await _navigationService.clearStackAndShow(Routes.loginView);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
viewModel.setSelectedOccupation(viewModel.occupations
|
viewModel.setSelectedOccupation(viewModel.occupations
|
||||||
.where((e) => (e.code ?? '') == viewModel.user?.occupation)
|
.where((e) => (e.code ?? '') == viewModel.user?.occupation)
|
||||||
.first);
|
.first);
|
||||||
viewModel.setSelectedCountry(viewModel.countries
|
viewModel.setSelectedCountry(viewModel.countries
|
||||||
.where((e) => (e.code ?? '') == viewModel.user?.country)
|
.where((e) => (e.code ?? '') == viewModel.user?.country)
|
||||||
.first);
|
.first);
|
||||||
if (viewModel.user?.country?.toLowerCase() == 'et') {
|
if (viewModel.user?.country?.toLowerCase() == 'et') {
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
void setEthiopianRegion(String region) {
|
void setEthiopianRegion(String region) {
|
||||||
_dropdownRegion = true;
|
_dropdownRegion = true;
|
||||||
_selectedRegion = _regions
|
_selectedRegion =
|
||||||
.firstWhere((r) => r.code?.toLowerCase() == region.toLowerCase());
|
_regions.firstWhere((r) => r.code?.toLowerCase() == region.toLowerCase());
|
||||||
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class ProgressViewModel extends ReactiveViewModel {
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices => [_learnService];
|
List<ListenableServiceMixin> get listenableServices => [_learnService];
|
||||||
|
|
||||||
|
|
||||||
// Total practice count
|
// Total practice count
|
||||||
int get _totalCount => _learnService.totalCount;
|
int get _totalCount => _learnService.totalCount;
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ class ProgressViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
int get totalProgress => _totalProgress;
|
int get totalProgress => _totalProgress;
|
||||||
|
|
||||||
|
|
||||||
// Courses
|
// Courses
|
||||||
final List<Map<String, dynamic>> _courses = [
|
final List<Map<String, dynamic>> _courses = [
|
||||||
{
|
{
|
||||||
|
|
@ -51,9 +53,8 @@ class ProgressViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
// Learning progress
|
// Learning progress
|
||||||
|
|
||||||
Future<void> getProgressSummary() async =>
|
Future<void> getProgressSummary() async => runBusyFuture(_getProgressSummary(),
|
||||||
runBusyFuture(_getProgressSummary(),
|
busyObject: StateObjects.progressSummary);
|
||||||
busyObject: StateObjects.progressSummary);
|
|
||||||
|
|
||||||
Future<void> _getProgressSummary() async {
|
Future<void> _getProgressSummary() async {
|
||||||
if (await _statusCheckerService.checkConnection()) {
|
if (await _statusCheckerService.checkConnection()) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/user.dart';
|
import '../../../models/user.dart';
|
||||||
|
import '../../../services/apple_auth_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
|
|
@ -25,19 +26,23 @@ class RegisterViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
final _appleAuthService = locator<AppleAuthService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_googleAuthService, _localizationService];
|
[_googleAuthService, _appleAuthService, _localizationService];
|
||||||
|
|
||||||
// Google user
|
// Google user
|
||||||
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
||||||
|
|
||||||
GoogleSignInAccount? get googleUser => _googleUser;
|
GoogleSignInAccount? get googleUser => _googleUser;
|
||||||
|
|
||||||
|
bool get isAppleSignInAvailable => _appleAuthService.isSupported;
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
Map<String, dynamic> get _selectedLanguage =>
|
||||||
_localizationService.selectedLanguage;
|
_localizationService.selectedLanguage;
|
||||||
|
|
@ -337,6 +342,50 @@ class RegisterViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register with Apple
|
||||||
|
Future<void> registerWithApple() async => await runBusyFuture(_appleLogin(),
|
||||||
|
busyObject: StateObjects.registerWithApple);
|
||||||
|
|
||||||
|
Future<void> _appleLogin() async {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
await _appleAuthService.appleAuth();
|
||||||
|
|
||||||
|
final credential = _appleAuthService.appleCredential;
|
||||||
|
final identityToken = credential?.identityToken;
|
||||||
|
|
||||||
|
if (identityToken == null || identityToken.isEmpty) {
|
||||||
|
showErrorToast('Apple login failed. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'id_token': identityToken,
|
||||||
|
'email': credential?.email,
|
||||||
|
'first_name': credential?.givenName,
|
||||||
|
'last_name': credential?.familyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
data.removeWhere((_, value) => value == null || value == '');
|
||||||
|
|
||||||
|
Map<String, dynamic> response = await _apiService.appleAuth(data);
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success) {
|
||||||
|
User user = response['data'] as User;
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'userId': user.userId,
|
||||||
|
'accessToken': user.accessToken,
|
||||||
|
'refreshToken': user.refreshToken
|
||||||
|
};
|
||||||
|
await _authenticationService.saveUserCredential(data);
|
||||||
|
clearUserData();
|
||||||
|
await replaceWithStartUp();
|
||||||
|
showSuccessToast(response['message']);
|
||||||
|
} else {
|
||||||
|
showErrorToast(response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> verifyOtp() async =>
|
Future<void> verifyOtp() async =>
|
||||||
await runBusyFuture(_verifyOtp(), busyObject: StateObjects.verifyOtp);
|
await runBusyFuture(_verifyOtp(), busyObject: StateObjects.verifyOtp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,9 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildRegisterWithEmailState(viewModel)
|
_buildRegisterWithEmailState(viewModel),
|
||||||
|
_buildRegisterWithGoogleState(viewModel),
|
||||||
|
_buildRegisterWithAppleState(viewModel)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -191,6 +193,8 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
List<Widget> _buildLowerColumnChildren(RegisterViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(RegisterViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
_buildRegisterWithGoogleButton(viewModel),
|
_buildRegisterWithGoogleButton(viewModel),
|
||||||
|
if (viewModel.isAppleSignInAvailable)
|
||||||
|
_buildRegisterWithAppleButton(viewModel),
|
||||||
_buildOptionTextDivider(),
|
_buildOptionTextDivider(),
|
||||||
_buildRegisterWithEmailButton(viewModel),
|
_buildRegisterWithEmailButton(viewModel),
|
||||||
verticalSpaceMedium
|
verticalSpaceMedium
|
||||||
|
|
@ -225,6 +229,18 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
onTap: () async => await viewModel.registerWithGoogle(),
|
onTap: () async => await viewModel.registerWithGoogle(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildRegisterWithAppleButton(RegisterViewModel viewModel) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: kcWhite,
|
||||||
|
borderColor: kcPrimaryColor,
|
||||||
|
foregroundColor: kcPrimaryColor,
|
||||||
|
text: LocaleKeys.register_with_apple.tr(),
|
||||||
|
leadingIcon: Icons.apple,
|
||||||
|
onTap: () async => await viewModel.registerWithApple(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
||||||
Widget _buildRegisterWithEmailButton(RegisterViewModel viewModel) =>
|
Widget _buildRegisterWithEmailButton(RegisterViewModel viewModel) =>
|
||||||
|
|
@ -243,4 +259,14 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
viewModel.busy(StateObjects.register)
|
viewModel.busy(StateObjects.register)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildRegisterWithGoogleState(RegisterViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.registerWithGoogle)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildRegisterWithAppleState(RegisterViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.registerWithApple)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/startup/startup_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
|
|
||||||
class FirstStartupScreen extends ViewModelWidget<StartupViewModel> {
|
|
||||||
final String? label;
|
|
||||||
|
|
||||||
const FirstStartupScreen({super.key,this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, StartupViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( ) => Scaffold(
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
Widget _buildScaffoldPadding( ) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( ) =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_white.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper( ) => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren( ) => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25W600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25W400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' ሰዓት ',
|
|
||||||
style: style25W600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25W400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_1.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper( ) =>
|
|
||||||
SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper( ) => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
|
||||||
Text('${label ?? LocaleKeys.loading.tr()} ...', style: style16W600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcWhite);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
import '../startup_viewmodel.dart';
|
|
||||||
|
|
||||||
class SecondStartupScreen extends ViewModelWidget<StartupViewModel> {
|
|
||||||
final String? label;
|
|
||||||
|
|
||||||
const SecondStartupScreen({super.key,this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, StartupViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( ) => Scaffold(
|
|
||||||
backgroundColor: Colors.amber,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
Widget _buildScaffoldPadding( ) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( ) =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_purple.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper( ) => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren( ) => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25P600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' እድሜ ',
|
|
||||||
style: style25P600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_2.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper( ) =>
|
|
||||||
SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper( ) => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
|
||||||
Text('${label ?? LocaleKeys.loading.tr()} ...', style: style16P600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcPrimaryColor);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
import '../../../common/translations/locale_keys.g.dart';
|
|
||||||
import '../../../widgets/custom_circular_progress_indicator.dart';
|
|
||||||
import '../startup_viewmodel.dart';
|
|
||||||
|
|
||||||
class ThirdStartupScreen extends ViewModelWidget<StartupViewModel> {
|
|
||||||
final String? label;
|
|
||||||
|
|
||||||
const ThirdStartupScreen({super.key,this.label});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, StartupViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper();
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( ) => Scaffold(
|
|
||||||
backgroundColor:kcWhite,
|
|
||||||
body: _buildScaffoldPadding(),
|
|
||||||
);
|
|
||||||
Widget _buildScaffoldPadding( ) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildScaffold(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildScaffoldChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( ) =>
|
|
||||||
[_buildUpperColumn(), _buildLowerColumnWrapper()];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren() =>
|
|
||||||
[verticalSpaceLarge, _buildIconWrapper(), verticalSpaceLarge];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/logo_purple.svg',
|
|
||||||
height: 25,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumnWrapper( ) => Expanded(
|
|
||||||
child: _buildLowerColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerColumn( ) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildLowerColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren( ) => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildImageWrapper(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSafeWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
text: 'እንግሊዝኛ\n',
|
|
||||||
style: style25P600,
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: 'በማንኛውም',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: ' ቦታ ',
|
|
||||||
style: style25P600,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: 'ይማሩ!',
|
|
||||||
style: style25P400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImageWrapper() => Expanded(child: _buildImageClipper());
|
|
||||||
|
|
||||||
Widget _buildImageClipper() => ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
child: _buildImage(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildImage() => Image.asset(
|
|
||||||
'assets/images/landing_3.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSafeWrapper( ) =>
|
|
||||||
SafeArea(child: _buildContinueButtonWrapper());
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper( ) => Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: _buildLoadingTextContainer(),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoadingTextContainer() => Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildLoadingTextWrapper(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLoadingTextWrapper() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: _buildLoadingTextChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLoadingTextChildren() => [
|
|
||||||
_buildLoadingText(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildIndicatorWrapper(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
|
||||||
Text('${label ?? LocaleKeys.loading.tr()} ...', style: style16P600);
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: _buildIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
|
||||||
const CustomCircularProgressIndicator(color: kcPrimaryColor);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:flutter_carousel_widget/flutter_carousel_widget.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/views/startup/screens/first_startup_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/startup/screens/second_startup_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/startup/screens/third_startup_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_circular_progress_indicator.dart';
|
import 'package:yimaru_app/ui/widgets/custom_circular_progress_indicator.dart';
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
import '../../common/app_colors.dart';
|
||||||
|
|
@ -17,7 +13,6 @@ import 'startup_viewmodel.dart';
|
||||||
|
|
||||||
class StartupView extends StackedView<StartupViewModel> {
|
class StartupView extends StackedView<StartupViewModel> {
|
||||||
final String? label;
|
final String? label;
|
||||||
|
|
||||||
const StartupView({Key? key, this.label}) : super(key: key);
|
const StartupView({Key? key, this.label}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -29,36 +24,83 @@ class StartupView extends StackedView<StartupViewModel> {
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(StartupViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(StartupViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildStartupScreens(viewModel),
|
body: _buildScaffoldState(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildStartupScreens(StartupViewModel viewModel) => FlutterCarousel(
|
Widget _buildScaffoldState(StartupViewModel viewModel) =>
|
||||||
options: FlutterCarouselOptions(
|
viewModel.busy(StateObjects.startupView)
|
||||||
autoPlay: true,
|
? _buildStartUpView()
|
||||||
viewportFraction: 1,
|
: _buildScaffold();
|
||||||
showIndicator: false,
|
|
||||||
height: double.maxFinite,
|
Widget _buildStartUpView() =>
|
||||||
),
|
StartupView(label: LocaleKeys.checking_user_info.tr());
|
||||||
items: _buildScreens(),
|
|
||||||
|
Widget _buildScaffold() => Stack(
|
||||||
|
children: _buildScaffoldChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScaffoldChildren() => [
|
||||||
_buildFirstStartup(),
|
_buildBackground(),
|
||||||
_buildSecondStartup(),
|
_buildColumn(),
|
||||||
_buildThirdWelcome(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildFirstStartup() => FirstStartupScreen(
|
Widget _buildBackground() => Image.asset(
|
||||||
label: label,
|
'assets/images/loading.png',
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
width: double.maxFinite,
|
||||||
|
height: double.maxFinite,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSecondStartup() => SecondStartupScreen(
|
Widget _buildColumn() => Column(
|
||||||
label: label,
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: _buildUpperColumnChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildThirdWelcome() => ThirdStartupScreen(
|
List<Widget> _buildUpperColumnChildren() =>
|
||||||
label: label,
|
[_buildIconWrapper(), _buildSafeWrapper()];
|
||||||
|
|
||||||
|
Widget _buildSafeWrapper() => SafeArea(child: _buildLoadingTextContainer());
|
||||||
|
|
||||||
|
Widget _buildLoadingTextContainer() => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
|
child: _buildLoadingTextWrapper(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildLoadingTextWrapper() => Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: _buildLoadingTextChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildLoadingTextChildren() => [
|
||||||
|
_buildLoadingText(),
|
||||||
|
horizontalSpaceSmall,
|
||||||
|
_buildIndicatorWrapper(),
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildLoadingText() =>
|
||||||
|
Text('${label ?? LocaleKeys.loading.tr()} ...', style: style16W600);
|
||||||
|
|
||||||
|
Widget _buildIndicatorWrapper() => SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: _buildIndicator(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildIndicator() =>
|
||||||
|
const CustomCircularProgressIndicator(color: kcWhite);
|
||||||
|
|
||||||
|
Widget _buildIconWrapper() => Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 120),
|
||||||
|
child: _buildIcon(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
|
'assets/icons/logo.svg',
|
||||||
|
height: 50,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import '../../../app/app.router.dart';
|
||||||
import '../../../models/user.dart';
|
import '../../../models/user.dart';
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/image_downloader_service.dart';
|
import '../../../services/image_downloader_service.dart';
|
||||||
import '../../../services/in_app_notification_service.dart';
|
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
|
|
@ -29,7 +28,6 @@ class StartupViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _imageDownloaderService = locator<ImageDownloaderService>();
|
final _imageDownloaderService = locator<ImageDownloaderService>();
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_onboardingService, _authenticationService];
|
[_onboardingService, _authenticationService];
|
||||||
|
|
@ -135,6 +133,8 @@ class StartupViewModel extends ReactiveViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remote api call
|
||||||
|
|
||||||
// Onboarding fields
|
// Onboarding fields
|
||||||
Future<void> getOnboardingFields() async {
|
Future<void> getOnboardingFields() async {
|
||||||
bool response = await _onboardingService.getOnboardingFields();
|
bool response = await _onboardingService.getOnboardingFields();
|
||||||
|
|
@ -144,6 +144,4 @@ class StartupViewModel extends ReactiveViewModel {
|
||||||
await replaceWithFailure();
|
await replaceWithFailure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import 'custom_linear_progress_indicator.dart';
|
||||||
class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
final int index;
|
final int index;
|
||||||
final bool last;
|
final bool last;
|
||||||
final bool first;
|
|
||||||
final LearnLesson lesson;
|
final LearnLesson lesson;
|
||||||
final GestureTapCallback? onLessonTap;
|
final GestureTapCallback? onLessonTap;
|
||||||
final GestureTapCallback? onPracticeTap;
|
final GestureTapCallback? onPracticeTap;
|
||||||
|
|
@ -27,7 +26,6 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
this.onLessonTap,
|
this.onLessonTap,
|
||||||
this.onPracticeTap,
|
this.onPracticeTap,
|
||||||
required this.last,
|
required this.last,
|
||||||
required this.first,
|
|
||||||
required this.index,
|
required this.index,
|
||||||
required this.lesson});
|
required this.lesson});
|
||||||
|
|
||||||
|
|
@ -37,13 +35,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
|
|
||||||
Widget _buildContainerWrapper(LearnLessonViewModel viewModel) =>
|
Widget _buildContainerWrapper(LearnLessonViewModel viewModel) =>
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: viewModel.user?.subscriptionStatus?.toLowerCase() == 'active'
|
onTap: !(lesson.access?.isAccessible ?? false) ? onPracticeTap : null,
|
||||||
? !(lesson.access?.isAccessible ?? false)
|
|
||||||
? onPracticeTap
|
|
||||||
: null
|
|
||||||
: !first
|
|
||||||
? onPracticeTap
|
|
||||||
: null,
|
|
||||||
child: _buildContainer(viewModel),
|
child: _buildContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -64,7 +56,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
Widget _buildTileStack(LearnLessonViewModel viewModel) => Stack(
|
Widget _buildTileStack(LearnLessonViewModel viewModel) => Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildExpansionTile(viewModel),
|
_buildExpansionTile(viewModel),
|
||||||
_buildContainerShaderState(viewModel)
|
_buildContainerShaderState()
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -78,6 +70,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
shape: Border.all(color: kcTransparent),
|
shape: Border.all(color: kcTransparent),
|
||||||
expandedAlignment: Alignment.centerLeft,
|
expandedAlignment: Alignment.centerLeft,
|
||||||
leading: _buildLeadingWrapper(viewModel),
|
leading: _buildLeadingWrapper(viewModel),
|
||||||
|
enabled: (lesson.access?.isAccessible ?? false),
|
||||||
controlAffinity: ListTileControlAffinity.trailing,
|
controlAffinity: ListTileControlAffinity.trailing,
|
||||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
|
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
|
||||||
|
|
@ -92,7 +85,6 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
collapsedBackgroundColor: (lesson.access?.isCompleted ?? false)
|
collapsedBackgroundColor: (lesson.access?.isCompleted ?? false)
|
||||||
? kcGreen.withOpacity(0.1)
|
? kcGreen.withOpacity(0.1)
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
enabled: first ? true : (lesson.access?.isAccessible ?? false),
|
|
||||||
children: _buildExpansionTileChildren(viewModel),
|
children: _buildExpansionTileChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -211,14 +203,9 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContainerShaderState(LearnLessonViewModel viewModel) =>
|
Widget _buildContainerShaderState() => !(lesson.access?.isAccessible ?? false)
|
||||||
viewModel.user?.subscriptionStatus?.toLowerCase() == 'active'
|
? _buildContainerShader()
|
||||||
? !(lesson.access?.isAccessible ?? false)
|
: Container();
|
||||||
? _buildContainerShader()
|
|
||||||
: Container()
|
|
||||||
: !first
|
|
||||||
? _buildContainerShader()
|
|
||||||
: Container();
|
|
||||||
|
|
||||||
Widget _buildContainerShader() => const CustomContainerShader();
|
Widget _buildContainerShader() => const CustomContainerShader();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:yimaru_app/models/in_app_notification.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
|
|
||||||
class NotificationCard extends StatelessWidget {
|
|
||||||
final InAppNotification notification;
|
|
||||||
|
|
||||||
const NotificationCard({super.key, required this.notification});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildContainer();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildContainer() => Container(
|
|
||||||
height: 100,
|
|
||||||
width: double.maxFinite,
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15,vertical: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: (notification.isRead ?? false)
|
|
||||||
? kcGreen.withOpacity(0.05)
|
|
||||||
: kcPrimaryColor.withOpacity(0.05),
|
|
||||||
border: Border.all(
|
|
||||||
color: (notification.isRead ?? false)
|
|
||||||
? kcGreen.withOpacity(0.1)
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: _buildRow(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildRow() => Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildRowChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildRowChildren()=> [
|
|
||||||
_buildIcon(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildColumnWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildIcon() => const Icon(
|
|
||||||
Icons.notifications_none,
|
|
||||||
size: 35,
|
|
||||||
color: kcMediumGrey,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumnWrapper()=> Expanded(child: _buildColumn());
|
|
||||||
|
|
||||||
Widget _buildColumn() => Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren() =>
|
|
||||||
[ _buildTitle(), _buildSubtitle()];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
notification.payload?.headline ?? '',
|
|
||||||
style: style16DG600,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
notification.payload?.message ?? '',
|
|
||||||
maxLines: 2,
|
|
||||||
style: style14MG400,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
import 'package:badges/badges.dart' as badges;
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:badges/badges.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
|
||||||
import '../common/app_colors.dart';
|
|
||||||
class NotificationIcon extends StatelessWidget {
|
|
||||||
final String count;
|
|
||||||
final GestureTapCallback? onTap;
|
|
||||||
const NotificationIcon({super.key,this.onTap,required this.count});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildNotificationIconWrapper();
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildNotificationIconWrapper() => Align(
|
|
||||||
alignment: Alignment.bottomRight,
|
|
||||||
child: _buildNotificationButton());
|
|
||||||
|
|
||||||
Widget _buildNotificationButton() =>
|
|
||||||
GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: _buildNotificationBadge(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildNotificationBadge()=> badges.Badge(
|
|
||||||
badgeContent: Text(count,style: style12W600,),
|
|
||||||
|
|
||||||
child: _buildNotificationIcon(),
|
|
||||||
);
|
|
||||||
Widget _buildNotificationIcon() => const Icon(
|
|
||||||
Icons.notifications_none,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -7,16 +7,13 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
import '../common/app_colors.dart';
|
import '../common/app_colors.dart';
|
||||||
import '../common/translations/locale_keys.g.dart';
|
import '../common/translations/locale_keys.g.dart';
|
||||||
import 'notification_icon.dart';
|
|
||||||
|
|
||||||
class ProfileAppBar extends StatelessWidget {
|
class ProfileAppBar extends StatelessWidget {
|
||||||
final String? name;
|
final String? name;
|
||||||
final String unreadCount;
|
|
||||||
final String? profileImage;
|
final String? profileImage;
|
||||||
final GestureTapCallback? onTap;
|
|
||||||
|
|
||||||
const ProfileAppBar(
|
const ProfileAppBar(
|
||||||
{super.key, this.onTap, required this.name,required this.unreadCount, required this.profileImage});
|
{super.key, required this.name, required this.profileImage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildStack();
|
Widget build(BuildContext context) => _buildStack();
|
||||||
|
|
@ -94,8 +91,11 @@ class ProfileAppBar extends StatelessWidget {
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Widget _buildNotificationIconWrapper() =>
|
Widget _buildNotificationIconWrapper() =>
|
||||||
NotificationIcon(count: unreadCount,onTap:onTap ,)
|
Align(alignment: Alignment.bottomRight, child: _buildNotificationIcon());
|
||||||
;
|
|
||||||
|
Widget _buildNotificationIcon() => const Icon(
|
||||||
|
Icons.notifications_none,
|
||||||
|
color: kcDarkGrey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import google_sign_in_ios
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import record_macos
|
import record_macos
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
import sign_in_with_apple
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import video_player_avfoundation
|
import video_player_avfoundation
|
||||||
|
|
@ -35,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
||||||
|
|
|
||||||
44
pubspec.lock
|
|
@ -113,14 +113,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.0"
|
version: "4.3.0"
|
||||||
badges:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: badges
|
|
||||||
sha256: cf1c88fb3777df69ccd630b80de5267f54efa4a39381b0404a7c03d56cb7c041
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.0"
|
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1129,10 +1121,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1565,6 +1557,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
sign_in_with_apple:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple
|
||||||
|
sha256: "5568378c3cc5993931955357d85e4c3344fa4365006915bdef965fa3de1dc0a5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.0"
|
||||||
|
sign_in_with_apple_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple_platform_interface
|
||||||
|
sha256: "981bca52cf3bb9c3ad7ef44aace2d543e5c468bb713fd8dda4275ff76dfa6659"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
sign_in_with_apple_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple_web
|
||||||
|
sha256: f316400827f52cafcf50d00e1a2e8a0abc534ca1264e856a81c5f06bd5b10fed
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -1726,10 +1742,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -2019,5 +2035,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.10.3 <4.0.0"
|
dart: ">=3.11.0 <4.0.0"
|
||||||
flutter: ">=3.38.4"
|
flutter: ">=3.41.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: yimaru_app
|
name: yimaru_app
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 0.1.41+43
|
version: 0.1.33+35
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -16,7 +16,6 @@ dependencies:
|
||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
async: ^2.13.1
|
async: ^2.13.1
|
||||||
pinput: ^6.0.1
|
pinput: ^6.0.1
|
||||||
badges: ^3.2.0
|
|
||||||
stacked: ^3.4.0
|
stacked: ^3.4.0
|
||||||
iconsax: ^0.0.8
|
iconsax: ^0.0.8
|
||||||
chewie: ^1.13.0
|
chewie: ^1.13.0
|
||||||
|
|
@ -56,6 +55,7 @@ dependencies:
|
||||||
flutter_phone_direct_caller: ^2.2.1
|
flutter_phone_direct_caller: ^2.2.1
|
||||||
flutter_local_notifications: ^20.1.0
|
flutter_local_notifications: ^20.1.0
|
||||||
internet_connection_checker_plus: ^2.9.1+2
|
internet_connection_checker_plus: ^2.9.1+2
|
||||||
|
sign_in_with_apple: ^8.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:yimaru_app/services/permission_handler_service.dart';
|
||||||
import 'package:yimaru_app/services/image_picker_service.dart';
|
import 'package:yimaru_app/services/image_picker_service.dart';
|
||||||
import 'package:yimaru_app/services/google_auth_service.dart';
|
import 'package:yimaru_app/services/google_auth_service.dart';
|
||||||
import 'package:yimaru_app/services/image_downloader_service.dart';
|
import 'package:yimaru_app/services/image_downloader_service.dart';
|
||||||
|
import 'package:yimaru_app/services/notification_service.dart';
|
||||||
import 'package:yimaru_app/services/smart_auth_service.dart';
|
import 'package:yimaru_app/services/smart_auth_service.dart';
|
||||||
import 'package:yimaru_app/services/course_service.dart';
|
import 'package:yimaru_app/services/course_service.dart';
|
||||||
import 'package:yimaru_app/services/audio_player_service.dart';
|
import 'package:yimaru_app/services/audio_player_service.dart';
|
||||||
|
|
@ -22,8 +23,6 @@ import 'package:yimaru_app/services/phone_caller_service.dart';
|
||||||
import 'package:yimaru_app/services/learn_service.dart';
|
import 'package:yimaru_app/services/learn_service.dart';
|
||||||
import 'package:yimaru_app/services/localization_service.dart';
|
import 'package:yimaru_app/services/localization_service.dart';
|
||||||
import 'package:yimaru_app/services/onboarding_service.dart';
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
import 'package:yimaru_app/services/in_app_notification_service.dart';
|
|
||||||
import 'package:yimaru_app/services/push_notification_service.dart';
|
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
@GenerateMocks(
|
@GenerateMocks(
|
||||||
|
|
@ -58,10 +57,6 @@ import 'package:yimaru_app/services/push_notification_service.dart';
|
||||||
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<LocalizationService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<LocalizationService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<OnboardingService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<OnboardingService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<InAppNotificationService>(
|
|
||||||
onMissingStub: OnMissingStub.returnDefault),
|
|
||||||
MockSpec<PushNotificationService>(
|
|
||||||
onMissingStub: OnMissingStub.returnDefault),
|
|
||||||
// @stacked-mock-spec
|
// @stacked-mock-spec
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -93,8 +88,6 @@ void registerServices() {
|
||||||
getAndRegisterLearnService();
|
getAndRegisterLearnService();
|
||||||
getAndRegisterLocalizationService();
|
getAndRegisterLocalizationService();
|
||||||
getAndRegisterOnboardingService();
|
getAndRegisterOnboardingService();
|
||||||
getAndRegisterInAppNotificationService();
|
|
||||||
getAndRegisterPushNotificationService();
|
|
||||||
// @stacked-mock-register
|
// @stacked-mock-register
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +208,13 @@ MockImageDownloaderService getAndRegisterImageDownloaderService() {
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MockNotificationService getAndRegisterNotificationService() {
|
||||||
|
_removeRegistrationIfExists<NotificationService>();
|
||||||
|
final service = MockNotificationService();
|
||||||
|
locator.registerSingleton<NotificationService>(service);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
MockSmartAuthService getAndRegisterSmartAuthService() {
|
MockSmartAuthService getAndRegisterSmartAuthService() {
|
||||||
_removeRegistrationIfExists<SmartAuthService>();
|
_removeRegistrationIfExists<SmartAuthService>();
|
||||||
final service = MockSmartAuthService();
|
final service = MockSmartAuthService();
|
||||||
|
|
@ -291,20 +291,6 @@ MockOnboardingService getAndRegisterOnboardingService() {
|
||||||
locator.registerSingleton<OnboardingService>(service);
|
locator.registerSingleton<OnboardingService>(service);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
MockInAppNotificationService getAndRegisterInAppNotificationService() {
|
|
||||||
_removeRegistrationIfExists<InAppNotificationService>();
|
|
||||||
final service = MockInAppNotificationService();
|
|
||||||
locator.registerSingleton<InAppNotificationService>(service);
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
MockPushNotificationService getAndRegisterPushNotificationService() {
|
|
||||||
_removeRegistrationIfExists<PushNotificationService>();
|
|
||||||
final service = MockPushNotificationService();
|
|
||||||
locator.registerSingleton<PushNotificationService>(service);
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
// @stacked-mock-create
|
// @stacked-mock-create
|
||||||
|
|
||||||
void _removeRegistrationIfExists<T extends Object>() {
|
void _removeRegistrationIfExists<T extends Object>() {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:yimaru_app/app/app.locator.dart';
|
|
||||||
|
|
||||||
import '../helpers/test_helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('InAppNotificationServiceTest -', () {
|
|
||||||
setUp(() => registerServices());
|
|
||||||
tearDown(() => locator.reset());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart';
|
||||||
import '../helpers/test_helpers.dart';
|
import '../helpers/test_helpers.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('PushNotificationServiceTest -', () {
|
group('NotificationServiceTest -', () {
|
||||||
setUp(() => registerServices());
|
setUp(() => registerServices());
|
||||||
tearDown(() => locator.reset());
|
tearDown(() => locator.reset());
|
||||||
});
|
});
|
||||||