Compare commits

..

20 Commits

Author SHA1 Message Date
jahongireshonqulov
a2fbd9f90d feat:register page ui done 2025-10-29 15:16:48 +05:00
jahongireshonqulov
ece15635eb feat:register page ui done 2025-10-29 15:16:44 +05:00
jahongireshonqulov
2ed2c430c0 feat:login page done 2025-10-29 12:00:33 +05:00
jahongireshonqulov
d3ad5b8ddd feat:login page connected with backend 2025-10-28 20:08:53 +05:00
jahongireshonqulov
b23808c731 feat:login page done 2025-10-28 19:41:08 +05:00
jahongireshonqulov
cdec9980af feat:login page done 2025-10-28 19:41:05 +05:00
jahongireshonqulov
4c652c2b47 feat:dio client done 2025-10-28 17:03:13 +05:00
jahongireshonqulov
c528f7a07e feat: Account page ui done 2025-10-27 15:14:17 +05:00
jahongireshonqulov
651a7e5e9d feat: changing language done 2025-10-25 20:13:11 +05:00
jahongireshonqulov
2750564b08 feat:browse bloc done 2025-10-25 17:54:59 +05:00
jahongireshonqulov
97aae6e108 feat:browse bloc done 2025-10-25 17:54:56 +05:00
jahongireshonqulov
57af573b6f feat:browse page ui done 2025-10-25 15:29:38 +05:00
jahongireshonqulov
33da49df6c feat: app text form field done 2025-10-25 12:20:00 +05:00
jahongireshonqulov
6a5b4b6e3a feat: Baskets page's loading,loaded state done 2025-10-25 11:38:17 +05:00
jahongireshonqulov
7474a8b677 feat:Order item created 2025-10-24 20:43:08 +05:00
jahongireshonqulov
7e9fbd2cf3 feat:Order item created 2025-10-24 20:43:05 +05:00
jahongireshonqulov
30f190aab9 feat:Baskets empty page ui done 2025-10-24 20:17:59 +05:00
jahongireshonqulov
ffbc153b55 feat:restaurants by category page done 2025-10-24 19:44:52 +05:00
jahongireshonqulov
e0f3d900d7 feat:filters done 2025-10-24 18:06:43 +05:00
jahongireshonqulov
f2ab615b4e feat: filters added to home page 2025-10-24 14:54:08 +05:00
140 changed files with 7558 additions and 186 deletions

View File

@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="food_delivery_client"
android:name="${applicationName}"

View File

@@ -0,0 +1,3 @@
<svg width="9" height="15" viewBox="0 0 9 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0H2.97391L9 7.5L2.97391 15H0L6.02609 7.5L0 0Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 175 B

View File

@@ -0,0 +1,3 @@
<svg width="22" height="18" viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.4469 9L14.5457 18H10.8296L16.6691 10.5H0V7.5H16.6691L10.8296 0H14.5457L21.4469 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 214 B

45
assets/icons/ic_carts.svg Normal file
View File

@@ -0,0 +1,45 @@
<svg width="177" height="176" viewBox="0 0 177 176" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_335_2606)">
<path d="M142.479 72.1698C146.691 66.6038 145.596 58.6778 140.032 54.4668C134.468 50.2558 126.542 51.3538 122.329 56.9208L109.553 73.7998C105.34 79.3658 106.436 87.2928 112 91.5038C117.564 95.7148 125.49 94.6158 129.703 89.0498L142.479 72.1698Z" fill="#A0BFF8"/>
<path d="M103.844 42.8671L88.4569 27.4801C87.9393 26.9626 87.2373 26.6719 86.5054 26.6719C85.7735 26.6719 85.0715 26.9626 84.5539 27.4801L69.1679 42.8671C68.6504 43.3847 68.3596 44.0867 68.3596 44.8186C68.3596 45.5506 68.6504 46.2526 69.1679 46.7701L84.5539 62.1571C85.0715 62.6747 85.7735 62.9654 86.5054 62.9654C87.2373 62.9654 87.9393 62.6747 88.4569 62.1571L103.844 46.7701C104.361 46.2526 104.652 45.5506 104.652 44.8186C104.652 44.0867 104.361 43.3847 103.844 42.8671Z" fill="#FFC043"/>
<path d="M95.0098 8.44C96.1291 8.43973 97.2023 7.99487 97.9935 7.20328C98.7848 6.41169 99.2291 5.33821 99.2288 4.219C99.2286 3.09979 98.7837 2.02652 97.9921 1.2353C97.2005 0.444086 96.1271 -0.000265098 95.0078 1.18655e-07C93.8886 1.18655e-07 92.8153 0.444606 92.0238 1.23601C91.2324 2.02741 90.7878 3.10079 90.7878 4.22C90.7878 5.33921 91.2324 6.41259 92.0238 7.20399C92.8153 7.99539 93.8886 8.44 95.0078 8.44H95.0098Z" fill="#05A357"/>
<path d="M106.169 36.6799C110.803 36.6799 114.559 32.9239 114.559 28.2899C114.559 23.6559 110.803 19.8999 106.169 19.8999C103.944 19.8999 101.81 20.7838 100.236 22.3573C98.6628 23.9307 97.7788 26.0647 97.7788 28.2899C97.7788 30.5151 98.6628 32.6491 100.236 34.2225C101.81 35.796 103.944 36.6799 106.169 36.6799Z" fill="#66D19E"/>
<path d="M119.741 121.93H56.3909L46.6309 74.0498H63.4209L126.961 79.5598C127.548 79.5976 128.12 79.7608 128.638 80.0384C129.156 80.3159 129.609 80.7014 129.966 81.1688C130.323 81.6358 130.576 82.1738 130.708 82.7465C130.84 83.3193 130.848 83.9137 130.731 84.4898L123.731 118.64C123.545 119.563 123.047 120.395 122.321 120.994C121.594 121.593 120.683 121.924 119.741 121.93Z" fill="#AB1300"/>
<path d="M133.81 121.93H73.1799L63.4199 74.0498L141.03 79.5598C141.617 79.5976 142.189 79.7608 142.707 80.0384C143.225 80.3159 143.678 80.7014 144.035 81.1688C144.392 81.6358 144.645 82.1738 144.777 82.7465C144.909 83.3193 144.917 83.9137 144.8 84.4898L137.8 118.64C137.614 119.563 137.116 120.395 136.39 120.994C135.663 121.593 134.752 121.924 133.81 121.93Z" fill="#E8503D"/>
<path d="M128.32 102.71C128.971 102.692 129.588 102.416 130.036 101.944C130.484 101.471 130.726 100.841 130.71 100.19V92.8999H125.93V100.19C125.914 100.841 126.157 101.471 126.605 101.943C127.053 102.415 127.669 102.691 128.32 102.71Z" fill="#FFD7D2"/>
<path d="M128.32 85.0698C127.669 85.0881 127.052 85.3637 126.604 85.836C126.156 86.3084 125.914 86.939 125.93 87.5898V92.8998H130.71V87.5898C130.727 86.9387 130.485 86.3075 130.037 85.8349C129.589 85.3623 128.971 85.0871 128.32 85.0698Z" fill="#F1998E"/>
<path d="M81.3898 102.71C82.0406 102.692 82.6575 102.416 83.1055 101.944C83.5535 101.471 83.7959 100.841 83.7798 100.19V92.8999H79.0098V100.19C79.0005 100.512 79.0547 100.832 79.1692 101.133C79.2838 101.434 79.4566 101.709 79.6776 101.943C79.8986 102.177 80.1636 102.365 80.4574 102.497C80.7512 102.628 81.068 102.701 81.3898 102.71Z" fill="#FFD7D2"/>
<path d="M81.3899 85.0698C81.068 85.0786 80.7511 85.1508 80.4571 85.2823C80.1632 85.4138 79.8981 85.602 79.6771 85.8361C79.456 86.0701 79.2833 86.3455 79.1688 86.6465C79.0543 86.9474 79.0003 87.268 79.0099 87.5898V92.8998H83.7799V87.5898C83.796 86.939 83.5535 86.3084 83.1055 85.836C82.6576 85.3637 82.0406 85.0881 81.3899 85.0698Z" fill="#F1998E"/>
<path d="M118.94 111.47C119.262 111.461 119.579 111.388 119.873 111.257C120.465 110.99 120.928 110.5 121.161 109.893C121.275 109.592 121.33 109.272 121.32 108.95V92.8999H116.52V108.95C116.513 109.275 116.569 109.597 116.687 109.9C116.804 110.203 116.98 110.479 117.205 110.714C117.43 110.948 117.699 111.135 117.997 111.265C118.295 111.394 118.615 111.464 118.94 111.47Z" fill="#FFD7D2"/>
<path d="M118.94 85.0698C118.289 85.0881 117.672 85.3637 117.224 85.836C116.776 86.3084 116.534 86.939 116.55 87.5898V92.8998H121.32V87.5898C121.329 87.268 121.275 86.9475 121.161 86.6466C121.046 86.3457 120.873 86.0704 120.652 85.8363C120.431 85.6023 120.166 85.4141 119.872 85.2826C119.579 85.1511 119.262 85.0788 118.94 85.0698Z" fill="#F1998E"/>
<path d="M109.52 111.47C110.171 111.452 110.788 111.176 111.236 110.704C111.684 110.231 111.926 109.601 111.91 108.95V92.8999H107.13V108.95C107.114 109.601 107.357 110.231 107.805 110.703C108.252 111.176 108.869 111.451 109.52 111.47Z" fill="#FFD7D2"/>
<path d="M109.52 85.0698C108.869 85.0881 108.252 85.3637 107.804 85.836C107.356 86.3084 107.114 86.939 107.13 87.5898V92.8998H111.91V87.5898C111.926 86.9391 111.683 86.3086 111.235 85.8363C110.787 85.364 110.171 85.0884 109.52 85.0698Z" fill="#F1998E"/>
<path d="M100.17 111.47C100.819 111.449 101.433 111.172 101.879 110.7C102.325 110.228 102.566 109.599 102.55 108.95V92.8999H97.7798V108.95C97.7637 109.601 98.0062 110.231 98.4541 110.704C98.9021 111.176 99.5191 111.452 100.17 111.47Z" fill="#FFD7D2"/>
<path d="M100.17 85.0698C99.5191 85.0881 98.9021 85.3637 98.4541 85.836C98.0062 86.3084 97.7637 86.939 97.7798 87.5898V92.8998H102.52V87.5898C102.535 86.9459 102.298 86.3215 101.859 85.8505C101.42 85.3794 100.813 85.0992 100.17 85.0698Z" fill="#F1998E"/>
<path d="M90.7799 111.47C91.4306 111.452 92.0476 111.176 92.4955 110.704C92.9435 110.231 93.186 109.601 93.1699 108.95V92.8999H88.3899V108.95C88.3743 109.601 88.6169 110.231 89.0648 110.703C89.5127 111.175 90.1293 111.451 90.7799 111.47Z" fill="#FFD7D2"/>
<path d="M90.7799 85.0698C90.1292 85.0881 89.5122 85.3637 89.0642 85.836C88.6163 86.3084 88.3738 86.939 88.3899 87.5898V92.8998H93.1699V87.5898C93.1861 86.939 92.9436 86.3084 92.4956 85.836C92.0476 85.3637 91.4307 85.0881 90.7799 85.0698Z" fill="#F1998E"/>
<path d="M72.8298 121.93L60.8298 65.59C60.4752 63.9325 59.5631 62.4466 58.2456 61.3802C56.9281 60.3138 55.2848 59.7314 53.5898 59.73H40.5198" stroke="#231F20" stroke-width="2.51" stroke-miterlimit="10"/>
<path d="M57.6098 121.93L45.6098 65.59C45.2551 63.9326 44.343 62.4468 43.0255 61.3804C41.708 60.3141 40.0648 59.7316 38.3698 59.73H30.8198" stroke="#231F20" stroke-width="2.51" stroke-miterlimit="10"/>
<path d="M121.011 121.86H61.3708C60.2604 121.86 59.1642 122.108 58.1617 122.586C57.1593 123.063 56.2759 123.758 55.5758 124.62C54.8769 125.483 54.3792 126.491 54.1189 127.57C53.8585 128.649 53.8421 129.773 54.0708 130.86C54.4189 132.538 55.3353 134.044 56.6653 135.124C57.9953 136.205 59.6573 136.793 61.3708 136.79H120.921" stroke="#231F20" stroke-width="2.51" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M71.0598 150.39C73.1815 150.39 75.2164 149.547 76.7167 148.047C78.217 146.547 79.0598 144.512 79.0598 142.39C79.0598 140.268 78.217 138.234 76.7167 136.733C75.2164 135.233 73.1815 134.39 71.0598 134.39C68.9381 134.39 66.9032 135.233 65.403 136.733C63.9027 138.234 63.0598 140.268 63.0598 142.39C63.0598 144.512 63.9027 146.547 65.403 148.047C66.9032 149.547 68.9381 150.39 71.0598 150.39Z" fill="#141414"/>
<path d="M70.9399 150.39H74.6099V134.4H70.9399V150.39Z" fill="#141414"/>
<path d="M74.6099 150.39C76.7316 150.39 78.7664 149.547 80.2667 148.047C81.767 146.547 82.6099 144.512 82.6099 142.39C82.6099 140.268 81.767 138.234 80.2667 136.733C78.7664 135.233 76.7316 134.39 74.6099 134.39C72.4881 134.39 70.4533 135.233 68.953 136.733C67.4527 138.234 66.6099 140.268 66.6099 142.39C66.6099 144.512 67.4527 146.547 68.953 148.047C70.4533 149.547 72.4881 150.39 74.6099 150.39Z" fill="#545454"/>
<path d="M74.6098 146.68C75.7476 146.68 76.8388 146.228 77.6433 145.424C78.4478 144.619 78.8998 143.528 78.8998 142.39C78.8998 141.252 78.4478 140.161 77.6433 139.357C76.8388 138.552 75.7476 138.1 74.6098 138.1C73.472 138.1 72.3809 138.552 71.5763 139.357C70.7718 140.161 70.3198 141.252 70.3198 142.39C70.3198 143.528 70.7718 144.619 71.5763 145.424C72.3809 146.228 73.472 146.68 74.6098 146.68Z" fill="#F6F6F6"/>
<path d="M71.3999 137.518L69.7249 139.194L77.2549 146.725L78.9309 145.049L71.3999 137.518Z" fill="#545454"/>
<path d="M123.42 150.39C125.542 150.39 127.576 149.547 129.077 148.047C130.577 146.547 131.42 144.512 131.42 142.39C131.42 140.268 130.577 138.234 129.077 136.733C127.576 135.233 125.542 134.39 123.42 134.39C121.298 134.39 119.263 135.233 117.763 136.733C116.263 138.234 115.42 140.268 115.42 142.39C115.42 144.512 116.263 146.547 117.763 148.047C119.263 149.547 121.298 150.39 123.42 150.39Z" fill="#141414"/>
<path d="M123.289 150.39H126.959V134.4H123.289V150.39Z" fill="#141414"/>
<path d="M126.959 150.39C129.081 150.39 131.116 149.547 132.616 148.047C134.116 146.547 134.959 144.512 134.959 142.39C134.959 140.268 134.116 138.234 132.616 136.733C131.116 135.233 129.081 134.39 126.959 134.39C124.837 134.39 122.802 135.233 121.302 136.733C119.802 138.234 118.959 140.268 118.959 142.39C118.959 144.512 119.802 146.547 121.302 148.047C122.802 149.547 124.837 150.39 126.959 150.39Z" fill="#545454"/>
<path d="M126.96 146.68C128.098 146.68 129.189 146.228 129.993 145.424C130.798 144.619 131.25 143.528 131.25 142.39C131.25 141.252 130.798 140.161 129.993 139.357C129.189 138.552 128.098 138.1 126.96 138.1C125.822 138.1 124.731 138.552 123.926 139.357C123.122 140.161 122.67 141.252 122.67 142.39C122.67 143.528 123.122 144.619 123.926 145.424C124.731 146.228 125.822 146.68 126.96 146.68Z" fill="#F6F6F6"/>
<path d="M123.764 137.514L122.088 139.19L129.619 146.721L131.294 145.045L123.764 137.514Z" fill="#545454"/>
<path d="M26.2999 63.1201H45.3699C46.9599 63.1201 48.2499 61.8331 48.2499 60.2451C48.2499 58.6571 46.9599 57.3701 45.3699 57.3701H26.2999C24.7099 57.3701 23.4199 58.6571 23.4199 60.2451C23.4199 61.8331 24.7099 63.1201 26.2999 63.1201Z" fill="#231F20"/>
<path d="M114.439 146.37C113.857 146.144 113.242 146.016 112.619 145.99C112.282 145.963 111.943 146.031 111.643 146.186C111.342 146.342 111.091 146.579 110.919 146.87C110.699 147.31 110.829 147.87 110.629 148.29C110.829 147.84 106.709 145.54 106.179 145.29C104.921 144.679 103.568 144.287 102.179 144.13C99.1789 143.82 96.9189 145.21 97.3589 148.45C93.8889 145.82 89.0489 142.32 84.5289 144.45C82.3289 145.45 80.9189 148.4 82.1989 150.45C85.0289 150.05 87.8789 150.77 90.6989 151.2C94.3659 151.675 98.0609 151.906 101.759 151.89L114.409 152.11C115.519 152.11 123.349 153.88 123.519 152.11C123.629 150.94 118.159 148.2 117.369 147.78C116.428 147.239 115.449 146.768 114.439 146.37ZM54.8299 138.09C53.8364 137.448 52.7302 137 51.5699 136.77C50.9876 136.666 50.389 136.702 49.8237 136.876C49.2584 137.05 48.7428 137.356 48.3199 137.77C47.9434 138.252 47.6789 138.811 47.5457 139.408C47.4126 140.005 47.414 140.624 47.5499 141.22C47.8199 142.404 48.1539 143.572 48.5499 144.72C45.3087 142.128 41.8415 139.832 38.1899 137.86C34.8399 136.06 31.1899 135.08 27.5799 133.76C23.9699 132.44 17.8999 131.59 16.8399 136.64C16.631 137.987 16.7758 139.365 17.2599 140.64C17.7345 142.086 18.455 143.439 19.3899 144.64C19.9399 145.41 21.8899 147.19 20.7699 148.19C19.6499 149.19 17.5399 147.39 16.5799 146.68C15.6199 145.97 14.3999 145.52 13.5799 146.62C13.0799 147.33 13.6799 148.26 13.1099 148.94C11.5999 150.73 7.86986 148.58 6.56986 147.54C5.965 146.95 5.26953 146.46 4.50986 146.09C4.12418 145.914 3.6898 145.877 3.27995 145.985C2.8701 146.092 2.50982 146.338 2.25986 146.68C1.25986 148.51 3.99986 151.06 5.47986 151.68C7.39986 152.45 9.64986 152.14 11.6599 152.14H63.1199C64.1199 152.14 68.1199 152.84 68.5399 151.51C68.8499 150.51 66.8499 148.85 66.3099 148.29C62.8099 144.53 59.3399 140.74 54.8299 138.09ZM34.5599 129.32C35.0797 129.32 35.5782 129.113 35.9456 128.745C36.3131 128.378 36.5195 127.879 36.5194 127.359C36.5192 126.84 36.3126 126.341 35.9449 125.974C35.5773 125.606 35.0787 125.4 34.5589 125.4C34.039 125.4 33.5405 125.606 33.1729 125.974C32.8054 126.342 32.5989 126.84 32.5989 127.36C32.5989 127.88 32.8054 128.378 33.1729 128.746C33.5405 129.113 34.039 129.32 34.5589 129.32H34.5599Z" fill="#D4E2FC"/>
<path d="M6.69999 119.32C7.21981 119.32 7.71835 119.113 8.08592 118.746C8.45349 118.378 8.65999 117.88 8.65999 117.36C8.65999 116.84 8.45349 116.342 8.08592 115.974C7.71835 115.606 7.21981 115.4 6.69999 115.4C6.18017 115.4 5.68163 115.606 5.31406 115.974C4.94649 116.342 4.73999 116.84 4.73999 117.36C4.73999 117.88 4.94649 118.378 5.31406 118.746C5.68163 119.113 6.18017 119.32 6.69999 119.32Z" fill="#5B91F5"/>
<path d="M2.12992 127.96C2.38731 127.96 2.64218 127.909 2.87998 127.811C3.11778 127.712 3.33385 127.568 3.51585 127.386C3.69785 127.204 3.84223 126.988 3.94073 126.75C4.03923 126.512 4.08992 126.257 4.08992 126C4.08992 125.743 4.03923 125.488 3.94073 125.25C3.84223 125.012 3.69785 124.796 3.51585 124.614C3.33385 124.432 3.11778 124.288 2.87998 124.189C2.64218 124.091 2.38731 124.04 2.12992 124.04C1.6101 124.04 1.11156 124.247 0.743993 124.614C0.376421 124.982 0.169922 125.48 0.169922 126C0.169922 126.52 0.376421 127.018 0.743993 127.386C1.11156 127.754 1.6101 127.96 2.12992 127.96Z" fill="#D4E2FC"/>
<path d="M176.82 150.38H2.8999V175.74H176.82V150.38Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_335_2606">
<rect width="177" height="176" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,3 @@
<svg width="19" height="13" viewBox="0 0 19 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 6.5L7.5 11.5L17.5 1.5" stroke="#4BA457" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 223 B

BIN
assets/icons/ic_clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

View File

@@ -0,0 +1,8 @@
<svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.7236 0.400391C20.0862 0.400391 23.5996 3.81531 23.5996 8C23.5996 12.1847 20.0862 15.5996 15.7236 15.5996C11.3612 15.5994 7.84863 12.1845 7.84863 8C7.84863 3.81546 11.3612 0.400637 15.7236 0.400391Z" stroke="black" stroke-width="0.8"/>
<line x1="0.827637" y1="5.19998" x2="7.44833" y2="5.19998" stroke="black" stroke-width="0.8"/>
<line x1="15.3241" y1="8" x2="15.3241" y2="1.6" stroke="black" stroke-width="0.8"/>
<line x1="2.48267" y1="10" x2="6.6206" y2="10" stroke="black" stroke-width="0.8"/>
<line y1="7.6" x2="6.62069" y2="7.6" stroke="black" stroke-width="0.8"/>
<path d="M19.9827 11.2972L14.8965 7.2" stroke="black" stroke-width="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 761 B

View File

@@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5 1.5L1.5 19.5" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.5 1.5L19.5 19.5" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 323 B

View File

@@ -0,0 +1,3 @@
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M25.3532 -1.17809e-05L17.0302 24.1971L12.8532 13.1168L-4.19789e-05 10.2697L25.3532 -1.17809e-05Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 225 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 6V3V0H16H7H6H4V6H0V19C0 21.7614 2.23858 24 5 24H19C21.7614 24 24 21.7614 24 19V6H19ZM7 3V6H16V3H7Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 271 B

View File

@@ -0,0 +1,5 @@
<svg width="23" height="21" viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.5174 3.10349C18.1037 3.10349 19.6554 5.06903 19.6554 7.44837C19.6554 8.68976 19.0347 9.82771 18.3106 10.6553C17.0692 11.8967 11.3795 16.5519 11.3795 16.5519C11.3795 16.5519 5.68973 11.8967 4.44833 10.6553C3.62073 9.82771 3.10349 8.68976 3.10349 7.44837C3.10349 5.06903 4.65523 3.10349 7.24147 3.10349C9.00011 3.10349 10.6553 4.75868 11.3795 6.20697C12.1036 4.75868 13.7588 3.10349 15.5174 3.10349ZM15.5174 0C13.9657 0 12.5174 0.620697 11.3795 1.44829C10.2415 0.517248 8.79321 0 7.24147 0C3.10349 0 0 3.20694 0 7.44837C0 9.41391 0.827596 11.276 2.27589 12.8277C3.72418 14.3795 11.3795 20.5865 11.3795 20.5865C11.3795 20.5865 19.0347 14.3795 20.483 12.8277C21.9313 11.276 22.7589 9.41391 22.7589 7.44837C22.7589 3.20694 19.6554 0 15.5174 0Z"
fill="#8A8A8A" />
</svg>

After

Width:  |  Height:  |  Size: 894 B

BIN
assets/icons/ic_eng.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

3
assets/icons/ic_gift.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="17" height="19" viewBox="0 0 17 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.208 1.84935e-06C5.908 1.84935e-06 6.55 0.267002 7.033 0.708002L8.333 1.892L9.633 0.708002C10.1312 0.251855 10.7825 -0.000788628 11.458 1.84935e-06C12.1759 0.00132267 12.864 0.287021 13.3717 0.794555C13.8795 1.30209 14.1654 1.99011 14.167 2.708C14.1657 3.22468 14.0184 3.73047 13.742 4.167H16.667V10H9.583V4.167H7.083V10H0V4.167H2.925C2.64861 3.73047 2.50127 3.22468 2.5 2.708C2.50158 1.99028 2.7874 1.30241 3.29491 0.794907C3.80241 0.287402 4.49028 0.00158681 5.208 1.84935e-06ZM7.083 12.5H0V18.333H7.083V12.5ZM9.583 18.333H16.667V12.5H9.583V18.333Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 721 B

3
assets/icons/ic_help.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.167 4.917C8.5 4.917 7.833 5.083 7.25 5.417L3.667 1.833C5.167 0.667 7.084 0 9.167 0C11.25 0 13.167 0.667 14.667 1.833L11.084 5.417C10.4992 5.08687 9.83855 4.91456 9.167 4.917ZM12.833 11C13.167 10.417 13.333 9.75 13.333 9.083C13.333 8.417 13.167 7.75 12.833 7.167L16.417 3.583C17.583 5.083 18.25 7 18.25 9.083C18.25 11.167 17.584 13.083 16.417 14.583L12.833 11ZM11.083 12.75C10.5 13.083 9.833 13.25 9.167 13.25C8.49545 13.2524 7.83483 13.0801 7.25 12.75L3.667 16.334C5.167 17.501 7.084 18.168 9.167 18.168C11.25 18.168 13.167 17.501 14.667 16.334L11.084 12.751L11.083 12.75ZM0.00100017 9.084C0.00100017 7.001 0.668 5.084 1.835 3.584L5.418 7.168C5.085 7.751 4.918 8.418 4.918 9.084C4.918 9.751 5.085 10.418 5.418 11.001L1.834 14.584C0.667 13.084 0 11.167 0 9.084H0.00100017Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 943 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><title>ionicons-v5-l</title><path d="M478.33,433.6l-90-218a22,22,0,0,0-40.67,0l-90,218a22,22,0,1,0,40.67,16.79L316.66,406H419.33l18.33,44.39A22,22,0,0,0,458,464a22,22,0,0,0,20.32-30.4ZM334.83,362,368,281.65,401.17,362Z"/><path d="M267.84,342.92a22,22,0,0,0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73,39.65-53.68,62.11-114.75,71.27-143.49H330a22,22,0,0,0,0-44H214V70a22,22,0,0,0-44,0V90H54a22,22,0,0,0,0,44H251.25c-9.52,26.95-27.05,69.5-53.79,108.36-31.41-41.68-43.08-68.65-43.17-68.87a22,22,0,0,0-40.58,17c.58,1.38,14.55,34.23,52.86,83.93.92,1.19,1.83,2.35,2.74,3.51-39.24,44.35-77.74,71.86-93.85,80.74a22,22,0,1,0,21.07,38.63c2.16-1.18,48.6-26.89,101.63-85.59,22.52,24.08,38,35.44,38.93,36.1a22,22,0,0,0,30.75-4.9Z"/></svg>

After

Width:  |  Height:  |  Size: 945 B

3
assets/icons/ic_like.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="22" height="20" viewBox="0 0 22 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 0C13.8 0 12.2 1.2 11 2.5C9.8 1.3 8.2 0 6 0C2.5 0 0 2.9 0 6.5C0 8.3 0.7 9.9 2 11L11 19.5L20 11C21.2 9.8 22 8.3 22 6.5C22 2.9 19.5 0 16 0Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 269 B

View File

@@ -0,0 +1,3 @@
<svg width="15" height="19" viewBox="0 0 15 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0V18.333L4.583 15.833L7.5 18.333L10.417 15.833L15 18.333V0H0ZM11.667 6.667H3.333V4.167H11.667V6.667Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -0,0 +1,3 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.333 18.333L18.333 8.333V0H10L0 10L8.333 18.333Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 179 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="black"/>
<path d="M12 4L13.7961 9.52786H19.6085L14.9062 12.9443L16.7023 18.4721L12 15.0557L7.29772 18.4721L9.09383 12.9443L4.39155 9.52786H10.2039L12 4Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 309 B

BIN
assets/icons/ic_rus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 16.25L14.3335 12.5833C15.2502 11.25 15.8333 9.6667 15.8333 7.9167C15.8333 3.58336 12.25 0 7.91665 0C3.58334 0 0 3.58336 0 7.9167C0 12.25 3.58334 15.8334 7.91665 15.8334C9.66665 15.8334 11.2501 15.25 12.5835 14.3333L16.25 18L18 16.25ZM2.5 8C2.5 5.00001 4.91667 2.58334 7.91665 2.58334C10.9166 2.58334 13.3333 5.00001 13.3333 8C13.3333 11 10.9166 13.4167 7.91665 13.4167C4.91667 13.4167 2.5 11 2.5 8Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 531 B

View File

@@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" fill="black"/>
<line x1="12" x2="12" y2="24" stroke="black" stroke-width="3"/>
<line y1="-1.5" x2="24" y2="-1.5" transform="matrix(1 0 0 -1 0 11.5)" stroke="black" stroke-width="3"/>
<line y1="-1.5" x2="24" y2="-1.5" transform="matrix(0.707107 -0.707107 -0.707107 -0.707107 3.5 19.9707)" stroke="black" stroke-width="3"/>
<line x1="19.9096" y1="21.0314" x2="2.93899" y2="4.0608" stroke="black" stroke-width="3"/>
<circle cx="12" cy="12" r="8" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H24V4.36328H22.1989C20.1906 4.36328 18.5625 5.99134 18.5625 7.99964C18.5625 10.008 20.1906 11.636 22.1989 11.636H24V16H0V11.636H1.80114C3.80945 11.636 5.4375 10.008 5.4375 7.99964C5.4375 5.99134 3.80945 4.36328 1.80114 4.36328H0V0Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 404 B

BIN
assets/icons/ic_uzb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.12 14H9.88L6.88 11H1V20H23V11H17.12L14.12 14Z" fill="black"/>
<path d="M1 4V8H8.12L11.12 11H12.88L15.88 8H23V4H1Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

View File

@@ -50,7 +50,135 @@
"ride": "Ride",
"chinese": "Chinese",
"dessert": "Dessert",
"more":"More"
"more":"More",
"orderDetails": "Order details",
"deliverNow": "Deliver now",
"schedule": "Schedule",
"enterNewAddress": "Enter a new address",
"nearby": "Nearby",
"currentLocation": "Current location",
"enable": "Enable",
"recentLocations": "Recent locations",
"allFilters": "All filters",
"sort": "Sort",
"pickedForYou": "Picked for you (default)",
"mostPopular": "Most popular",
"rating": "Rating",
"deliveryTime": "Delivery time",
"fromUberEats": "From Uber Eats",
"deals": "Deals",
"bestOverall": "Best overall",
"priceRange": "Price range",
"maxDeliveryFee": "Max. Delivery Fee",
"dietary": "Dietary",
"vegetarian": "Vegetarian",
"vegan": "Vegan",
"glutenFree": "Gluten-free",
"halal": "Halal",
"allergyFriendly": "Allergy friendly",
"atLeast":"At least",
"apply": "Apply",
"pickedForYouDefault": "Picked for you (default)",
"popular": "Most popular",
"topRated": "Top rated",
"fast": "Fast",
"delivery": "Delivery",
"featuredStores": "Featured stores",
"fromUberEats": "From {name}",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Opens at {time}",
"@opensAt": {
"placeholders":{
"time": {
"type": "String"
}
}
},
"spendAndSave": "Spend {spend}, save {save}",
"@spendAndSave": {
"placeholders":{
"spend": {
"type": "String"
},
"save": {
"type": "String"
}
}
},
"cartsTitle": "Carts",
"addItemsStartBasket": "Add items to start a basket",
"basketHint": "Once you add items from a restaurant or store, your basket will appear here.",
"startShopping": "Start Shopping",
"orders": "Orders",
"recentSearches": "Recent searches",
"cafe": "Cafe",
"irish": "Irish",
"topCategories": "Top Categories",
"breakfastAndBrunch": "Breakfast and Brunch",
"coffeeAndTea": "Coffee and Tea",
"chinese": "Chinese",
"indian": "Indian",
"latestDeals": "Latest Deals",
"restaurantRewards": "Restaurant Rewards",
"bestOverall": "Best Overall",
"nationwideShipping": "Nationwide Shipping",
"mexican": "Mexican",
"fastFood": "Fast Food",
"healthy": "Healthy",
"pizza": "Pizza",
"sandwich": "Sandwich",
"asian": "Asian",
"bakery": "Bakery",
"allCategories": "All categories",
"categoriesShort": "Food, shopping, drinks, etc.",
"yourFavourites": "Your favourites",
"restaurantRewards": "Restaurant Rewards",
"wallet": "Wallet",
"sendAGift": "Send a gift",
"businessPreferences": "Business preferences",
"businessSub": "Make work meals quicker and easier",
"help": "Help",
"promotions": "Promotions",
"uberPass": "Uber Pass",
"uberPassSub": "Join free for 1 month",
"deliverWithUber": "Deliver with Uber",
"settings": "Settings",
"home": "Home",
"browse": "Browse",
"baskets": "Baskets",
"account": "Account",
"changeLanguage": "Change language",
"language": "Language",
"login": "Login",
"phone_number": "Phone number",
"enter_phone_number": "Enter phone number",
"password": "Password",
"enter_password": "Enter password",
"forgot_password": "Forgot password",
"continue_str": "Continue",
"dont_have_account": "Don't have an account?",
"sign_up": "SignUp",
"field_cannot_be_empty": "This field cannot be empty",
"password_too_short": "Password must be at least 6 characters long",
"invalid_phone_format": "Invalid phone number format",
"first_name": "First name",
"enter_first_name": "Enter first name",
"repeat_password": "Repeat password",
"enter_repeat_password": "Enter repeat password",
"already_has_account": "Already have an account?",
"unexpected_error": "Unexpected error"
}

View File

@@ -57,6 +57,127 @@
"ride": "Поездка",
"chinese": "Китайская",
"dessert": "Десерт",
"more":"Ещё"
"more":"Ещё",
"orderDetails": "Детали заказа",
"deliverNow": "Доставить сейчас",
"schedule": "Запланировать",
"enterNewAddress": "Введите новый адрес",
"nearby": "Рядом",
"currentLocation": "Текущее местоположение",
"enable": "Включить",
"recentLocations": "Недавние адреса",
"allFilters": "Все фильтры",
"sort": "Сортировка",
"pickedForYou": "Подобрано для вас (по умолчанию)",
"mostPopular": "Самые популярные",
"rating": "Рейтинг",
"deliveryTime": "Время доставки",
"fromUberEats": "От Uber Eats",
"deals": "Скидки",
"bestOverall": "Лучший выбор",
"priceRange": "Диапазон цен",
"maxDeliveryFee": "Макс. стоимость доставки",
"dietary": "Диета",
"vegetarian": "Вегетарианское",
"vegan": "Веганское",
"glutenFree": "Без глютена",
"halal": "Халяль",
"allergyFriendly": "Без аллергенов",
"atLeast":"Kак минимум",
"apply": "Применить",
"pickedForYouDefault": "Выбрано для вас (по умолчанию)",
"popular": "Самые популярные",
"topRated": "Высокий рейтинг",
"fast": "Быстро",
"delivery": "Доставка",
"featuredStores": "Популярные магазины",
"fromUberEats": "От {name}",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Открывается в {time}",
"opensAt@placeholders": {
"time": {}
},
"spendAndSave": "Потратьте {spend}, сэкономьте {save}",
"spendAndSave@placeholders": {
"spend": {},
"save": {}
},
"cartsTitle": "Корзины",
"addItemsStartBasket": "Добавьте товары, чтобы создать корзину",
"basketHint": "Когда вы добавите товары из ресторана или магазина, ваша корзина появится здесь.",
"startShopping": "Начать покупки",
"orders": "Заказы",
"recentSearches": "Недавние запросы",
"cafe": "Кафе",
"irish": "Ирландская кухня",
"topCategories": "Популярные категории",
"breakfastAndBrunch": "Завтрак и бранч",
"coffeeAndTea": "Кофе и чай",
"chinese": "Китайская кухня",
"indian": "Индийская кухня",
"latestDeals": "Новые предложения",
"restaurantRewards": "Ресторанные бонусы",
"bestOverall": "Лучшие варианты",
"nationwideShipping": "Доставка по всей стране",
"mexican": "Мексиканская кухня",
"fastFood": "Фастфуд",
"healthy": "Здоровая еда",
"pizza": "Пицца",
"sandwich": "Сэндвич",
"asian": "Азиатская кухня",
"bakery": "Пекарня",
"categoriesShort": "Еда, покупки, напитки и т.д.",
"allCategories": "Все категории",
"yourFavourites": "Избранное",
"restaurantRewards": "Бонусы ресторанов",
"wallet": "Кошелёк",
"sendAGift": "Отправить подарок",
"businessPreferences": "Рабочие предпочтения",
"businessSub": "Сделайте рабочие обеды быстрее и проще",
"help": "Помощь",
"promotions": "Акции",
"uberPass": "Uber Pass",
"uberPassSub": "Присоединяйтесь бесплатно на 1 месяц",
"deliverWithUber": "Доставляйте с Uber",
"settings": "Настройки",
"home": "Главная",
"browse": "Категории",
"baskets": "Корзина",
"account": "Аккаунт",
"language": "Язык",
"changeLanguage": "Сменить язык",
"login": "Вход",
"phone_number": "Номер телефона",
"enter_phone_number": "Введите номер телефона",
"password": "Пароль",
"enter_password": "Введите пароль",
"forgot_password": "Забыли пароль",
"continue_str": "Продолжить",
"dont_have_account": "У вас нет аккаунта?",
"sign_up": "Зарегистрироваться",
"field_cannot_be_empty": "Это поле не может быть пустым",
"password_too_short": "Пароль не может быть короче 6 символов",
"invalid_phone_format": "Неверный формат номера телефона",
"first_name": "Имя",
"enter_first_name": "Введите имя",
"repeat_password": "Повторите пароль",
"enter_repeat_password": "Введите пароль ещё раз",
"already_has_account": "Уже есть аккаунт?",
"unexpected_error": "Неожиданная ошибка"
}

View File

@@ -57,5 +57,128 @@
"ride": "Yol",
"chinese": "Xitoy",
"dessert": "Desert",
"more":"Ko'proq"
"more":"Ko'proq",
"orderDetails": "Buyurtma tafsilotlari",
"deliverNow": "Hozir yetkazish",
"schedule": "Rejalashtirish",
"enterNewAddress": "Yangi manzil kiriting",
"nearby": "Yaqin joylar",
"currentLocation": "Joriy joylashuv",
"enable": "Yoqqish",
"recentLocations": "Yaqinda ishlatilgan manzillar",
"allFilters": "Barcha filtrlar",
"sort": "Saralash",
"pickedForYou": "Siz uchun",
"mostPopular": "Eng ommabop",
"rating": "Reyting",
"deliveryTime": "Yetkazib berish vaqti",
"fromUberEats": "Uber Eats dan",
"deals": "Aksiyalar",
"bestOverall": "Eng yaxshisi",
"priceRange": "Narx oraligi",
"maxDeliveryFee": "Maks. yetkazish narxi",
"dietary": "Parhez",
"vegetarian": "Vegetarian",
"vegan": "Vegan",
"glutenFree": "Glutensiz",
"halal": "Halol",
"allergyFriendly": "Allergiyaga mos",
"atLeast":"Kаmida",
"apply": "Qollash",
"pickedForYouDefault": "Siz uchun tanlangan (standart)",
"popular": "Eng ommabop",
"topRated": "Yuqori reytingli",
"fast": "Tezkor",
"delivery": "Yetkazish",
"featuredStores": "Mashhur dokonlar",
"fromUberEats": "{name} tomonidan",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Soat {time} dan ochiladi",
"opensAt@placeholders": {
"time": {}
},
"spendAndSave": "{spend} sarflang, {save} tejang",
"spendAndSave@placeholders": {
"spend": {},
"save": {}
},
"cartsTitle": "Savatlar",
"addItemsStartBasket": "Savatni boshlash uchun mahsulot qoshing",
"basketHint": "Restorandan yoki do'kondan mahsulot qoshsangiz, savatingiz shu yerda paydo boladi.",
"startShopping": "Xaridni boshlash",
"orders": "Buyurtmalar",
"recentSearches": "Yaqinda qidirilganlar",
"cafe": "Kafe",
"irish": "Irlandcha",
"topCategories": "Eng ommabop toifalar",
"breakfastAndBrunch": "Nonushta va bransh",
"coffeeAndTea": "Qahva va choy",
"chinese": "Xitoy taomlari",
"indian": "Hind taomlari",
"latestDeals": "Yangi chegirmalar",
"restaurantRewards": "Restoran mukofotlari",
"bestOverall": "Eng yaxshilari",
"nationwideShipping": "Butun mamlakat boylab yetkazib berish",
"mexican": "Meksika taomlari",
"fastFood": "Tezkor ovqatlar",
"healthy": "Soglom ovqatlar",
"pizza": "Pitsa",
"sandwich": "Sendvich",
"asian": "Osiyo taomlari",
"bakery": "Qandolatxona",
"categoriesShort": "Ovqat, xaridlar, ichimliklar va boshqalar.",
"allCategories": "Barcha toifalar",
"yourFavourites": "Sevimlilar",
"restaurantRewards": "Restoran bonuslari",
"wallet": "Hamyon",
"sendAGift": "Sovga yuborish",
"businessPreferences": "Biznes sozlamalari",
"businessSub": "Ishdagi ovqatlarni tezroq va osonroq qiling",
"help": "Yordam",
"promotions": "Aksiyalar",
"uberPass": "Uber Pass",
"uberPassSub": "1 oy bepul ulaning",
"deliverWithUber": "Uber bilan yetkazib bering",
"settings": "Sozlamalar",
"home": "Bosh sahifa",
"browse": "Kategoriya",
"baskets": "Savatcha",
"account": "Profil",
"language": "Til",
"changeLanguage": "Tilni o'zgartirish",
"login": "Kirish",
"phone_number": "Telefon raqami",
"enter_phone_number": "Telefon raqamingizni kiriting",
"password": "Parol",
"enter_password": "Parolni kiriting",
"forgot_password": "Parolni unutdingizmi",
"continue_str": "Davom etish",
"dont_have_account": "Hisobingiz yoqmi?",
"sign_up": "Royxatdan otish",
"field_cannot_be_empty": "Bu maydon bo'sh bo'lishi mumkin emas",
"password_too_short": "Parol 6 ta belgidan kam bo'lishi mumkin emas",
"invalid_phone_format": "Noto'g'ri telefon raqam formati",
"first_name": "Ism",
"enter_first_name": "Ismingizni kiriting",
"repeat_password": "Parolni takrorlang",
"enter_repeat_password": "Parolni qayta kiriting",
"already_has_account": "Akkountingiz bormi?",
"unexpected_error": "Kutilmagan xatolik"
}

View File

@@ -0,0 +1,5 @@
abstract class ApiConst {
static const String baseUrl = "https://superapp.felixits.uz/api/v1";
static const String login = "/auth/login";
}

View File

@@ -1,6 +1,8 @@
abstract class AppLocaleKeys {
///Storage keys
static const String language = 'language';
static const String browseSearchHistory = 'browse-search-history';
static const String token = 'token';
static const String fontBold = "fontBold";
static const String fontMedium = "fontMedium";
@@ -9,4 +11,14 @@ abstract class AppLocaleKeys {
static const String imageUrl =
"https://xsznseejebbai1lj.public.blob.vercel-storage.com/homepage/hero/hero-1.webp";
static const String foodImageUrl =
"https://www.precisionorthomd.com/wp-content/uploads/2023/10/percision-blog-header-junk-food-102323.jpg";
static const String lorem = '''Lorem Ipsum is simply dummy text of the
printing and typesetting industry. Lorem Ipsum
has been the industry's standard dummy text ever
since the 1500s, when an unknown printer took a
galley of type and scrambled it to make a type
specimen book''';
}

View File

@@ -2,3 +2,4 @@ export 'app_locale_keys.dart';
export 'sizes_consts.dart';
export 'l10n.dart';
export 'time_delay_cons.dart';
export 'api_const.dart';

View File

@@ -1,6 +1,7 @@
abstract class TimeDelayConst {
static const Duration durationMill150 = Duration(milliseconds: 150);
static const Duration durationMill300 = Duration(milliseconds: 300);
static const Duration durationMill800 = Duration(milliseconds: 800);
static const Duration durationMill3500 = Duration(milliseconds: 3500);
static const Duration duration3 = Duration(seconds: 3);
}

View File

@@ -12,3 +12,5 @@ export 'l10n/app_localizations_ru.dart';
export 'l10n/app_localizations_uz.dart';
export 'services/services.dart';
export 'utils/app_utils.dart';
export 'exceptions/exceptions.dart';
export 'exceptions/failure.dart';

View File

@@ -9,9 +9,18 @@
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:dio/dio.dart' as _i361;
import 'package:get_it/get_it.dart' as _i174;
import 'package:injectable/injectable.dart' as _i526;
import '../../feature/auth/data/datasource/auth_datasource.dart' as _i246;
import '../../feature/auth/domain/repository/auth_repository.dart' as _i884;
import '../../feature/auth/domain/usecases/login_usecase.dart' as _i241;
import '../../feature/auth/presentation/blocs/login_bloc/login_bloc.dart'
as _i1065;
import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728;
import '../../feature/browse/presentation/blocs/browse_bloc/browse_bloc.dart'
as _i991;
import '../../feature/common/presentation/blocs/language_bloc/language_bloc.dart'
as _i942;
import '../../feature/home/presentation/blocs/home_bloc/home_bloc.dart'
@@ -21,7 +30,9 @@ import '../../feature/main/presentation/blocs/main_bloc/main_bloc.dart'
import '../../feature/on_boarding/presentation/blocs/splash_bloc/splash_bloc.dart'
as _i311;
import '../../food_delivery_client.dart' as _i321;
import '../network/dio_client.dart' as _i667;
import '../router/app_routes.dart' as _i152;
import '../services/request_handler_service.dart' as _i354;
import '../services/storage_service.dart' as _i306;
extension GetItInjectableX on _i174.GetIt {
@@ -31,14 +42,42 @@ extension GetItInjectableX on _i174.GetIt {
_i526.EnvironmentFilter? environmentFilter,
}) {
final gh = _i526.GetItHelper(this, environment, environmentFilter);
final dioModule = _$DioModule();
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
gh.factory<_i580.MainBloc>(() => _i580.MainBloc());
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
gh.singleton<_i306.StorageService>(() => _i306.StorageService());
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
gh.lazySingleton<_i667.DioClient>(() => _i667.DioClient());
gh.factory<_i942.LanguageBloc>(
() => _i942.LanguageBloc(gh<_i321.StorageService>()),
);
gh.lazySingleton<_i361.Dio>(() => dioModule.dio(gh<_i667.DioClient>()));
gh.singleton<_i354.RequestHandlerService>(
() => _i354.RequestHandlerService(gh<_i361.Dio>()),
);
gh.lazySingleton<_i246.AuthDatasource>(
() => _i246.AuthDatasourceImpl(gh<_i354.RequestHandlerService>()),
);
gh.lazySingleton<_i884.AuthRepository>(
() => _i884.AuthRepositoryImpl(
gh<_i354.RequestHandlerService>(),
gh<_i246.AuthDatasource>(),
),
);
gh.factory<_i241.LoginUseCase>(
() => _i241.LoginUseCase(gh<_i884.AuthRepository>()),
);
gh.factory<_i1065.LoginBloc>(
() => _i1065.LoginBloc(
gh<_i241.LoginUseCase>(),
gh<_i321.StorageService>(),
),
);
return this;
}
}
class _$DioModule extends _i667.DioModule {}

View File

@@ -0,0 +1,32 @@
import 'package:dio/dio.dart';
class ServerException implements Exception {
final String errorMessage;
final String errorKey;
final num statusCode;
const ServerException({
required this.statusCode,
required this.errorMessage,
required this.errorKey,
});
@override
String toString() {
return 'ServerException(statusCode: $statusCode, errorMessage: $errorMessage, errorKey: $errorKey)';
}
}
class CustomDioException implements Exception {
final String errorMessage;
final DioExceptionType type;
final int? statusCode;
CustomDioException({required this.errorMessage, required this.type, this.statusCode});
}
class ParsingException implements Exception {
final String errorMessage;
const ParsingException({required this.errorMessage});
}

View File

@@ -0,0 +1,44 @@
import 'package:equatable/equatable.dart';
import 'package:dio/dio.dart';
class Failure extends Equatable {
final String? errorMessage;
final String? errorKey;
const Failure({
this.errorMessage,
this.errorKey,
}); //error key kere bomasa required qilish shartamas
@override
List<Object?> get props => [
errorMessage,
errorKey,
];
}
class ServerFailure extends Failure {
final num statusCode;
const ServerFailure({
required super.errorMessage,
required this.statusCode,
required super.errorKey,
});
}
class DioFailure extends Failure {
final DioExceptionType type;
final int? statusCode;
const DioFailure({
required super.errorMessage,
this.type = DioExceptionType.badResponse,
this.statusCode,
});
}
class ParsingFailure extends Failure {
const ParsingFailure({required super.errorMessage});
}
class CacheFailure extends Failure {}

View File

@@ -0,0 +1,31 @@
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
abstract class Formatters {
static final phoneFormatter = MaskTextInputFormatter(
mask: '## ### ## ##',
filter: {"#": RegExp(r'[0-9]')},
type: MaskAutoCompletionType.lazy,
);
static final cardFormatter = MaskTextInputFormatter(
mask: '#### #### #### ####',
filter: {"#": RegExp(r'[0-9]')},
type: MaskAutoCompletionType.lazy,
);
static final cardNumberFormatter = MaskTextInputFormatter(
mask: '#### #### #### ####',
filter: {"#": RegExp(r'[0-9]')},
type: MaskAutoCompletionType.lazy,
);
static final cardExpirationDateFormatter = MaskTextInputFormatter(
mask: '##/##',
filter: {"#": RegExp(r'[0-9]')},
type: MaskAutoCompletionType.lazy,
);
static final moneyFormatter = MaskTextInputFormatter(
mask: '########',
filter: {"#": RegExp(r'[0-9]')},
type: MaskAutoCompletionType.lazy,
);
}

View File

@@ -0,0 +1,28 @@
import 'package:food_delivery_client/core/core.dart';
abstract class Validators {
static String? validatePhoneNumber(String phoneNumber) {
if (phoneNumber.isEmpty) {
return navigatorKey.currentContext?.loc.field_cannot_be_empty;
} else if (phoneNumber.length < 12) {
return navigatorKey.currentContext?.loc.invalid_phone_format;
}
return null;
}
static String? validatePassword(String password) {
if (password.isEmpty) {
return navigatorKey.currentContext?.loc.field_cannot_be_empty;
} else if (password.length < 6) {
return navigatorKey.currentContext?.loc.password_too_short;
}
return null;
}
static String? validateFields(String value) {
if (value.isEmpty) {
return navigatorKey.currentContext?.loc.field_cannot_be_empty;
}
return null;
}
}

View File

@@ -327,6 +327,540 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'More'**
String get more;
/// No description provided for @orderDetails.
///
/// In en, this message translates to:
/// **'Order details'**
String get orderDetails;
/// No description provided for @deliverNow.
///
/// In en, this message translates to:
/// **'Deliver now'**
String get deliverNow;
/// No description provided for @schedule.
///
/// In en, this message translates to:
/// **'Schedule'**
String get schedule;
/// No description provided for @enterNewAddress.
///
/// In en, this message translates to:
/// **'Enter a new address'**
String get enterNewAddress;
/// No description provided for @nearby.
///
/// In en, this message translates to:
/// **'Nearby'**
String get nearby;
/// No description provided for @currentLocation.
///
/// In en, this message translates to:
/// **'Current location'**
String get currentLocation;
/// No description provided for @enable.
///
/// In en, this message translates to:
/// **'Enable'**
String get enable;
/// No description provided for @recentLocations.
///
/// In en, this message translates to:
/// **'Recent locations'**
String get recentLocations;
/// No description provided for @allFilters.
///
/// In en, this message translates to:
/// **'All filters'**
String get allFilters;
/// No description provided for @sort.
///
/// In en, this message translates to:
/// **'Sort'**
String get sort;
/// No description provided for @pickedForYou.
///
/// In en, this message translates to:
/// **'Picked for you (default)'**
String get pickedForYou;
/// No description provided for @mostPopular.
///
/// In en, this message translates to:
/// **'Most popular'**
String get mostPopular;
/// No description provided for @rating.
///
/// In en, this message translates to:
/// **'Rating'**
String get rating;
/// No description provided for @deliveryTime.
///
/// In en, this message translates to:
/// **'Delivery time'**
String get deliveryTime;
/// No description provided for @fromUberEats.
///
/// In en, this message translates to:
/// **'From {name}'**
String fromUberEats(String name);
/// No description provided for @deals.
///
/// In en, this message translates to:
/// **'Deals'**
String get deals;
/// No description provided for @bestOverall.
///
/// In en, this message translates to:
/// **'Best Overall'**
String get bestOverall;
/// No description provided for @priceRange.
///
/// In en, this message translates to:
/// **'Price range'**
String get priceRange;
/// No description provided for @maxDeliveryFee.
///
/// In en, this message translates to:
/// **'Max. Delivery Fee'**
String get maxDeliveryFee;
/// No description provided for @dietary.
///
/// In en, this message translates to:
/// **'Dietary'**
String get dietary;
/// No description provided for @vegetarian.
///
/// In en, this message translates to:
/// **'Vegetarian'**
String get vegetarian;
/// No description provided for @vegan.
///
/// In en, this message translates to:
/// **'Vegan'**
String get vegan;
/// No description provided for @glutenFree.
///
/// In en, this message translates to:
/// **'Gluten-free'**
String get glutenFree;
/// No description provided for @allergyFriendly.
///
/// In en, this message translates to:
/// **'Allergy friendly'**
String get allergyFriendly;
/// No description provided for @atLeast.
///
/// In en, this message translates to:
/// **'At least'**
String get atLeast;
/// No description provided for @apply.
///
/// In en, this message translates to:
/// **'Apply'**
String get apply;
/// No description provided for @pickedForYouDefault.
///
/// In en, this message translates to:
/// **'Picked for you (default)'**
String get pickedForYouDefault;
/// No description provided for @popular.
///
/// In en, this message translates to:
/// **'Most popular'**
String get popular;
/// No description provided for @topRated.
///
/// In en, this message translates to:
/// **'Top rated'**
String get topRated;
/// No description provided for @fast.
///
/// In en, this message translates to:
/// **'Fast'**
String get fast;
/// No description provided for @featuredStores.
///
/// In en, this message translates to:
/// **'Featured stores'**
String get featuredStores;
/// No description provided for @opensAt.
///
/// In en, this message translates to:
/// **'Opens at {time}'**
String opensAt(String time);
/// No description provided for @spendAndSave.
///
/// In en, this message translates to:
/// **'Spend {spend}, save {save}'**
String spendAndSave(String spend, String save);
/// No description provided for @cartsTitle.
///
/// In en, this message translates to:
/// **'Carts'**
String get cartsTitle;
/// No description provided for @addItemsStartBasket.
///
/// In en, this message translates to:
/// **'Add items to start a basket'**
String get addItemsStartBasket;
/// No description provided for @basketHint.
///
/// In en, this message translates to:
/// **'Once you add items from a restaurant or store, your basket will appear here.'**
String get basketHint;
/// No description provided for @startShopping.
///
/// In en, this message translates to:
/// **'Start Shopping'**
String get startShopping;
/// No description provided for @orders.
///
/// In en, this message translates to:
/// **'Orders'**
String get orders;
/// No description provided for @recentSearches.
///
/// In en, this message translates to:
/// **'Recent searches'**
String get recentSearches;
/// No description provided for @cafe.
///
/// In en, this message translates to:
/// **'Cafe'**
String get cafe;
/// No description provided for @irish.
///
/// In en, this message translates to:
/// **'Irish'**
String get irish;
/// No description provided for @topCategories.
///
/// In en, this message translates to:
/// **'Top Categories'**
String get topCategories;
/// No description provided for @breakfastAndBrunch.
///
/// In en, this message translates to:
/// **'Breakfast and Brunch'**
String get breakfastAndBrunch;
/// No description provided for @coffeeAndTea.
///
/// In en, this message translates to:
/// **'Coffee and Tea'**
String get coffeeAndTea;
/// No description provided for @latestDeals.
///
/// In en, this message translates to:
/// **'Latest Deals'**
String get latestDeals;
/// No description provided for @restaurantRewards.
///
/// In en, this message translates to:
/// **'Restaurant Rewards'**
String get restaurantRewards;
/// No description provided for @nationwideShipping.
///
/// In en, this message translates to:
/// **'Nationwide Shipping'**
String get nationwideShipping;
/// No description provided for @mexican.
///
/// In en, this message translates to:
/// **'Mexican'**
String get mexican;
/// No description provided for @fastFood.
///
/// In en, this message translates to:
/// **'Fast Food'**
String get fastFood;
/// No description provided for @healthy.
///
/// In en, this message translates to:
/// **'Healthy'**
String get healthy;
/// No description provided for @pizza.
///
/// In en, this message translates to:
/// **'Pizza'**
String get pizza;
/// No description provided for @sandwich.
///
/// In en, this message translates to:
/// **'Sandwich'**
String get sandwich;
/// No description provided for @bakery.
///
/// In en, this message translates to:
/// **'Bakery'**
String get bakery;
/// No description provided for @categoriesShort.
///
/// In en, this message translates to:
/// **'Food, shopping, drinks, etc.'**
String get categoriesShort;
/// No description provided for @yourFavourites.
///
/// In en, this message translates to:
/// **'Your favourites'**
String get yourFavourites;
/// No description provided for @wallet.
///
/// In en, this message translates to:
/// **'Wallet'**
String get wallet;
/// No description provided for @sendAGift.
///
/// In en, this message translates to:
/// **'Send a gift'**
String get sendAGift;
/// No description provided for @businessPreferences.
///
/// In en, this message translates to:
/// **'Business preferences'**
String get businessPreferences;
/// No description provided for @businessSub.
///
/// In en, this message translates to:
/// **'Make work meals quicker and easier'**
String get businessSub;
/// No description provided for @help.
///
/// In en, this message translates to:
/// **'Help'**
String get help;
/// No description provided for @promotions.
///
/// In en, this message translates to:
/// **'Promotions'**
String get promotions;
/// No description provided for @uberPass.
///
/// In en, this message translates to:
/// **'Uber Pass'**
String get uberPass;
/// No description provided for @uberPassSub.
///
/// In en, this message translates to:
/// **'Join free for 1 month'**
String get uberPassSub;
/// No description provided for @deliverWithUber.
///
/// In en, this message translates to:
/// **'Deliver with Uber'**
String get deliverWithUber;
/// No description provided for @settings.
///
/// In en, this message translates to:
/// **'Settings'**
String get settings;
/// No description provided for @home.
///
/// In en, this message translates to:
/// **'Home'**
String get home;
/// No description provided for @browse.
///
/// In en, this message translates to:
/// **'Browse'**
String get browse;
/// No description provided for @baskets.
///
/// In en, this message translates to:
/// **'Baskets'**
String get baskets;
/// No description provided for @account.
///
/// In en, this message translates to:
/// **'Account'**
String get account;
/// No description provided for @changeLanguage.
///
/// In en, this message translates to:
/// **'Change language'**
String get changeLanguage;
/// No description provided for @language.
///
/// In en, this message translates to:
/// **'Language'**
String get language;
/// No description provided for @login.
///
/// In en, this message translates to:
/// **'Login'**
String get login;
/// No description provided for @phone_number.
///
/// In en, this message translates to:
/// **'Phone number'**
String get phone_number;
/// No description provided for @enter_phone_number.
///
/// In en, this message translates to:
/// **'Enter phone number'**
String get enter_phone_number;
/// No description provided for @password.
///
/// In en, this message translates to:
/// **'Password'**
String get password;
/// No description provided for @enter_password.
///
/// In en, this message translates to:
/// **'Enter password'**
String get enter_password;
/// No description provided for @forgot_password.
///
/// In en, this message translates to:
/// **'Forgot password'**
String get forgot_password;
/// No description provided for @continue_str.
///
/// In en, this message translates to:
/// **'Continue'**
String get continue_str;
/// No description provided for @dont_have_account.
///
/// In en, this message translates to:
/// **'Don\'t have an account?'**
String get dont_have_account;
/// No description provided for @sign_up.
///
/// In en, this message translates to:
/// **'SignUp'**
String get sign_up;
/// No description provided for @field_cannot_be_empty.
///
/// In en, this message translates to:
/// **'This field cannot be empty'**
String get field_cannot_be_empty;
/// No description provided for @password_too_short.
///
/// In en, this message translates to:
/// **'Password must be at least 6 characters long'**
String get password_too_short;
/// No description provided for @invalid_phone_format.
///
/// In en, this message translates to:
/// **'Invalid phone number format'**
String get invalid_phone_format;
/// No description provided for @first_name.
///
/// In en, this message translates to:
/// **'First name'**
String get first_name;
/// No description provided for @enter_first_name.
///
/// In en, this message translates to:
/// **'Enter first name'**
String get enter_first_name;
/// No description provided for @repeat_password.
///
/// In en, this message translates to:
/// **'Repeat password'**
String get repeat_password;
/// No description provided for @enter_repeat_password.
///
/// In en, this message translates to:
/// **'Enter repeat password'**
String get enter_repeat_password;
/// No description provided for @already_has_account.
///
/// In en, this message translates to:
/// **'Already have an account?'**
String get already_has_account;
/// No description provided for @unexpected_error.
///
/// In en, this message translates to:
/// **'Unexpected error'**
String get unexpected_error;
}
class _AppLocalizationsDelegate

View File

@@ -126,4 +126,279 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get more => 'More';
@override
String get orderDetails => 'Order details';
@override
String get deliverNow => 'Deliver now';
@override
String get schedule => 'Schedule';
@override
String get enterNewAddress => 'Enter a new address';
@override
String get nearby => 'Nearby';
@override
String get currentLocation => 'Current location';
@override
String get enable => 'Enable';
@override
String get recentLocations => 'Recent locations';
@override
String get allFilters => 'All filters';
@override
String get sort => 'Sort';
@override
String get pickedForYou => 'Picked for you (default)';
@override
String get mostPopular => 'Most popular';
@override
String get rating => 'Rating';
@override
String get deliveryTime => 'Delivery time';
@override
String fromUberEats(String name) {
return 'From $name';
}
@override
String get deals => 'Deals';
@override
String get bestOverall => 'Best Overall';
@override
String get priceRange => 'Price range';
@override
String get maxDeliveryFee => 'Max. Delivery Fee';
@override
String get dietary => 'Dietary';
@override
String get vegetarian => 'Vegetarian';
@override
String get vegan => 'Vegan';
@override
String get glutenFree => 'Gluten-free';
@override
String get allergyFriendly => 'Allergy friendly';
@override
String get atLeast => 'At least';
@override
String get apply => 'Apply';
@override
String get pickedForYouDefault => 'Picked for you (default)';
@override
String get popular => 'Most popular';
@override
String get topRated => 'Top rated';
@override
String get fast => 'Fast';
@override
String get featuredStores => 'Featured stores';
@override
String opensAt(String time) {
return 'Opens at $time';
}
@override
String spendAndSave(String spend, String save) {
return 'Spend $spend, save $save';
}
@override
String get cartsTitle => 'Carts';
@override
String get addItemsStartBasket => 'Add items to start a basket';
@override
String get basketHint =>
'Once you add items from a restaurant or store, your basket will appear here.';
@override
String get startShopping => 'Start Shopping';
@override
String get orders => 'Orders';
@override
String get recentSearches => 'Recent searches';
@override
String get cafe => 'Cafe';
@override
String get irish => 'Irish';
@override
String get topCategories => 'Top Categories';
@override
String get breakfastAndBrunch => 'Breakfast and Brunch';
@override
String get coffeeAndTea => 'Coffee and Tea';
@override
String get latestDeals => 'Latest Deals';
@override
String get restaurantRewards => 'Restaurant Rewards';
@override
String get nationwideShipping => 'Nationwide Shipping';
@override
String get mexican => 'Mexican';
@override
String get fastFood => 'Fast Food';
@override
String get healthy => 'Healthy';
@override
String get pizza => 'Pizza';
@override
String get sandwich => 'Sandwich';
@override
String get bakery => 'Bakery';
@override
String get categoriesShort => 'Food, shopping, drinks, etc.';
@override
String get yourFavourites => 'Your favourites';
@override
String get wallet => 'Wallet';
@override
String get sendAGift => 'Send a gift';
@override
String get businessPreferences => 'Business preferences';
@override
String get businessSub => 'Make work meals quicker and easier';
@override
String get help => 'Help';
@override
String get promotions => 'Promotions';
@override
String get uberPass => 'Uber Pass';
@override
String get uberPassSub => 'Join free for 1 month';
@override
String get deliverWithUber => 'Deliver with Uber';
@override
String get settings => 'Settings';
@override
String get home => 'Home';
@override
String get browse => 'Browse';
@override
String get baskets => 'Baskets';
@override
String get account => 'Account';
@override
String get changeLanguage => 'Change language';
@override
String get language => 'Language';
@override
String get login => 'Login';
@override
String get phone_number => 'Phone number';
@override
String get enter_phone_number => 'Enter phone number';
@override
String get password => 'Password';
@override
String get enter_password => 'Enter password';
@override
String get forgot_password => 'Forgot password';
@override
String get continue_str => 'Continue';
@override
String get dont_have_account => 'Don\'t have an account?';
@override
String get sign_up => 'SignUp';
@override
String get field_cannot_be_empty => 'This field cannot be empty';
@override
String get password_too_short =>
'Password must be at least 6 characters long';
@override
String get invalid_phone_format => 'Invalid phone number format';
@override
String get first_name => 'First name';
@override
String get enter_first_name => 'Enter first name';
@override
String get repeat_password => 'Repeat password';
@override
String get enter_repeat_password => 'Enter repeat password';
@override
String get already_has_account => 'Already have an account?';
@override
String get unexpected_error => 'Unexpected error';
}

View File

@@ -90,7 +90,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get takeout => 'На вынос';
@override
String get asian => 'Азиатская';
String get asian => 'Азиатская кухня';
@override
String get iceCream => 'Мороженое';
@@ -105,7 +105,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get caribbean => 'Карибская';
@override
String get indian => 'Индийская';
String get indian => 'Индийская кухня';
@override
String get french => 'Французская';
@@ -120,11 +120,285 @@ class AppLocalizationsRu extends AppLocalizations {
String get ride => 'Поездка';
@override
String get chinese => 'Китайская';
String get chinese => 'Китайская кухня';
@override
String get dessert => 'Десерт';
@override
String get more => 'Ещё';
@override
String get orderDetails => 'Детали заказа';
@override
String get deliverNow => 'Доставить сейчас';
@override
String get schedule => 'Запланировать';
@override
String get enterNewAddress => 'Введите новый адрес';
@override
String get nearby => 'Рядом';
@override
String get currentLocation => 'Текущее местоположение';
@override
String get enable => 'Включить';
@override
String get recentLocations => 'Недавние адреса';
@override
String get allFilters => 'Все фильтры';
@override
String get sort => 'Сортировка';
@override
String get pickedForYou => 'Подобрано для вас (по умолчанию)';
@override
String get mostPopular => 'Самые популярные';
@override
String get rating => 'Рейтинг';
@override
String get deliveryTime => 'Время доставки';
@override
String fromUberEats(String name) {
return 'От $name';
}
@override
String get deals => 'Скидки';
@override
String get bestOverall => 'Лучшие варианты';
@override
String get priceRange => 'Диапазон цен';
@override
String get maxDeliveryFee => 'Макс. стоимость доставки';
@override
String get dietary => 'Диета';
@override
String get vegetarian => 'Вегетарианское';
@override
String get vegan => 'Веганское';
@override
String get glutenFree => 'Без глютена';
@override
String get allergyFriendly => 'Без аллергенов';
@override
String get atLeast => 'Kак минимум';
@override
String get apply => 'Применить';
@override
String get pickedForYouDefault => 'Выбрано для вас (по умолчанию)';
@override
String get popular => 'Самые популярные';
@override
String get topRated => 'Высокий рейтинг';
@override
String get fast => 'Быстро';
@override
String get featuredStores => 'Популярные магазины';
@override
String opensAt(String time) {
return 'Открывается в $time';
}
@override
String spendAndSave(String spend, String save) {
return 'Потратьте $spend, сэкономьте $save';
}
@override
String get cartsTitle => 'Корзины';
@override
String get addItemsStartBasket => 'Добавьте товары, чтобы создать корзину';
@override
String get basketHint =>
'Когда вы добавите товары из ресторана или магазина, ваша корзина появится здесь.';
@override
String get startShopping => 'Начать покупки';
@override
String get orders => 'Заказы';
@override
String get recentSearches => 'Недавние запросы';
@override
String get cafe => 'Кафе';
@override
String get irish => 'Ирландская кухня';
@override
String get topCategories => 'Популярные категории';
@override
String get breakfastAndBrunch => 'Завтрак и бранч';
@override
String get coffeeAndTea => 'Кофе и чай';
@override
String get latestDeals => 'Новые предложения';
@override
String get restaurantRewards => 'Бонусы ресторанов';
@override
String get nationwideShipping => 'Доставка по всей стране';
@override
String get mexican => 'Мексиканская кухня';
@override
String get fastFood => 'Фастфуд';
@override
String get healthy => 'Здоровая еда';
@override
String get pizza => 'Пицца';
@override
String get sandwich => 'Сэндвич';
@override
String get bakery => 'Пекарня';
@override
String get categoriesShort => 'Еда, покупки, напитки и т.д.';
@override
String get yourFavourites => 'Избранное';
@override
String get wallet => 'Кошелёк';
@override
String get sendAGift => 'Отправить подарок';
@override
String get businessPreferences => 'Рабочие предпочтения';
@override
String get businessSub => 'Сделайте рабочие обеды быстрее и проще';
@override
String get help => 'Помощь';
@override
String get promotions => 'Акции';
@override
String get uberPass => 'Uber Pass';
@override
String get uberPassSub => 'Присоединяйтесь бесплатно на 1 месяц';
@override
String get deliverWithUber => 'Доставляйте с Uber';
@override
String get settings => 'Настройки';
@override
String get home => 'Главная';
@override
String get browse => 'Категории';
@override
String get baskets => 'Корзина';
@override
String get account => 'Аккаунт';
@override
String get changeLanguage => 'Сменить язык';
@override
String get language => 'Язык';
@override
String get login => 'Вход';
@override
String get phone_number => 'Номер телефона';
@override
String get enter_phone_number => 'Введите номер телефона';
@override
String get password => 'Пароль';
@override
String get enter_password => 'Введите пароль';
@override
String get forgot_password => 'Забыли пароль';
@override
String get continue_str => 'Продолжить';
@override
String get dont_have_account => 'У вас нет аккаунта?';
@override
String get sign_up => 'Зарегистрироваться';
@override
String get field_cannot_be_empty => 'Это поле не может быть пустым';
@override
String get password_too_short => 'Пароль не может быть короче 6 символов';
@override
String get invalid_phone_format => 'Неверный формат номера телефона';
@override
String get first_name => 'Имя';
@override
String get enter_first_name => 'Введите имя';
@override
String get repeat_password => 'Повторите пароль';
@override
String get enter_repeat_password => 'Введите пароль ещё раз';
@override
String get already_has_account => 'Уже есть аккаунт?';
@override
String get unexpected_error => 'Неожиданная ошибка';
}

View File

@@ -54,7 +54,7 @@ class AppLocalizationsUz extends AppLocalizations {
}
@override
String get delivery => 'Yetkazib berish';
String get delivery => 'Yetkazish';
@override
String get pickUp => 'Olib ketish';
@@ -90,7 +90,7 @@ class AppLocalizationsUz extends AppLocalizations {
String get takeout => 'Olib ketish';
@override
String get asian => 'Osiyo';
String get asian => 'Osiyo taomlari';
@override
String get iceCream => 'Muzqaymoq';
@@ -105,7 +105,7 @@ class AppLocalizationsUz extends AppLocalizations {
String get caribbean => 'Karib';
@override
String get indian => 'Hind';
String get indian => 'Hind taomlari';
@override
String get french => 'Fransuz';
@@ -120,11 +120,286 @@ class AppLocalizationsUz extends AppLocalizations {
String get ride => 'Yol';
@override
String get chinese => 'Xitoy';
String get chinese => 'Xitoy taomlari';
@override
String get dessert => 'Desert';
@override
String get more => 'Ko\'proq';
@override
String get orderDetails => 'Buyurtma tafsilotlari';
@override
String get deliverNow => 'Hozir yetkazish';
@override
String get schedule => 'Rejalashtirish';
@override
String get enterNewAddress => 'Yangi manzil kiriting';
@override
String get nearby => 'Yaqin joylar';
@override
String get currentLocation => 'Joriy joylashuv';
@override
String get enable => 'Yoqqish';
@override
String get recentLocations => 'Yaqinda ishlatilgan manzillar';
@override
String get allFilters => 'Barcha filtrlar';
@override
String get sort => 'Saralash';
@override
String get pickedForYou => 'Siz uchun';
@override
String get mostPopular => 'Eng ommabop';
@override
String get rating => 'Reyting';
@override
String get deliveryTime => 'Yetkazib berish vaqti';
@override
String fromUberEats(String name) {
return '$name tomonidan';
}
@override
String get deals => 'Aksiyalar';
@override
String get bestOverall => 'Eng yaxshilari';
@override
String get priceRange => 'Narx oraligi';
@override
String get maxDeliveryFee => 'Maks. yetkazish narxi';
@override
String get dietary => 'Parhez';
@override
String get vegetarian => 'Vegetarian';
@override
String get vegan => 'Vegan';
@override
String get glutenFree => 'Glutensiz';
@override
String get allergyFriendly => 'Allergiyaga mos';
@override
String get atLeast => 'Kаmida';
@override
String get apply => 'Qollash';
@override
String get pickedForYouDefault => 'Siz uchun tanlangan (standart)';
@override
String get popular => 'Eng ommabop';
@override
String get topRated => 'Yuqori reytingli';
@override
String get fast => 'Tezkor';
@override
String get featuredStores => 'Mashhur dokonlar';
@override
String opensAt(String time) {
return 'Soat $time dan ochiladi';
}
@override
String spendAndSave(String spend, String save) {
return '$spend sarflang, $save tejang';
}
@override
String get cartsTitle => 'Savatlar';
@override
String get addItemsStartBasket => 'Savatni boshlash uchun mahsulot qoshing';
@override
String get basketHint =>
'Restorandan yoki do\'kondan mahsulot qoshsangiz, savatingiz shu yerda paydo boladi.';
@override
String get startShopping => 'Xaridni boshlash';
@override
String get orders => 'Buyurtmalar';
@override
String get recentSearches => 'Yaqinda qidirilganlar';
@override
String get cafe => 'Kafe';
@override
String get irish => 'Irlandcha';
@override
String get topCategories => 'Eng ommabop toifalar';
@override
String get breakfastAndBrunch => 'Nonushta va bransh';
@override
String get coffeeAndTea => 'Qahva va choy';
@override
String get latestDeals => 'Yangi chegirmalar';
@override
String get restaurantRewards => 'Restoran bonuslari';
@override
String get nationwideShipping => 'Butun mamlakat boylab yetkazib berish';
@override
String get mexican => 'Meksika taomlari';
@override
String get fastFood => 'Tezkor ovqatlar';
@override
String get healthy => 'Soglom ovqatlar';
@override
String get pizza => 'Pitsa';
@override
String get sandwich => 'Sendvich';
@override
String get bakery => 'Qandolatxona';
@override
String get categoriesShort => 'Ovqat, xaridlar, ichimliklar va boshqalar.';
@override
String get yourFavourites => 'Sevimlilar';
@override
String get wallet => 'Hamyon';
@override
String get sendAGift => 'Sovga yuborish';
@override
String get businessPreferences => 'Biznes sozlamalari';
@override
String get businessSub => 'Ishdagi ovqatlarni tezroq va osonroq qiling';
@override
String get help => 'Yordam';
@override
String get promotions => 'Aksiyalar';
@override
String get uberPass => 'Uber Pass';
@override
String get uberPassSub => '1 oy bepul ulaning';
@override
String get deliverWithUber => 'Uber bilan yetkazib bering';
@override
String get settings => 'Sozlamalar';
@override
String get home => 'Bosh sahifa';
@override
String get browse => 'Kategoriya';
@override
String get baskets => 'Savatcha';
@override
String get account => 'Profil';
@override
String get changeLanguage => 'Tilni o\'zgartirish';
@override
String get language => 'Til';
@override
String get login => 'Kirish';
@override
String get phone_number => 'Telefon raqami';
@override
String get enter_phone_number => 'Telefon raqamingizni kiriting';
@override
String get password => 'Parol';
@override
String get enter_password => 'Parolni kiriting';
@override
String get forgot_password => 'Parolni unutdingizmi';
@override
String get continue_str => 'Davom etish';
@override
String get dont_have_account => 'Hisobingiz yoqmi?';
@override
String get sign_up => 'Royxatdan otish';
@override
String get field_cannot_be_empty => 'Bu maydon bo\'sh bo\'lishi mumkin emas';
@override
String get password_too_short =>
'Parol 6 ta belgidan kam bo\'lishi mumkin emas';
@override
String get invalid_phone_format => 'Noto\'g\'ri telefon raqam formati';
@override
String get first_name => 'Ism';
@override
String get enter_first_name => 'Ismingizni kiriting';
@override
String get repeat_password => 'Parolni takrorlang';
@override
String get enter_repeat_password => 'Parolni qayta kiriting';
@override
String get already_has_account => 'Akkountingiz bormi?';
@override
String get unexpected_error => 'Kutilmagan xatolik';
}

View File

@@ -0,0 +1,38 @@
import 'package:dio/dio.dart';
import 'package:food_delivery_client/core/network/header_interceptors.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
import 'error_handler_interceptor.dart';
@module
abstract class DioModule {
@lazySingleton
Dio dio(DioClient dioClient) => dioClient.dio;
}
@lazySingleton
class DioClient {
final BaseOptions _dioBaseOptions = BaseOptions(
baseUrl: ApiConst.baseUrl,
connectTimeout: TimeDelayConst.durationMill3500,
receiveTimeout: TimeDelayConst.durationMill3500,
followRedirects: false,
validateStatus: (status) => status != null && status >= 200 && status < 300,
);
Dio get dio {
final Dio dio = Dio(_dioBaseOptions);
dio.interceptors
..add(HeaderInterceptors())
..add(ErrorHandlerInterceptors())
..add(
LogInterceptor(
requestHeader: true,
requestBody: true,
responseBody: true,
error: true,
request: true,
),
);
return dio;
}
}

View File

@@ -0,0 +1,41 @@
import 'package:dio/dio.dart';
import '../../feature/common/data/models/error_model.dart';
class ErrorHandlerInterceptors extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.response != null && err.response!.statusCode != null) {
if (err.response?.data is String) {
final errorMessage = err.response?.data as String?;
final error = ErrorModel(
detail: errorMessage?.replaceAll(RegExp(r'<[^>]+>'), '') ?? '',
);
handler.next(
DioException(
requestOptions: err.requestOptions,
response: Response(
requestOptions: err.requestOptions,
data: error.toJson(),
),
),
);
return;
} else {
handler.next(err);
return;
}
}
const error = ErrorModel(detail: "");
handler.next(
DioException(
requestOptions: err.requestOptions,
response: Response(
requestOptions: err.requestOptions,
data: error.toJson(),
),
),
);
return;
}
}

View File

@@ -0,0 +1,17 @@
import 'package:dio/dio.dart';
class HeaderInterceptors extends Interceptor {
HeaderInterceptors._internal();
static final HeaderInterceptors _interceptors =
HeaderInterceptors._internal();
factory HeaderInterceptors() {
return _interceptors;
}
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
handler.next(options);
}
}

View File

@@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:food_delivery_client/feature/home/presentation/pages/categories_page/categories_page.dart';
import 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';
import 'package:food_delivery_client/feature/auth/presentation/pages/forgot_password_page/forgot_password_page.dart';
import 'package:food_delivery_client/feature/auth/presentation/pages/login_page/login_page.dart';
import 'package:food_delivery_client/feature/auth/presentation/pages/register_page/register_page.dart';
import 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/restaurants_by_category_page.dart';
import '../../food_delivery_client.dart';
@@ -11,9 +13,23 @@ class AppRoutes {
final GoRouter router = GoRouter(
navigatorKey: navigatorKey,
initialLocation: Routes.splash,
routes: [
GoRoute(path: Routes.splash, builder: (context, state) => SplashPage()),
GoRoute(
path: Routes.login,
pageBuilder: (context, state) => CupertinoPage(child: LoginPage()),
),
GoRoute(
path: Routes.register,
pageBuilder: (context, state) => CupertinoPage(child: RegisterPage()),
),
GoRoute(
path: Routes.forgotPassword,
pageBuilder: (context, state) =>
CupertinoPage(child: ForgotPasswordPage()),
),
GoRoute(
path: Routes.main,
pageBuilder: (context, state) => CupertinoPage(child: MainPage()),
@@ -22,6 +38,22 @@ class AppRoutes {
path: Routes.categories,
pageBuilder: (context, state) => CupertinoPage(child: CategoriesPage()),
),
GoRoute(
path: Routes.filters,
pageBuilder: (context, state) => CupertinoPage(
child: FiltersPage(homeBloc: state.extra as HomeBloc),
),
),
GoRoute(
path: Routes.restaurantsByCategory,
pageBuilder: (context, state) => CupertinoPage(
child: RestaurantsByCategoryPage(categoryName: state.extra as String),
),
),
GoRoute(
path: Routes.browse,
pageBuilder: (context, state) => CupertinoPage(child: BrowsePage()),
),
],
);
}

View File

@@ -4,5 +4,8 @@ abstract class Routes {
static const String register = '/register';
static const String main = '/main';
static const String categories = '/categories';
static const String filters = '/filters';
static const String browse = '/browse';
static const String forgotPassword = "/forgot-password";
static const String restaurantsByCategory = '/restaurants-by-category';
}

View File

@@ -0,0 +1,76 @@
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
import '../../feature/common/data/models/error_model.dart';
enum RequestMethodEnum { get, post, put, delete, patch }
@singleton
class RequestHandlerService {
final Dio dio;
const RequestHandlerService(this.dio);
Future<T> handleRequest<T>({
required Future<T> Function(Response) fromJson,
required String path,
RequestMethodEnum? method,
Options? options,
Map<String, dynamic>? queryParameters,
Object? data,
Dio? newDio,
}) async {
try {
final response = await (newDio ?? dio).request(
path,
options:
options ??
Options(method: method?.name ?? RequestMethodEnum.get.name),
queryParameters: queryParameters,
data: data,
);
final result = fromJson.call(response);
return result;
} on DioException catch (e) {
final errorResponse = ErrorModel.fromJson(e.response?.data);
throw CustomDioException(
errorMessage: errorResponse.detail,
type: e.type,
statusCode: e.response?.statusCode,
);
} on ParsingException {
rethrow;
} on Exception catch (e) {
throw ParsingException(errorMessage: e.toString());
} catch (e) {
throw ParsingException(errorMessage: e.toString());
}
}
Future<Either<Failure, T>> handleRequestInRepository<T>({
required Future<T> Function() onRequest,
String debugLabel = '',
}) async {
try {
final result = await onRequest.call();
return Right(result);
} on ParsingException catch (e) {
log("ParsingException in $debugLabel: ${e.errorMessage}");
return Left(ParsingFailure(errorMessage: e.errorMessage));
} on CustomDioException catch (e) {
log("CustomDioException in $debugLabel: ${e.errorMessage}");
return Left(
DioFailure(
errorMessage: e.errorMessage,
type: e.type,
statusCode: e.statusCode,
),
);
} on Exception catch (e) {
log("Exception in $debugLabel: ${e.toString()}");
return Left(ParsingFailure(errorMessage: e.toString()));
}
}
}

View File

@@ -12,6 +12,16 @@ class StorageService {
_sharedPreference.setString(key, value);
}
void setStringList({required String key, required String value}) {
final oldList = _sharedPreference.getStringList(key);
final newList = oldList?..add(value);
_sharedPreference.setStringList(key, newList ?? []);
}
List<String> getStringList({required String key}) {
return _sharedPreference.getStringList(key) ?? [];
}
String? getString({required String key}) {
return _sharedPreference.getString(key);
}

View File

@@ -3,6 +3,7 @@ import '../../food_delivery_client.dart';
abstract class AppColors {
static const Color cTransparent = Colors.transparent;
static const Color cRed = Colors.red;
static const Color cYellow = Colors.yellow;
static const Color cFFFFFF = Color(0xFFFFFFFF);
static const Color c000000 = Color(0xFF000000);
@@ -19,5 +20,11 @@ abstract class AppColors {
static const Color cC99EE2 = Color(0xFFC99EE2);
static const Color cE29EC7 = Color(0xFFE29EC7);
static const Color c545454 = Color(0xFF545454);
static const Color cEFF3FE = Color(0xFFEFF3FE);
static const Color c05A357 = Color(0xFF05A357);
static const Color cE8E8E8 = Color(0xFFE8E8E8);
static const Color c660000 = Color(0x66000000);
static const Color c6A6E7F = Color(0xFF6A6E7F);
static const Color c7F7F7F = Color(0xFF7F7F7F);
}

View File

@@ -13,6 +13,7 @@ abstract class AppIcons {
static const String icAccountActive = "$baseUrl/ic_account_active.svg";
static const String icBack = "$baseUrl/ic_back.svg";
static const String icDislike = "$baseUrl/ic_dislike.svg";
static const String icDislikeGrey = "$baseUrl/ic_dislike_grey.svg";
static const String icEat = "$baseUrl/ic_eat.svg";
static const String icEye = "$baseUrl/ic_eye.svg";
static const String icFilter = "$baseUrl/ic_filter.svg";
@@ -22,6 +23,42 @@ abstract class AppIcons {
static const String icUber = "$baseUrl/ic_uber.svg";
static const String icLocation = "$baseUrl/ic_location.svg";
static const String icArrowBottom = "$baseUrl/ic_arrow_btm.svg";
static const String icEmptyBasket = "$baseUrl/ic_empty_basket.svg";
static const String icPicked = "$baseUrl/ic_picked.svg";
static const String icMostPopular = "$baseUrl/ic_popular.svg";
static const String icStar = "$baseUrl/ic_rating.svg";
static const String icDeliveryTime = "$baseUrl/ic_delivery_time.svg";
static const String icDeals = "$baseUrl/ic_deals.svg";
static const String icClose = "$baseUrl/ic_close.svg";
static const String icCurrentLocation = "$baseUrl/ic_current_loc.svg";
static const String icEdit = "$baseUrl/ic_edit.svg";
static const String icSearch = "$baseUrl/ic_search.svg";
static const String icCheck = "$baseUrl/ic_check.svg";
static const String icCheck1 = "$baseUrl/ic_check1.svg";
static const String icArrowRight = "$baseUrl/ic_arrow_right.svg";
static const String icDeliver = "$baseUrl/ic_deliver.svg";
static const String icGift = "$baseUrl/ic_gift.svg";
static const String icHelp = "$baseUrl/ic_help.svg";
static const String icLike = "$baseUrl/ic_like.svg";
static const String icPromotions = "$baseUrl/ic_promotions.svg";
static const String icSettings = "$baseUrl/ic_settings.svg";
static const String icRewards = "$baseUrl/ic_rewards.svg";
static const String icUberPass = "$baseUrl/ic_uber_pass.svg";
static const String icWallet = "$baseUrl/ic_wallet.svg";
static const String icOrdersSvg = "$baseUrl/ic_orders_svg.svg";
static const String icLanguage = "$baseUrl/ic_language.svg";
static const String icArrowRightLight = "$baseUrl/ic_arrow_right_light.svg";
///.png icons
static const String icBestOverall = "$baseUrl/ic_best.png";
static const String icVegetarian = "$baseUrl/ic_vegetarian.png";
static const String icVegen = "$baseUrl/ic_vegen.png";
static const String icGlutenFree = "$baseUrl/ic_gluten_free.png";
static const String icAllergyFriendly = "$baseUrl/ic_allergy_friendly.png";
static const String icClock = "$baseUrl/ic_clock.svg";
static const String icOrders = "$baseUrl/ic_orders.png";
static const String icUz = "$baseUrl/ic_uzb.png";
static const String icRu = "$baseUrl/ic_rus.png";
static const String icEn = "$baseUrl/ic_eng.png";
}

View File

@@ -22,6 +22,6 @@ abstract class AppImages {
static const String imgChinese = "$baseUrl/img_chinese.png";
static const String imgDesert = "$baseUrl/img_desert.png";
static const String imgPickUp = "$baseUrl/img_pick_up.png";
static const String imgAvatar = "$baseUrl/img_avatar.jpg";
static const String imgBurger2 = "$baseUrl/img_burger2.png";
}

View File

@@ -28,6 +28,13 @@ abstract class AppTextStyles {
fontWeight: FontWeight.w400,
);
static const TextStyle size16Regular = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_16,
fontFamily: _fontRegular,
fontWeight: FontWeight.w400,
);
static const TextStyle size20Regular = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_20,
@@ -63,6 +70,40 @@ abstract class AppTextStyles {
fontWeight: FontWeight.w500,
);
static const TextStyle size20Medium = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_20,
fontFamily: _fontMedium,
fontWeight: FontWeight.w500,
);
static const TextStyle size24Medium = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_24,
fontFamily: _fontMedium,
fontWeight: FontWeight.w500,
);
static const TextStyle size14Bold= TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_14,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size15Bold= TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_15,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size16Bold= TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_16,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size17Bold = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_17,
@@ -76,6 +117,20 @@ abstract class AppTextStyles {
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size30Bold = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_30,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size36Bold = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_36,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
}
/*

View File

@@ -3,6 +3,18 @@ import '../../food_delivery_client.dart';
abstract class AppTheme {
static ThemeData get lightTheme => ThemeData.light().copyWith(
brightness: Brightness.light,
// colorScheme: ColorScheme(
// brightness: Brightness.light,
// primary: AppColors.cFFFFFF,
// onPrimary:AppColors.cFFFFFF,
// secondary: AppColors.cFFFFFF,
// onSecondary: AppColors.cFFFFFF,
// error:AppColors.cRed,
// onError: AppColors.cRed,
// surface: AppColors.cFFFFFF,
// onSurface: AppColors.cFFFFFF,
// ),
appBarTheme: AppBarTheme(
elevation: 0,
backgroundColor: AppColors.cFFFFFF,
@@ -10,6 +22,20 @@ abstract class AppTheme {
surfaceTintColor: AppColors.cTransparent,
),
scaffoldBackgroundColor: AppColors.cFFFFFF,
progressIndicatorTheme: ProgressIndicatorThemeData(
color: AppColors.cFFFFFF,
circularTrackColor: AppColors.cFFFFFF,
linearTrackColor: AppColors.cFFFFFF,
borderRadius: BorderRadiusGeometry.circular(30),
),
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
},
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
elevation: 0,
showSelectedLabels: true,

View File

@@ -0,0 +1,15 @@
import 'package:dartz/dartz.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
mixin UseCase<Type, Params> {
Future<Either<Failure, Type>> call(Params params);
}
mixin StreamUseCase<Type, Params> {
Stream<Either<Failure, Type>> call(Params params);
}
class NoParams extends Equatable {
@override
List<Object?> get props => [];
}

View File

@@ -1,6 +1,8 @@
import '../../food_delivery_client.dart';
abstract class AppUtils {
static const SizedBox kSizedBox = SizedBox.shrink();
static const Radius kRadius = Radius.zero;
static const Radius kRadius8 = Radius.circular(8);
static const Radius kRadius12 = Radius.circular(12);
@@ -11,6 +13,7 @@ abstract class AppUtils {
static const Radius kRadius22 = Radius.circular(22);
static const Radius kRadius24 = Radius.circular(24);
static const Radius kRadius25 = Radius.circular(25);
static const Radius kRadius30 = Radius.circular(30);
static const BorderRadius kBorderRadius = BorderRadius.zero;
static const BorderRadius kBorderRadius2 = BorderRadius.all(
Radius.circular(2),
@@ -36,6 +39,9 @@ abstract class AppUtils {
static const BorderRadius kBorderRadius14 = BorderRadius.all(
Radius.circular(14),
);
static const BorderRadius kBorderRadius15 = BorderRadius.all(
Radius.circular(15),
);
static const BorderRadius kBorderRadius16 = BorderRadius.all(
Radius.circular(16),
);
@@ -79,6 +85,19 @@ abstract class AppUtils {
static const BorderRadius kBorderRadius40 = BorderRadius.all(
Radius.circular(40),
);
static const BorderRadius kBorderRadiusTop15 = BorderRadius.only(
topLeft: kRadius15,
topRight: kRadius15,
);
static const BorderRadius kBorderRadiusTop20 = BorderRadius.only(
topLeft: kRadius20,
topRight: kRadius20,
);
static const BorderRadius kBorderRadiusTop30 = BorderRadius.only(
topLeft: kRadius30,
topRight: kRadius30,
);
static const BorderRadius kBorderRadiusTop20Bottom20 = BorderRadius.only(
bottomRight: kRadius20,
topRight: kRadius20,
@@ -87,4 +106,8 @@ abstract class AppUtils {
bottomRight: kRadius15,
topRight: kRadius15,
);
static const BorderRadius kBorderRadiusBottom15 = BorderRadius.only(
bottomLeft: kRadius15,
bottomRight: kRadius15,
);
}

View File

@@ -0,0 +1,21 @@
import '../../../../core/theme/app_icons.dart';
mixin AccountMixins {
final List<String> leadingIcons = [
AppIcons.icOrdersSvg,
AppIcons.icLike,
AppIcons.icRewards,
AppIcons.icWallet,
AppIcons.icGift,
AppIcons.icHelp,
AppIcons.icPromotions,
AppIcons.icUberPass,
AppIcons.icDeliver,
AppIcons.icLanguage,
AppIcons.icSettings,
];
final List<String> flags = [AppIcons.icEn, AppIcons.icUz, AppIcons.icRu];
final List<String> languages = ["English", "O'zbekcha", "Русский"];
}

View File

@@ -1,3 +1,5 @@
import 'package:food_delivery_client/feature/account/presentation/pages/account_page/widgets/w_account_body.dart';
import '../../../../../food_delivery_client.dart';
class AccountPage extends StatelessWidget {
@@ -5,38 +7,7 @@ class AccountPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) {
return WLayout(
child: Scaffold(
body: Center(
child: Column(
children: [
Text(context.loc.iCantSignIn),
TextButton(
onPressed: () {
if (state.currentLocale == Locale("uz")) {
context.read<LanguageBloc>().add(
LanguageEvent.changed(Locale('ru')),
);
} else if (state.currentLocale == Locale("ru")) {
context.read<LanguageBloc>().add(
LanguageEvent.changed(Locale('en')),
);
} else {
context.read<LanguageBloc>().add(
LanguageEvent.changed(Locale('uz')),
);
}
},
child: Text("changelang"),
),
],
),
),
),
);
},
);
return WAccountBody();
}
}

View File

@@ -0,0 +1,208 @@
import 'package:food_delivery_client/feature/account/presentation/mixins/account_mixins.dart';
import '../../../../../../food_delivery_client.dart';
class WAccountBody extends StatelessWidget with AccountMixins {
WAccountBody({super.key});
@override
Widget build(BuildContext context) {
final List<String> titles = [
context.loc.orders,
context.loc.yourFavourites,
context.loc.restaurantRewards,
context.loc.wallet,
context.loc.sendAGift,
context.loc.help,
context.loc.promotions,
context.loc.uberPass,
context.loc.deliverWithUber,
context.loc.changeLanguage,
context.loc.settings,
];
return WLayout(
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(56),
child: WAccountAppBar().paddingSymmetric(horizontal: 19),
),
body: LayoutBuilder(
builder: (context, constraints) => ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: ListView.builder(
shrinkWrap: true,
itemCount: leadingIcons.length,
padding: EdgeInsets.symmetric(vertical:5),
physics: const AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemBuilder: (context, index) => WAccountRowItem(
onTap: () {
if (index == 9) {
WChangeLanguage().show(context);
}
},
svgPath: leadingIcons[index],
title: titles[index],
),
),
),
),
),
);
}
}
class WAccountAppBar extends StatelessWidget {
const WAccountAppBar({super.key});
@override
Widget build(BuildContext context) {
return AppBar(
centerTitle: false,
leading: ClipRRect(
borderRadius: AppUtils.kBorderRadius40,
child: SizedBox(
child: Image.asset(
AppImages.imgAvatar,
height: 36,
width: 36,
fit: BoxFit.cover,
),
),
).paddingAll(8),
title: Text('Felix', style: AppTextStyles.size18Medium),
);
}
}
class WAccountRowItem extends StatelessWidget {
const WAccountRowItem({
super.key,
required this.svgPath,
required this.title,
this.subTitle,
this.leadingIcon,
required this.onTap,
});
final String svgPath;
final String title;
final String? subTitle;
final Widget? leadingIcon;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Ink(
child: Row(
spacing: 24,
mainAxisAlignment: MainAxisAlignment.start,
children: [
leadingIcon ??
SizedBox(
height: 24,
width: 24,
child: SvgPicture.asset(svgPath),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppTextStyles.size14Medium),
if (subTitle != null)
Text(
subTitle!,
style: AppTextStyles.size14Medium.copyWith(
color: AppColors.c34A853,
),
),
],
),
],
).paddingSymmetric(vertical: 16, horizontal: 22),
),
);
}
}
class WChangeLanguage extends StatelessWidget with AccountMixins {
WChangeLanguage({super.key});
show(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) => Wrap(children: [this]),
);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) {
return Material(
color: AppColors.cFFFFFF,
borderRadius: AppUtils.kBorderRadiusTop20,
child: SizedBox(
width: context.w,
child: SafeArea(
child: Column(
children: [
10.verticalSpace,
SizedBox(
height: 6,
width: 100,
child: DecoratedBox(
decoration: BoxDecoration(
color: AppColors.cEEEEEE,
borderRadius: AppUtils.kBorderRadius8,
),
),
),
10.verticalSpace,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
context.loc.changeLanguage,
style: AppTextStyles.size20Medium,
),
IconButton(
onPressed: () {
context.pop();
},
icon: SvgPicture.asset(AppIcons.icClose),
),
],
).paddingSymmetric(horizontal: 16),
15.verticalSpace,
Column(
children: List.generate(3, (index) {
return AppListTile(
onPressed: () {
context.read<LanguageBloc>().add(
LanguageEvent.changed(L10n.locales[index]),
);
},
isSelected: L10n.locales[index] == state.currentLocale,
svgPath: '',
leading: SizedBox(
height: 24,
width: 24,
child: Image.asset(flags[index]),
),
title: languages[index],
titleTextStyle: AppTextStyles.size14Medium,
);
}),
),
10.verticalSpace
],
),
),
),
);
},
);
}
}

View File

@@ -0,0 +1,30 @@
import 'package:food_delivery_client/core/services/request_handler_service.dart';
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
abstract class AuthDatasource {
Future<LoginResponseModel> login({
required String phoneNumber,
required String password,
});
}
@LazySingleton(as: AuthDatasource)
class AuthDatasourceImpl implements AuthDatasource {
final RequestHandlerService _requestHandlerService;
AuthDatasourceImpl(this._requestHandlerService);
@override
Future<LoginResponseModel> login({
required String phoneNumber,
required String password,
}) async {
return _requestHandlerService.handleRequest(
path: ApiConst.login,
method: RequestMethodEnum.post,
data: {"password": password, "phoneNumber": phoneNumber},
fromJson: (response) async => LoginResponseModel.fromJson(response.data),
);
}
}

View File

@@ -0,0 +1,26 @@
import 'package:equatable/equatable.dart';
class LoginResponseModel extends Equatable {
final String token;
const LoginResponseModel({required this.token});
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
return LoginResponseModel(
token: json['token'] as String,
);
}
Map<String, dynamic> toJson() => {
'token': token,
};
LoginResponseModel copyWith({String? token}) {
return LoginResponseModel(
token: token ?? this.token,
);
}
@override
List<Object?> get props => [token];
}

View File

@@ -0,0 +1,35 @@
import 'package:dartz/dartz.dart';
import 'package:food_delivery_client/core/services/request_handler_service.dart';
import 'package:food_delivery_client/feature/auth/data/datasource/auth_datasource.dart';
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
abstract class AuthRepository {
Future<Either<Failure, LoginResponseModel>> login({
required String phoneNumber,
required String password,
});
}
@LazySingleton(as: AuthRepository)
class AuthRepositoryImpl implements AuthRepository {
final RequestHandlerService _requestHandlerService;
final AuthDatasource _authDatasource;
AuthRepositoryImpl(this._requestHandlerService, this._authDatasource);
@override
Future<Either<Failure, LoginResponseModel>> login({
required String phoneNumber,
required String password,
}) async {
return _requestHandlerService.handleRequestInRepository(
onRequest: () async {
return _authDatasource.login(
phoneNumber: phoneNumber,
password: password,
);
},
);
}
}

View File

@@ -0,0 +1,26 @@
import 'package:dartz/dartz.dart';
import 'package:food_delivery_client/core/usecase/usecase.dart';
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
import 'package:food_delivery_client/feature/auth/domain/repository/auth_repository.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
@injectable
class LoginUseCase implements UseCase<LoginResponseModel, LoginParams> {
final AuthRepository _authRepository;
LoginUseCase(this._authRepository);
@override
Future<Either<Failure, LoginResponseModel>> call(LoginParams params) async {
return _authRepository.login(
phoneNumber: params.phoneNumber,
password: params.password,
);
}
}
class LoginParams {
final String phoneNumber;
final String password;
LoginParams({required this.phoneNumber, required this.password});
}

View File

@@ -0,0 +1,41 @@
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
import 'package:food_delivery_client/feature/common/presentation/widgets/w_toastification.dart';
import 'package:food_delivery_client/food_delivery_client.dart';
part 'login_event.dart';
part 'login_state.dart';
part 'login_bloc.freezed.dart';
@injectable
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final LoginUseCase _loginUseCase;
final StorageService _storageService;
LoginBloc(this._loginUseCase, this._storageService)
: super(const LoginState()) {
on<_Login>(_onLogin);
}
Future<void> _onLogin(_Login event, Emitter<LoginState> emit) async {
emit(state.copyWith(status: RequestStatus.loading));
final response = await _loginUseCase.call(event.params);
response.fold(
(l) {
log("${l.errorMessage}");
showErrorToast(l.errorMessage);
emit(state.copyWith(status: RequestStatus.error));
},
(r) {
showSuccessToast("Login success");
_storageService.setString(key: AppLocaleKeys.token, value: r.token);
final token = _storageService.getString(key: AppLocaleKeys.token);
log('Token:$token');
emit(state.copyWith(status: RequestStatus.loaded));
},
);
}
}

View File

@@ -0,0 +1,535 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'login_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$LoginEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is LoginEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'LoginEvent()';
}
}
/// @nodoc
class $LoginEventCopyWith<$Res> {
$LoginEventCopyWith(LoginEvent _, $Res Function(LoginEvent) __);
}
/// Adds pattern-matching-related methods to [LoginEvent].
extension LoginEventPatterns on LoginEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Checked value)? checked,TResult Function( _Login value)? login,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Checked() when checked != null:
return checked(_that);case _Login() when login != null:
return login(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Checked value) checked,required TResult Function( _Login value) login,}){
final _that = this;
switch (_that) {
case _Checked():
return checked(_that);case _Login():
return login(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Checked value)? checked,TResult? Function( _Login value)? login,}){
final _that = this;
switch (_that) {
case _Checked() when checked != null:
return checked(_that);case _Login() when login != null:
return login(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? checked,TResult Function( LoginParams params)? login,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Checked() when checked != null:
return checked();case _Login() when login != null:
return login(_that.params);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() checked,required TResult Function( LoginParams params) login,}) {final _that = this;
switch (_that) {
case _Checked():
return checked();case _Login():
return login(_that.params);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? checked,TResult? Function( LoginParams params)? login,}) {final _that = this;
switch (_that) {
case _Checked() when checked != null:
return checked();case _Login() when login != null:
return login(_that.params);case _:
return null;
}
}
}
/// @nodoc
class _Checked implements LoginEvent {
const _Checked();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Checked);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'LoginEvent.checked()';
}
}
/// @nodoc
class _Login implements LoginEvent {
const _Login(this.params);
final LoginParams params;
/// Create a copy of LoginEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LoginCopyWith<_Login> get copyWith => __$LoginCopyWithImpl<_Login>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Login&&(identical(other.params, params) || other.params == params));
}
@override
int get hashCode => Object.hash(runtimeType,params);
@override
String toString() {
return 'LoginEvent.login(params: $params)';
}
}
/// @nodoc
abstract mixin class _$LoginCopyWith<$Res> implements $LoginEventCopyWith<$Res> {
factory _$LoginCopyWith(_Login value, $Res Function(_Login) _then) = __$LoginCopyWithImpl;
@useResult
$Res call({
LoginParams params
});
}
/// @nodoc
class __$LoginCopyWithImpl<$Res>
implements _$LoginCopyWith<$Res> {
__$LoginCopyWithImpl(this._self, this._then);
final _Login _self;
final $Res Function(_Login) _then;
/// Create a copy of LoginEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? params = null,}) {
return _then(_Login(
null == params ? _self.params : params // ignore: cast_nullable_to_non_nullable
as LoginParams,
));
}
}
/// @nodoc
mixin _$LoginState {
RequestStatus get status;
/// Create a copy of LoginState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$LoginStateCopyWith<LoginState> get copyWith => _$LoginStateCopyWithImpl<LoginState>(this as LoginState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is LoginState&&(identical(other.status, status) || other.status == status));
}
@override
int get hashCode => Object.hash(runtimeType,status);
@override
String toString() {
return 'LoginState(status: $status)';
}
}
/// @nodoc
abstract mixin class $LoginStateCopyWith<$Res> {
factory $LoginStateCopyWith(LoginState value, $Res Function(LoginState) _then) = _$LoginStateCopyWithImpl;
@useResult
$Res call({
RequestStatus status
});
}
/// @nodoc
class _$LoginStateCopyWithImpl<$Res>
implements $LoginStateCopyWith<$Res> {
_$LoginStateCopyWithImpl(this._self, this._then);
final LoginState _self;
final $Res Function(LoginState) _then;
/// Create a copy of LoginState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? status = null,}) {
return _then(_self.copyWith(
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as RequestStatus,
));
}
}
/// Adds pattern-matching-related methods to [LoginState].
extension LoginStatePatterns on LoginState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LoginState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _LoginState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LoginState value) $default,){
final _that = this;
switch (_that) {
case _LoginState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LoginState value)? $default,){
final _that = this;
switch (_that) {
case _LoginState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( RequestStatus status)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _LoginState() when $default != null:
return $default(_that.status);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( RequestStatus status) $default,) {final _that = this;
switch (_that) {
case _LoginState():
return $default(_that.status);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( RequestStatus status)? $default,) {final _that = this;
switch (_that) {
case _LoginState() when $default != null:
return $default(_that.status);case _:
return null;
}
}
}
/// @nodoc
class _LoginState implements LoginState {
const _LoginState({this.status = RequestStatus.initial});
@override@JsonKey() final RequestStatus status;
/// Create a copy of LoginState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LoginStateCopyWith<_LoginState> get copyWith => __$LoginStateCopyWithImpl<_LoginState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LoginState&&(identical(other.status, status) || other.status == status));
}
@override
int get hashCode => Object.hash(runtimeType,status);
@override
String toString() {
return 'LoginState(status: $status)';
}
}
/// @nodoc
abstract mixin class _$LoginStateCopyWith<$Res> implements $LoginStateCopyWith<$Res> {
factory _$LoginStateCopyWith(_LoginState value, $Res Function(_LoginState) _then) = __$LoginStateCopyWithImpl;
@override @useResult
$Res call({
RequestStatus status
});
}
/// @nodoc
class __$LoginStateCopyWithImpl<$Res>
implements _$LoginStateCopyWith<$Res> {
__$LoginStateCopyWithImpl(this._self, this._then);
final _LoginState _self;
final $Res Function(_LoginState) _then;
/// Create a copy of LoginState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? status = null,}) {
return _then(_LoginState(
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as RequestStatus,
));
}
}
// dart format on

View File

@@ -0,0 +1,8 @@
part of 'login_bloc.dart';
@freezed
class LoginEvent with _$LoginEvent {
const factory LoginEvent.checked() = _Checked;
const factory LoginEvent.login(LoginParams params) = _Login;
}

View File

@@ -0,0 +1,8 @@
part of 'login_bloc.dart';
@freezed
abstract class LoginState with _$LoginState {
const factory LoginState({
@Default(RequestStatus.initial) RequestStatus status,
}) = _LoginState;
}

View File

@@ -0,0 +1,12 @@
import '../../../../../food_delivery_client.dart';
class ForgotPasswordPage extends StatelessWidget {
const ForgotPasswordPage({super.key});
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(body: Column(children: [Text('Forgot password')])),
);
}
}

View File

@@ -0,0 +1,18 @@
import 'package:food_delivery_client/feature/auth/presentation/blocs/login_bloc/login_bloc.dart';
import 'package:food_delivery_client/feature/auth/presentation/pages/login_page/widgets/login_body.dart';
import '../../../../../food_delivery_client.dart';
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => sl<LoginBloc>(),
child: WLayout(
top: false,
child: Scaffold(resizeToAvoidBottomInset: true, body: WLoginBody()),
),
);
}
}

View File

@@ -0,0 +1,170 @@
import 'package:food_delivery_client/core/helpers/formatters.dart';
import 'package:food_delivery_client/core/helpers/validator_helpers.dart';
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
import 'package:food_delivery_client/feature/auth/presentation/widgets/w_auth_background.dart';
import '../../../../../../food_delivery_client.dart';
import '../../../blocs/login_bloc/login_bloc.dart';
class WLoginBody extends StatefulWidget {
const WLoginBody({super.key});
@override
State<WLoginBody> createState() => _WLoginBodyState();
}
class _WLoginBodyState extends State<WLoginBody> {
late final TextEditingController _phoneController;
late final TextEditingController _passwordController;
final _formKey = GlobalKey<FormState>();
@override
void initState() {
_phoneController = TextEditingController();
_passwordController = TextEditingController();
super.initState();
}
@override
void dispose() {
_phoneController.dispose();
_passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<LoginBloc, LoginState>(
builder: (context, state) {
return Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: WAuthBackground(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
25.verticalSpace,
Align(
alignment: AlignmentGeometry.center,
child: Text(
context.loc.login,
style: AppTextStyles.size24Bold,
),
),
20.verticalSpace,
Text(
context.loc.phone_number,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
hintText: context.loc.enter_phone_number,
prefixIcon: Text(
"+ 998",
style: AppTextStyles.size16Regular.copyWith(fontSize: 16),
),
borderRadius: AppUtils.kBorderRadius8,
controller: _phoneController,
keyBoardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
Formatters.phoneFormatter,
LengthLimitingTextInputFormatter(12),
],
validator: (value) {
return Validators.validatePhoneNumber(
_phoneController.text.trim(),
);
},
),
10.verticalSpace,
Text(
context.loc.password,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
height: 50,
obscureText: true,
hintText: context.loc.enter_password,
keyBoardType: TextInputType.text,
borderRadius: AppUtils.kBorderRadius8,
controller: _passwordController,
validator: (value) {
return Validators.validatePassword(
_passwordController.text.trim(),
);
},
),
Align(
alignment: AlignmentGeometry.centerRight,
child: TextButton(
onPressed: () {
context.push(Routes.forgotPassword);
},
child: Text(
context.loc.forgot_password,
style: AppTextStyles.size14Medium.copyWith(
color: AppColors.c34A853,
),
),
),
),
40.verticalSpace,
AppButton(
name: context.loc.continue_str,
isLoading: state.status.isLoading(),
trailing: SvgPicture.asset(
AppIcons.icArrowRightLight,
).paddingOnly(left: 10),
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
context.read<LoginBloc>().add(
LoginEvent.login(
LoginParams(
phoneNumber:
"+998${_phoneController.text.trim().replaceAll(" ", "")}",
password: _passwordController.text.trim(),
),
),
);
}
},
borderRadius: 15,
backgroundColor: AppColors.c34A853,
),
20.verticalSpace,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.loc.dont_have_account,
style: AppTextStyles.size14Medium,
),
TextButton(
onPressed: () {
context.pushReplacement(Routes.register);
},
child: Text(
context.loc.sign_up,
style: AppTextStyles.size15Bold.copyWith(
color: AppColors.c34A853,
),
),
),
],
),
20.verticalSpace,
],
).paddingSymmetric(horizontal: 16),
),
);
},
);
}
}

View File

@@ -0,0 +1,14 @@
import 'package:food_delivery_client/feature/auth/presentation/pages/register_page/widgets/w_register_body.dart';
import '../../../../../food_delivery_client.dart';
class RegisterPage extends StatelessWidget {
const RegisterPage({super.key});
@override
Widget build(BuildContext context) {
return WLayout(
top: false,
child: Scaffold(body: WRegisterBody()));
}
}

View File

@@ -0,0 +1,205 @@
import 'package:food_delivery_client/core/helpers/validator_helpers.dart';
import 'package:food_delivery_client/feature/auth/presentation/widgets/w_auth_background.dart';
import '../../../../../../food_delivery_client.dart';
class WRegisterBody extends StatefulWidget {
const WRegisterBody({super.key});
@override
State<WRegisterBody> createState() => _WRegisterBodyState();
}
class _WRegisterBodyState extends State<WRegisterBody> {
late TextEditingController _firstNameController;
late TextEditingController _lastNameController;
late TextEditingController _phoneNumberController;
late TextEditingController _passwordController;
late TextEditingController _repeatPasswordController;
final _formKey = GlobalKey<FormState>();
@override
void initState() {
_firstNameController = TextEditingController();
_lastNameController = TextEditingController();
_phoneNumberController = TextEditingController();
_passwordController = TextEditingController();
_repeatPasswordController = TextEditingController();
super.initState();
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_phoneNumberController.dispose();
_passwordController.dispose();
_repeatPasswordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: WAuthBackground(
child: SizedBox(
width: context.w,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
20.verticalSpace,
Align(
alignment: AlignmentGeometry.center,
child: Text(
context.loc.sign_up,
style: AppTextStyles.size24Bold,
),
),
20.verticalSpace,
Text(
context.loc.first_name,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
hintText: context.loc.enter_first_name,
controller: _firstNameController,
borderRadius: AppUtils.kBorderRadius8,
keyBoardType: TextInputType.name,
validator: (value) {
return Validators.validateFields(
_firstNameController.text.trim(),
);
},
),
10.verticalSpace,
Text(
'Last name',
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
hintText: "Enter LastName",
controller: _lastNameController,
borderRadius: AppUtils.kBorderRadius8,
keyBoardType: TextInputType.text,
validator: (value) {
return Validators.validateFields(
_lastNameController.text.trim(),
);
},
),
10.verticalSpace,
/* Text(
context.loc.phone_number,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
hintText: context.loc.enter_phone_number,
controller: _phoneNumberController,
borderRadius: AppUtils.kBorderRadius8,
keyBoardType: TextInputType.phone,
prefixIcon: Text("+ 998", style: AppTextStyles.size16Regular),
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
Formatters.phoneFormatter,
LengthLimitingTextInputFormatter(12),
],
validator: (value) {
return Validators.validatePhoneNumber(
_phoneNumberController.text.trim(),
);
},
),
*/
10.verticalSpace,
Text(
context.loc.enter_password,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
obscureText: true,
hintText: context.loc.password,
controller: _passwordController,
borderRadius: AppUtils.kBorderRadius8,
keyBoardType: TextInputType.visiblePassword,
validator: (value) {
return Validators.validatePassword(
_passwordController.text.trim(),
);
},
),
10.verticalSpace,
Text(
context.loc.repeat_password,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
obscureText: true,
hintText: context.loc.enter_repeat_password,
controller: _repeatPasswordController,
borderRadius: AppUtils.kBorderRadius8,
keyBoardType: TextInputType.visiblePassword,
validator: (value) {
return Validators.validatePassword(
_repeatPasswordController.text.trim(),
);
},
),
20.verticalSpace,
AppButton(
name: context.loc.continue_str,
borderRadius: 15,
backgroundColor: AppColors.c34A853,
trailing: SvgPicture.asset(
AppIcons.icArrowRightLight,
).paddingOnly(left: 8),
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {}
},
),
20.verticalSpace,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.loc.already_has_account,
style: AppTextStyles.size14Medium,
),
TextButton(
onPressed: () {
context.pushReplacement(Routes.login);
},
child: Text(
context.loc.login,
style: AppTextStyles.size15Bold.copyWith(
color: AppColors.c34A853,
),
),
),
],
),
],
).paddingSymmetric(horizontal: 16),
),
),
);
}
}

View File

@@ -0,0 +1,35 @@
import '../../../../food_delivery_client.dart';
class WAuthBackground extends StatelessWidget {
const WAuthBackground({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context) {
return Stack(
children: [
SizedBox(
height: context.h * .3,
child: Image.asset(AppImages.imgBurger2, fit: BoxFit.cover),
),
SingleChildScrollView(
// keyboardDismissBehavior:
// ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
children: [
SizedBox(height: context.h * .2),
DecoratedBox(
decoration: BoxDecoration(
color: AppColors.cFFFFFF,
borderRadius: AppUtils.kBorderRadiusTop20,
),
child: child,
),
],
),
),
],
);
}
}

View File

@@ -1 +1,8 @@
export 'presentation/pages/basket_page/basket_page.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_basket_empty.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_basket_header.dart';
export 'presentation/blocs/basket_bloc.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_basket_body.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_basket_carts.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_basket_loading.dart';
export 'package:food_delivery_client/feature/basket/presentation/pages/basket_page/widgets/w_order_item.dart';

View File

@@ -0,0 +1,20 @@
import 'package:food_delivery_client/food_delivery_client.dart';
part 'basket_event.dart';
part 'basket_state.dart';
part 'basket_bloc.freezed.dart';
@injectable
class BasketBloc extends Bloc<BasketEvent, BasketState> {
BasketBloc() : super(const BasketState()) {
on<_Started>(_onStarted);
}
_onStarted(_Started event, Emitter<BasketState> emit) async {
emit(state.copyWith(status: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(status: RequestStatus.loaded, orders: []));
}
}

View File

@@ -0,0 +1,472 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'basket_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$BasketEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BasketEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BasketEvent()';
}
}
/// @nodoc
class $BasketEventCopyWith<$Res> {
$BasketEventCopyWith(BasketEvent _, $Res Function(BasketEvent) __);
}
/// Adds pattern-matching-related methods to [BasketEvent].
extension BasketEventPatterns on BasketEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Started value)? started,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Started value) started,}){
final _that = this;
switch (_that) {
case _Started():
return started(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Started value)? started,}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? started,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() started,}) {final _that = this;
switch (_that) {
case _Started():
return started();case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? started,}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _:
return null;
}
}
}
/// @nodoc
class _Started implements BasketEvent {
const _Started();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Started);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BasketEvent.started()';
}
}
/// @nodoc
mixin _$BasketState {
RequestStatus get status; List get orders;
/// Create a copy of BasketState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$BasketStateCopyWith<BasketState> get copyWith => _$BasketStateCopyWithImpl<BasketState>(this as BasketState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BasketState&&(identical(other.status, status) || other.status == status)&&const DeepCollectionEquality().equals(other.orders, orders));
}
@override
int get hashCode => Object.hash(runtimeType,status,const DeepCollectionEquality().hash(orders));
@override
String toString() {
return 'BasketState(status: $status, orders: $orders)';
}
}
/// @nodoc
abstract mixin class $BasketStateCopyWith<$Res> {
factory $BasketStateCopyWith(BasketState value, $Res Function(BasketState) _then) = _$BasketStateCopyWithImpl;
@useResult
$Res call({
RequestStatus status, List orders
});
}
/// @nodoc
class _$BasketStateCopyWithImpl<$Res>
implements $BasketStateCopyWith<$Res> {
_$BasketStateCopyWithImpl(this._self, this._then);
final BasketState _self;
final $Res Function(BasketState) _then;
/// Create a copy of BasketState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? status = null,Object? orders = null,}) {
return _then(_self.copyWith(
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as RequestStatus,orders: null == orders ? _self.orders : orders // ignore: cast_nullable_to_non_nullable
as List,
));
}
}
/// Adds pattern-matching-related methods to [BasketState].
extension BasketStatePatterns on BasketState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _BasketState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _BasketState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _BasketState value) $default,){
final _that = this;
switch (_that) {
case _BasketState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _BasketState value)? $default,){
final _that = this;
switch (_that) {
case _BasketState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( RequestStatus status, List orders)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _BasketState() when $default != null:
return $default(_that.status,_that.orders);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( RequestStatus status, List orders) $default,) {final _that = this;
switch (_that) {
case _BasketState():
return $default(_that.status,_that.orders);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( RequestStatus status, List orders)? $default,) {final _that = this;
switch (_that) {
case _BasketState() when $default != null:
return $default(_that.status,_that.orders);case _:
return null;
}
}
}
/// @nodoc
class _BasketState implements BasketState {
const _BasketState({this.status = RequestStatus.initial, final List orders = const []}): _orders = orders;
@override@JsonKey() final RequestStatus status;
final List _orders;
@override@JsonKey() List get orders {
if (_orders is EqualUnmodifiableListView) return _orders;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_orders);
}
/// Create a copy of BasketState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$BasketStateCopyWith<_BasketState> get copyWith => __$BasketStateCopyWithImpl<_BasketState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BasketState&&(identical(other.status, status) || other.status == status)&&const DeepCollectionEquality().equals(other._orders, _orders));
}
@override
int get hashCode => Object.hash(runtimeType,status,const DeepCollectionEquality().hash(_orders));
@override
String toString() {
return 'BasketState(status: $status, orders: $orders)';
}
}
/// @nodoc
abstract mixin class _$BasketStateCopyWith<$Res> implements $BasketStateCopyWith<$Res> {
factory _$BasketStateCopyWith(_BasketState value, $Res Function(_BasketState) _then) = __$BasketStateCopyWithImpl;
@override @useResult
$Res call({
RequestStatus status, List orders
});
}
/// @nodoc
class __$BasketStateCopyWithImpl<$Res>
implements _$BasketStateCopyWith<$Res> {
__$BasketStateCopyWithImpl(this._self, this._then);
final _BasketState _self;
final $Res Function(_BasketState) _then;
/// Create a copy of BasketState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? status = null,Object? orders = null,}) {
return _then(_BasketState(
status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as RequestStatus,orders: null == orders ? _self._orders : orders // ignore: cast_nullable_to_non_nullable
as List,
));
}
}
// dart format on

View File

@@ -0,0 +1,6 @@
part of 'basket_bloc.dart';
@freezed
class BasketEvent with _$BasketEvent {
const factory BasketEvent.started() = _Started;
}

View File

@@ -0,0 +1,9 @@
part of 'basket_bloc.dart';
@freezed
abstract class BasketState with _$BasketState {
const factory BasketState({
@Default(RequestStatus.initial) RequestStatus status,
@Default([]) List orders,
}) = _BasketState;
}

View File

@@ -5,8 +5,13 @@ class BasketPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(body: Center(child: Text(context.loc.useYourTAxiAccount))),
return BlocProvider(
create: (context) => sl<BasketBloc>()..add(BasketEvent.started()),
child: BlocBuilder<BasketBloc, BasketState>(
builder: (context, state) {
return WLayout(child: Scaffold(body: WBasketBody()));
},
),
);
}
}

View File

@@ -0,0 +1,23 @@
import '../../../../../../food_delivery_client.dart';
class WBasketBody extends StatelessWidget {
const WBasketBody({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BasketBloc, BasketState>(
builder: (context, state) {
return Column(
children: [
WBasketHeader(),
if (state.status.isLoading()) WBasketLoading(),
if (state.status.isLoaded())
if (state.orders.isEmpty) WBasketEmpty() else WBasketCarts(),
],
);
},
);
}
}

View File

@@ -0,0 +1,29 @@
import '../../../../../../food_delivery_client.dart';
class WBasketCarts extends StatelessWidget {
const WBasketCarts({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BasketBloc, BasketState>(
builder: (context, state) {
return Expanded(
child: RefreshIndicator(
onRefresh: () async {
context.read<BasketBloc>().add(BasketEvent.started());
await Future.delayed(TimeDelayConst.duration3);
},
child: ListView.builder(
shrinkWrap: true,
itemCount: 10,
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) => OrderItem(),
),
),
);
},
);
}
}

View File

@@ -0,0 +1,46 @@
import '../../../../../../food_delivery_client.dart';
class WBasketEmpty extends StatelessWidget {
const WBasketEmpty({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<MainBloc, MainState>(
builder: (context, state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
70.verticalSpace,
SvgPicture.asset(AppIcons.icEmptyBasket),
Text(
context.loc.addItemsStartBasket,
textAlign: TextAlign.center,
style: AppTextStyles.size20Medium,
),
12.verticalSpace,
Text(
context.loc.basketHint,
textAlign: TextAlign.center,
style: AppTextStyles.size16Regular.copyWith(
color: AppColors.c545454,
height: 24 / 16,
),
),
38.verticalSpace,
AppButton(
name: context.loc.startShopping,
onPressed: () {
context.read<MainBloc>().add(MainEvent.loaded(0));
},
height: 45,
width: 250,
borderRadius: 99,
),
],
);
},
).paddingSymmetric(horizontal: 35);
}
}

View File

@@ -0,0 +1,45 @@
import '../../../../../../food_delivery_client.dart';
class WBasketHeader extends StatelessWidget {
const WBasketHeader({super.key});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
8.verticalSpace,
Align(
alignment: AlignmentGeometry.centerRight,
child: InkWell(
borderRadius: BorderRadius.circular(99),
onTap: () {},
child: Ink(
decoration: BoxDecoration(
color: AppColors.cEEEEEE,
borderRadius: BorderRadius.circular(99),
),
child: Row(
spacing: 10,
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
AppIcons.icOrders,
height: 20,
width: 20,
fit: BoxFit.cover,
),
Text(context.loc.orders, style: AppTextStyles.size14Medium),
],
).paddingSymmetric(vertical: 10, horizontal: 16),
),
),
),
Align(
alignment: AlignmentGeometry.centerLeft,
child: Text(context.loc.cartsTitle, style: AppTextStyles.size36Bold),
),
],
).paddingSymmetric(horizontal: 15);
}
}

View File

@@ -0,0 +1,80 @@
import '../../../../../../food_delivery_client.dart';
class WBasketLoading extends StatelessWidget {
const WBasketLoading({super.key});
@override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 10,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) =>
Skeletonizer(enabled: true, child: OrderItemSkeletonizer()),
),
);
}
}
class OrderItemSkeletonizer extends StatelessWidget {
const OrderItemSkeletonizer({super.key});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Ink(
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadius40,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.imageUrl,
height: 70,
width: 70,
fit: BoxFit.cover,
),
),
16.horizontalSpace,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Begs & Megs", style: AppTextStyles.size16Medium),
Text(
AppLocaleKeys.lorem,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
Text(
"Deliver to San Franciscao Bay Area",
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios_outlined,
color: AppColors.cFFFFFF,
),
],
).paddingSymmetric(vertical: 10, horizontal: 18),
10.verticalSpace,
WDivider(indent: 120, endIndent: 20, height: 1),
],
),
),
);
}
}

View File

@@ -0,0 +1,86 @@
import '../../../../../../food_delivery_client.dart';
class OrderItem extends StatelessWidget {
const OrderItem({super.key});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Ink(
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadius40,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.imageUrl,
height: 70,
width: 70,
fit: BoxFit.cover,
),
),
16.horizontalSpace,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocaleKeys.lorem,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppTextStyles.size16Medium,
),
Row(
spacing: 5,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Text(
AppLocaleKeys.lorem,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
),
Icon(Icons.circle, size: 5, color: AppColors.c6B6B6B),
Expanded(
child: Text(
AppLocaleKeys.lorem,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
),
],
),
Text(
AppLocaleKeys.lorem,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
],
),
),
10.horizontalSpace,
SvgPicture.asset(AppIcons.icArrowRight),
],
).paddingSymmetric(vertical: 10, horizontal: 18),
10.verticalSpace,
WDivider(indent: 120, endIndent: 20, height: 1),
],
),
),
);
}
}

View File

@@ -1 +1,10 @@
export 'presentation/pages/browse_page/browse_page.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_body.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_item.dart';
export "presentation/blocs/browse_bloc/browse_bloc.dart";
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories_skeletonizer.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_skeletonizer.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories.dart';
export 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories_skeletonizer.dart';

View File

@@ -0,0 +1,48 @@
import 'package:food_delivery_client/food_delivery_client.dart';
part 'browse_event.dart';
part 'browse_state.dart';
part 'browse_bloc.freezed.dart';
@injectable
class BrowseBloc extends Bloc<BrowseEvent, BrowseState> {
BrowseBloc() : super(const BrowseState()) {
on<_GetTopCategories>(_onGetTopCategories);
on<_GetAllCategories>(_onGetAllCategories);
on<_GetSearchHistory>(_onGetSearchHistory);
on<_FocusChanged>(_onFocusChanged);
}
Future<void> _onGetTopCategories(
_GetTopCategories event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(topCategorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(topCategorySt: RequestStatus.loaded));
}
Future<void> _onGetAllCategories(
_GetAllCategories event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(allCategorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(allCategorySt: RequestStatus.loaded));
}
Future<void> _onGetSearchHistory(
_GetSearchHistory event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
}
void _onFocusChanged(_FocusChanged event, Emitter<BrowseState> emit) {
emit(state.copyWith(isActive: event.isActive ?? !(state.isActive)));
}
}

View File

@@ -0,0 +1,667 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'browse_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$BrowseEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BrowseEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent()';
}
}
/// @nodoc
class $BrowseEventCopyWith<$Res> {
$BrowseEventCopyWith(BrowseEvent _, $Res Function(BrowseEvent) __);
}
/// Adds pattern-matching-related methods to [BrowseEvent].
extension BrowseEventPatterns on BrowseEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Started value)? started,TResult Function( _GetTopCategories value)? getTopCategories,TResult Function( _GetAllCategories value)? getAllCategories,TResult Function( _GetSearchHistory value)? getSearchHistory,TResult Function( _FocusChanged value)? focusChanged,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _GetTopCategories() when getTopCategories != null:
return getTopCategories(_that);case _GetAllCategories() when getAllCategories != null:
return getAllCategories(_that);case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory(_that);case _FocusChanged() when focusChanged != null:
return focusChanged(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Started value) started,required TResult Function( _GetTopCategories value) getTopCategories,required TResult Function( _GetAllCategories value) getAllCategories,required TResult Function( _GetSearchHistory value) getSearchHistory,required TResult Function( _FocusChanged value) focusChanged,}){
final _that = this;
switch (_that) {
case _Started():
return started(_that);case _GetTopCategories():
return getTopCategories(_that);case _GetAllCategories():
return getAllCategories(_that);case _GetSearchHistory():
return getSearchHistory(_that);case _FocusChanged():
return focusChanged(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Started value)? started,TResult? Function( _GetTopCategories value)? getTopCategories,TResult? Function( _GetAllCategories value)? getAllCategories,TResult? Function( _GetSearchHistory value)? getSearchHistory,TResult? Function( _FocusChanged value)? focusChanged,}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _GetTopCategories() when getTopCategories != null:
return getTopCategories(_that);case _GetAllCategories() when getAllCategories != null:
return getAllCategories(_that);case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory(_that);case _FocusChanged() when focusChanged != null:
return focusChanged(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? started,TResult Function()? getTopCategories,TResult Function()? getAllCategories,TResult Function()? getSearchHistory,TResult Function( bool? isActive)? focusChanged,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _GetTopCategories() when getTopCategories != null:
return getTopCategories();case _GetAllCategories() when getAllCategories != null:
return getAllCategories();case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory();case _FocusChanged() when focusChanged != null:
return focusChanged(_that.isActive);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() started,required TResult Function() getTopCategories,required TResult Function() getAllCategories,required TResult Function() getSearchHistory,required TResult Function( bool? isActive) focusChanged,}) {final _that = this;
switch (_that) {
case _Started():
return started();case _GetTopCategories():
return getTopCategories();case _GetAllCategories():
return getAllCategories();case _GetSearchHistory():
return getSearchHistory();case _FocusChanged():
return focusChanged(_that.isActive);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? started,TResult? Function()? getTopCategories,TResult? Function()? getAllCategories,TResult? Function()? getSearchHistory,TResult? Function( bool? isActive)? focusChanged,}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _GetTopCategories() when getTopCategories != null:
return getTopCategories();case _GetAllCategories() when getAllCategories != null:
return getAllCategories();case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory();case _FocusChanged() when focusChanged != null:
return focusChanged(_that.isActive);case _:
return null;
}
}
}
/// @nodoc
class _Started implements BrowseEvent {
const _Started();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Started);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.started()';
}
}
/// @nodoc
class _GetTopCategories implements BrowseEvent {
const _GetTopCategories();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetTopCategories);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getTopCategories()';
}
}
/// @nodoc
class _GetAllCategories implements BrowseEvent {
const _GetAllCategories();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetAllCategories);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getAllCategories()';
}
}
/// @nodoc
class _GetSearchHistory implements BrowseEvent {
const _GetSearchHistory();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetSearchHistory);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getSearchHistory()';
}
}
/// @nodoc
class _FocusChanged implements BrowseEvent {
const _FocusChanged(this.isActive);
final bool? isActive;
/// Create a copy of BrowseEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$FocusChangedCopyWith<_FocusChanged> get copyWith => __$FocusChangedCopyWithImpl<_FocusChanged>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FocusChanged&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,isActive);
@override
String toString() {
return 'BrowseEvent.focusChanged(isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class _$FocusChangedCopyWith<$Res> implements $BrowseEventCopyWith<$Res> {
factory _$FocusChangedCopyWith(_FocusChanged value, $Res Function(_FocusChanged) _then) = __$FocusChangedCopyWithImpl;
@useResult
$Res call({
bool? isActive
});
}
/// @nodoc
class __$FocusChangedCopyWithImpl<$Res>
implements _$FocusChangedCopyWith<$Res> {
__$FocusChangedCopyWithImpl(this._self, this._then);
final _FocusChanged _self;
final $Res Function(_FocusChanged) _then;
/// Create a copy of BrowseEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? isActive = freezed,}) {
return _then(_FocusChanged(
freezed == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
/// @nodoc
mixin _$BrowseState {
RequestStatus get topCategorySt; RequestStatus get allCategorySt; RequestStatus get searchHistorySt; List<String> get searchHistory; bool get isActive;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$BrowseStateCopyWith<BrowseState> get copyWith => _$BrowseStateCopyWithImpl<BrowseState>(this as BrowseState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BrowseState&&(identical(other.topCategorySt, topCategorySt) || other.topCategorySt == topCategorySt)&&(identical(other.allCategorySt, allCategorySt) || other.allCategorySt == allCategorySt)&&(identical(other.searchHistorySt, searchHistorySt) || other.searchHistorySt == searchHistorySt)&&const DeepCollectionEquality().equals(other.searchHistory, searchHistory)&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,topCategorySt,allCategorySt,searchHistorySt,const DeepCollectionEquality().hash(searchHistory),isActive);
@override
String toString() {
return 'BrowseState(topCategorySt: $topCategorySt, allCategorySt: $allCategorySt, searchHistorySt: $searchHistorySt, searchHistory: $searchHistory, isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class $BrowseStateCopyWith<$Res> {
factory $BrowseStateCopyWith(BrowseState value, $Res Function(BrowseState) _then) = _$BrowseStateCopyWithImpl;
@useResult
$Res call({
RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive
});
}
/// @nodoc
class _$BrowseStateCopyWithImpl<$Res>
implements $BrowseStateCopyWith<$Res> {
_$BrowseStateCopyWithImpl(this._self, this._then);
final BrowseState _self;
final $Res Function(BrowseState) _then;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? topCategorySt = null,Object? allCategorySt = null,Object? searchHistorySt = null,Object? searchHistory = null,Object? isActive = null,}) {
return _then(_self.copyWith(
topCategorySt: null == topCategorySt ? _self.topCategorySt : topCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,allCategorySt: null == allCategorySt ? _self.allCategorySt : allCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistorySt: null == searchHistorySt ? _self.searchHistorySt : searchHistorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistory: null == searchHistory ? _self.searchHistory : searchHistory // ignore: cast_nullable_to_non_nullable
as List<String>,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [BrowseState].
extension BrowseStatePatterns on BrowseState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _BrowseState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _BrowseState value) $default,){
final _that = this;
switch (_that) {
case _BrowseState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _BrowseState value)? $default,){
final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive) $default,) {final _that = this;
switch (_that) {
case _BrowseState():
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive)? $default,) {final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
return null;
}
}
}
/// @nodoc
class _BrowseState implements BrowseState {
const _BrowseState({this.topCategorySt = RequestStatus.initial, this.allCategorySt = RequestStatus.initial, this.searchHistorySt = RequestStatus.initial, final List<String> searchHistory = const [], this.isActive = false}): _searchHistory = searchHistory;
@override@JsonKey() final RequestStatus topCategorySt;
@override@JsonKey() final RequestStatus allCategorySt;
@override@JsonKey() final RequestStatus searchHistorySt;
final List<String> _searchHistory;
@override@JsonKey() List<String> get searchHistory {
if (_searchHistory is EqualUnmodifiableListView) return _searchHistory;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_searchHistory);
}
@override@JsonKey() final bool isActive;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$BrowseStateCopyWith<_BrowseState> get copyWith => __$BrowseStateCopyWithImpl<_BrowseState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BrowseState&&(identical(other.topCategorySt, topCategorySt) || other.topCategorySt == topCategorySt)&&(identical(other.allCategorySt, allCategorySt) || other.allCategorySt == allCategorySt)&&(identical(other.searchHistorySt, searchHistorySt) || other.searchHistorySt == searchHistorySt)&&const DeepCollectionEquality().equals(other._searchHistory, _searchHistory)&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,topCategorySt,allCategorySt,searchHistorySt,const DeepCollectionEquality().hash(_searchHistory),isActive);
@override
String toString() {
return 'BrowseState(topCategorySt: $topCategorySt, allCategorySt: $allCategorySt, searchHistorySt: $searchHistorySt, searchHistory: $searchHistory, isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class _$BrowseStateCopyWith<$Res> implements $BrowseStateCopyWith<$Res> {
factory _$BrowseStateCopyWith(_BrowseState value, $Res Function(_BrowseState) _then) = __$BrowseStateCopyWithImpl;
@override @useResult
$Res call({
RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive
});
}
/// @nodoc
class __$BrowseStateCopyWithImpl<$Res>
implements _$BrowseStateCopyWith<$Res> {
__$BrowseStateCopyWithImpl(this._self, this._then);
final _BrowseState _self;
final $Res Function(_BrowseState) _then;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? topCategorySt = null,Object? allCategorySt = null,Object? searchHistorySt = null,Object? searchHistory = null,Object? isActive = null,}) {
return _then(_BrowseState(
topCategorySt: null == topCategorySt ? _self.topCategorySt : topCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,allCategorySt: null == allCategorySt ? _self.allCategorySt : allCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistorySt: null == searchHistorySt ? _self.searchHistorySt : searchHistorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistory: null == searchHistory ? _self._searchHistory : searchHistory // ignore: cast_nullable_to_non_nullable
as List<String>,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
// dart format on

View File

@@ -0,0 +1,14 @@
part of 'browse_bloc.dart';
@freezed
class BrowseEvent with _$BrowseEvent {
const factory BrowseEvent.started() = _Started;
const factory BrowseEvent.getTopCategories() = _GetTopCategories;
const factory BrowseEvent.getAllCategories() = _GetAllCategories;
const factory BrowseEvent.getSearchHistory() = _GetSearchHistory;
const factory BrowseEvent.focusChanged(bool? isActive) = _FocusChanged;
}

View File

@@ -0,0 +1,12 @@
part of 'browse_bloc.dart';
@freezed
abstract class BrowseState with _$BrowseState {
const factory BrowseState({
@Default(RequestStatus.initial) RequestStatus topCategorySt,
@Default(RequestStatus.initial) RequestStatus allCategorySt,
@Default(RequestStatus.initial) RequestStatus searchHistorySt,
@Default([]) List<String> searchHistory,
@Default(false) bool isActive,
}) = _BrowseState;
}

View File

@@ -1,3 +1,4 @@
import '../../../../../food_delivery_client.dart';
class BrowsePage extends StatelessWidget {
@@ -5,8 +6,11 @@ class BrowsePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(body: Center(child: Text(context.loc.mobileNumber))),
return BlocProvider(
create: (context) => sl<BrowseBloc>()
..add(BrowseEvent.getTopCategories())
..add(BrowseEvent.getAllCategories()),
child: WLayout(child: Scaffold(body: WBrowseBody())),
);
}
}

View File

@@ -0,0 +1,52 @@
import '../../../../../../food_delivery_client.dart';
class WAllCategories extends StatelessWidget {
const WAllCategories({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
if (state.allCategorySt.isLoaded()) {
return WAllCategoriesBody();
}
return WAllCategoriesSkeletonizer();
},
);
}
}
class WAllCategoriesBody extends StatelessWidget {
const WAllCategoriesBody({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
25.verticalSpace,
Text(
context.loc.allCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 10,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 175,
),
itemBuilder: (context, index) {
return WBrowseItem();
},
),
],
);
}
}

View File

@@ -0,0 +1,41 @@
import '../../../../../../food_delivery_client.dart';
class WAllCategoriesSkeletonizer extends StatelessWidget {
const WAllCategoriesSkeletonizer({
super.key,
});
@override
Widget build(BuildContext context) {
return Skeletonizer(
enabled: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
25.verticalSpace,
Text(
context.loc.allCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 10,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 140,
),
itemBuilder: (context, index) {
return WBrowseSkeletonizerItem();
},
),
],
),
);
}
}

View File

@@ -0,0 +1,117 @@
import '../../../../../../food_delivery_client.dart';
class WBrowseBody extends StatefulWidget {
const WBrowseBody({super.key});
@override
State<WBrowseBody> createState() => _WBrowseBodyState();
}
class _WBrowseBodyState extends State<WBrowseBody> {
late FocusNode _focusNode;
late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController();
_focusNode = FocusNode();
_focusNode.addListener(() {
context.read<BrowseBloc>().add(BrowseEvent.focusChanged(true));
});
super.initState();
}
void listener() {
_focusNode.addListener(() {
log("${_focusNode.hasFocus}");
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DecoratedBox(
decoration: BoxDecoration(color: AppColors.cFFFFFF),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
10.verticalSpace,
Row(
spacing: 15,
children: [
/*
InkWell(
onTap: () {},
borderRadius: AppUtils.kBorderRadius25,
child: Ink(
height: 44,
width: 44,
decoration: BoxDecoration(
color: AppColors.cEEEEEE,
borderRadius: AppUtils.kBorderRadius25,
),
child: SizedBox(
height: 44,
width: 44,
child: SvgPicture.asset(
AppIcons.icBack,
height: 20,
width: 20,
).paddingAll(10),
),
),
),
*/
Expanded(
child: AppTextFormField(
focusNode: _focusNode,
controller: _controller,
prefixIcon: SvgPicture.asset(AppIcons.icSearch),
hintText: context.loc.categoriesShort,
hintTextStyle: AppTextStyles.size16Medium.copyWith(
color: AppColors.c660000,
),
),
),
],
),
15.verticalSpace,
],
),
),
Expanded(
child: RefreshIndicator.adaptive(
onRefresh: () async {
context.read<BrowseBloc>()
..add(BrowseEvent.getTopCategories())
..add(BrowseEvent.getAllCategories());
},
child: SingleChildScrollView(
child: Column(
children: [
WTopCategories(),
WAllCategories(),
40.verticalSpace,
],
),
),
),
),
],
);
},
).paddingSymmetric(horizontal: 16);
}
}

View File

@@ -0,0 +1,57 @@
import '../../../../../../food_delivery_client.dart';
class WBrowseItem extends StatelessWidget {
const WBrowseItem({
super.key,
});
@override
Widget build(BuildContext context) {
return Bounceable(
onTap: () {},
child: Ink(
decoration: BoxDecoration(
color: AppColors.cFFFFFF,
borderRadius: AppUtils.kBorderRadius15,
),
child: Column(
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadiusTop15,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.foodImageUrl,
width: context.w,
height:120,
fit: BoxFit.cover,
),
),
Expanded(
child: SizedBox(
width: context.w,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: AppUtils.kBorderRadiusBottom15,
border: Border.all(
color: AppColors.cE8E8E8,
width: 1,
),
),
child: Align(
alignment: AlignmentGeometry.center,
child: Text(
"Restaurant",
textAlign: TextAlign.center,
style: AppTextStyles.size16Regular.copyWith(
height: 20 / 16,
),
).paddingSymmetric(horizontal: 30,vertical:5),
),
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,52 @@
import '../../../../../../food_delivery_client.dart';
class WBrowseSkeletonizerItem extends StatelessWidget {
const WBrowseSkeletonizerItem({
super.key,
});
@override
Widget build(BuildContext context) {
return Bounceable(
onTap: () {},
child: Ink(
decoration: BoxDecoration(
color: AppColors.cFFFFFF,
borderRadius: AppUtils.kBorderRadius15,
),
child: Column(
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadiusTop15,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.foodImageUrl,
width: context.w,
height: 96,
fit: BoxFit.cover,
),
),
SizedBox(
width: context.w,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: AppUtils.kBorderRadiusBottom15,
border: Border.all(
color: AppColors.cE6E6E6,
width: 1,
),
),
child: Text(
"Restaurant Rewards",
textAlign: TextAlign.center,
style: AppTextStyles.size16Regular.copyWith(
height: 20 / 16,
),
).paddingSymmetric(horizontal: 30),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,52 @@
import '../../../../../../food_delivery_client.dart';
class WTopCategories extends StatelessWidget {
const WTopCategories({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
if (state.topCategorySt.isLoaded()) {
return WTopCategoriesBody();
}
return WTopCategoriesSkeletonizer();
},
);
}
}
class WTopCategoriesBody extends StatelessWidget {
const WTopCategoriesBody({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.loc.topCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 6,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 175,
),
itemBuilder: (context, index) {
return WBrowseItem();
},
),
],
);
}
}

View File

@@ -0,0 +1,40 @@
import '../../../../../../food_delivery_client.dart';
class WTopCategoriesSkeletonizer extends StatelessWidget {
const WTopCategoriesSkeletonizer({super.key});
@override
Widget build(BuildContext context) {
return Skeletonizer(
enabled: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.loc.topCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 6,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 140,
),
itemBuilder: (context, index) {
return WBrowseSkeletonizerItem();
},
),
],
),
);
}
}

Some files were not shown because too many files have changed in this diff Show More