forked from eatvio/eatvio_app
Merge pull request 'fix: test-flight' (#405) from main into test-flight
Reviewed-on: eatvio/eatvio_app#405
This commit is contained in:
@@ -8,48 +8,7 @@ jobs:
|
||||
build:
|
||||
runs-on: [macos-arm64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download provisioning
|
||||
uses: mso7nueh/apple-provisioning-profiles-downloader@v1.0.8
|
||||
with:
|
||||
profile-type: IOS_APP_STORE
|
||||
bundle-id: com.eatvioapp.app
|
||||
issuer-id: ${{ vars.APPSTORE_ISSUER_ID }}
|
||||
api-key-id: ${{ vars.APPSTORE_KEY_ID }}
|
||||
api-private-key: ${{ vars.APPSTORE_PRIVATE_KEY }}
|
||||
|
||||
- name: Unlock keychain
|
||||
- name: Run Fastlane
|
||||
run: |
|
||||
security unlock-keychain -p "EeChahboo9Ei" login.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k "EeChahboo9Ei" login.keychain
|
||||
|
||||
- name: Ensure private key access
|
||||
run: |
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k "EeChahboo9Ei" ~/Library/Keychains/login.keychain-db
|
||||
|
||||
- name: List identities in keychain
|
||||
run: |
|
||||
security list-keychains
|
||||
security find-identity -v -p codesigning login.keychain
|
||||
|
||||
- name: Set keychain default
|
||||
run: |
|
||||
security default-keychain -s login.keychain
|
||||
|
||||
- name: Build with Flutter
|
||||
run: |
|
||||
flutter clean
|
||||
flutter pub get
|
||||
flutter pub upgrade
|
||||
flutter pub run build_runner build --delete-conflicting-outputs
|
||||
flutter build ipa --export-options-plist=Support/ExportOptions.plist --release
|
||||
|
||||
- name: Upload to TestFlight
|
||||
uses: mso7nueh/upload-testflight-build@master
|
||||
with:
|
||||
app-path: ./build/ios/ipa/eatvio_app.ipa
|
||||
issuer-id: ${{ vars.APPSTORE_ISSUER_ID }}
|
||||
api-key-id: ${{ vars.APPSTORE_KEY_ID }}
|
||||
api-private-key: ${{ vars.APPSTORE_PRIVATE_KEY }}
|
||||
cd ios
|
||||
fastlane beta
|
||||
@@ -41,6 +41,8 @@ jobs:
|
||||
wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip -O commandlinetools.zip
|
||||
unzip commandlinetools.zip
|
||||
mkdir -p ${{ env.my_local_cache_dir }}Android/Sdk/cmdline-tools/latest
|
||||
rm -rf ${{ env.my_local_cache_dir }}Android/Sdk/cmdline-tools/latest
|
||||
mkdir -p ${{ env.my_local_cache_dir }}Android/Sdk/cmdline-tools/latest
|
||||
mv cmdline-tools/* ${{ env.my_local_cache_dir }}Android/Sdk/cmdline-tools/latest/
|
||||
export ANDROID_SDK_ROOT=${{ env.my_local_cache_dir }}Android/Sdk
|
||||
export PATH=$PATH:${{ env.my_local_cache_dir }}Android/Sdk/cmdline-tools/latest/bin
|
||||
|
||||
11
assets/icons/edit_paint.svg
Normal file
11
assets/icons/edit_paint.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1_84405)">
|
||||
<path d="M14.1226 0.273893C13.9443 0.330415 13.7009 0.430415 13.5791 0.495632C13.4356 0.57824 11.6661 2.31737 8.0052 5.97389C3.29651 10.6782 2.63129 11.3565 2.51825 11.5869C2.39216 11.8348 2.37911 11.913 2.25738 13.2391C2.1052 14.8782 2.09651 15.213 2.20955 15.4609C2.37911 15.8348 2.70085 16.0826 3.1052 16.1478C3.29651 16.1782 6.02694 15.9435 6.33998 15.8695C6.83564 15.7478 6.70955 15.8652 12.2835 10.2913C18.1313 4.44346 17.8574 4.73911 18.0443 3.99998C18.2139 3.33911 18.1095 2.62607 17.7574 2.01737C17.6922 1.89998 17.3704 1.53911 17.0443 1.21737C16.3965 0.569545 16.0835 0.365197 15.5574 0.23911C15.14 0.143457 14.5226 0.156502 14.1226 0.273893ZM15.2835 1.63476C15.4574 1.69563 15.5922 1.80433 16.0226 2.23476C16.4487 2.66085 16.5617 2.79998 16.6182 2.97389C16.8009 3.51737 16.6791 3.83041 16.0226 4.47824L15.5617 4.93476L14.44 3.81302L13.3226 2.69128L13.8226 2.19998C14.1965 1.83476 14.3748 1.69128 14.5182 1.63911C14.7748 1.55215 15.0182 1.54781 15.2835 1.63476ZM10.2922 10.2087C7.96607 12.5348 6.02259 14.4478 5.97477 14.4565C5.87042 14.4826 3.58781 14.6956 3.57477 14.6782C3.57042 14.6739 3.6139 14.1217 3.67477 13.4522L3.78781 12.2391L8.03564 7.99128L12.2791 3.73911L13.3965 4.8565L14.5182 5.97824L10.2922 10.2087Z" fill="#2F80ED"/>
|
||||
<path d="M0.409546 18.4521C0.244329 18.526 0.148677 18.6304 0.06172 18.8391C-0.0295844 19.0565 -0.0208887 19.213 0.0965026 19.4347C0.166068 19.5652 0.257372 19.6565 0.387807 19.726L0.574764 19.826H9.9965H19.4182L19.6052 19.726C19.8226 19.613 19.9965 19.3347 19.9965 19.113C19.9965 18.9304 19.8313 18.613 19.6791 18.5043L19.5574 18.413L10.0487 18.4043C2.22259 18.3956 0.518242 18.4043 0.409546 18.4521Z" fill="#2F80ED"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1_84405">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
6
assets/icons/red_trash.svg
Normal file
6
assets/icons/red_trash.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.01268 0.0752392C5.47681 0.262703 5.0649 0.668873 4.87694 1.20002C4.81696 1.36405 4.80096 1.52417 4.80096 1.87957V2.34042H3.12934C1.5737 2.34042 1.43773 2.34432 1.22978 2.41462C0.813875 2.55522 0.473952 2.8247 0.226009 3.21134C-0.101916 3.72686 -0.069923 4.57044 0.301992 5.10549C0.465954 5.33982 0.825872 5.63273 1.06182 5.72256L1.22178 5.78114L1.75766 12.0807C2.04959 15.5487 2.30553 18.47 2.32553 18.5716C2.4415 19.1925 2.95738 19.7471 3.59724 19.9385C3.87317 20.0205 14.1268 20.0205 14.4028 19.9385C14.6947 19.8526 14.8907 19.7393 15.1346 19.5245C15.3825 19.298 15.6145 18.8957 15.6745 18.5755C15.6945 18.47 15.9504 15.5487 16.2423 12.0846L16.7782 5.78114L16.9382 5.72256C17.1741 5.63273 17.534 5.33982 17.698 5.10549C18.0699 4.57044 18.1019 3.72686 17.774 3.21134C17.526 2.8247 17.1861 2.55522 16.7702 2.41462C16.5623 2.34432 16.4263 2.34042 14.8707 2.34042H13.199V1.87957C13.199 1.52417 13.183 1.36405 13.1231 1.20002C12.9351 0.66106 12.5192 0.254892 11.9713 0.0713348C11.7554 0.00103569 11.6194 -0.00287056 8.984 0.00103569C6.3966 0.00103569 6.20864 0.00884628 6.01268 0.0752392ZM11.6714 1.26641C11.8953 1.3992 11.9673 1.55932 11.9913 1.9733L12.0113 2.34042H9H5.98869L6.00869 1.9733C6.03668 1.47731 6.15665 1.28594 6.50057 1.20392C6.56856 1.1883 7.72829 1.17658 9.07998 1.18049C11.4634 1.1883 11.5434 1.19221 11.6714 1.26641ZM16.4783 3.61751C16.6622 3.72686 16.7582 3.89479 16.7582 4.09788C16.7582 4.30096 16.6622 4.4689 16.4783 4.57825L16.3383 4.66417H9C1.73366 4.66417 1.66168 4.66417 1.52971 4.58606C1.07382 4.31659 1.17779 3.67218 1.69767 3.54721C1.76566 3.53159 5.0889 3.52378 9.07998 3.52378L16.3383 3.53159L16.4783 3.61751ZM15.5185 5.88268C15.5185 5.90221 15.2826 8.70634 14.9946 12.1236C14.5787 17.0445 14.4587 18.3607 14.4068 18.4661C14.3228 18.6341 14.1828 18.7356 13.9749 18.7825C13.7669 18.8293 4.23309 18.8293 4.02514 18.7825C3.81719 18.7356 3.67722 18.6341 3.59324 18.4661C3.54125 18.3607 3.42128 17.0445 3.00537 12.1236C2.71744 8.70634 2.48149 5.90221 2.48149 5.88268C2.48149 5.86706 5.41682 5.85534 9 5.85534C12.5872 5.85534 15.5185 5.86706 15.5185 5.88268Z" fill="#FF3B3B"/>
|
||||
<path d="M5.06478 7.10111C4.85683 7.23389 4.80084 7.36668 4.80084 7.71036C4.80084 7.8822 4.93681 10.1005 5.09677 12.6391C5.4207 17.7084 5.38471 17.4038 5.66464 17.5756C5.8446 17.681 6.17653 17.6771 6.34449 17.5639C6.54844 17.4272 6.60043 17.3061 6.60043 16.9585C6.60043 16.7906 6.46446 14.5762 6.3045 12.0337C6.01656 7.50337 6.00857 7.41355 5.91659 7.28467C5.8646 7.21046 5.77662 7.12454 5.71663 7.08939C5.56467 6.99957 5.21275 7.00738 5.06478 7.10111Z" fill="#FF3B3B"/>
|
||||
<path d="M8.66393 7.10121C8.60395 7.14027 8.51597 7.22619 8.47598 7.28477C8.40399 7.39412 8.39999 7.56596 8.39999 12.3385C8.39999 17.1109 8.40399 17.2828 8.47598 17.3921C8.59995 17.5718 8.75191 17.6499 8.99986 17.6499C9.2478 17.6499 9.39977 17.5718 9.52374 17.3921C9.59572 17.2828 9.59972 17.1109 9.59972 12.3385C9.59972 7.56596 9.59572 7.39412 9.52374 7.28477C9.39977 7.10512 9.2478 7.02701 8.99986 7.02701C8.85189 7.02701 8.74392 7.05044 8.66393 7.10121Z" fill="#FF3B3B"/>
|
||||
<path d="M12.2632 7.10121C11.9833 7.28086 12.0193 6.95671 11.6953 12.0377C11.5354 14.5763 11.3994 16.7946 11.3994 16.9664C11.3994 17.3101 11.4554 17.4429 11.6634 17.5757C11.8193 17.6772 12.1672 17.6772 12.3352 17.5757C12.6151 17.4039 12.5791 17.7085 12.9031 12.6392C13.063 10.1006 13.199 7.88231 13.199 7.71047C13.199 7.36678 13.143 7.234 12.9351 7.10121C12.7751 6.99967 12.4192 6.99967 12.2632 7.10121Z" fill="#FF3B3B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
5
assets/icons/remove_from_public.svg
Normal file
5
assets/icons/remove_from_public.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.41406 3.63281C6.50391 3.85547 3.34766 5.75391 0.675781 8.89453C0.078125 9.59766 0 9.72266 0 10C0 10.2773 0.078125 10.4023 0.675781 11.1055C2.87891 13.6953 5.51953 15.5156 7.95703 16.1289C8.66016 16.3047 9.25781 16.375 10 16.375C10.7578 16.375 11.3594 16.3008 12.0898 16.1133C14.5156 15.4922 17.1328 13.6797 19.3242 11.1055C19.9219 10.4023 20 10.2773 20 10C20 9.72266 19.9219 9.59766 19.3242 8.89453C17.1211 6.30469 14.4805 4.48437 12.043 3.87109C11.2031 3.66015 10.2188 3.57422 9.41406 3.63281ZM11.0742 5.05859C13.1172 5.42187 15.2031 6.64453 17.2305 8.66797C17.8945 9.33594 18.4375 9.93359 18.4375 10C18.4375 10.1211 16.8438 11.7617 16.1914 12.3086C14.457 13.7656 12.7617 14.6367 11.0547 14.9492C10.5977 15.0312 9.49609 15.0391 9.04297 14.9648C7.15625 14.6562 5.21484 13.6016 3.3125 11.8594C2.63672 11.2422 1.5625 10.0977 1.5625 10C1.5625 9.87891 3.15625 8.23828 3.80859 7.69141C5.71094 6.09375 7.59375 5.1875 9.43359 4.98437C9.73438 4.95312 10.7266 4.99609 11.0742 5.05859Z" fill="#2F80ED"/>
|
||||
<path d="M9.49999 6.05859C8.40234 6.1875 7.32421 6.85156 6.69531 7.79687C5.64843 9.36719 5.85546 11.4687 7.19531 12.8047C8.74218 14.3555 11.2578 14.3555 12.8047 12.8047C14.3555 11.2578 14.3555 8.74219 12.8047 7.19531C12.168 6.55469 11.3437 6.16016 10.4492 6.05469C10.0547 6.01172 9.90624 6.01172 9.49999 6.05859ZM10.5273 7.44141C10.6797 7.47266 10.9687 7.58203 11.1719 7.67969C12.0352 8.10937 12.6172 9.03906 12.6172 10C12.6172 10.9609 12.0352 11.8906 11.1719 12.3203C10.3672 12.7148 9.63281 12.7148 8.82812 12.3203C7.96484 11.8906 7.38281 10.9609 7.38281 10C7.38281 9.61328 7.48046 9.23828 7.67968 8.82812C8.19921 7.78125 9.38281 7.20312 10.5273 7.44141Z" fill="#2F80ED"/>
|
||||
<rect x="3" y="2" width="21" height="1.5" rx="0.75" transform="rotate(45 3 2)" fill="#2F80ED"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
3
assets/icons/star.svg
Normal file
3
assets/icons/star.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="32" height="29" viewBox="0 0 32 29" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.8652 10.0557C19.133 10.8796 19.9012 11.4374 20.7676 11.4375H30.041L22.5391 16.8887C21.8818 17.3662 21.5825 18.1896 21.7686 18.9697L21.8125 19.125L24.6777 27.9443L17.1758 22.4932C16.5186 22.0157 15.6434 21.9866 14.959 22.4043L14.8242 22.4932L7.32227 27.9443L10.1875 19.125C10.4385 18.3524 10.1967 17.5101 9.58789 16.9883L9.46094 16.8887L1.95898 11.4375H11.2324C12.0446 11.4374 12.77 10.9472 13.0781 10.207L13.1348 10.0557L16 1.23633L18.8652 10.0557Z" stroke="#2F80ED" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 602 B |
9
assets/images/logo_welcome.svg
Normal file
9
assets/images/logo_welcome.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="168" height="104" viewBox="0 0 168 104" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.2589 85.7787L6.61498 101.745C5.53182 103.243 4.29393 103.991 2.90131 103.991C0.967105 103.991 0 102.667 0 100.02V78.7182C0 75.5622 1.07026 73.9846 3.21078 73.9846C5.3513 73.9846 6.42155 75.5622 6.42155 78.7182V92.438L18.2975 76.1511C19.3549 74.707 20.4897 73.9846 21.7017 73.9846C23.6875 73.9846 24.6804 75.482 24.6804 78.4774V99.2577C24.6804 102.414 23.6102 103.991 21.4696 103.991C19.3291 103.991 18.2589 102.414 18.2589 99.2577V85.7787Z" fill="#323F4B"/>
|
||||
<path d="M43.4542 80.5167C41.1284 80.5167 39.6813 80.4498 39.1128 80.316C37.3813 79.9409 36.5156 78.9758 36.5156 77.4213C36.5156 75.3317 38.0403 74.2861 41.0896 74.2861H52.2921C55.3415 74.2861 56.8661 75.3317 56.8661 77.4213C56.8661 78.9758 56.0005 79.9409 54.269 80.316C53.7006 80.4498 52.2534 80.5167 49.9276 80.5167V99.2482C49.9276 102.41 48.8551 103.991 46.7103 103.991C44.5395 103.991 43.4542 102.41 43.4542 99.2482V80.5167Z" fill="#323F4B"/>
|
||||
<path d="M73.0443 103.69C71.43 103.69 70.3026 103.407 69.6621 102.844C69.0215 102.253 68.7012 101.125 68.7012 99.4604V78.9989C68.7012 77.2537 69.0215 76.0321 69.6621 75.3338C70.3026 74.6356 71.4557 74.2861 73.1212 74.2861H78.348C80.8846 74.2861 83.037 74.8367 84.8051 75.9379C86.9574 77.2538 88.034 79.1465 88.034 81.6171C88.034 84.8121 86.9318 86.9738 84.7282 88.1021V88.2226C86.3683 88.7597 87.5466 89.5521 88.2645 90.599C88.9817 91.6196 89.3403 93.0288 89.3403 94.8282C89.3403 97.8087 88.3542 100.078 86.3811 101.635C84.6386 103.005 82.2941 103.69 79.3477 103.69H73.0443ZM75.0814 91.002V97.9299H78.2712C79.6295 97.9299 80.6413 97.7416 81.308 97.3658C82.1789 96.8559 82.6143 95.943 82.6143 94.6271C82.6143 93.0966 82.1917 92.076 81.3464 91.5654C80.7309 91.1895 79.6679 91.002 78.1559 91.002H75.0814ZM75.0814 80.006V85.7657H77.8485C79.1044 85.7657 79.9881 85.6045 80.5004 85.2821C81.2183 84.8528 81.5769 84.0469 81.5769 82.8659C81.5769 80.9588 80.3339 80.006 77.8485 80.006H75.0814Z" fill="#323F4B"/>
|
||||
<path d="M121.166 85.7787L109.522 101.745C108.439 103.243 107.201 103.991 105.808 103.991C103.875 103.991 102.907 102.667 102.907 100.02V78.7182C102.907 75.5622 103.978 73.9846 106.118 73.9846C108.259 73.9846 109.329 75.5622 109.329 78.7182V92.438L121.205 76.1511C122.262 74.707 123.397 73.9846 124.609 73.9846C126.595 73.9846 127.588 75.482 127.588 78.4774V99.2577C127.588 102.414 126.518 103.991 124.377 103.991C122.237 103.991 121.166 102.414 121.166 99.2577V85.7787Z" fill="#323F4B"/>
|
||||
<path d="M140.722 89.0277C140.722 84.6422 141.919 81.0714 144.312 78.3168C146.784 75.4287 150.127 73.9846 154.341 73.9846C158.582 73.9846 161.938 75.4152 164.409 78.2771C166.803 81.0317 168 84.6152 168 89.0277C168 93.4139 166.803 96.9847 164.409 99.7394C161.912 102.574 158.556 103.991 154.341 103.991C150.127 103.991 146.784 102.561 144.312 99.6988C141.919 96.9712 140.722 93.4139 140.722 89.0277ZM147.59 89.108C147.59 91.5153 148.123 93.5077 149.19 95.0853C150.387 96.9307 152.104 97.8534 154.341 97.8534C156.579 97.8534 158.309 96.9442 159.531 95.1258C160.599 93.5212 161.132 91.5153 161.132 89.108C161.132 86.6212 160.625 84.5755 159.609 82.9709C158.387 81.0714 156.631 80.1225 154.341 80.1225C152.052 80.1225 150.309 81.0714 149.112 82.9709C148.097 84.5755 147.59 86.6212 147.59 89.108Z" fill="#323F4B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M84.0105 0C102.659 0 117.773 8.59537 117.773 28.1847C117.773 47.752 102.659 63.6323 84.0105 63.6323C65.3404 63.6323 50.2266 47.752 50.2266 28.1847C50.2266 8.59537 65.3404 0 84.0105 0Z" fill="#43A6F2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M83.8669 41.4666C79.4151 41.4666 75.0485 40.5474 70.9749 38.7731C66.9016 36.9774 63.2272 34.348 60.1827 31.0559C58.776 29.5595 58.8599 27.1653 60.3297 25.7544C61.8204 24.3222 64.1511 24.4077 65.5578 25.9041C67.9094 28.4479 70.7439 30.4788 73.8935 31.8469C77.0428 33.2364 80.4233 33.9419 83.8669 33.9419C87.2889 33.9419 90.6695 33.2364 93.8187 31.8469C96.9687 30.4788 99.8029 28.4479 102.154 25.9041C103.562 24.4077 105.892 24.3222 107.382 25.7544C108.853 27.1653 108.936 29.5595 107.53 31.0559C104.485 34.348 100.811 36.9774 96.7374 38.7731C92.6644 40.5474 88.2972 41.4666 83.8669 41.4666Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
1
assets/splash/bg.json
Normal file
1
assets/splash/bg.json
Normal file
@@ -0,0 +1 @@
|
||||
{"nm":"background","ddd":0,"h":1920,"w":1080,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":155,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"s":{"a":0,"k":[1160,880]}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100},"w":{"a":0,"k":6},"c":{"a":0,"k":[1,1,1]}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[374.412,342.611],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[22.822,357.191],"t":31},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[-420.714,389.994],"t":61},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[50.932,404.573],"t":91},{"s":[376.797,364.48],"t":120}]},"g":{"p":3,"k":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0.00784313725490196,0.4392156862745098,1,0.5,0.10196078431372549,0.4666666666666667,0.9411764705882353,1,0.9490196078431372,0.9490196078431372,0.9490196078431372],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0.3411764705882353,0.6039215686274509,0.9411764705882353,0.5,0.0392156862745098,0.4549019607843137,1,1,0.1568627450980392,0.42745098039215684,0.8823529411764706],"t":31},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0.3176470588235294,0.5568627450980392,0.8666666666666667,0.5,0.6392156862745098,0.796078431372549,1,1,1,1,1],"t":61},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0.1843137254901961,0.5019607843137255,0.9294117647058824,0.5,0.0784313725490196,0.596078431372549,0.7529411764705882,1,0,0.43529411764705883,1],"t":91},{"s":[0,0.00784313725490196,0.4392156862745098,1,0.5,0.5686274509803921,0.7411764705882353,0.9686274509803922,1,0.29411764705882354,0.5529411764705883,0.8862745098039215],"t":120}]}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[-430.769,-404.573],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[23.726,-364.48],"t":31},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[312.726,-353.48],"t":61},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[29.739,-353.48],"t":91},{"s":[-407.606,-357.125],"t":120}]},"r":1,"o":{"a":0,"k":100}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[93.29,219.491],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":1,"nm":"Deep Red Solid 1","sr":1,"st":0,"op":155,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[540,960,0]},"s":{"a":0,"k":[100,100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"ef":[],"sc":"#5095ef","sh":1920,"sw":1080,"ind":2}],"v":"4.6.10","fr":15,"op":155,"ip":0,"assets":[]}
|
||||
BIN
assets/splash/bg.lottie
Normal file
BIN
assets/splash/bg.lottie
Normal file
Binary file not shown.
@@ -386,12 +386,10 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = "VL68C36HYS";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = VL68C36HYS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -411,8 +409,7 @@
|
||||
MARKETING_VERSION = 1.0.50;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Distribution";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Distribution;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -539,12 +536,10 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = "VL68C36HYS";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = VL68C36HYS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -564,8 +559,7 @@
|
||||
MARKETING_VERSION = 1.0.50;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Distribution";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Distribution;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -580,12 +574,10 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
DEVELOPMENT_TEAM = "VL68C36HYS";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = VL68C36HYS;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -605,8 +597,7 @@
|
||||
MARKETING_VERSION = 1.0.50;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "Distribution";
|
||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Distribution;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/pages/auth_screen.dart';
|
||||
@@ -52,16 +54,21 @@ import 'package:eatvio_app/features/settings/presentation/pages/physical_form_sc
|
||||
import 'package:eatvio_app/features/settings/presentation/pages/pressure_screen.dart';
|
||||
import 'package:eatvio_app/features/settings/presentation/pages/settings_screen.dart';
|
||||
import 'package:eatvio_app/features/support/presentation/pages/support_screen.dart';
|
||||
import 'package:eatvio_app/features/update_screen/presentation/update_screen.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart';
|
||||
import 'package:eatvio_app/features/welcome/presentation/pages/welcome_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
class AppRouter {
|
||||
static GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
static GoRouter appRouter = GoRouter(
|
||||
initialLocation: '/my-profile-screen',
|
||||
initialLocation: '/update-screen',
|
||||
navigatorKey: navigatorKey,
|
||||
routes: [
|
||||
GoRoute(
|
||||
@@ -123,6 +130,37 @@ class AppRouter {
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
path: '/welcome-screen',
|
||||
name: 'welcomeScreen',
|
||||
builder: (context, state) => const WelcomeScreen(),
|
||||
redirect: (context, state) async {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
final welcomeScreenWasShowed = sharedPreferences.getBool('welcomeScreenWasShowed');
|
||||
if (welcomeScreenWasShowed == true) {
|
||||
return '/my-profile-screen';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/update-screen',
|
||||
name: 'updateScreen',
|
||||
builder: (context, state) => const UpdateScreen(),
|
||||
redirect: (context, state) async {
|
||||
final versions = (await sl<Dio>().get('$baseUrl/api/app_versions')).data;
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String version = packageInfo.version;
|
||||
Version currentVersion = Version.parse(version);
|
||||
Version latestVersion = Version.parse(versions['min_version']);
|
||||
if (latestVersion > currentVersion) {
|
||||
return null;
|
||||
} else {
|
||||
return '/welcome-screen';
|
||||
}
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/consultant-finance-screen',
|
||||
name: 'consultantFinanceScreen',
|
||||
@@ -136,7 +174,10 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: CardSettingsScreen.path,
|
||||
name: CardSettingsScreen.name,
|
||||
builder: (context, state) => const CardSettingsScreen(),
|
||||
builder: (context, state) {
|
||||
final chosenPlanId = state.extra as int?;
|
||||
return CardSettingsScreen(chosenPlanId: chosenPlanId);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/about-plan-screen',
|
||||
@@ -182,7 +223,8 @@ class AppRouter {
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final chatId = data['chatId'] as String;
|
||||
return ChatScreen(chatId: chatId);
|
||||
final sendInitialMessage = data['sendInitialMessage'] as bool?;
|
||||
return ChatScreen(chatId: chatId, sendInitialMessage: sendInitialMessage,);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// String baseUrl = 'https://eatvio.ru';
|
||||
String baseUrl = 'https://dev2.eatvio.com';
|
||||
String baseUrl = 'https://eatvio.ru';
|
||||
// String baseUrl = 'https://dev2.eatvio.com';
|
||||
|
||||
const List<int> durationValues = [7, 14, 21];
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_c
|
||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||
import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/repositories/create_plan_repository.dart';
|
||||
import 'package:eatvio_app/features/create_plan/services/create_plan_service.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/consultant_comments_cubit/consultant_comments_cubit.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/diets/services/diet_service.dart';
|
||||
@@ -96,11 +98,11 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<WsManager>(() => WsManager(wsService: sl()));
|
||||
sl.registerLazySingleton<NewMessagesCubit>(() => NewMessagesCubit());
|
||||
sl.registerLazySingleton<NotificationsCubit>(() => NotificationsCubit(wsManager: sl()));
|
||||
sl.registerLazySingleton<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||
sl.registerLazySingleton<ProfileAvatarCubit>(() => ProfileAvatarCubit(profileRepository: sl()));
|
||||
sl.registerLazySingleton<ChatsCubit>(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
|
||||
|
||||
// Cubit factories
|
||||
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
||||
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(cardsRepository: sl(), chatRepository: sl(), wsManager: sl()));
|
||||
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));
|
||||
@@ -112,12 +114,12 @@ Future<void> init() async {
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
sl.registerFactory<DiaryCubit>(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl()));
|
||||
sl.registerFactory<DiaryCubit>(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl()));
|
||||
sl.registerFactory<AboutDietCubit>(() => AboutDietCubit(dietsRepository: sl(), profileRepository: sl()));
|
||||
sl.registerFactory<BlogPostCreateCubit>(() => BlogPostCreateCubit(blogPostRepository: sl()));
|
||||
sl.registerFactory<SubCubit>(() => SubCubit(profileRepository: sl()));
|
||||
sl.registerFactory<CreateDietCubit>(() => CreateDietCubit(profileRepository: sl(), createDietRepository: sl(), glossaryRepository: sl()));
|
||||
sl.registerFactory<CreatePlanCubit>(() => CreatePlanCubit());
|
||||
sl.registerFactory<CreatePlanCubit>(() => CreatePlanCubit(createPlanRepository: sl()));
|
||||
sl.registerFactory<FeedProfileCubit>(() => FeedProfileCubit(profileRepository: sl()));
|
||||
sl.registerFactory<AboutPlanCubit>(() => AboutPlanCubit(planRepository: sl()));
|
||||
sl.registerFactory<CreateRecipeCubit>(() => CreateRecipeCubit(recipeRepository: sl()));
|
||||
@@ -158,6 +160,7 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<CardsRepository>(() => CardsRepository(cardsService: sl()));
|
||||
sl.registerLazySingleton<ConsultationsRepository>(() => ConsultationsRepository(consultationService: sl()));
|
||||
sl.registerLazySingleton<CancelPlanRepository>(() => CancelPlanRepository(cancelService: sl()));
|
||||
sl.registerLazySingleton<CreatePlanRepository>(() => CreatePlanRepository(createPlanService: sl()));
|
||||
|
||||
// Services
|
||||
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
|
||||
@@ -184,6 +187,7 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<CardsService>(() => CardsService(sl()));
|
||||
sl.registerLazySingleton<ConsultationService>(() => ConsultationService(sl()));
|
||||
sl.registerLazySingleton<CancelPlanService>(() => CancelPlanService(sl()));
|
||||
sl.registerLazySingleton<CreatePlanService>(() => CreatePlanService(sl()));
|
||||
|
||||
// External
|
||||
sl.registerLazySingleton(
|
||||
|
||||
@@ -147,6 +147,8 @@ class PrimaryColors {
|
||||
|
||||
Color get greenA70001 => const Color(0XFF00BE13);
|
||||
|
||||
Color get green => const Color(0XFF0BB450);
|
||||
|
||||
// LightGreen
|
||||
Color get lightGreen300 => const Color(0XFFB2DF8A);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
|
||||
Future<void> showBottomSheetWithBlur({
|
||||
required BuildContext context,
|
||||
required Widget child,
|
||||
double height = 200,
|
||||
double? height = 200,
|
||||
bool hasBlur = true,
|
||||
bool enableDrag = true,
|
||||
bool userRootNavigator = false,
|
||||
|
||||
230
lib/core/widgets/custom_popup.dart
Normal file
230
lib/core/widgets/custom_popup.dart
Normal file
@@ -0,0 +1,230 @@
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class CustomPopup extends StatelessWidget {
|
||||
final bool isAuthor;
|
||||
final ComplainedContent? complainedContentType;
|
||||
final String path;
|
||||
final String? slug;
|
||||
final int? id;
|
||||
final FeedBlogPostModel? feedBlogPostModel;
|
||||
|
||||
const CustomPopup({
|
||||
super.key,
|
||||
required this.isAuthor,
|
||||
this.complainedContentType,
|
||||
required this.path,
|
||||
this.id,
|
||||
this.slug,
|
||||
this.feedBlogPostModel,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
final RenderBox button = context.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final Offset position = button.localToGlobal(Offset.zero, ancestor: overlay);
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
position.dx,
|
||||
position.dy + button.size.height,
|
||||
position.dx + button.size.width,
|
||||
position.dy,
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
color: Colors.white,
|
||||
constraints: const BoxConstraints(minWidth: 260),
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 2,
|
||||
items: _buildMenuItems(s, context),
|
||||
);
|
||||
},
|
||||
child: const Icon(
|
||||
Icons.more_horiz_rounded,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<PopupMenuEntry> _buildMenuItems(s, context) {
|
||||
final entries = <PopupMenuEntry>[];
|
||||
|
||||
void addItem(String icon, String text, Function() onTap) {
|
||||
entries.add(_buildCompactItem(icon: icon, text: text, onTap: onTap));
|
||||
entries.add(_buildDivider());
|
||||
}
|
||||
|
||||
if (isAuthor) {
|
||||
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
||||
showInfoToast(s.link_was_copied);
|
||||
});
|
||||
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
Share.shareUri(
|
||||
Uri.parse(
|
||||
'$baseUrl/ru/$path',
|
||||
),
|
||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
});
|
||||
addItem('assets/icons/edit_paint.svg', 'Редактировать', () {
|
||||
if (complainedContentType == ComplainedContent.posts) {
|
||||
GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel);
|
||||
} else {
|
||||
showInfoToast('В разработке');
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (complainedContentType == ComplainedContent.plan || complainedContentType == ComplainedContent.diet) {
|
||||
addItem('assets/icons/remove_from_public.svg', 'Снять с публикации', () async {
|
||||
if (complainedContentType == ComplainedContent.diet) {
|
||||
final result = await sl<MyDietsCubit>().unpublishDiet(id!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('Диета перенесена в архив, обновите ленту');
|
||||
} else if (complainedContentType == ComplainedContent.plan) {
|
||||
final result = await sl<MyPlansCubit>().unpublish(slug!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('План перенесен в архив, обновите ленту');
|
||||
}
|
||||
});
|
||||
}
|
||||
addItem('assets/icons/red_trash.svg', 'Удалить', () async {
|
||||
if (complainedContentType == ComplainedContent.posts) {
|
||||
final result = await sl<BlogPostCreateCubit>().deleteBlogPost(id!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('Пост удален, обновите ленту');
|
||||
} else if (complainedContentType == ComplainedContent.recipe) {
|
||||
final result = await sl<RecipesCubit>().deleteRecipe(slug!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('Рецепт удален, обновите ленту');
|
||||
} else if (complainedContentType == ComplainedContent.diet) {
|
||||
final result = await sl<DietsCubit>().deleteDiet(id!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('Диета удалена, обновите ленту');
|
||||
} else if (complainedContentType == ComplainedContent.plan) {
|
||||
final result = await sl<MyPlansCubit>().deletePlan(slug!);
|
||||
if (!context.mounted) return;
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
showSuccessToast('План удален, обновите ленту');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
addItem('assets/icons/copy2.svg', 'Скопировать ссылку', () {
|
||||
Clipboard.setData(ClipboardData(text: '$baseUrl/ru/$path'));
|
||||
showInfoToast(s.link_was_copied);
|
||||
});
|
||||
addItem('assets/icons/share2.svg', 'Поделиться', () {
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
Share.shareUri(
|
||||
Uri.parse(
|
||||
'$baseUrl/ru/$path',
|
||||
),
|
||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
});
|
||||
addItem('assets/icons/complain.svg', 'Пожаловаться', () {
|
||||
if (complainedContentType != null) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => ComplainingBottomSheet(
|
||||
complainedContentType: complainedContentType!,
|
||||
id: id,
|
||||
slug: slug,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (entries.isNotEmpty && entries.last is PopupMenuItem) {
|
||||
entries.removeLast();
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
PopupMenuItem _buildCompactItem({required String icon, required String text, required Function() onTap}) {
|
||||
return PopupMenuItem(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
height: 36,
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(text, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
|
||||
const Spacer(),
|
||||
SvgPicture.asset(icon),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
PopupMenuItem _buildDivider() {
|
||||
return PopupMenuItem(
|
||||
enabled: false,
|
||||
height: 1,
|
||||
padding: EdgeInsets.zero,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||
height: 1,
|
||||
color: appTheme.dividerColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ class CustomTextFormField extends StatelessWidget {
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
style: const TextStyle(fontSize: 16, color: Colors.black, fontWeight: FontWeight.w500),
|
||||
style: textStyle ?? const TextStyle(fontSize: 16, color: Colors.black, fontWeight: FontWeight.w500),
|
||||
obscureText: obscureText!,
|
||||
textInputAction: textInputAction,
|
||||
maxLines: maxLines,
|
||||
@@ -115,20 +115,17 @@ class CustomTextFormField extends StatelessWidget {
|
||||
prefixIconConstraints: prefixConstraints,
|
||||
suffixIcon: suffix,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
suffixStyle: textStyle ?? const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF323F4B)),
|
||||
suffixStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF323F4B)),
|
||||
suffixIconConstraints: suffixConstraints,
|
||||
isDense: false,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||
fillColor: const Color(0xFFF6F6F6),
|
||||
filled: true,
|
||||
border:
|
||||
borderDecoration ??
|
||||
border: borderDecoration ??
|
||||
OutlineInputBorder(borderRadius: BorderRadius.circular(20), borderSide: hasError ? BorderSide(color: appTheme.red, width: 1) : BorderSide.none),
|
||||
enabledBorder:
|
||||
borderDecoration ??
|
||||
enabledBorder: borderDecoration ??
|
||||
OutlineInputBorder(borderRadius: BorderRadius.circular(20), borderSide: hasError ? BorderSide(color: appTheme.red, width: 1) : BorderSide.none),
|
||||
focusedBorder:
|
||||
borderDecoration ??
|
||||
focusedBorder: borderDecoration ??
|
||||
OutlineInputBorder(borderRadius: BorderRadius.circular(20), borderSide: hasError ? BorderSide(color: appTheme.red, width: 1) : BorderSide.none),
|
||||
),
|
||||
keyboardType: keyboardType,
|
||||
|
||||
@@ -7,9 +7,10 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class SuccessPublishedDietBottomSheet extends StatelessWidget {
|
||||
const SuccessPublishedDietBottomSheet({super.key, required this.title});
|
||||
class SuccessPublishedDietOrPlanBottomSheet extends StatelessWidget {
|
||||
const SuccessPublishedDietOrPlanBottomSheet({super.key, required this.title, this.isPlan = false});
|
||||
final String title;
|
||||
final bool isPlan;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
@@ -27,7 +28,7 @@ class SuccessPublishedDietBottomSheet extends StatelessWidget {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
Text(
|
||||
'опубликованна',
|
||||
isPlan ? 'опубликован' : 'опубликованна',
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(
|
||||
|
||||
@@ -3,10 +3,8 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart';
|
||||
@@ -14,7 +12,6 @@ import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
@@ -104,8 +101,10 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
||||
height: 1.2,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
isDense: false, // убираем true, чтобы padding учитывался корректно
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), // вертикальный паддинг увеличен
|
||||
isDense: false,
|
||||
// убираем true, чтобы padding учитывался корректно
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
// вертикальный паддинг увеличен
|
||||
hintText: 'Комментарий',
|
||||
hintStyle: const TextStyle(
|
||||
fontSize: 16,
|
||||
@@ -161,39 +160,14 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
||||
appBar: AppBar(
|
||||
title: Text(widget.blogPost.title),
|
||||
actions: [
|
||||
PopupMenuButton(
|
||||
onSelected: (value) async {
|
||||
if (value == 'delete') {
|
||||
final result = await sl<BlogPostCreateCubit>().deleteBlogPost(widget.blogPost.id);
|
||||
if (!context.mounted) return;
|
||||
if (!result) {
|
||||
showErrorDialog(context, title: S.current.could_not_delete_blog_post);
|
||||
return;
|
||||
}
|
||||
context.read<FeedCubit>().loadFeedBlogPostList();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
if (value == 'edit') {
|
||||
GoRouter.of(context).replaceNamed('blogPostCreateScreen', extra: widget.blogPost);
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
if (widget.blogPost.author.authorIsMe) const PopupMenuItem(value: 'edit', child: Text('Редактировать')),
|
||||
if (widget.blogPost.author.authorIsMe) const PopupMenuItem(value: 'delete', child: Text('Удалить')),
|
||||
if (!widget.blogPost.author.authorIsMe)
|
||||
PopupMenuItem(
|
||||
value: 'report',
|
||||
child: const Text('Пожаловаться'),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => ComplainingBottomSheet(complainedContentType: ComplainedContent.posts, id: widget.blogPost.id),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
CustomPopup(
|
||||
isAuthor: widget.blogPost.author.authorIsMe,
|
||||
complainedContentType: ComplainedContent.posts,
|
||||
path: 'blog_post/${(widget.blogPost.id)}',
|
||||
id: widget.blogPost.id,
|
||||
feedBlogPostModel: widget.blogPost,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
@@ -209,7 +183,13 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
CircleAvatar(radius: 16, backgroundImage: NetworkImage(widget.blogPost.author.authorProfileIcon)),
|
||||
CircleAvatar(
|
||||
radius: 16,
|
||||
foregroundImage: NetworkImage(
|
||||
widget.blogPost.author.authorProfileIcon,
|
||||
),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
@@ -81,7 +81,8 @@ class _BottomNavigationBarWidgetState extends State<BottomNavigationBarWidget> {
|
||||
BottomNavigationBarItem(
|
||||
label: '',
|
||||
icon: CircleAvatar(
|
||||
backgroundImage: NetworkImage(widget.profileModel.profilePhotoUrl),
|
||||
foregroundImage: NetworkImage(widget.profileModel.profilePhotoUrl),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
radius: 16,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'cancel_plan_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CancelPlanState {}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CancelPlanStateCopyWith<$Res> {
|
||||
factory $CancelPlanStateCopyWith(
|
||||
CancelPlanState value, $Res Function(CancelPlanState) then) =
|
||||
_$CancelPlanStateCopyWithImpl<$Res, CancelPlanState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CancelPlanStateCopyWithImpl<$Res, $Val extends CancelPlanState>
|
||||
implements $CancelPlanStateCopyWith<$Res> {
|
||||
_$CancelPlanStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CancelPlanState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CancelPlanStateImplCopyWith<$Res> {
|
||||
factory _$$CancelPlanStateImplCopyWith(_$CancelPlanStateImpl value,
|
||||
$Res Function(_$CancelPlanStateImpl) then) =
|
||||
__$$CancelPlanStateImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CancelPlanStateImplCopyWithImpl<$Res>
|
||||
extends _$CancelPlanStateCopyWithImpl<$Res, _$CancelPlanStateImpl>
|
||||
implements _$$CancelPlanStateImplCopyWith<$Res> {
|
||||
__$$CancelPlanStateImplCopyWithImpl(
|
||||
_$CancelPlanStateImpl _value, $Res Function(_$CancelPlanStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of CancelPlanState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$CancelPlanStateImpl implements _CancelPlanState {
|
||||
_$CancelPlanStateImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CancelPlanState()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$CancelPlanStateImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
}
|
||||
|
||||
abstract class _CancelPlanState implements CancelPlanState {
|
||||
factory _CancelPlanState() = _$CancelPlanStateImpl;
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'cancelation_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
CancelationModel _$CancelationModelFromJson(Map<String, dynamic> json) {
|
||||
return _CancelationModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CancelationModel {
|
||||
String get description => throw _privateConstructorUsedError;
|
||||
int get price => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this CancelationModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of CancelationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$CancelationModelCopyWith<CancelationModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CancelationModelCopyWith<$Res> {
|
||||
factory $CancelationModelCopyWith(
|
||||
CancelationModel value, $Res Function(CancelationModel) then) =
|
||||
_$CancelationModelCopyWithImpl<$Res, CancelationModel>;
|
||||
@useResult
|
||||
$Res call({String description, int price});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CancelationModelCopyWithImpl<$Res, $Val extends CancelationModel>
|
||||
implements $CancelationModelCopyWith<$Res> {
|
||||
_$CancelationModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CancelationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? description = null,
|
||||
Object? price = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
price: null == price
|
||||
? _value.price
|
||||
: price // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CancelationModelImplCopyWith<$Res>
|
||||
implements $CancelationModelCopyWith<$Res> {
|
||||
factory _$$CancelationModelImplCopyWith(_$CancelationModelImpl value,
|
||||
$Res Function(_$CancelationModelImpl) then) =
|
||||
__$$CancelationModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String description, int price});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CancelationModelImplCopyWithImpl<$Res>
|
||||
extends _$CancelationModelCopyWithImpl<$Res, _$CancelationModelImpl>
|
||||
implements _$$CancelationModelImplCopyWith<$Res> {
|
||||
__$$CancelationModelImplCopyWithImpl(_$CancelationModelImpl _value,
|
||||
$Res Function(_$CancelationModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of CancelationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? description = null,
|
||||
Object? price = null,
|
||||
}) {
|
||||
return _then(_$CancelationModelImpl(
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
price: null == price
|
||||
? _value.price
|
||||
: price // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$CancelationModelImpl implements _CancelationModel {
|
||||
_$CancelationModelImpl({required this.description, required this.price});
|
||||
|
||||
factory _$CancelationModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$CancelationModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String description;
|
||||
@override
|
||||
final int price;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CancelationModel(description: $description, price: $price)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$CancelationModelImpl &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description) &&
|
||||
(identical(other.price, price) || other.price == price));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, description, price);
|
||||
|
||||
/// Create a copy of CancelationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CancelationModelImplCopyWith<_$CancelationModelImpl> get copyWith =>
|
||||
__$$CancelationModelImplCopyWithImpl<_$CancelationModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$CancelationModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _CancelationModel implements CancelationModel {
|
||||
factory _CancelationModel(
|
||||
{required final String description,
|
||||
required final int price}) = _$CancelationModelImpl;
|
||||
|
||||
factory _CancelationModel.fromJson(Map<String, dynamic> json) =
|
||||
_$CancelationModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get description;
|
||||
@override
|
||||
int get price;
|
||||
|
||||
/// Create a copy of CancelationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CancelationModelImplCopyWith<_$CancelationModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'cancelation_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$CancelationModelImpl _$$CancelationModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$CancelationModelImpl(
|
||||
description: json['description'] as String,
|
||||
price: (json['price'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$CancelationModelImplToJson(
|
||||
_$CancelationModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'description': instance.description,
|
||||
'price': instance.price,
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'cancel_plan_service.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RetrofitGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations
|
||||
|
||||
class _CancelPlanService implements CancelPlanService {
|
||||
_CancelPlanService(this._dio, {this.baseUrl, this.errorLogger});
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
String? baseUrl;
|
||||
|
||||
final ParseErrorLogger? errorLogger;
|
||||
|
||||
@override
|
||||
Future<void> cancelChosenPlan({
|
||||
required int id,
|
||||
CancelationModel? body,
|
||||
}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = body;
|
||||
final _options = _setStreamType<void>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/chosen_plans/${id}/cancel',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
requestOptions.responseType == ResponseType.stream)) {
|
||||
if (T == String) {
|
||||
requestOptions.responseType = ResponseType.plain;
|
||||
} else {
|
||||
requestOptions.responseType = ResponseType.json;
|
||||
}
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
String _combineBaseUrls(String dioBaseUrl, String? baseUrl) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty) {
|
||||
return dioBaseUrl;
|
||||
}
|
||||
|
||||
final url = Uri.parse(baseUrl);
|
||||
|
||||
if (url.isAbsolute) {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
|
||||
}
|
||||
}
|
||||
14
lib/features/chat/models/plan_complain_model.dart
Normal file
14
lib/features/chat/models/plan_complain_model.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'plan_complain_model.freezed.dart';
|
||||
part 'plan_complain_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class PlanComplainModel with _$PlanComplainModel {
|
||||
|
||||
factory PlanComplainModel({
|
||||
@JsonKey(name: 'description') required String description,
|
||||
}) = _PlanComplainModel;
|
||||
|
||||
factory PlanComplainModel.fromJson(Map<String, dynamic> json) => _$PlanComplainModelFromJson(json);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/plan_complain_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/my_finance/models/card_model.dart';
|
||||
@@ -72,7 +73,7 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
initChat(String chatId) async {
|
||||
initChat(String chatId, {bool sendInitialMessage = false}) async {
|
||||
try {
|
||||
final chatRoom = await chatRepository.getChatRoom(chatId);
|
||||
ChosenPlanModel? chosenPlan;
|
||||
@@ -96,6 +97,10 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
if (chatRoom.chosenPlan?.consultantId == chatRoom.users.receiver.id) {
|
||||
await checkCards();
|
||||
}
|
||||
|
||||
if (sendInitialMessage) {
|
||||
await chatRepository.sendMessage(chatId: chatId, data: 'Здравствуйте, хочу заказать у вас: ${chosenPlan?.plan.name ?? 'план'}');
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
typingSubscription?.cancel();
|
||||
@@ -205,6 +210,30 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> complainAboutConsultation({required String description}) async {
|
||||
try {
|
||||
final planId = (state as ChatRoomStateLoaded).chatRoom.chosenPlan?.id;
|
||||
if (planId == null) return false;
|
||||
await chatRepository.complainAboutConsultation(id: planId, body: PlanComplainModel(description: description));
|
||||
return true;
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> finishChosenPlan() async {
|
||||
try {
|
||||
final planId = (state as ChatRoomStateLoaded).chatRoom.chosenPlan?.id;
|
||||
if (planId == null) return false;
|
||||
await chatRepository.finishChosenPlan(id: planId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
wsManager.unsubscribeDirectChatChannel();
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/notification_banner.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/info_by_order_screen.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart';
|
||||
@@ -28,7 +29,8 @@ import 'package:visibility_detector/visibility_detector.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final String chatId;
|
||||
const ChatScreen({required this.chatId, super.key});
|
||||
final bool? sendInitialMessage;
|
||||
const ChatScreen({required this.chatId, super.key, required this.sendInitialMessage});
|
||||
|
||||
@override
|
||||
State<ChatScreen> createState() => _ChatScreenState();
|
||||
@@ -46,7 +48,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
scrollController.addListener(_onScroll);
|
||||
chatRoomCubit.initChat(widget.chatId);
|
||||
chatRoomCubit.initChat(widget.chatId, sendInitialMessage: widget.sendInitialMessage ?? false);
|
||||
}
|
||||
|
||||
_onScroll() {
|
||||
@@ -84,25 +86,37 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
_buildChat(BuildContext context, ChatRoomStateLoaded state) {
|
||||
final chosenPlan = state.chatRoom.chosenPlan;
|
||||
final amIConsultant = chosenPlan?.consultantId == state.chatRoom.users.sender.id;
|
||||
final showUserDetailsButton = amIConsultant &&
|
||||
[
|
||||
ChosenPlanStateEnum.stateStartDateHasBeenSet,
|
||||
ChosenPlanStateEnum.statePendingPayment,
|
||||
ChosenPlanStateEnum.stateInCoordination,
|
||||
].contains(chosenPlan?.chosenPlanState);
|
||||
final showUserDetailsButton = [
|
||||
ChosenPlanStateEnum.stateStartDateHasBeenSet,
|
||||
ChosenPlanStateEnum.statePendingPayment,
|
||||
ChosenPlanStateEnum.stateInCoordination,
|
||||
].contains(chosenPlan?.chosenPlanState);
|
||||
|
||||
final showAboutOrderButton =
|
||||
state.chatRoom.chosenPlan != null && state.chatRoom.chosenPlan!.chosenPlanState != ChosenPlanStateEnum.stateCanceledByTheInitiator;
|
||||
BannerType? bannerType;
|
||||
if (chosenPlan == null) {
|
||||
bannerType = null;
|
||||
} else if (amIConsultant && state.hasCard) {
|
||||
} else if (amIConsultant && !state.hasCard) {
|
||||
bannerType = BannerType.card;
|
||||
} else if (amIConsultant && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
|
||||
bannerType = BannerType.date;
|
||||
} else if (!amIConsultant &&
|
||||
(chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet || chosenPlan.chosenPlanState == ChosenPlanStateEnum.statePendingPayment)) {
|
||||
bannerType = BannerType.payment;
|
||||
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateDone) {
|
||||
bannerType = BannerType.collectCharge;
|
||||
} else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateLastDayFinished && !amIConsultant) {
|
||||
bannerType = BannerType.finishPlan;
|
||||
}
|
||||
|
||||
PacketOptions? chosenOption;
|
||||
if (chosenPlan?.optionType == 'options1') {
|
||||
chosenOption = chosenPlan?.plan.packet1Options;
|
||||
} else if (chosenPlan?.optionType == 'options2') {
|
||||
chosenOption = chosenPlan?.plan.packet2Options;
|
||||
} else if (chosenPlan?.optionType == 'options3') {
|
||||
chosenOption = chosenPlan?.plan.packet3Options;
|
||||
}
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
@@ -128,6 +142,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
foregroundImage: NetworkImage(state.chatRoom.users.receiver.profilePhotoUrl!),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
),
|
||||
if (state.chatRoom.users.receiver.profilePhotoUrl == null)
|
||||
Container(
|
||||
@@ -288,7 +303,15 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
),
|
||||
),
|
||||
if (bannerType != null)
|
||||
Padding(padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: NotificationBanner(bannerType: bannerType)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||
child: NotificationBanner(
|
||||
bannerType: bannerType,
|
||||
chosenPlanId: chosenPlan?.id,
|
||||
planName: chosenPlan?.plan.name,
|
||||
planPrice: chosenOption?.price.toDouble(),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -40,9 +40,10 @@ class _ChatEntryWidgetState extends State<ChatEntryWidget> {
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundImage: NetworkImage(
|
||||
foregroundImage: NetworkImage(
|
||||
widget.chatRoom.users.toChatUser.profilePhotoUrl,
|
||||
),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class CompletePlanBottomSheet extends StatefulWidget {
|
||||
const CompletePlanBottomSheet({super.key, required this.cubit});
|
||||
final ChatRoomCubit cubit;
|
||||
|
||||
@override
|
||||
State<CompletePlanBottomSheet> createState() => _CompletePlanBottomSheetState();
|
||||
}
|
||||
|
||||
class _CompletePlanBottomSheetState extends State<CompletePlanBottomSheet> {
|
||||
bool? isFailure;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
if (isFailure == true) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text('Произошла ошибка, попробуйте позже', style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomOutlinedButton(
|
||||
text: s.ok,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text('Подтверждение плана', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
'Вы уверенны что хотите подтвердить прохождения плана?',
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomOutlinedButton(
|
||||
text: s.confirm,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
final result = await widget.cubit.finishChosenPlan();
|
||||
if (result) {
|
||||
if (context.mounted) {
|
||||
context.pop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
isFailure = true;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/pages/payment_screen.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/complete_plan_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/plan_complain_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -13,8 +17,11 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class NotificationBanner extends StatefulWidget {
|
||||
const NotificationBanner({super.key, required this.bannerType});
|
||||
const NotificationBanner({super.key, required this.bannerType, this.planPrice, this.planName, this.chosenPlanId});
|
||||
final BannerType bannerType;
|
||||
final double? planPrice;
|
||||
final String? planName;
|
||||
final int? chosenPlanId;
|
||||
|
||||
@override
|
||||
State<NotificationBanner> createState() => _NotificationBannerState();
|
||||
@@ -31,96 +38,208 @@ class _NotificationBannerState extends State<NotificationBanner> {
|
||||
color: appTheme.gray50,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12, right: 8, left: 12),
|
||||
child: SvgPicture.asset('assets/icons/reversed_exclamation_mark.svg', height: 68, width: 68),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.bannerType != BannerType.collectCharge && widget.bannerType != BannerType.finishPlan)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12, right: 8, left: 12),
|
||||
child: SvgPicture.asset('assets/icons/reversed_exclamation_mark.svg', height: 68, width: 68),
|
||||
)
|
||||
else
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 12, right: 8, left: 12),
|
||||
child: _StarIcon(),
|
||||
),
|
||||
if (isLoading)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 40, top: 24),
|
||||
child: Loader(),
|
||||
)
|
||||
else
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: switch (widget.bannerType) {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ChosePlanDateWidget(
|
||||
chatCubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(s.choose_date, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.card => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushReplacement(
|
||||
CardSettingsScreen.path,
|
||||
);
|
||||
},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.payment => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.tap_on_link_to_pay, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final planId = (context.read<ChatRoomCubit>().state as ChatRoomStateLoaded).chatRoom.chosenPlan?.id;
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
final paymentLink = await context.read<ChatRoomCubit>().getPaymentLink();
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
if (paymentLink != null && planId != null) {
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).pushReplacement(
|
||||
PaymentScreen.path,
|
||||
extra: {'url': paymentLink, 'planId': planId},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(s.pay, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.collectCharge => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child:
|
||||
Text('${s.congratsYouHaveFinishedPlan} «${widget.planName}»', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text('${s.userConfirmedPlanCompletion} ${widget.planPrice}₽', style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
BannerType.finishPlan => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text('${s.congratsYouHaveFinishedPlan} «${widget.planName}». ${s.pleaseConfirmPlan}',
|
||||
style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: size.width * 0.7,
|
||||
child: Text(s.planWillBeConfirmedAfterThreeDays, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isLoading)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 40, top: 24),
|
||||
child: Loader(),
|
||||
)
|
||||
else
|
||||
if (widget.bannerType == BannerType.collectCharge)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: switch (widget.bannerType) {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ChosePlanDateWidget(
|
||||
chatCubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(s.choose_date, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.card => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushReplacement(
|
||||
CardSettingsScreen.path,
|
||||
);
|
||||
},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.payment => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.tap_on_link_to_pay, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final planId = (context.read<ChatRoomCubit>().state as ChatRoomStateLoaded).chatRoom.chosenPlan?.id;
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
final paymentLink = await context.read<ChatRoomCubit>().getPaymentLink();
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
if (paymentLink != null && planId != null) {
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).pushReplacement(
|
||||
PaymentScreen.path,
|
||||
extra: {'url': paymentLink, 'planId': planId},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(s.pay, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: CustomOutlinedButton(
|
||||
text: s.collectCharge,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)),
|
||||
onPressed: () async {
|
||||
GoRouter.of(context).push(CardSettingsScreen.path, extra: widget.chosenPlanId);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.bannerType == BannerType.finishPlan) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: CustomOutlinedButton(
|
||||
text: s.confirm,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
height: null,
|
||||
child: CompletePlanBottomSheet(
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: SizedBox(
|
||||
child: Text(s.youCanComplain, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
height: null,
|
||||
child: PlanComplainBottomSheet(
|
||||
cubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(s.leaveComplainRequest, style: TextStyles.textSMedium.copyWith(color: appTheme.red))),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum BannerType { date, card, payment }
|
||||
class _StarIcon extends StatelessWidget {
|
||||
const _StarIcon();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(color: appTheme.whiteA700, shape: BoxShape.circle),
|
||||
child: SvgPicture.asset('assets/icons/star.svg'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum BannerType { date, card, payment, collectCharge, finishPlan }
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class PlanComplainBottomSheet extends StatefulWidget {
|
||||
const PlanComplainBottomSheet({super.key, required this.cubit});
|
||||
final ChatRoomCubit cubit;
|
||||
|
||||
@override
|
||||
State<PlanComplainBottomSheet> createState() => _PlanComplainBottomSheetState();
|
||||
}
|
||||
|
||||
class _PlanComplainBottomSheetState extends State<PlanComplainBottomSheet> {
|
||||
final controller = TextEditingController();
|
||||
bool? result;
|
||||
int? textLength;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
if (result == true) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text('Подача жалобы', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text('Жалоба отправлена на рассмотрение. Обычно это занимает до трёх рабочих дней.', style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomOutlinedButton(
|
||||
text: s.ok,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
],
|
||||
);
|
||||
} else if (result == false) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text('Подача жалобы', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text('Произошла ошибка, попробуйте позже', style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomOutlinedButton(
|
||||
text: s.ok,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text('Подача жалобы', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Align(alignment: Alignment.centerLeft, child: Text('Опишите причину жалобы', style: TextStyles.textSMedium.copyWith(color: appTheme.black))),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomTextFormField(
|
||||
controller: controller,
|
||||
hasError: textLength != null && textLength! < 3,
|
||||
onChanged: (p0) {
|
||||
setState(() {
|
||||
textLength = p0.length;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (textLength != null && textLength! < 3) ...[
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols),
|
||||
],
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
CustomOutlinedButton(
|
||||
text: s.confirm,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
if (controller.text.length < 3) {
|
||||
return;
|
||||
}
|
||||
final result = await widget.cubit.complainAboutConsultation(description: controller.text);
|
||||
setState(() {
|
||||
this.result = result;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'package:eatvio_app/features/chat/models/chat_messages_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/payment_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/plan_complain_model.dart';
|
||||
import 'package:eatvio_app/features/chat/services/chat_service.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
@@ -132,4 +133,25 @@ class ChatRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> finishChosenPlan({
|
||||
required int id,
|
||||
}) async {
|
||||
try {
|
||||
await chatService.finishChosenPlan(id: id);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> complainAboutConsultation({
|
||||
required int id,
|
||||
required PlanComplainModel body,
|
||||
}) async {
|
||||
try {
|
||||
await chatService.complainAboutConsultation(id: id, body: body);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:eatvio_app/features/chat/models/chat_messages_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/payment_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/plan_complain_model.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
@@ -68,4 +69,15 @@ abstract class ChatService {
|
||||
Future<ChosenPlanModel> getChosenPlan({
|
||||
@Path() required int id,
|
||||
});
|
||||
|
||||
@POST('/api/chosen_plans/{id}/confirm_finish')
|
||||
Future<void> finishChosenPlan({
|
||||
@Path() required int id,
|
||||
});
|
||||
|
||||
@POST('/api/chosen_plans/{id}/complain')
|
||||
Future<void> complainAboutConsultation({
|
||||
@Path() required int id,
|
||||
@Body() required PlanComplainModel body,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,8 +37,9 @@ class DiaryModel with _$DiaryModel {
|
||||
}
|
||||
|
||||
DateTime parseUnformattedDate(String date) {
|
||||
final dateChunks = date.split('/').map(int.parse).toList();
|
||||
return DateTime(dateChunks.last, dateChunks.first, dateChunks[1]);
|
||||
final dateChunks = date.split('-').map(int.parse).toList();
|
||||
|
||||
return DateTime(dateChunks.first, dateChunks[1], dateChunks.last);
|
||||
}
|
||||
|
||||
enum DiaryStateEnum {
|
||||
|
||||
@@ -1,799 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'consultation_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
ConsultationModel _$ConsultationModelFromJson(Map<String, dynamic> json) {
|
||||
return _ConsultationModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ConsultationModel {
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'last_state')
|
||||
ChosenPlanStateEnum get chosenPlanState => throw _privateConstructorUsedError;
|
||||
String get planTitle => throw _privateConstructorUsedError;
|
||||
String get userName => throw _privateConstructorUsedError;
|
||||
String get userSlug => throw _privateConstructorUsedError;
|
||||
double get consultantPayment => throw _privateConstructorUsedError;
|
||||
int get duration => throw _privateConstructorUsedError;
|
||||
int get currentDiaryDay => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate)
|
||||
DateTime get startDate => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate)
|
||||
DateTime get endDate => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'consultant_id')
|
||||
int get consultantId => throw _privateConstructorUsedError;
|
||||
List<DiaryModel> get diaries => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ConsultationModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConsultationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ConsultationModelCopyWith<ConsultationModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ConsultationModelCopyWith<$Res> {
|
||||
factory $ConsultationModelCopyWith(
|
||||
ConsultationModel value, $Res Function(ConsultationModel) then) =
|
||||
_$ConsultationModelCopyWithImpl<$Res, ConsultationModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
@JsonKey(name: 'last_state') ChosenPlanStateEnum chosenPlanState,
|
||||
String planTitle,
|
||||
String userName,
|
||||
String userSlug,
|
||||
double consultantPayment,
|
||||
int duration,
|
||||
int currentDiaryDay,
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate) DateTime startDate,
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate) DateTime endDate,
|
||||
@JsonKey(name: 'consultant_id') int consultantId,
|
||||
List<DiaryModel> diaries});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ConsultationModelCopyWithImpl<$Res, $Val extends ConsultationModel>
|
||||
implements $ConsultationModelCopyWith<$Res> {
|
||||
_$ConsultationModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ConsultationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? chosenPlanState = null,
|
||||
Object? planTitle = null,
|
||||
Object? userName = null,
|
||||
Object? userSlug = null,
|
||||
Object? consultantPayment = null,
|
||||
Object? duration = null,
|
||||
Object? currentDiaryDay = null,
|
||||
Object? startDate = null,
|
||||
Object? endDate = null,
|
||||
Object? consultantId = null,
|
||||
Object? diaries = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chosenPlanState: null == chosenPlanState
|
||||
? _value.chosenPlanState
|
||||
: chosenPlanState // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanStateEnum,
|
||||
planTitle: null == planTitle
|
||||
? _value.planTitle
|
||||
: planTitle // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userName: null == userName
|
||||
? _value.userName
|
||||
: userName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userSlug: null == userSlug
|
||||
? _value.userSlug
|
||||
: userSlug // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
consultantPayment: null == consultantPayment
|
||||
? _value.consultantPayment
|
||||
: consultantPayment // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
duration: null == duration
|
||||
? _value.duration
|
||||
: duration // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
currentDiaryDay: null == currentDiaryDay
|
||||
? _value.currentDiaryDay
|
||||
: currentDiaryDay // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
endDate: null == endDate
|
||||
? _value.endDate
|
||||
: endDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
consultantId: null == consultantId
|
||||
? _value.consultantId
|
||||
: consultantId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
diaries: null == diaries
|
||||
? _value.diaries
|
||||
: diaries // ignore: cast_nullable_to_non_nullable
|
||||
as List<DiaryModel>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ConsultationModelImplCopyWith<$Res>
|
||||
implements $ConsultationModelCopyWith<$Res> {
|
||||
factory _$$ConsultationModelImplCopyWith(_$ConsultationModelImpl value,
|
||||
$Res Function(_$ConsultationModelImpl) then) =
|
||||
__$$ConsultationModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
@JsonKey(name: 'last_state') ChosenPlanStateEnum chosenPlanState,
|
||||
String planTitle,
|
||||
String userName,
|
||||
String userSlug,
|
||||
double consultantPayment,
|
||||
int duration,
|
||||
int currentDiaryDay,
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate) DateTime startDate,
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate) DateTime endDate,
|
||||
@JsonKey(name: 'consultant_id') int consultantId,
|
||||
List<DiaryModel> diaries});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ConsultationModelImplCopyWithImpl<$Res>
|
||||
extends _$ConsultationModelCopyWithImpl<$Res, _$ConsultationModelImpl>
|
||||
implements _$$ConsultationModelImplCopyWith<$Res> {
|
||||
__$$ConsultationModelImplCopyWithImpl(_$ConsultationModelImpl _value,
|
||||
$Res Function(_$ConsultationModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ConsultationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? chosenPlanState = null,
|
||||
Object? planTitle = null,
|
||||
Object? userName = null,
|
||||
Object? userSlug = null,
|
||||
Object? consultantPayment = null,
|
||||
Object? duration = null,
|
||||
Object? currentDiaryDay = null,
|
||||
Object? startDate = null,
|
||||
Object? endDate = null,
|
||||
Object? consultantId = null,
|
||||
Object? diaries = null,
|
||||
}) {
|
||||
return _then(_$ConsultationModelImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chosenPlanState: null == chosenPlanState
|
||||
? _value.chosenPlanState
|
||||
: chosenPlanState // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanStateEnum,
|
||||
planTitle: null == planTitle
|
||||
? _value.planTitle
|
||||
: planTitle // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userName: null == userName
|
||||
? _value.userName
|
||||
: userName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userSlug: null == userSlug
|
||||
? _value.userSlug
|
||||
: userSlug // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
consultantPayment: null == consultantPayment
|
||||
? _value.consultantPayment
|
||||
: consultantPayment // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
duration: null == duration
|
||||
? _value.duration
|
||||
: duration // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
currentDiaryDay: null == currentDiaryDay
|
||||
? _value.currentDiaryDay
|
||||
: currentDiaryDay // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
endDate: null == endDate
|
||||
? _value.endDate
|
||||
: endDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
consultantId: null == consultantId
|
||||
? _value.consultantId
|
||||
: consultantId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
diaries: null == diaries
|
||||
? _value._diaries
|
||||
: diaries // ignore: cast_nullable_to_non_nullable
|
||||
as List<DiaryModel>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ConsultationModelImpl implements _ConsultationModel {
|
||||
_$ConsultationModelImpl(
|
||||
{required this.id,
|
||||
@JsonKey(name: 'last_state') required this.chosenPlanState,
|
||||
required this.planTitle,
|
||||
required this.userName,
|
||||
required this.userSlug,
|
||||
required this.consultantPayment,
|
||||
required this.duration,
|
||||
required this.currentDiaryDay,
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate) required this.startDate,
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate) required this.endDate,
|
||||
@JsonKey(name: 'consultant_id') required this.consultantId,
|
||||
required final List<DiaryModel> diaries})
|
||||
: _diaries = diaries;
|
||||
|
||||
factory _$ConsultationModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ConsultationModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int id;
|
||||
@override
|
||||
@JsonKey(name: 'last_state')
|
||||
final ChosenPlanStateEnum chosenPlanState;
|
||||
@override
|
||||
final String planTitle;
|
||||
@override
|
||||
final String userName;
|
||||
@override
|
||||
final String userSlug;
|
||||
@override
|
||||
final double consultantPayment;
|
||||
@override
|
||||
final int duration;
|
||||
@override
|
||||
final int currentDiaryDay;
|
||||
@override
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate)
|
||||
final DateTime startDate;
|
||||
@override
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate)
|
||||
final DateTime endDate;
|
||||
@override
|
||||
@JsonKey(name: 'consultant_id')
|
||||
final int consultantId;
|
||||
final List<DiaryModel> _diaries;
|
||||
@override
|
||||
List<DiaryModel> get diaries {
|
||||
if (_diaries is EqualUnmodifiableListView) return _diaries;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_diaries);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConsultationModel(id: $id, chosenPlanState: $chosenPlanState, planTitle: $planTitle, userName: $userName, userSlug: $userSlug, consultantPayment: $consultantPayment, duration: $duration, currentDiaryDay: $currentDiaryDay, startDate: $startDate, endDate: $endDate, consultantId: $consultantId, diaries: $diaries)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConsultationModelImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.chosenPlanState, chosenPlanState) ||
|
||||
other.chosenPlanState == chosenPlanState) &&
|
||||
(identical(other.planTitle, planTitle) ||
|
||||
other.planTitle == planTitle) &&
|
||||
(identical(other.userName, userName) ||
|
||||
other.userName == userName) &&
|
||||
(identical(other.userSlug, userSlug) ||
|
||||
other.userSlug == userSlug) &&
|
||||
(identical(other.consultantPayment, consultantPayment) ||
|
||||
other.consultantPayment == consultantPayment) &&
|
||||
(identical(other.duration, duration) ||
|
||||
other.duration == duration) &&
|
||||
(identical(other.currentDiaryDay, currentDiaryDay) ||
|
||||
other.currentDiaryDay == currentDiaryDay) &&
|
||||
(identical(other.startDate, startDate) ||
|
||||
other.startDate == startDate) &&
|
||||
(identical(other.endDate, endDate) || other.endDate == endDate) &&
|
||||
(identical(other.consultantId, consultantId) ||
|
||||
other.consultantId == consultantId) &&
|
||||
const DeepCollectionEquality().equals(other._diaries, _diaries));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
chosenPlanState,
|
||||
planTitle,
|
||||
userName,
|
||||
userSlug,
|
||||
consultantPayment,
|
||||
duration,
|
||||
currentDiaryDay,
|
||||
startDate,
|
||||
endDate,
|
||||
consultantId,
|
||||
const DeepCollectionEquality().hash(_diaries));
|
||||
|
||||
/// Create a copy of ConsultationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ConsultationModelImplCopyWith<_$ConsultationModelImpl> get copyWith =>
|
||||
__$$ConsultationModelImplCopyWithImpl<_$ConsultationModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ConsultationModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ConsultationModel implements ConsultationModel {
|
||||
factory _ConsultationModel(
|
||||
{required final int id,
|
||||
@JsonKey(name: 'last_state')
|
||||
required final ChosenPlanStateEnum chosenPlanState,
|
||||
required final String planTitle,
|
||||
required final String userName,
|
||||
required final String userSlug,
|
||||
required final double consultantPayment,
|
||||
required final int duration,
|
||||
required final int currentDiaryDay,
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate)
|
||||
required final DateTime startDate,
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate)
|
||||
required final DateTime endDate,
|
||||
@JsonKey(name: 'consultant_id') required final int consultantId,
|
||||
required final List<DiaryModel> diaries}) = _$ConsultationModelImpl;
|
||||
|
||||
factory _ConsultationModel.fromJson(Map<String, dynamic> json) =
|
||||
_$ConsultationModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
int get id;
|
||||
@override
|
||||
@JsonKey(name: 'last_state')
|
||||
ChosenPlanStateEnum get chosenPlanState;
|
||||
@override
|
||||
String get planTitle;
|
||||
@override
|
||||
String get userName;
|
||||
@override
|
||||
String get userSlug;
|
||||
@override
|
||||
double get consultantPayment;
|
||||
@override
|
||||
int get duration;
|
||||
@override
|
||||
int get currentDiaryDay;
|
||||
@override
|
||||
@JsonKey(name: 'start_date', fromJson: parseDate)
|
||||
DateTime get startDate;
|
||||
@override
|
||||
@JsonKey(name: 'end_date', fromJson: parseDate)
|
||||
DateTime get endDate;
|
||||
@override
|
||||
@JsonKey(name: 'consultant_id')
|
||||
int get consultantId;
|
||||
@override
|
||||
List<DiaryModel> get diaries;
|
||||
|
||||
/// Create a copy of ConsultationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ConsultationModelImplCopyWith<_$ConsultationModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
DiaryModel _$DiaryModelFromJson(Map<String, dynamic> json) {
|
||||
return _DiaryModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DiaryModel {
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
DiaryStateEnum get state => throw _privateConstructorUsedError;
|
||||
@JsonKey(fromJson: parseUnformattedDate)
|
||||
DateTime get date => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this DiaryModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of DiaryModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$DiaryModelCopyWith<DiaryModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $DiaryModelCopyWith<$Res> {
|
||||
factory $DiaryModelCopyWith(
|
||||
DiaryModel value, $Res Function(DiaryModel) then) =
|
||||
_$DiaryModelCopyWithImpl<$Res, DiaryModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
DiaryStateEnum state,
|
||||
@JsonKey(fromJson: parseUnformattedDate) DateTime date});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$DiaryModelCopyWithImpl<$Res, $Val extends DiaryModel>
|
||||
implements $DiaryModelCopyWith<$Res> {
|
||||
_$DiaryModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of DiaryModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? state = null,
|
||||
Object? date = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as DiaryStateEnum,
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DiaryModelImplCopyWith<$Res>
|
||||
implements $DiaryModelCopyWith<$Res> {
|
||||
factory _$$DiaryModelImplCopyWith(
|
||||
_$DiaryModelImpl value, $Res Function(_$DiaryModelImpl) then) =
|
||||
__$$DiaryModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
DiaryStateEnum state,
|
||||
@JsonKey(fromJson: parseUnformattedDate) DateTime date});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DiaryModelImplCopyWithImpl<$Res>
|
||||
extends _$DiaryModelCopyWithImpl<$Res, _$DiaryModelImpl>
|
||||
implements _$$DiaryModelImplCopyWith<$Res> {
|
||||
__$$DiaryModelImplCopyWithImpl(
|
||||
_$DiaryModelImpl _value, $Res Function(_$DiaryModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of DiaryModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? state = null,
|
||||
Object? date = null,
|
||||
}) {
|
||||
return _then(_$DiaryModelImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as DiaryStateEnum,
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$DiaryModelImpl implements _DiaryModel {
|
||||
_$DiaryModelImpl(
|
||||
{required this.id,
|
||||
required this.state,
|
||||
@JsonKey(fromJson: parseUnformattedDate) required this.date});
|
||||
|
||||
factory _$DiaryModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$DiaryModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int id;
|
||||
@override
|
||||
final DiaryStateEnum state;
|
||||
@override
|
||||
@JsonKey(fromJson: parseUnformattedDate)
|
||||
final DateTime date;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DiaryModel(id: $id, state: $state, date: $date)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DiaryModelImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
(identical(other.date, date) || other.date == date));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, state, date);
|
||||
|
||||
/// Create a copy of DiaryModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith =>
|
||||
__$$DiaryModelImplCopyWithImpl<_$DiaryModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$DiaryModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _DiaryModel implements DiaryModel {
|
||||
factory _DiaryModel(
|
||||
{required final int id,
|
||||
required final DiaryStateEnum state,
|
||||
@JsonKey(fromJson: parseUnformattedDate)
|
||||
required final DateTime date}) = _$DiaryModelImpl;
|
||||
|
||||
factory _DiaryModel.fromJson(Map<String, dynamic> json) =
|
||||
_$DiaryModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
int get id;
|
||||
@override
|
||||
DiaryStateEnum get state;
|
||||
@override
|
||||
@JsonKey(fromJson: parseUnformattedDate)
|
||||
DateTime get date;
|
||||
|
||||
/// Create a copy of DiaryModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$DiaryModelImplCopyWith<_$DiaryModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
ConsultationPaginationModel _$ConsultationPaginationModelFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return _ConsultationPaginationModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ConsultationPaginationModel {
|
||||
List<ConsultationModel> get data => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ConsultationPaginationModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConsultationPaginationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ConsultationPaginationModelCopyWith<ConsultationPaginationModel>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ConsultationPaginationModelCopyWith<$Res> {
|
||||
factory $ConsultationPaginationModelCopyWith(
|
||||
ConsultationPaginationModel value,
|
||||
$Res Function(ConsultationPaginationModel) then) =
|
||||
_$ConsultationPaginationModelCopyWithImpl<$Res,
|
||||
ConsultationPaginationModel>;
|
||||
@useResult
|
||||
$Res call({List<ConsultationModel> data});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ConsultationPaginationModelCopyWithImpl<$Res,
|
||||
$Val extends ConsultationPaginationModel>
|
||||
implements $ConsultationPaginationModelCopyWith<$Res> {
|
||||
_$ConsultationPaginationModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ConsultationPaginationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? data = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
data: null == data
|
||||
? _value.data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as List<ConsultationModel>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ConsultationPaginationModelImplCopyWith<$Res>
|
||||
implements $ConsultationPaginationModelCopyWith<$Res> {
|
||||
factory _$$ConsultationPaginationModelImplCopyWith(
|
||||
_$ConsultationPaginationModelImpl value,
|
||||
$Res Function(_$ConsultationPaginationModelImpl) then) =
|
||||
__$$ConsultationPaginationModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({List<ConsultationModel> data});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ConsultationPaginationModelImplCopyWithImpl<$Res>
|
||||
extends _$ConsultationPaginationModelCopyWithImpl<$Res,
|
||||
_$ConsultationPaginationModelImpl>
|
||||
implements _$$ConsultationPaginationModelImplCopyWith<$Res> {
|
||||
__$$ConsultationPaginationModelImplCopyWithImpl(
|
||||
_$ConsultationPaginationModelImpl _value,
|
||||
$Res Function(_$ConsultationPaginationModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ConsultationPaginationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? data = null,
|
||||
}) {
|
||||
return _then(_$ConsultationPaginationModelImpl(
|
||||
data: null == data
|
||||
? _value._data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as List<ConsultationModel>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ConsultationPaginationModelImpl
|
||||
implements _ConsultationPaginationModel {
|
||||
_$ConsultationPaginationModelImpl(
|
||||
{required final List<ConsultationModel> data})
|
||||
: _data = data;
|
||||
|
||||
factory _$ConsultationPaginationModelImpl.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$$ConsultationPaginationModelImplFromJson(json);
|
||||
|
||||
final List<ConsultationModel> _data;
|
||||
@override
|
||||
List<ConsultationModel> get data {
|
||||
if (_data is EqualUnmodifiableListView) return _data;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_data);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConsultationPaginationModel(data: $data)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConsultationPaginationModelImpl &&
|
||||
const DeepCollectionEquality().equals(other._data, _data));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_data));
|
||||
|
||||
/// Create a copy of ConsultationPaginationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ConsultationPaginationModelImplCopyWith<_$ConsultationPaginationModelImpl>
|
||||
get copyWith => __$$ConsultationPaginationModelImplCopyWithImpl<
|
||||
_$ConsultationPaginationModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ConsultationPaginationModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ConsultationPaginationModel
|
||||
implements ConsultationPaginationModel {
|
||||
factory _ConsultationPaginationModel(
|
||||
{required final List<ConsultationModel> data}) =
|
||||
_$ConsultationPaginationModelImpl;
|
||||
|
||||
factory _ConsultationPaginationModel.fromJson(Map<String, dynamic> json) =
|
||||
_$ConsultationPaginationModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
List<ConsultationModel> get data;
|
||||
|
||||
/// Create a copy of ConsultationPaginationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ConsultationPaginationModelImplCopyWith<_$ConsultationPaginationModelImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'consultation_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ConsultationModelImpl _$$ConsultationModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ConsultationModelImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
chosenPlanState:
|
||||
$enumDecode(_$ChosenPlanStateEnumEnumMap, json['last_state']),
|
||||
planTitle: json['planTitle'] as String,
|
||||
userName: json['userName'] as String,
|
||||
userSlug: json['userSlug'] as String,
|
||||
consultantPayment: (json['consultantPayment'] as num).toDouble(),
|
||||
duration: (json['duration'] as num).toInt(),
|
||||
currentDiaryDay: (json['currentDiaryDay'] as num).toInt(),
|
||||
startDate: parseDate(json['start_date'] as String),
|
||||
endDate: parseDate(json['end_date'] as String),
|
||||
consultantId: (json['consultant_id'] as num).toInt(),
|
||||
diaries: (json['diaries'] as List<dynamic>)
|
||||
.map((e) => DiaryModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ConsultationModelImplToJson(
|
||||
_$ConsultationModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'last_state': _$ChosenPlanStateEnumEnumMap[instance.chosenPlanState]!,
|
||||
'planTitle': instance.planTitle,
|
||||
'userName': instance.userName,
|
||||
'userSlug': instance.userSlug,
|
||||
'consultantPayment': instance.consultantPayment,
|
||||
'duration': instance.duration,
|
||||
'currentDiaryDay': instance.currentDiaryDay,
|
||||
'start_date': instance.startDate.toIso8601String(),
|
||||
'end_date': instance.endDate.toIso8601String(),
|
||||
'consultant_id': instance.consultantId,
|
||||
'diaries': instance.diaries,
|
||||
};
|
||||
|
||||
const _$ChosenPlanStateEnumEnumMap = {
|
||||
ChosenPlanStateEnum.stateInited: 'initied',
|
||||
ChosenPlanStateEnum.stateStartDateHasBeenSet: 'start_date_has_been_set',
|
||||
ChosenPlanStateEnum.stateInCoordination: 'in_coordination',
|
||||
ChosenPlanStateEnum.stateStarted: 'started',
|
||||
ChosenPlanStateEnum.stateInProgress: 'in_progress',
|
||||
ChosenPlanStateEnum.statePendingPayment: 'pending_payment',
|
||||
ChosenPlanStateEnum.stateConfirmedByConsultant: 'confirmed_by_consultant',
|
||||
ChosenPlanStateEnum.statePaid: 'paid',
|
||||
ChosenPlanStateEnum.stateCanceledByTheInitiator: 'canceled_by_the_initiator',
|
||||
ChosenPlanStateEnum.stateLastDayStarted: 'last_day_started',
|
||||
ChosenPlanStateEnum.stateLastDayFinished: 'last_day_finished',
|
||||
ChosenPlanStateEnum.stateComplained: 'complained',
|
||||
ChosenPlanStateEnum.stateDone: 'done',
|
||||
ChosenPlanStateEnum.stateChargeWasCollected: 'charge_was_collected',
|
||||
};
|
||||
|
||||
_$DiaryModelImpl _$$DiaryModelImplFromJson(Map<String, dynamic> json) =>
|
||||
_$DiaryModelImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
state: $enumDecode(_$DiaryStateEnumEnumMap, json['state']),
|
||||
date: parseUnformattedDate(json['date'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$DiaryModelImplToJson(_$DiaryModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'state': _$DiaryStateEnumEnumMap[instance.state]!,
|
||||
'date': instance.date.toIso8601String(),
|
||||
};
|
||||
|
||||
const _$DiaryStateEnumEnumMap = {
|
||||
DiaryStateEnum.init: 'init',
|
||||
DiaryStateEnum.started: 'started',
|
||||
DiaryStateEnum.finished: 'finished',
|
||||
DiaryStateEnum.commented: 'commented',
|
||||
DiaryStateEnum.reviewedByUser: 'reviewed_by_user',
|
||||
DiaryStateEnum.lastDayStarted: 'last_day_started',
|
||||
DiaryStateEnum.lastDayFinished: 'last_day_finished',
|
||||
DiaryStateEnum.lastDayCommented: 'last_day_commented',
|
||||
};
|
||||
|
||||
_$ConsultationPaginationModelImpl _$$ConsultationPaginationModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ConsultationPaginationModelImpl(
|
||||
data: (json['data'] as List<dynamic>)
|
||||
.map((e) => ConsultationModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ConsultationPaginationModelImplToJson(
|
||||
_$ConsultationPaginationModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data,
|
||||
};
|
||||
@@ -1,175 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'consultations_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ConsultationsState {
|
||||
BaseState get state => throw _privateConstructorUsedError;
|
||||
List<ConsultationModel> get consultations =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConsultationsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ConsultationsStateCopyWith<ConsultationsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ConsultationsStateCopyWith<$Res> {
|
||||
factory $ConsultationsStateCopyWith(
|
||||
ConsultationsState value, $Res Function(ConsultationsState) then) =
|
||||
_$ConsultationsStateCopyWithImpl<$Res, ConsultationsState>;
|
||||
@useResult
|
||||
$Res call({BaseState state, List<ConsultationModel> consultations});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ConsultationsStateCopyWithImpl<$Res, $Val extends ConsultationsState>
|
||||
implements $ConsultationsStateCopyWith<$Res> {
|
||||
_$ConsultationsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ConsultationsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? state = null,
|
||||
Object? consultations = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as BaseState,
|
||||
consultations: null == consultations
|
||||
? _value.consultations
|
||||
: consultations // ignore: cast_nullable_to_non_nullable
|
||||
as List<ConsultationModel>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ConsultationsStateImplCopyWith<$Res>
|
||||
implements $ConsultationsStateCopyWith<$Res> {
|
||||
factory _$$ConsultationsStateImplCopyWith(_$ConsultationsStateImpl value,
|
||||
$Res Function(_$ConsultationsStateImpl) then) =
|
||||
__$$ConsultationsStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({BaseState state, List<ConsultationModel> consultations});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ConsultationsStateImplCopyWithImpl<$Res>
|
||||
extends _$ConsultationsStateCopyWithImpl<$Res, _$ConsultationsStateImpl>
|
||||
implements _$$ConsultationsStateImplCopyWith<$Res> {
|
||||
__$$ConsultationsStateImplCopyWithImpl(_$ConsultationsStateImpl _value,
|
||||
$Res Function(_$ConsultationsStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ConsultationsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? state = null,
|
||||
Object? consultations = null,
|
||||
}) {
|
||||
return _then(_$ConsultationsStateImpl(
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as BaseState,
|
||||
consultations: null == consultations
|
||||
? _value._consultations
|
||||
: consultations // ignore: cast_nullable_to_non_nullable
|
||||
as List<ConsultationModel>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ConsultationsStateImpl implements _ConsultationsState {
|
||||
_$ConsultationsStateImpl(
|
||||
{this.state = BaseState.initial,
|
||||
final List<ConsultationModel> consultations = const []})
|
||||
: _consultations = consultations;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final BaseState state;
|
||||
final List<ConsultationModel> _consultations;
|
||||
@override
|
||||
@JsonKey()
|
||||
List<ConsultationModel> get consultations {
|
||||
if (_consultations is EqualUnmodifiableListView) return _consultations;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_consultations);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConsultationsState(state: $state, consultations: $consultations)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConsultationsStateImpl &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._consultations, _consultations));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, state, const DeepCollectionEquality().hash(_consultations));
|
||||
|
||||
/// Create a copy of ConsultationsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ConsultationsStateImplCopyWith<_$ConsultationsStateImpl> get copyWith =>
|
||||
__$$ConsultationsStateImplCopyWithImpl<_$ConsultationsStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _ConsultationsState implements ConsultationsState {
|
||||
factory _ConsultationsState(
|
||||
{final BaseState state,
|
||||
final List<ConsultationModel> consultations}) = _$ConsultationsStateImpl;
|
||||
|
||||
@override
|
||||
BaseState get state;
|
||||
@override
|
||||
List<ConsultationModel> get consultations;
|
||||
|
||||
/// Create a copy of ConsultationsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ConsultationsStateImplCopyWith<_$ConsultationsStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -10,5 +10,4 @@ abstract class ConsultationService {
|
||||
|
||||
@GET('/api/consultations')
|
||||
Future<ConsultationPaginationModel> getConsultations();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'consultation_service.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RetrofitGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations
|
||||
|
||||
class _ConsultationService implements ConsultationService {
|
||||
_ConsultationService(this._dio, {this.baseUrl, this.errorLogger});
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
String? baseUrl;
|
||||
|
||||
final ParseErrorLogger? errorLogger;
|
||||
|
||||
@override
|
||||
Future<ConsultationPaginationModel> getConsultations() async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
const Map<String, dynamic>? _data = null;
|
||||
final _options = _setStreamType<ConsultationPaginationModel>(
|
||||
Options(method: 'GET', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/consultations',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late ConsultationPaginationModel _value;
|
||||
try {
|
||||
_value = ConsultationPaginationModel.fromJson(_result.data!);
|
||||
} on Object catch (e, s) {
|
||||
errorLogger?.logError(e, s, _options);
|
||||
rethrow;
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
requestOptions.responseType == ResponseType.stream)) {
|
||||
if (T == String) {
|
||||
requestOptions.responseType = ResponseType.plain;
|
||||
} else {
|
||||
requestOptions.responseType = ResponseType.json;
|
||||
}
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
String _combineBaseUrls(String dioBaseUrl, String? baseUrl) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty) {
|
||||
return dioBaseUrl;
|
||||
}
|
||||
|
||||
final url = Uri.parse(baseUrl);
|
||||
|
||||
if (url.isAbsolute) {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(
|
||||
child: SuccessPublishedDietOrPlanBottomSheet(
|
||||
title: state.dietData.name ?? 'Диета',
|
||||
),
|
||||
);
|
||||
@@ -83,7 +83,7 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
context.pop();
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(
|
||||
child: SuccessPublishedDietOrPlanBottomSheet(
|
||||
title: '${state.dietData.name ?? 'Диета'} сохраненна в черновиках',
|
||||
),
|
||||
);
|
||||
@@ -193,8 +193,8 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
context.read<CreateDietCubit>().setDietState(DietState.draft);
|
||||
if (widget.diet != null) {
|
||||
final result = await context.read<CreateDietCubit>().updateDiet(
|
||||
widget.diet!.id,
|
||||
);
|
||||
widget.diet!.id,
|
||||
);
|
||||
if (result == 'error') {
|
||||
if (!context.mounted) return;
|
||||
showErrorDialog(context, title: '${s.could_not_update_diet} ${state.dietData.name}');
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/string_extentions.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
|
||||
import 'package:eatvio_app/core/widgets/cpfc_container.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class DietPreviewScreen extends StatefulWidget {
|
||||
@@ -190,30 +190,12 @@ class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
disableActions: true,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
|
||||
@@ -15,8 +15,8 @@ class CreatePlanModel with _$CreatePlanModel {
|
||||
const factory CreatePlanModel({
|
||||
String? name,
|
||||
String? details,
|
||||
String? state,
|
||||
int? duration,
|
||||
@Default('active') String? state,
|
||||
int? duration,
|
||||
required List<bool> type,
|
||||
XFile? image,
|
||||
required List<PacketOptions> options,
|
||||
@@ -25,9 +25,12 @@ class CreatePlanModel with _$CreatePlanModel {
|
||||
Future<Map<String, dynamic>> toCreationJson() async => {
|
||||
'name': name,
|
||||
'duration': duration,
|
||||
'state': state,
|
||||
'type': type,
|
||||
'state': 'active',
|
||||
'description_md': details,
|
||||
'type[slim]': type[0] ? '1' : '0',
|
||||
'type[fit]': type[1] ? '1' : '0',
|
||||
'type[wellness]': type[2] ? '1' : '0',
|
||||
'type[behavior]': type[3] ? '1' : '0',
|
||||
'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image!.path))).path, filename: image!.name) : null,
|
||||
};
|
||||
|
||||
|
||||
11
lib/features/create_plan/models/plan_slug_model.dart
Normal file
11
lib/features/create_plan/models/plan_slug_model.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'plan_slug_model.freezed.dart';
|
||||
part 'plan_slug_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class PlanSlugModel with _$PlanSlugModel {
|
||||
factory PlanSlugModel({@JsonKey(name: 'slug') required String slug}) = _PlanSlugModel;
|
||||
|
||||
factory PlanSlugModel.fromJson(Map<String, dynamic> json) => _$PlanSlugModelFromJson(json);
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/success_published_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/widgets/option_widget.dart';
|
||||
@@ -15,6 +19,7 @@ import 'package:eatvio_app/features/create_plan/presentation/widgets/select_exac
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class CreatePlanScreen extends StatelessWidget {
|
||||
static const name = 'createPlanScreen';
|
||||
@@ -36,177 +41,229 @@ class CreatePlanScreenContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
s.adding_plan,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
MainBackgroundBouble(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
s.label,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
hintText: s.plan_label_desc,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setName(value);
|
||||
},
|
||||
maxLength: 150,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
s.plan_duration,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const PlanDurationDropDownWidget(),
|
||||
const SizedBox(height: 20),
|
||||
const PlanImagePickerWidget(),
|
||||
const SizedBox(height: 16),
|
||||
const PlanTypeChoiceWidget(),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
s.plan_desc,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SizedBox(
|
||||
height: 132,
|
||||
child: CustomTextFormField(
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
maxLength: 1000,
|
||||
maxLines: null,
|
||||
minLines: null,
|
||||
expands: true,
|
||||
hintText: s.plan_desc_example,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setDetails(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
s.services,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.blueGray400),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const OptionsCountButton(),
|
||||
const SizedBox(height: 20),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.selectedOptionIndex != current.selectedOptionIndex,
|
||||
builder: (context, state) {
|
||||
if (state.selectedOptionIndex == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
'${s.option} ${(state.selectedOptionIndex ?? 0) + 1}',
|
||||
style: TextStyles.textLSemibold.copyWith(color: appTheme.blueGray400),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const OptionWidget(),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomOutlinedButton(
|
||||
onPressed: () {},
|
||||
text: s.to_draft,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomOutlinedButton(
|
||||
onPressed: () async {},
|
||||
text: s.preview,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomOutlinedButton(
|
||||
onPressed: () {},
|
||||
text: s.publish,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
return BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.planCreated != current.planCreated || previous.isLoading != current.isLoading,
|
||||
builder: (context, state) {
|
||||
if (state.planCreated) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!context.mounted) return;
|
||||
context.pop();
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
child: SuccessPublishedDietOrPlanBottomSheet(
|
||||
title: state.planData.name ?? 'План',
|
||||
isPlan: true,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
s.adding_plan,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
builder: (context, state) {
|
||||
if (state.selectedOptionIndex == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(bottom: 24.0),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SelectExactOptionWidget(),
|
||||
body: Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
MainBackgroundBouble(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
s.label,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.validationState != current.validationState,
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: [
|
||||
CustomTextFormField(
|
||||
hintText: s.plan_label_desc,
|
||||
hasError: state.validationState.titleHasError,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setName(value);
|
||||
},
|
||||
maxLength: 150,
|
||||
),
|
||||
if (state.validationState.titleHasError) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
s.plan_duration,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const PlanDurationDropDownWidget(),
|
||||
const SizedBox(height: 20),
|
||||
const PlanImagePickerWidget(),
|
||||
const SizedBox(height: 16),
|
||||
const PlanTypeChoiceWidget(),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
s.plan_desc,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.validationState != current.validationState,
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 132,
|
||||
child: CustomTextFormField(
|
||||
hasError: state.validationState.descriptionHasError,
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
maxLength: 1000,
|
||||
maxLines: null,
|
||||
minLines: null,
|
||||
expands: true,
|
||||
hintText: s.plan_desc_example,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setDetails(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (state.validationState.descriptionHasError) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
s.services,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.blueGray400),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const OptionsCountButton(),
|
||||
const SizedBox(height: 20),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.selectedOptionIndex != current.selectedOptionIndex,
|
||||
builder: (context, state) {
|
||||
if (state.selectedOptionIndex == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
'${s.option} ${(state.selectedOptionIndex ?? 0) + 1}',
|
||||
style: TextStyles.textLSemibold.copyWith(color: appTheme.blueGray400),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const OptionWidget(),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// CustomOutlinedButton(
|
||||
// onPressed: () {},
|
||||
// text: s.to_draft,
|
||||
// height: 52,
|
||||
// buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
// buttonStyle: ButtonStyle(
|
||||
// side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
// backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
// CustomOutlinedButton(
|
||||
// onPressed: () async {},
|
||||
// text: s.preview,
|
||||
// height: 52,
|
||||
// buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
// buttonStyle: ButtonStyle(
|
||||
// side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
// backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
state.isLoading
|
||||
? const Loader()
|
||||
: CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
await context.read<CreatePlanCubit>().publishPlan();
|
||||
},
|
||||
text: s.publish,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
builder: (context, state) {
|
||||
if (state.selectedOptionIndex == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(bottom: 24.0),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SelectExactOptionWidget(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,65 @@
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/features/create_plan/repositories/create_plan_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
|
||||
class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
CreatePlanCubit() : super(CreatePlanState.initial());
|
||||
final CreatePlanRepository createPlanRepository;
|
||||
CreatePlanCubit({required this.createPlanRepository}) : super(CreatePlanState.initial());
|
||||
|
||||
void setDetails(String text) {
|
||||
emit(state.copyWith(planData: state.planData.copyWith(details: text)));
|
||||
validateDetails();
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
emit(state.copyWith(planData: state.planData.copyWith(name: name)));
|
||||
validateName();
|
||||
}
|
||||
|
||||
void setOptionTitle(String title) {
|
||||
final options = [...state.planData.options];
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(short: title);
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(short: title);
|
||||
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
|
||||
validateSelectedOptionTitle();
|
||||
}
|
||||
|
||||
void setPrice(double price){
|
||||
void setPrice(double price) {
|
||||
final selectedOptionIndex = state.selectedOptionIndex ?? 0;
|
||||
final options = [...state.planData.options];
|
||||
options[selectedOptionIndex] = options[selectedOptionIndex].copyWith(price: price);
|
||||
final options = [...state.planData.options];
|
||||
options[selectedOptionIndex] = options[selectedOptionIndex].copyWith(price: price);
|
||||
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
|
||||
validateSelectedOptionPrice();
|
||||
}
|
||||
|
||||
void setOptionDescription(String description) {
|
||||
final options = [...state.planData.options];
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(description: description);
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(description: description);
|
||||
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
|
||||
validateSelectedOptionDescription();
|
||||
}
|
||||
|
||||
void setOptionContent(String content, index) {
|
||||
final options = [...state.planData.options];
|
||||
void setOptionContent(String content, index) {
|
||||
final options = [...state.planData.options];
|
||||
final items = [...options[state.selectedOptionIndex ?? 0].items];
|
||||
if (items.length <= index) {
|
||||
items.add(content);
|
||||
}else {
|
||||
} else {
|
||||
items[index] = content;
|
||||
}
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: items);
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: items);
|
||||
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
|
||||
validateSelectedOptionItems();
|
||||
}
|
||||
|
||||
void removeOptionContentItem(int index) {
|
||||
final options = [...state.planData.options];
|
||||
final updatedItems = [...options[state.selectedOptionIndex ?? 0].items];
|
||||
updatedItems.removeAt(index);
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: updatedItems);
|
||||
options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: updatedItems);
|
||||
emit(state.copyWith(planData: state.planData.copyWith(options: options)));
|
||||
validateSelectedOptionItems();
|
||||
}
|
||||
|
||||
void setDuration(int index) {
|
||||
@@ -62,10 +71,12 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
),
|
||||
),
|
||||
);
|
||||
validateDuration();
|
||||
}
|
||||
|
||||
void setImage(XFile? image) {
|
||||
emit(state.copyWith(planData: state.planData.copyWith(image: image)));
|
||||
validateImage();
|
||||
}
|
||||
|
||||
void setPlanState(String planState) {
|
||||
@@ -74,9 +85,319 @@ class CreatePlanCubit extends Cubit<CreatePlanState> {
|
||||
|
||||
void setPlanType(List<bool> type) {
|
||||
emit(state.copyWith(planData: state.planData.copyWith(type: type)));
|
||||
if (type.any((elem) => elem)) {
|
||||
validateType();
|
||||
}
|
||||
}
|
||||
|
||||
void setSelectedOptionIndex(int? index) {
|
||||
emit(state.copyWith(selectedOptionIndex: index));
|
||||
}
|
||||
|
||||
bool validateName() {
|
||||
final name = state.planData.name;
|
||||
if (name == null || name.length < 3) {
|
||||
emit(state.copyWith.validationState(titleHasError: true));
|
||||
return false;
|
||||
}
|
||||
emit(state.copyWith.validationState(titleHasError: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateDetails() {
|
||||
final details = state.planData.details;
|
||||
if (details == null || details.length < 3) {
|
||||
emit(state.copyWith.validationState(descriptionHasError: true));
|
||||
return false;
|
||||
}
|
||||
emit(state.copyWith.validationState(descriptionHasError: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateDuration() {
|
||||
if (state.planData.duration == null) {
|
||||
emit(state.copyWith.validationState(durationHasError: true));
|
||||
return false;
|
||||
}
|
||||
emit(state.copyWith.validationState(durationHasError: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateType() {
|
||||
final type = state.planData.type;
|
||||
if (type.isEmpty || type.every((elem) => elem)) {
|
||||
emit(state.copyWith.validationState(typeHasError: true));
|
||||
return false;
|
||||
}
|
||||
emit(state.copyWith.validationState(typeHasError: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateImage() {
|
||||
if (state.planData.image == null) {
|
||||
emit(state.copyWith.validationState(imageHasError: true));
|
||||
return false;
|
||||
}
|
||||
emit(state.copyWith.validationState(imageHasError: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateSelectedOptionPrice() {
|
||||
final option = state.planData.options[state.selectedOptionIndex ?? 0];
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
if (option.price < 1200) {
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(priceHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return false;
|
||||
}
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(priceHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validatePriceOfAllFilledOptions() {
|
||||
final options = state.planData.options;
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
bool result = true;
|
||||
if (options[0].price < 1200) {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(priceHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(priceHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
|
||||
if (options[1].price < 1200) {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(priceHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(priceHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
|
||||
if (options[2].price < 1200) {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(priceHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(priceHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validateSelectedOptionItems() {
|
||||
final option = state.planData.options[state.selectedOptionIndex ?? 0];
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
bool result = true;
|
||||
if (option.items.isEmpty) {
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(isItemsEmpty: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return false;
|
||||
}
|
||||
final itemsErrors = Map<int, bool>.from(optionsValidationsStates[state.selectedOptionIndex ?? 0].itemsErrors);
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(isItemsEmpty: false);
|
||||
for (final (index, item) in option.items.indexed) {
|
||||
if (item.length < 3) {
|
||||
itemsErrors[index] = true;
|
||||
result = false;
|
||||
} else {
|
||||
itemsErrors[index] = false;
|
||||
}
|
||||
}
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(itemsErrors: itemsErrors);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validateItemsOfAllFilledOptions() {
|
||||
final options = state.planData.options;
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
bool result = true;
|
||||
|
||||
if (options[0].items.isEmpty) {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(isItemsEmpty: true);
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(isItemsEmpty: false);
|
||||
}
|
||||
|
||||
final option1ItemsErrors = Map<int, bool>.from(optionsValidationsStates[0].itemsErrors);
|
||||
for (final (index, item) in options[0].items.indexed) {
|
||||
if (item.length < 3) {
|
||||
option1ItemsErrors[index] = true;
|
||||
result = false;
|
||||
} else {
|
||||
option1ItemsErrors[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(itemsErrors: option1ItemsErrors);
|
||||
if (state.selectedOptionIndex == null) {
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return result;
|
||||
}
|
||||
if (options[1].items.isEmpty) {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(isItemsEmpty: true);
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(isItemsEmpty: false);
|
||||
}
|
||||
|
||||
final option2ItemsErrors = Map<int, bool>.from(optionsValidationsStates[1].itemsErrors);
|
||||
for (final (index, item) in options[1].items.indexed) {
|
||||
if (item.length < 3) {
|
||||
option2ItemsErrors[index] = true;
|
||||
result = false;
|
||||
} else {
|
||||
option2ItemsErrors[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(itemsErrors: option2ItemsErrors);
|
||||
|
||||
if (options[2].items.isEmpty) {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(isItemsEmpty: true);
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(isItemsEmpty: false);
|
||||
}
|
||||
|
||||
final option3ItemsErrors = Map<int, bool>.from(optionsValidationsStates[2].itemsErrors);
|
||||
for (final (index, item) in options[2].items.indexed) {
|
||||
if (item.length < 3) {
|
||||
option3ItemsErrors[index] = true;
|
||||
result = false;
|
||||
} else {
|
||||
option3ItemsErrors[index] = false;
|
||||
}
|
||||
}
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(itemsErrors: option3ItemsErrors);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validateSelectedOptionTitle() {
|
||||
final option = state.planData.options[state.selectedOptionIndex ?? 0];
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
if (option.short.length < 3) {
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(titleHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return false;
|
||||
}
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(titleHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateTitlesOfAllFilledOptions() {
|
||||
final options = state.planData.options;
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
bool result = true;
|
||||
if (options[0].short.length < 3) {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(titleHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(titleHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
if (state.selectedOptionIndex == null) return result;
|
||||
|
||||
if (options[1].short.length < 3) {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(titleHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(titleHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
|
||||
if (options[2].short.length < 3) {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(titleHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(titleHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validateSelectedOptionDescription() {
|
||||
final option = state.planData.options[state.selectedOptionIndex ?? 0];
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
if (option.description.length < 3) {
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(descriptionHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return false;
|
||||
}
|
||||
optionsValidationsStates[state.selectedOptionIndex ?? 0] = optionsValidationsStates[state.selectedOptionIndex ?? 0].copyWith(descriptionHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateDescriptionsOfAllOptions() {
|
||||
final options = state.planData.options;
|
||||
final optionsValidationsStates = [...state.validationState.optionsValidationState];
|
||||
bool result = true;
|
||||
|
||||
if (options[0].description.length < 3) {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(descriptionHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[0] = optionsValidationsStates[0].copyWith(descriptionHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
if (state.selectedOptionIndex == null) return result;
|
||||
if (options[1].description.length < 3) {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(descriptionHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[1] = optionsValidationsStates[1].copyWith(descriptionHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
|
||||
if (options[2].description.length < 3) {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(descriptionHasError: true);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
result = false;
|
||||
} else {
|
||||
optionsValidationsStates[2] = optionsValidationsStates[2].copyWith(descriptionHasError: false);
|
||||
emit(state.copyWith.validationState(optionsValidationState: optionsValidationsStates));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validateAllFields() {
|
||||
final isNameValid = validateName();
|
||||
final isDetailsValid = validateDetails();
|
||||
final isImageValid = validateImage();
|
||||
final isDurationValid = validateDuration();
|
||||
final areTitlesValid = validateTitlesOfAllFilledOptions();
|
||||
final arePricesValid = validatePriceOfAllFilledOptions();
|
||||
final areDescriptionsValid = validateDescriptionsOfAllOptions();
|
||||
final areItemsValid = validateItemsOfAllFilledOptions();
|
||||
return isNameValid && isDetailsValid && isImageValid && isDurationValid && areTitlesValid && arePricesValid && areDescriptionsValid && areItemsValid;
|
||||
}
|
||||
|
||||
Future<void> publishPlan() async {
|
||||
if (validateAllFields()) {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final planModel = await state.planData.toCreationJson();
|
||||
final plan = await createPlanRepository.createPlan(model: planModel);
|
||||
if (state.planData.options[1].short.isNotEmpty) {
|
||||
final options = state.planData.toOptionsCreationJson();
|
||||
await createPlanRepository.createPacketOptions(slug: plan.slug, model: options);
|
||||
} else {
|
||||
final option = state.planData.toOptionCreationJson();
|
||||
await createPlanRepository.createPacketOption(slug: plan.slug, model: option);
|
||||
}
|
||||
emit(state.copyWith(isLoading: false, planCreated: true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ class CreatePlanState with _$CreatePlanState {
|
||||
const factory CreatePlanState({
|
||||
required bool isLoading,
|
||||
required String? errorMessage,
|
||||
required CreatePlanModel planData,
|
||||
required CreatePlanModel planData,
|
||||
required PlanValidationState validationState,
|
||||
required bool planCreated,
|
||||
int? durationIndex,
|
||||
int? selectedOptionIndex,
|
||||
}) = _CreatePlanState;
|
||||
@@ -17,9 +19,55 @@ class CreatePlanState with _$CreatePlanState {
|
||||
factory CreatePlanState.initial() => CreatePlanState(
|
||||
isLoading: false,
|
||||
errorMessage: null,
|
||||
planCreated: false,
|
||||
validationState: PlanValidationState.empty(),
|
||||
planData: CreatePlanModel(
|
||||
type: [false, false, false, false],
|
||||
options: [PacketOptions.empty(), PacketOptions.empty(), PacketOptions.empty()],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class PlanValidationState with _$PlanValidationState {
|
||||
factory PlanValidationState({
|
||||
required bool titleHasError,
|
||||
required bool durationHasError,
|
||||
required bool typeHasError,
|
||||
required bool descriptionHasError,
|
||||
required bool imageHasError,
|
||||
required List<OptionValidationState> optionsValidationState,
|
||||
}) = _PlanValidationState;
|
||||
|
||||
factory PlanValidationState.empty() => PlanValidationState(
|
||||
titleHasError: false,
|
||||
durationHasError: false,
|
||||
typeHasError: false,
|
||||
descriptionHasError: false,
|
||||
imageHasError: false,
|
||||
optionsValidationState: [
|
||||
OptionValidationState.empty(),
|
||||
OptionValidationState.empty(),
|
||||
OptionValidationState.empty(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class OptionValidationState with _$OptionValidationState {
|
||||
factory OptionValidationState({
|
||||
required bool titleHasError,
|
||||
required bool priceHasError,
|
||||
required bool descriptionHasError,
|
||||
required Map<int, bool> itemsErrors,
|
||||
required bool isItemsEmpty,
|
||||
}) = _OptionValidationState;
|
||||
|
||||
factory OptionValidationState.empty() => OptionValidationState(
|
||||
descriptionHasError: false,
|
||||
titleHasError: false,
|
||||
priceHasError: false,
|
||||
isItemsEmpty: false,
|
||||
itemsErrors: {},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -39,34 +41,53 @@ class _AddItemWidgetState extends State<AddItemWidget> {
|
||||
if (widget.items.length > widget.index && controller.text != widget.items[widget.index]) {
|
||||
controller.text = widget.items[widget.index];
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
controller: controller,
|
||||
hintText: widget.enableHint ? s.option_content_hint_text : null,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setOptionContent(value, widget.index);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.canBeDeleted) ...[
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreatePlanCubit>().removeOptionContentItem(widget.index);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.lightGray0,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: SvgPicture.asset('assets/icons/trash_can.svg', width: 20, height: 24),
|
||||
return BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
buildWhen: (previous, current) => previous.validationState != current.validationState,
|
||||
builder: (context, state) {
|
||||
final hasError = state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].isItemsEmpty ||
|
||||
(state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].itemsErrors[widget.index] ?? false);
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
controller: controller,
|
||||
hasError: hasError,
|
||||
hintText: widget.enableHint ? s.option_content_hint_text : null,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setOptionContent(value, widget.index);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.canBeDeleted) ...[
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreatePlanCubit>().removeOptionContentItem(widget.index);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.lightGray0,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: SvgPicture.asset('assets/icons/trash_can.svg', width: 20, height: 24),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
if (state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].isItemsEmpty) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.addAtLeastOneItem)
|
||||
] else if (state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].itemsErrors[widget.index] ?? false) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols)
|
||||
]
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/widgets/add_item_widget.dart';
|
||||
@@ -32,35 +33,9 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
super.initState();
|
||||
customerPriceController.addListener(() {
|
||||
if (!customerPriceController.text.endsWith('₽')) {
|
||||
final textWithoutCurrency = customerPriceController.text.replaceAll('₽', '');
|
||||
customerPriceController.value = TextEditingValue(
|
||||
text: "$textWithoutCurrency₽",
|
||||
selection: TextSelection.collapsed(offset: textWithoutCurrency.length),
|
||||
);
|
||||
}
|
||||
final price = double.tryParse(customerPriceController.text.replaceAll('₽', ''));
|
||||
if (price != null && price < 1200) {
|
||||
customerPriceController.value = const TextEditingValue(
|
||||
text: "1200₽",
|
||||
selection: TextSelection.collapsed(offset: 4),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
creatorPriceController.addListener(() {
|
||||
if (!creatorPriceController.text.endsWith('₽')) {
|
||||
final textWithoutCurrency = creatorPriceController.text.replaceAll('₽', '');
|
||||
creatorPriceController.value = TextEditingValue(
|
||||
text: "$textWithoutCurrency₽",
|
||||
selection: TextSelection.collapsed(offset: textWithoutCurrency.length),
|
||||
);
|
||||
}
|
||||
final price = double.tryParse(creatorPriceController.text.replaceAll('₽', ''));
|
||||
if (price != null && price < 1000) {
|
||||
creatorPriceController.value = const TextEditingValue(
|
||||
text: "1000₽",
|
||||
selection: TextSelection.collapsed(offset: 4),
|
||||
);
|
||||
final text = customerPriceController.text.replaceAll('₽', '');
|
||||
customerPriceController.text = '$text₽';
|
||||
customerPriceController.selection = TextSelection.collapsed(offset: text.length);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -94,12 +69,17 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
const SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
hintText: optionNameHintText,
|
||||
hasError: state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].titleHasError,
|
||||
controller: optionTitleController,
|
||||
onChanged: (value) {
|
||||
context.read<CreatePlanCubit>().setOptionTitle(value);
|
||||
},
|
||||
maxLength: 150,
|
||||
),
|
||||
if (state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].titleHasError) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
s.option_desc,
|
||||
@@ -114,6 +94,7 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
child: CustomTextFormField(
|
||||
controller: optionDescriptionController,
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
hasError: state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].descriptionHasError,
|
||||
maxLength: 1000,
|
||||
minLines: null,
|
||||
maxLines: null,
|
||||
@@ -124,6 +105,10 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if (state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].descriptionHasError) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.atLeast3Symbols),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
@@ -141,14 +126,8 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
const SizedBox(height: 4),
|
||||
CustomTextFormField(
|
||||
controller: creatorPriceController,
|
||||
onChanged: (value) {
|
||||
double? price = double.tryParse(value.replaceAll('₽', ''));
|
||||
if (price != null) {
|
||||
price = price * 1.2;
|
||||
customerPriceController.text = price.toStringAsFixed(2);
|
||||
context.read<CreatePlanCubit>().setPrice(price);
|
||||
}
|
||||
},
|
||||
readOnly: true,
|
||||
textStyle: TextStyle(color: appTheme.gray),
|
||||
maxLength: 20,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -169,10 +148,11 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
CustomTextFormField(
|
||||
controller: customerPriceController,
|
||||
textInputType: const TextInputType.numberWithOptions(decimal: true),
|
||||
hasError: state.validationState.optionsValidationState[state.selectedOptionIndex ?? 0].priceHasError,
|
||||
onChanged: (value) {
|
||||
final price = double.tryParse(value.replaceAll('₽', ''));
|
||||
creatorPriceController.text = '${((price ?? 0) * 0.8).toStringAsFixed(2)}₽';
|
||||
if (price != null) {
|
||||
creatorPriceController.text = (price * 0.8).toStringAsFixed(2);
|
||||
context.read<CreatePlanCubit>().setPrice(price);
|
||||
}
|
||||
},
|
||||
@@ -235,33 +215,33 @@ class _OptionWidgetState extends State<OptionWidget> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const CustomDivider(),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: isChecked,
|
||||
activeColor: appTheme.gray,
|
||||
checkColor: appTheme.gray,
|
||||
fillColor: const WidgetStatePropertyAll(Colors.transparent),
|
||||
side: WidgetStateBorderSide.resolveWith(
|
||||
(Set<WidgetState> states) {
|
||||
return BorderSide(width: 1, color: appTheme.gray);
|
||||
},
|
||||
),
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
isChecked = value ?? false;
|
||||
});
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
s.option_personal_diet_desc,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// const SizedBox(height: 16),
|
||||
// Row(
|
||||
// children: [
|
||||
// Checkbox(
|
||||
// value: isChecked,
|
||||
// activeColor: appTheme.gray,
|
||||
// checkColor: appTheme.gray,
|
||||
// fillColor: const WidgetStatePropertyAll(Colors.transparent),
|
||||
// side: WidgetStateBorderSide.resolveWith(
|
||||
// (Set<WidgetState> states) {
|
||||
// return BorderSide(width: 1, color: appTheme.gray);
|
||||
// },
|
||||
// ),
|
||||
// onChanged: (bool? value) {
|
||||
// setState(() {
|
||||
// isChecked = value ?? false;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: Text(
|
||||
// s.option_personal_diet_desc,
|
||||
// style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
@@ -36,28 +37,37 @@ class _PlanDurationDropDownWidgetState extends State<PlanDurationDropDownWidget>
|
||||
final s = S.of(context);
|
||||
return BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
builder: (context, state) {
|
||||
return CustomDropDownButton(
|
||||
hint: Text(
|
||||
s.choose_plan_duration,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
context.read<CreatePlanCubit>().setDuration(durationDropDownTitles.indexOf(value));
|
||||
}
|
||||
},
|
||||
items: durationDropDownTitles
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: durationDropDownTitles[index],
|
||||
child: Text(
|
||||
durationDropDownTitles[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
value: state.durationIndex == null ? null : durationDropDownTitles[state.durationIndex ?? 0],
|
||||
return Column(
|
||||
children: [
|
||||
CustomDropDownButton(
|
||||
hasError: state.validationState.durationHasError,
|
||||
hint: Text(
|
||||
s.choose_plan_duration,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
context.read<CreatePlanCubit>().setDuration(durationDropDownTitles.indexOf(value));
|
||||
}
|
||||
},
|
||||
items: durationDropDownTitles
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: durationDropDownTitles[index],
|
||||
child: Text(
|
||||
durationDropDownTitles[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
value: state.durationIndex == null ? null : durationDropDownTitles[state.durationIndex ?? 0],
|
||||
),
|
||||
if (state.validationState.durationHasError) ...[
|
||||
const SizedBox(height: 4),
|
||||
ValidationErrorWidget(error: s.choose_plan_duration),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
@@ -72,74 +73,79 @@ class _PlanImagePickerWidgetState extends State<PlanImagePickerWidget> {
|
||||
final s = S.of(context);
|
||||
return BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_showImagePickerOptions(s, context.read<CreatePlanCubit>());
|
||||
},
|
||||
child: Container(
|
||||
height: 240,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: state.planData.image != null ? DecorationImage(fit: BoxFit.cover, image: FileImage(File(state.planData.image?.path ?? ''))) : null,
|
||||
color: appTheme.gray50,
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_showImagePickerOptions(s, context.read<CreatePlanCubit>());
|
||||
},
|
||||
child: Container(
|
||||
height: 240,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
image: state.planData.image != null ? DecorationImage(fit: BoxFit.cover, image: FileImage(File(state.planData.image?.path ?? ''))) : null,
|
||||
color: appTheme.gray50,
|
||||
),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
padding: state.planData.image != null ? null : const EdgeInsets.all(8),
|
||||
child: state.planData.image != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(top: 6, right: 6),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreatePlanCubit>().setImage(null);
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.dividerColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close_rounded,
|
||||
color: Colors.grey,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Stack(
|
||||
children: [
|
||||
DottedBorder(
|
||||
stackFit: StackFit.expand,
|
||||
dashPattern: const [14, 14],
|
||||
color: state.validationState.imageHasError ? appTheme.red : appTheme.dottedBorder,
|
||||
borderType: BorderType.RRect,
|
||||
radius: const Radius.circular(12),
|
||||
child: const SizedBox.expand(),
|
||||
),
|
||||
Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
SvgPicture.asset('assets/icons/eatvio_logo.svg'),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
s.add_cover,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.gray),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
padding: state.planData.image != null ? null : const EdgeInsets.all(8),
|
||||
child: state.planData.image != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(top: 6, right: 6),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreatePlanCubit>().setImage(null);
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.dividerColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close_rounded,
|
||||
color: Colors.grey,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Stack(
|
||||
children: [
|
||||
DottedBorder(
|
||||
stackFit: StackFit.expand,
|
||||
dashPattern: const [14, 14],
|
||||
color: appTheme.dottedBorder,
|
||||
borderType: BorderType.RRect,
|
||||
radius: const Radius.circular(12),
|
||||
child: const SizedBox.expand(),
|
||||
),
|
||||
Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
SvgPicture.asset('assets/icons/eatvio_logo.svg'),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
s.add_cover,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.gray),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (state.validationState.imageHasError) ...[const SizedBox(height: 8), ValidationErrorWidget(error: s.add_cover)],
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
@@ -50,49 +51,55 @@ class _PlanTypeChoiceWidgetState extends State<PlanTypeChoiceWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return BlocBuilder<CreatePlanCubit, CreatePlanState>(
|
||||
builder: (context, state) {
|
||||
return Row(
|
||||
return Column(
|
||||
children: [
|
||||
...List.generate(4, (index) {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final planTypes = [...state.planData.type];
|
||||
planTypes[index] = !planTypes[index];
|
||||
context.read<CreatePlanCubit>().setPlanType(planTypes);
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(right: index == 3 ? 0 : 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: state.planData.type[index] ? appTheme.cardBackground : appTheme.whiteA700,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: state.planData.type[index] ? appTheme.blueA400 : appTheme.lightGray00,
|
||||
Row(
|
||||
children: [
|
||||
...List.generate(4, (index) {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final planTypes = [...state.planData.type];
|
||||
planTypes[index] = !planTypes[index];
|
||||
context.read<CreatePlanCubit>().setPlanType(planTypes);
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(right: index == 3 ? 0 : 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: state.planData.type[index] ? appTheme.cardBackground : appTheme.whiteA700,
|
||||
border: Border.all(
|
||||
width: 1,
|
||||
color: state.planData.type[index] ? appTheme.blueA400 : appTheme.lightGray00,
|
||||
),
|
||||
),
|
||||
height: 104,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Image.asset(
|
||||
choiceContent[index].$1,
|
||||
height: 30,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
choiceContent[index].$2,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.textFS10FW500.copyWith(color: appTheme.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
height: 104,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Image.asset(
|
||||
choiceContent[index].$1,
|
||||
height: 30,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
choiceContent[index].$2,
|
||||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.textFS10FW500.copyWith(color: appTheme.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
if (state.validationState.typeHasError) ...[const SizedBox(height: 8), ValidationErrorWidget(error: s.chosePlanType)]
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/create_plan/models/plan_slug_model.dart';
|
||||
import 'package:eatvio_app/features/create_plan/services/create_plan_service.dart';
|
||||
|
||||
class CreatePlanRepository {
|
||||
@@ -5,10 +7,11 @@ class CreatePlanRepository {
|
||||
|
||||
CreatePlanRepository({required this.createPlanService});
|
||||
|
||||
Future<void> createPlan({
|
||||
Future<PlanSlugModel> createPlan({
|
||||
required Map<String, dynamic> model,
|
||||
}) async {
|
||||
createPlanService.createPlan(model: model);
|
||||
final formData = FormData.fromMap(model);
|
||||
return await createPlanService.createPlan(formData: formData);
|
||||
}
|
||||
|
||||
Future<void> createPacketOption({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/create_plan/models/plan_slug_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
part 'create_plan_service.g.dart';
|
||||
@@ -9,8 +10,8 @@ abstract class CreatePlanService {
|
||||
|
||||
@POST('/api/plans/create')
|
||||
@MultiPart()
|
||||
Future<void> createPlan({
|
||||
@Body() required Map<String, dynamic> model,
|
||||
Future<PlanSlugModel> createPlan({
|
||||
@Body() required FormData formData,
|
||||
});
|
||||
|
||||
@POST('/api/plans/create/{slug}/packet_option')
|
||||
@@ -19,7 +20,7 @@ abstract class CreatePlanService {
|
||||
@Body() required Map<String, dynamic> model,
|
||||
});
|
||||
|
||||
@POST('/api/plans/create/{slug}/packet_options')
|
||||
@POST('/api/plans/create/{slug}/packet_options')
|
||||
Future<void> createPacketOptions({
|
||||
@Path() required String slug,
|
||||
@Body() required Map<String, dynamic> model,
|
||||
|
||||
@@ -1,581 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'consultant_comment_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
ConsultantCommentModel _$ConsultantCommentModelFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return _ConsultantCommentModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ConsultantCommentModel {
|
||||
String? get comment => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'meals')
|
||||
Map<String, MealCommentModel> get mealsComments =>
|
||||
throw _privateConstructorUsedError;
|
||||
List<PortionCommentModel> get portions => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ConsultantCommentModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConsultantCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ConsultantCommentModelCopyWith<ConsultantCommentModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ConsultantCommentModelCopyWith<$Res> {
|
||||
factory $ConsultantCommentModelCopyWith(ConsultantCommentModel value,
|
||||
$Res Function(ConsultantCommentModel) then) =
|
||||
_$ConsultantCommentModelCopyWithImpl<$Res, ConsultantCommentModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? comment,
|
||||
@JsonKey(name: 'meals') Map<String, MealCommentModel> mealsComments,
|
||||
List<PortionCommentModel> portions});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ConsultantCommentModelCopyWithImpl<$Res,
|
||||
$Val extends ConsultantCommentModel>
|
||||
implements $ConsultantCommentModelCopyWith<$Res> {
|
||||
_$ConsultantCommentModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ConsultantCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = freezed,
|
||||
Object? mealsComments = null,
|
||||
Object? portions = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
comment: freezed == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
mealsComments: null == mealsComments
|
||||
? _value.mealsComments
|
||||
: mealsComments // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, MealCommentModel>,
|
||||
portions: null == portions
|
||||
? _value.portions
|
||||
: portions // ignore: cast_nullable_to_non_nullable
|
||||
as List<PortionCommentModel>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ConsultantCommentModelImplCopyWith<$Res>
|
||||
implements $ConsultantCommentModelCopyWith<$Res> {
|
||||
factory _$$ConsultantCommentModelImplCopyWith(
|
||||
_$ConsultantCommentModelImpl value,
|
||||
$Res Function(_$ConsultantCommentModelImpl) then) =
|
||||
__$$ConsultantCommentModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? comment,
|
||||
@JsonKey(name: 'meals') Map<String, MealCommentModel> mealsComments,
|
||||
List<PortionCommentModel> portions});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ConsultantCommentModelImplCopyWithImpl<$Res>
|
||||
extends _$ConsultantCommentModelCopyWithImpl<$Res,
|
||||
_$ConsultantCommentModelImpl>
|
||||
implements _$$ConsultantCommentModelImplCopyWith<$Res> {
|
||||
__$$ConsultantCommentModelImplCopyWithImpl(
|
||||
_$ConsultantCommentModelImpl _value,
|
||||
$Res Function(_$ConsultantCommentModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ConsultantCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = freezed,
|
||||
Object? mealsComments = null,
|
||||
Object? portions = null,
|
||||
}) {
|
||||
return _then(_$ConsultantCommentModelImpl(
|
||||
comment: freezed == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
mealsComments: null == mealsComments
|
||||
? _value._mealsComments
|
||||
: mealsComments // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, MealCommentModel>,
|
||||
portions: null == portions
|
||||
? _value._portions
|
||||
: portions // ignore: cast_nullable_to_non_nullable
|
||||
as List<PortionCommentModel>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ConsultantCommentModelImpl implements _ConsultantCommentModel {
|
||||
_$ConsultantCommentModelImpl(
|
||||
{this.comment,
|
||||
@JsonKey(name: 'meals')
|
||||
final Map<String, MealCommentModel> mealsComments = const {},
|
||||
final List<PortionCommentModel> portions = const []})
|
||||
: _mealsComments = mealsComments,
|
||||
_portions = portions;
|
||||
|
||||
factory _$ConsultantCommentModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ConsultantCommentModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String? comment;
|
||||
final Map<String, MealCommentModel> _mealsComments;
|
||||
@override
|
||||
@JsonKey(name: 'meals')
|
||||
Map<String, MealCommentModel> get mealsComments {
|
||||
if (_mealsComments is EqualUnmodifiableMapView) return _mealsComments;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_mealsComments);
|
||||
}
|
||||
|
||||
final List<PortionCommentModel> _portions;
|
||||
@override
|
||||
@JsonKey()
|
||||
List<PortionCommentModel> get portions {
|
||||
if (_portions is EqualUnmodifiableListView) return _portions;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_portions);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConsultantCommentModel(comment: $comment, mealsComments: $mealsComments, portions: $portions)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConsultantCommentModelImpl &&
|
||||
(identical(other.comment, comment) || other.comment == comment) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._mealsComments, _mealsComments) &&
|
||||
const DeepCollectionEquality().equals(other._portions, _portions));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
comment,
|
||||
const DeepCollectionEquality().hash(_mealsComments),
|
||||
const DeepCollectionEquality().hash(_portions));
|
||||
|
||||
/// Create a copy of ConsultantCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ConsultantCommentModelImplCopyWith<_$ConsultantCommentModelImpl>
|
||||
get copyWith => __$$ConsultantCommentModelImplCopyWithImpl<
|
||||
_$ConsultantCommentModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ConsultantCommentModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ConsultantCommentModel implements ConsultantCommentModel {
|
||||
factory _ConsultantCommentModel(
|
||||
{final String? comment,
|
||||
@JsonKey(name: 'meals') final Map<String, MealCommentModel> mealsComments,
|
||||
final List<PortionCommentModel> portions}) = _$ConsultantCommentModelImpl;
|
||||
|
||||
factory _ConsultantCommentModel.fromJson(Map<String, dynamic> json) =
|
||||
_$ConsultantCommentModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String? get comment;
|
||||
@override
|
||||
@JsonKey(name: 'meals')
|
||||
Map<String, MealCommentModel> get mealsComments;
|
||||
@override
|
||||
List<PortionCommentModel> get portions;
|
||||
|
||||
/// Create a copy of ConsultantCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ConsultantCommentModelImplCopyWith<_$ConsultantCommentModelImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
PortionCommentModel _$PortionCommentModelFromJson(Map<String, dynamic> json) {
|
||||
return _PortionCommentModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PortionCommentModel {
|
||||
String get comment => throw _privateConstructorUsedError;
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PortionCommentModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of PortionCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PortionCommentModelCopyWith<PortionCommentModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $PortionCommentModelCopyWith<$Res> {
|
||||
factory $PortionCommentModelCopyWith(
|
||||
PortionCommentModel value, $Res Function(PortionCommentModel) then) =
|
||||
_$PortionCommentModelCopyWithImpl<$Res, PortionCommentModel>;
|
||||
@useResult
|
||||
$Res call({String comment, int id});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$PortionCommentModelCopyWithImpl<$Res, $Val extends PortionCommentModel>
|
||||
implements $PortionCommentModelCopyWith<$Res> {
|
||||
_$PortionCommentModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PortionCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? id = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PortionCommentModelImplCopyWith<$Res>
|
||||
implements $PortionCommentModelCopyWith<$Res> {
|
||||
factory _$$PortionCommentModelImplCopyWith(_$PortionCommentModelImpl value,
|
||||
$Res Function(_$PortionCommentModelImpl) then) =
|
||||
__$$PortionCommentModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String comment, int id});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PortionCommentModelImplCopyWithImpl<$Res>
|
||||
extends _$PortionCommentModelCopyWithImpl<$Res, _$PortionCommentModelImpl>
|
||||
implements _$$PortionCommentModelImplCopyWith<$Res> {
|
||||
__$$PortionCommentModelImplCopyWithImpl(_$PortionCommentModelImpl _value,
|
||||
$Res Function(_$PortionCommentModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PortionCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? id = null,
|
||||
}) {
|
||||
return _then(_$PortionCommentModelImpl(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$PortionCommentModelImpl implements _PortionCommentModel {
|
||||
_$PortionCommentModelImpl({required this.comment, required this.id});
|
||||
|
||||
factory _$PortionCommentModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PortionCommentModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String comment;
|
||||
@override
|
||||
final int id;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PortionCommentModel(comment: $comment, id: $id)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PortionCommentModelImpl &&
|
||||
(identical(other.comment, comment) || other.comment == comment) &&
|
||||
(identical(other.id, id) || other.id == id));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, comment, id);
|
||||
|
||||
/// Create a copy of PortionCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PortionCommentModelImplCopyWith<_$PortionCommentModelImpl> get copyWith =>
|
||||
__$$PortionCommentModelImplCopyWithImpl<_$PortionCommentModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$PortionCommentModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _PortionCommentModel implements PortionCommentModel {
|
||||
factory _PortionCommentModel(
|
||||
{required final String comment,
|
||||
required final int id}) = _$PortionCommentModelImpl;
|
||||
|
||||
factory _PortionCommentModel.fromJson(Map<String, dynamic> json) =
|
||||
_$PortionCommentModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get comment;
|
||||
@override
|
||||
int get id;
|
||||
|
||||
/// Create a copy of PortionCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PortionCommentModelImplCopyWith<_$PortionCommentModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
MealCommentModel _$MealCommentModelFromJson(Map<String, dynamic> json) {
|
||||
return _MealCommentModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$MealCommentModel {
|
||||
String get comment => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'type_no')
|
||||
int get typeNumber => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this MealCommentModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of MealCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$MealCommentModelCopyWith<MealCommentModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $MealCommentModelCopyWith<$Res> {
|
||||
factory $MealCommentModelCopyWith(
|
||||
MealCommentModel value, $Res Function(MealCommentModel) then) =
|
||||
_$MealCommentModelCopyWithImpl<$Res, MealCommentModel>;
|
||||
@useResult
|
||||
$Res call({String comment, @JsonKey(name: 'type_no') int typeNumber});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$MealCommentModelCopyWithImpl<$Res, $Val extends MealCommentModel>
|
||||
implements $MealCommentModelCopyWith<$Res> {
|
||||
_$MealCommentModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of MealCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? typeNumber = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
typeNumber: null == typeNumber
|
||||
? _value.typeNumber
|
||||
: typeNumber // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$MealCommentModelImplCopyWith<$Res>
|
||||
implements $MealCommentModelCopyWith<$Res> {
|
||||
factory _$$MealCommentModelImplCopyWith(_$MealCommentModelImpl value,
|
||||
$Res Function(_$MealCommentModelImpl) then) =
|
||||
__$$MealCommentModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String comment, @JsonKey(name: 'type_no') int typeNumber});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$MealCommentModelImplCopyWithImpl<$Res>
|
||||
extends _$MealCommentModelCopyWithImpl<$Res, _$MealCommentModelImpl>
|
||||
implements _$$MealCommentModelImplCopyWith<$Res> {
|
||||
__$$MealCommentModelImplCopyWithImpl(_$MealCommentModelImpl _value,
|
||||
$Res Function(_$MealCommentModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of MealCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? typeNumber = null,
|
||||
}) {
|
||||
return _then(_$MealCommentModelImpl(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
typeNumber: null == typeNumber
|
||||
? _value.typeNumber
|
||||
: typeNumber // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$MealCommentModelImpl implements _MealCommentModel {
|
||||
_$MealCommentModelImpl(
|
||||
{required this.comment,
|
||||
@JsonKey(name: 'type_no') required this.typeNumber});
|
||||
|
||||
factory _$MealCommentModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$MealCommentModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String comment;
|
||||
@override
|
||||
@JsonKey(name: 'type_no')
|
||||
final int typeNumber;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MealCommentModel(comment: $comment, typeNumber: $typeNumber)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$MealCommentModelImpl &&
|
||||
(identical(other.comment, comment) || other.comment == comment) &&
|
||||
(identical(other.typeNumber, typeNumber) ||
|
||||
other.typeNumber == typeNumber));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, comment, typeNumber);
|
||||
|
||||
/// Create a copy of MealCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$MealCommentModelImplCopyWith<_$MealCommentModelImpl> get copyWith =>
|
||||
__$$MealCommentModelImplCopyWithImpl<_$MealCommentModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$MealCommentModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _MealCommentModel implements MealCommentModel {
|
||||
factory _MealCommentModel(
|
||||
{required final String comment,
|
||||
@JsonKey(name: 'type_no') required final int typeNumber}) =
|
||||
_$MealCommentModelImpl;
|
||||
|
||||
factory _MealCommentModel.fromJson(Map<String, dynamic> json) =
|
||||
_$MealCommentModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get comment;
|
||||
@override
|
||||
@JsonKey(name: 'type_no')
|
||||
int get typeNumber;
|
||||
|
||||
/// Create a copy of MealCommentModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$MealCommentModelImplCopyWith<_$MealCommentModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'consultant_comment_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ConsultantCommentModelImpl _$$ConsultantCommentModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ConsultantCommentModelImpl(
|
||||
comment: json['comment'] as String?,
|
||||
mealsComments: (json['meals'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(
|
||||
k, MealCommentModel.fromJson(e as Map<String, dynamic>)),
|
||||
) ??
|
||||
const {},
|
||||
portions: (json['portions'] as List<dynamic>?)
|
||||
?.map((e) =>
|
||||
PortionCommentModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ConsultantCommentModelImplToJson(
|
||||
_$ConsultantCommentModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'comment': instance.comment,
|
||||
'meals': instance.mealsComments,
|
||||
'portions': instance.portions,
|
||||
};
|
||||
|
||||
_$PortionCommentModelImpl _$$PortionCommentModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$PortionCommentModelImpl(
|
||||
comment: json['comment'] as String,
|
||||
id: (json['id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$PortionCommentModelImplToJson(
|
||||
_$PortionCommentModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'comment': instance.comment,
|
||||
'id': instance.id,
|
||||
};
|
||||
|
||||
_$MealCommentModelImpl _$$MealCommentModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$MealCommentModelImpl(
|
||||
comment: json['comment'] as String,
|
||||
typeNumber: (json['type_no'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$MealCommentModelImplToJson(
|
||||
_$MealCommentModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'comment': instance.comment,
|
||||
'type_no': instance.typeNumber,
|
||||
};
|
||||
@@ -36,6 +36,7 @@ class MealComment with _$MealComment {
|
||||
|
||||
factory MealComment({
|
||||
required String comment,
|
||||
required int typeNo,
|
||||
}) = _MealComment;
|
||||
|
||||
factory MealComment.fromJson(Map<String, dynamic> json) => _$MealCommentFromJson(json);
|
||||
@@ -45,7 +46,7 @@ class MealComment with _$MealComment {
|
||||
class PortionComment with _$PortionComment {
|
||||
|
||||
factory PortionComment({
|
||||
@JsonKey(name: 'commentable_id') required int portionId,
|
||||
@JsonKey(name: 'id') required int portionId,
|
||||
required String comment,
|
||||
}) = _PortionComment;
|
||||
|
||||
|
||||
@@ -479,6 +479,7 @@ MealComment _$MealCommentFromJson(Map<String, dynamic> json) {
|
||||
/// @nodoc
|
||||
mixin _$MealComment {
|
||||
String get comment => throw _privateConstructorUsedError;
|
||||
int get typeNo => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this MealComment to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -496,7 +497,7 @@ abstract class $MealCommentCopyWith<$Res> {
|
||||
MealComment value, $Res Function(MealComment) then) =
|
||||
_$MealCommentCopyWithImpl<$Res, MealComment>;
|
||||
@useResult
|
||||
$Res call({String comment});
|
||||
$Res call({String comment, int typeNo});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -515,12 +516,17 @@ class _$MealCommentCopyWithImpl<$Res, $Val extends MealComment>
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? typeNo = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
typeNo: null == typeNo
|
||||
? _value.typeNo
|
||||
: typeNo // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -533,7 +539,7 @@ abstract class _$$MealCommentImplCopyWith<$Res>
|
||||
__$$MealCommentImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String comment});
|
||||
$Res call({String comment, int typeNo});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -550,12 +556,17 @@ class __$$MealCommentImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? comment = null,
|
||||
Object? typeNo = null,
|
||||
}) {
|
||||
return _then(_$MealCommentImpl(
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
typeNo: null == typeNo
|
||||
? _value.typeNo
|
||||
: typeNo // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -563,17 +574,19 @@ class __$$MealCommentImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$MealCommentImpl implements _MealComment {
|
||||
_$MealCommentImpl({required this.comment});
|
||||
_$MealCommentImpl({required this.comment, required this.typeNo});
|
||||
|
||||
factory _$MealCommentImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$MealCommentImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String comment;
|
||||
@override
|
||||
final int typeNo;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MealComment(comment: $comment)';
|
||||
return 'MealComment(comment: $comment, typeNo: $typeNo)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -581,12 +594,13 @@ class _$MealCommentImpl implements _MealComment {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$MealCommentImpl &&
|
||||
(identical(other.comment, comment) || other.comment == comment));
|
||||
(identical(other.comment, comment) || other.comment == comment) &&
|
||||
(identical(other.typeNo, typeNo) || other.typeNo == typeNo));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, comment);
|
||||
int get hashCode => Object.hash(runtimeType, comment, typeNo);
|
||||
|
||||
/// Create a copy of MealComment
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -605,13 +619,17 @@ class _$MealCommentImpl implements _MealComment {
|
||||
}
|
||||
|
||||
abstract class _MealComment implements MealComment {
|
||||
factory _MealComment({required final String comment}) = _$MealCommentImpl;
|
||||
factory _MealComment(
|
||||
{required final String comment,
|
||||
required final int typeNo}) = _$MealCommentImpl;
|
||||
|
||||
factory _MealComment.fromJson(Map<String, dynamic> json) =
|
||||
_$MealCommentImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get comment;
|
||||
@override
|
||||
int get typeNo;
|
||||
|
||||
/// Create a copy of MealComment
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -627,7 +645,7 @@ PortionComment _$PortionCommentFromJson(Map<String, dynamic> json) {
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PortionComment {
|
||||
@JsonKey(name: 'commentable_id')
|
||||
@JsonKey(name: 'id')
|
||||
int get portionId => throw _privateConstructorUsedError;
|
||||
String get comment => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -647,7 +665,7 @@ abstract class $PortionCommentCopyWith<$Res> {
|
||||
PortionComment value, $Res Function(PortionComment) then) =
|
||||
_$PortionCommentCopyWithImpl<$Res, PortionComment>;
|
||||
@useResult
|
||||
$Res call({@JsonKey(name: 'commentable_id') int portionId, String comment});
|
||||
$Res call({@JsonKey(name: 'id') int portionId, String comment});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -689,7 +707,7 @@ abstract class _$$PortionCommentImplCopyWith<$Res>
|
||||
__$$PortionCommentImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({@JsonKey(name: 'commentable_id') int portionId, String comment});
|
||||
$Res call({@JsonKey(name: 'id') int portionId, String comment});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -725,14 +743,13 @@ class __$$PortionCommentImplCopyWithImpl<$Res>
|
||||
@JsonSerializable()
|
||||
class _$PortionCommentImpl implements _PortionComment {
|
||||
_$PortionCommentImpl(
|
||||
{@JsonKey(name: 'commentable_id') required this.portionId,
|
||||
required this.comment});
|
||||
{@JsonKey(name: 'id') required this.portionId, required this.comment});
|
||||
|
||||
factory _$PortionCommentImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PortionCommentImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'commentable_id')
|
||||
@JsonKey(name: 'id')
|
||||
final int portionId;
|
||||
@override
|
||||
final String comment;
|
||||
@@ -775,14 +792,14 @@ class _$PortionCommentImpl implements _PortionComment {
|
||||
|
||||
abstract class _PortionComment implements PortionComment {
|
||||
factory _PortionComment(
|
||||
{@JsonKey(name: 'commentable_id') required final int portionId,
|
||||
{@JsonKey(name: 'id') required final int portionId,
|
||||
required final String comment}) = _$PortionCommentImpl;
|
||||
|
||||
factory _PortionComment.fromJson(Map<String, dynamic> json) =
|
||||
_$PortionCommentImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'commentable_id')
|
||||
@JsonKey(name: 'id')
|
||||
int get portionId;
|
||||
@override
|
||||
String get comment;
|
||||
|
||||
@@ -48,22 +48,24 @@ Map<String, dynamic> _$$ConsultantCommentsImplToJson(
|
||||
_$MealCommentImpl _$$MealCommentImplFromJson(Map<String, dynamic> json) =>
|
||||
_$MealCommentImpl(
|
||||
comment: json['comment'] as String,
|
||||
typeNo: (json['typeNo'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$MealCommentImplToJson(_$MealCommentImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'comment': instance.comment,
|
||||
'typeNo': instance.typeNo,
|
||||
};
|
||||
|
||||
_$PortionCommentImpl _$$PortionCommentImplFromJson(Map<String, dynamic> json) =>
|
||||
_$PortionCommentImpl(
|
||||
portionId: (json['commentable_id'] as num).toInt(),
|
||||
portionId: (json['id'] as num).toInt(),
|
||||
comment: json['comment'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$PortionCommentImplToJson(
|
||||
_$PortionCommentImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'commentable_id': instance.portionId,
|
||||
'id': instance.portionId,
|
||||
'comment': instance.comment,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,10 @@ enum PortionState {
|
||||
@freezed
|
||||
class DiaryDayWrapperModel with _$DiaryDayWrapperModel {
|
||||
const factory DiaryDayWrapperModel({
|
||||
@JsonKey(name: "diary") required DiaryDayModel diary,
|
||||
@JsonKey(
|
||||
name: "diary",
|
||||
)
|
||||
required DiaryDayModel diary,
|
||||
}) = _DiaryDayWrapperModel;
|
||||
|
||||
factory DiaryDayWrapperModel.fromJson(Map<String, dynamic> json) => _$DiaryDayWrapperModelFromJson(json);
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'consultant_comments_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ConsultantCommentsState {
|
||||
ConsultantCommentModel get commentsModel =>
|
||||
throw _privateConstructorUsedError;
|
||||
bool get dayCommentNeedsToBeFilled => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ConsultantCommentsStateCopyWith<ConsultantCommentsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ConsultantCommentsStateCopyWith<$Res> {
|
||||
factory $ConsultantCommentsStateCopyWith(ConsultantCommentsState value,
|
||||
$Res Function(ConsultantCommentsState) then) =
|
||||
_$ConsultantCommentsStateCopyWithImpl<$Res, ConsultantCommentsState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{ConsultantCommentModel commentsModel, bool dayCommentNeedsToBeFilled});
|
||||
|
||||
$ConsultantCommentModelCopyWith<$Res> get commentsModel;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ConsultantCommentsStateCopyWithImpl<$Res,
|
||||
$Val extends ConsultantCommentsState>
|
||||
implements $ConsultantCommentsStateCopyWith<$Res> {
|
||||
_$ConsultantCommentsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? commentsModel = null,
|
||||
Object? dayCommentNeedsToBeFilled = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
commentsModel: null == commentsModel
|
||||
? _value.commentsModel
|
||||
: commentsModel // ignore: cast_nullable_to_non_nullable
|
||||
as ConsultantCommentModel,
|
||||
dayCommentNeedsToBeFilled: null == dayCommentNeedsToBeFilled
|
||||
? _value.dayCommentNeedsToBeFilled
|
||||
: dayCommentNeedsToBeFilled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ConsultantCommentModelCopyWith<$Res> get commentsModel {
|
||||
return $ConsultantCommentModelCopyWith<$Res>(_value.commentsModel, (value) {
|
||||
return _then(_value.copyWith(commentsModel: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ConsultantCommentsStateImplCopyWith<$Res>
|
||||
implements $ConsultantCommentsStateCopyWith<$Res> {
|
||||
factory _$$ConsultantCommentsStateImplCopyWith(
|
||||
_$ConsultantCommentsStateImpl value,
|
||||
$Res Function(_$ConsultantCommentsStateImpl) then) =
|
||||
__$$ConsultantCommentsStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{ConsultantCommentModel commentsModel, bool dayCommentNeedsToBeFilled});
|
||||
|
||||
@override
|
||||
$ConsultantCommentModelCopyWith<$Res> get commentsModel;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ConsultantCommentsStateImplCopyWithImpl<$Res>
|
||||
extends _$ConsultantCommentsStateCopyWithImpl<$Res,
|
||||
_$ConsultantCommentsStateImpl>
|
||||
implements _$$ConsultantCommentsStateImplCopyWith<$Res> {
|
||||
__$$ConsultantCommentsStateImplCopyWithImpl(
|
||||
_$ConsultantCommentsStateImpl _value,
|
||||
$Res Function(_$ConsultantCommentsStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? commentsModel = null,
|
||||
Object? dayCommentNeedsToBeFilled = null,
|
||||
}) {
|
||||
return _then(_$ConsultantCommentsStateImpl(
|
||||
commentsModel: null == commentsModel
|
||||
? _value.commentsModel
|
||||
: commentsModel // ignore: cast_nullable_to_non_nullable
|
||||
as ConsultantCommentModel,
|
||||
dayCommentNeedsToBeFilled: null == dayCommentNeedsToBeFilled
|
||||
? _value.dayCommentNeedsToBeFilled
|
||||
: dayCommentNeedsToBeFilled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ConsultantCommentsStateImpl implements _ConsultantCommentsState {
|
||||
_$ConsultantCommentsStateImpl(
|
||||
{required this.commentsModel, this.dayCommentNeedsToBeFilled = false});
|
||||
|
||||
@override
|
||||
final ConsultantCommentModel commentsModel;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool dayCommentNeedsToBeFilled;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ConsultantCommentsState(commentsModel: $commentsModel, dayCommentNeedsToBeFilled: $dayCommentNeedsToBeFilled)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ConsultantCommentsStateImpl &&
|
||||
(identical(other.commentsModel, commentsModel) ||
|
||||
other.commentsModel == commentsModel) &&
|
||||
(identical(other.dayCommentNeedsToBeFilled,
|
||||
dayCommentNeedsToBeFilled) ||
|
||||
other.dayCommentNeedsToBeFilled == dayCommentNeedsToBeFilled));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, commentsModel, dayCommentNeedsToBeFilled);
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ConsultantCommentsStateImplCopyWith<_$ConsultantCommentsStateImpl>
|
||||
get copyWith => __$$ConsultantCommentsStateImplCopyWithImpl<
|
||||
_$ConsultantCommentsStateImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _ConsultantCommentsState implements ConsultantCommentsState {
|
||||
factory _ConsultantCommentsState(
|
||||
{required final ConsultantCommentModel commentsModel,
|
||||
final bool dayCommentNeedsToBeFilled}) = _$ConsultantCommentsStateImpl;
|
||||
|
||||
@override
|
||||
ConsultantCommentModel get commentsModel;
|
||||
@override
|
||||
bool get dayCommentNeedsToBeFilled;
|
||||
|
||||
/// Create a copy of ConsultantCommentsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ConsultantCommentsStateImplCopyWith<_$ConsultantCommentsStateImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/features/diary/repositories/diary_repository.dart';
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DiaryCubit extends Cubit<DiaryState> {
|
||||
@@ -19,8 +20,13 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
late int selectedMeal;
|
||||
final DiaryRepository diaryRepository;
|
||||
final GlossaryRepository glossaryRepository;
|
||||
final ProfileRepository profileRepository;
|
||||
int? diaryId;
|
||||
DiaryCubit({required this.diaryRepository, required this.glossaryRepository}) : super(const DiaryState.loading()) {
|
||||
DiaryCubit({
|
||||
required this.diaryRepository,
|
||||
required this.glossaryRepository,
|
||||
required this.profileRepository,
|
||||
}) : super(const DiaryState.loading()) {
|
||||
today = DateTime.now();
|
||||
selectedDay = today;
|
||||
diaryRepository.forceFetchStream.listen((_) {
|
||||
@@ -42,6 +48,7 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
|
||||
fetchDiary([bool needLoading = false, int? diaryId]) async {
|
||||
this.diaryId ??= diaryId;
|
||||
await profileRepository.getChosenDiets();
|
||||
if (needLoading) {
|
||||
emit(const DiaryState.loading());
|
||||
selectedMeal = 1;
|
||||
@@ -88,7 +95,12 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
}) async {
|
||||
await diaryRepository.finishDiaryDay(diaryId: diaryId, wakeUp: wakeUp, retire: retire, comment: comment);
|
||||
await diaryRepository.finishDiaryDay(
|
||||
diaryId: diaryId,
|
||||
wakeUp: wakeUp,
|
||||
retire: retire,
|
||||
comment: comment.isEmpty ? null : comment,
|
||||
);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,12 @@ class DiaryScreenContent extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
if (diaryId == null) const CalendarWidget(),
|
||||
if (state is DiaryStateLoading) const Loader(),
|
||||
if (state is DiaryStateLoading) ...[
|
||||
const SizedBox(
|
||||
height: 60,
|
||||
),
|
||||
const Loader()
|
||||
],
|
||||
if (state is DiaryStateLoaded)
|
||||
WakeupAndRetireWidget(
|
||||
showRetire: state.diary.typeOfDiary.hasChosenPlan,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
@@ -6,7 +7,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MealButtonWidget extends StatefulWidget {
|
||||
final int mealNumber;
|
||||
|
||||
const MealButtonWidget({
|
||||
super.key,
|
||||
required this.mealNumber,
|
||||
@@ -22,6 +22,18 @@ class _MealButtonWidgetState extends State<MealButtonWidget> {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
final consultantComment = state.consultantReview?.consultantComments.mealsComments.firstWhereOrNull(
|
||||
(element) => element.typeNo == widget.mealNumber,
|
||||
);
|
||||
|
||||
final Color bgColor;
|
||||
if (state.selectedMeal == widget.mealNumber) {
|
||||
bgColor = appTheme.blueA400;
|
||||
} else if (consultantComment != null) {
|
||||
bgColor = appTheme.commentBg;
|
||||
} else {
|
||||
bgColor = const Color(0xFFF1F2F6);
|
||||
}
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
context.read<DiaryCubit>().setSelectedMeal(widget.mealNumber);
|
||||
@@ -32,7 +44,7 @@ class _MealButtonWidgetState extends State<MealButtonWidget> {
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
color: state.selectedMeal == widget.mealNumber ? appTheme.blueA400 : const Color(0xFFF1F2F6),
|
||||
color: bgColor,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
@@ -81,8 +82,10 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
final mealsComments = state.consultantReview?.consultantComments.mealsComments;
|
||||
if (mealsComments != null && (state.selectedMeal - 1 < mealsComments.length)) {
|
||||
final consultantCommentOfMeal = state.consultantReview?.consultantComments.mealsComments.firstWhereOrNull(
|
||||
(element) => element.typeNo == state.selectedMeal,
|
||||
);
|
||||
if (consultantCommentOfMeal != null) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
@@ -90,7 +93,7 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CommentContainer(comment: mealsComments[state.selectedMeal - 1].comment),
|
||||
CommentContainer(comment: consultantCommentOfMeal.comment),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,13 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
super.initState();
|
||||
diaryCubit = context.read<DiaryCubit>();
|
||||
portionName = widget.portion.portion == 'gr' ? 'гр' : 'шт';
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet ? true : false;
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(ProductWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
portionName = widget.portion.portion == 'gr' ? 'гр' : 'шт';
|
||||
isEaten = widget.portion.portionState == PortionState.eatenFromDiet ? true : false;
|
||||
}
|
||||
|
||||
@@ -64,8 +70,9 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
state.diary.typeOfDiary.diaryState == DiaryStateEnum.reviewedByUser;
|
||||
final isDiaryFinished =
|
||||
state.diary.typeOfDiary.diaryState == DiaryStateEnum.finished || state.diary.typeOfDiary.diaryState == DiaryStateEnum.lastDayFinished;
|
||||
final canEditPortion = !state.isConsultantView && !isDiaryCommented && !isDiaryFinished;
|
||||
final canEditPortion = !state.isConsultantView && !isDiaryCommented && !isDiaryFinished && !widget.portion.fromDiet;
|
||||
final consultantComments = state.consultantReview?.consultantComments;
|
||||
final canMarkAsEaten = !state.isConsultantView && !isDiaryCommented && !isDiaryFinished;
|
||||
PortionComment? portionComment;
|
||||
if (consultantComments != null) {
|
||||
portionComment = consultantComments.portionsComments.firstWhereOrNull((elem) => elem.portionId == widget.portion.id);
|
||||
@@ -108,7 +115,7 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset('assets/icons/edit.svg'));
|
||||
} else if (!isDiaryCommented) {
|
||||
} else if (!isDiaryCommented && !widget.portion.fromDiet) {
|
||||
trailing = const Icon(Icons.more_vert_rounded);
|
||||
}
|
||||
return Column(
|
||||
@@ -121,24 +128,26 @@ class _ProductWidgetState extends State<ProductWidget> {
|
||||
scale: 1.2,
|
||||
child: Checkbox(
|
||||
value: isEaten,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
isEaten = value!;
|
||||
});
|
||||
if (isEaten) {
|
||||
diaryCubit.markEaten(
|
||||
diaryId: state.diary.id,
|
||||
mealId: state.selectedMeal,
|
||||
portionId: widget.portion.id,
|
||||
);
|
||||
} else {
|
||||
diaryCubit.unmarkEaten(
|
||||
diaryId: state.diary.id,
|
||||
mealId: state.selectedMeal,
|
||||
portionId: widget.portion.id,
|
||||
);
|
||||
}
|
||||
},
|
||||
onChanged: canMarkAsEaten
|
||||
? (value) {
|
||||
setState(() {
|
||||
isEaten = value!;
|
||||
});
|
||||
if (isEaten) {
|
||||
diaryCubit.markEaten(
|
||||
diaryId: state.diary.id,
|
||||
mealId: state.selectedMeal,
|
||||
portionId: widget.portion.id,
|
||||
);
|
||||
} else {
|
||||
diaryCubit.unmarkEaten(
|
||||
diaryId: state.diary.id,
|
||||
mealId: state.selectedMeal,
|
||||
portionId: widget.portion.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
activeColor: appTheme.blueA400,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
|
||||
class DiaryRepository {
|
||||
final DiaryService diaryService;
|
||||
final StreamController<String> _diaryForceFetchController = StreamController<String>();
|
||||
final StreamController<String> _diaryForceFetchController = StreamController<String>.broadcast();
|
||||
|
||||
Stream<String> get forceFetchStream => _diaryForceFetchController.stream;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:eatvio_app/core/enums/product_type.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
@@ -18,7 +19,6 @@ import 'package:eatvio_app/features/diets/presentation/widgets/cancel_diet_botto
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/start_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
|
||||
@@ -31,7 +31,6 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class AboutDietScreen extends StatefulWidget {
|
||||
@@ -317,31 +316,13 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
@@ -515,31 +496,13 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: DataErrorWidget(
|
||||
@@ -559,31 +522,13 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: const Loader(),
|
||||
|
||||
@@ -12,75 +12,78 @@ class AuthorCard extends StatelessWidget {
|
||||
final String title;
|
||||
final Color? backgroundColor;
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: backgroundColor ?? appTheme.cardBackground),
|
||||
child: Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, top: 16, bottom: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(author.authorProfileIcon),
|
||||
fit: BoxFit.cover,
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed('profileScreen', extra: author);
|
||||
},
|
||||
child: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: backgroundColor ?? appTheme.cardBackground),
|
||||
child: Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, top: 16, bottom: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(author.authorProfileIcon),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
author.authorName,
|
||||
style: TextStyles.textLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: titleStyle ?? TextStyles.textSSemibold.copyWith(
|
||||
color: appTheme.gray,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'Консультант',
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
subtitle: Text(
|
||||
author.authorName,
|
||||
style: TextStyles.textLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
if (author.authorPlaceInRating != null)
|
||||
InfoBouble(
|
||||
radius: 12,
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
children: [
|
||||
Text(
|
||||
'${author.authorPlaceInRating}-й в рейтинге',
|
||||
style: TextStyles.textMMediumAuto.copyWith(
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
title,
|
||||
style: titleStyle ?? TextStyles.textSSemibold.copyWith(
|
||||
color: appTheme.gray,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'Консультант',
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
if (author.authorPlaceInRating != null)
|
||||
InfoBouble(
|
||||
radius: 12,
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
children: [
|
||||
Text(
|
||||
'${author.authorPlaceInRating}-й в рейтинге',
|
||||
style: TextStyles.textMMediumAuto.copyWith(
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: GestureDetector(
|
||||
onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: author),
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: Container(
|
||||
width: 28,
|
||||
height: 28,
|
||||
@@ -98,8 +101,8 @@ class AuthorCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,14 @@ class DietRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteDiet(int id) async {
|
||||
try {
|
||||
return await dietsService.deleteDiet(id: id);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void emitLikesStateToFeed(LikesState state) => _dietLikeStateStreamController.add(state);
|
||||
void emitFavoriteStateToFeed(FavoriteState state) => _dietFavoriteStateStreamController.add(state);
|
||||
void emitCommentsStateToFeed(CommentsState state) => _dietCommentsStateStreamController.add(state);
|
||||
|
||||
@@ -39,4 +39,9 @@ abstract class DietService {
|
||||
Future<void> cancelDiet({
|
||||
@Path() required int id,
|
||||
});
|
||||
|
||||
@DELETE('/api/diets/delete/{id}')
|
||||
Future<void> deleteDiet({
|
||||
@Path() required int id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/my_finance/models/card_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'plan_pagination_model.freezed.dart';
|
||||
@@ -29,9 +30,9 @@ class PlanModel with _$PlanModel {
|
||||
@JsonKey(name: "type", fromJson: planTypeFromJson) required PlanType type,
|
||||
@JsonKey(name: "description_md") required String details,
|
||||
@JsonKey(name: "packets_count") required int packetsCount,
|
||||
@JsonKey(name: "packet1_options") PacketOptions? packet1Options,
|
||||
@JsonKey(name: "packet2_options") PacketOptions? packet2Options,
|
||||
@JsonKey(name: "packet3_options") PacketOptions? packet3Options,
|
||||
@JsonKey(name: "packet1_options", fromJson: parseOption) PacketOptions? packet1Options,
|
||||
@JsonKey(name: "packet2_options", fromJson: parseOption) PacketOptions? packet2Options,
|
||||
@JsonKey(name: "packet3_options", fromJson: parseOption) PacketOptions? packet3Options,
|
||||
@JsonKey(name: "author") required Author author,
|
||||
@JsonKey(name: "total_likes") required int totalLikes,
|
||||
@JsonKey(name: "total_views") required int totalViews,
|
||||
@@ -45,6 +46,13 @@ class PlanModel with _$PlanModel {
|
||||
factory PlanModel.fromJson(Map<String, dynamic> json) => _$PlanModelFromJson(json);
|
||||
}
|
||||
|
||||
PacketOptions? parseOption(json) {
|
||||
if (json is Map<String, dynamic>) {
|
||||
return PacketOptions.fromJson(json);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
PlanType planTypeFromJson(dynamic json) {
|
||||
if (json is List<dynamic>) {
|
||||
return const PlanType(fit: false, slim: false, behavior: false, wellness: false);
|
||||
@@ -70,10 +78,10 @@ class PacketOptions with _$PacketOptions {
|
||||
class PlanType with _$PlanType {
|
||||
const PlanType._();
|
||||
const factory PlanType({
|
||||
@JsonKey(name: "fit") required bool? fit,
|
||||
@JsonKey(name: "slim") required bool? slim,
|
||||
@JsonKey(name: "behavior") required bool? behavior,
|
||||
@JsonKey(name: "wellness") required bool? wellness,
|
||||
@JsonKey(name: "fit", fromJson: parseBool) required bool? fit,
|
||||
@JsonKey(name: "slim", fromJson: parseBool) required bool? slim,
|
||||
@JsonKey(name: "behavior", fromJson: parseBool) required bool? behavior,
|
||||
@JsonKey(name: "wellness", fromJson: parseBool) required bool? wellness,
|
||||
}) = _PlanType;
|
||||
|
||||
factory PlanType.fromJson(Map<String, dynamic> json) => _$PlanTypeFromJson(json);
|
||||
|
||||
@@ -29,6 +29,7 @@ class DietsCubit extends Cubit<DietsState> {
|
||||
late final StreamSubscription likesStateSubscription;
|
||||
late final StreamSubscription favoriteStateSubscription;
|
||||
late final StreamSubscription commentsStateSubscription;
|
||||
|
||||
DietsCubit({
|
||||
required this.feedRepository,
|
||||
required this.dietsRepository,
|
||||
@@ -342,4 +343,13 @@ class DietsCubit extends Cubit<DietsState> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> deleteDiet(int dietId) async {
|
||||
try {
|
||||
await dietsRepository.deleteDiet(dietId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class RecipesCubit extends Cubit<RecipesState> {
|
||||
tags: _selectedTags.toList(),
|
||||
query: query,
|
||||
);
|
||||
|
||||
|
||||
final recipesTags = (await recipeRepository.getRecipesTags());
|
||||
emit(
|
||||
state.copyWith(
|
||||
@@ -129,7 +129,7 @@ class RecipesCubit extends Cubit<RecipesState> {
|
||||
EasyDebounce.debounce(
|
||||
'add_or_remove_plan_from_favorite',
|
||||
const Duration(milliseconds: 200),
|
||||
() async {
|
||||
() async {
|
||||
try {
|
||||
await aboutRecipeRepository.addToFavorite(slug);
|
||||
} catch (e) {
|
||||
@@ -169,7 +169,7 @@ class RecipesCubit extends Cubit<RecipesState> {
|
||||
EasyDebounce.debounce(
|
||||
'add_or_remove_plan_from_favorite',
|
||||
const Duration(milliseconds: 200),
|
||||
() async {
|
||||
() async {
|
||||
try {
|
||||
await aboutRecipeRepository.removeFromFavorite(slug);
|
||||
} catch (e) {
|
||||
@@ -225,7 +225,7 @@ class RecipesCubit extends Cubit<RecipesState> {
|
||||
EasyDebounce.debounce(
|
||||
'like_plan',
|
||||
const Duration(milliseconds: 200),
|
||||
() async {
|
||||
() async {
|
||||
try {
|
||||
await aboutRecipeRepository.likeRecipe(slug);
|
||||
} catch (e) {
|
||||
@@ -300,4 +300,13 @@ class RecipesCubit extends Cubit<RecipesState> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> deleteRecipe(String slug) async {
|
||||
try {
|
||||
await aboutRecipeRepository.deleteRecipe(slug);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
|
||||
@@ -14,7 +14,6 @@ import 'package:eatvio_app/features/feed/presentation/widgets/subscribe_button_w
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
@@ -81,6 +80,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
||||
foregroundImage: NetworkImage(
|
||||
state.feedBlogPostList[widget.index].author.authorProfileIcon,
|
||||
),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
@@ -118,30 +118,12 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
|
||||
slug: state.feedBlogPostList[widget.index].author.authorSlug,
|
||||
),
|
||||
),
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
complainedContentType: ComplainedContent.posts,
|
||||
path: 'blog_post/${(state.feedBlogPostList[widget.index].id)}',
|
||||
id: state.feedBlogPostList[widget.index].id,
|
||||
),
|
||||
anchor: const Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: const Icon(Icons.more_horiz),
|
||||
),
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: state.feedBlogPostList[widget.index].author.authorIsMe,
|
||||
complainedContentType: ComplainedContent.posts,
|
||||
path: 'blog_post/${(state.feedBlogPostList[widget.index].id)}',
|
||||
id: state.feedBlogPostList[widget.index].id,
|
||||
feedBlogPostModel: state.feedBlogPostList[widget.index],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -42,6 +42,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
const SizedBox(height: 48),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -60,6 +61,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
children: [
|
||||
CircleAvatar(
|
||||
foregroundImage: NetworkImage(comment.authorProfileIcon),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
radius: radius,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
|
||||
@@ -64,6 +64,7 @@ class ConsultantWidget extends StatelessWidget {
|
||||
const SizedBox(width: 8),
|
||||
CircleAvatar(
|
||||
foregroundImage: NetworkImage(consultant.photo),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
@@ -80,7 +81,7 @@ class ConsultantWidget extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Рейтинг: RATING',
|
||||
'Рейтинг: ${consultant.totalScores}',
|
||||
style: TextStyle(
|
||||
color: appTheme.blueA400,
|
||||
height: 1,
|
||||
@@ -105,7 +106,10 @@ class ConsultantWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text('description'),
|
||||
Text(
|
||||
consultant.description,
|
||||
maxLines: 2,
|
||||
),
|
||||
if (consultant.badges.isNotEmpty) const SizedBox(height: 8),
|
||||
_badges(consultant.badges, context),
|
||||
],
|
||||
|
||||
@@ -3,9 +3,9 @@ import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
@@ -13,7 +13,6 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
@@ -83,28 +82,17 @@ class _DietsWidgetState extends State<DietsWidget> {
|
||||
Positioned(
|
||||
right: 12,
|
||||
top: 12,
|
||||
child: PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'diet/${widget.diet.id}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
),
|
||||
anchor: const Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: const Icon(Icons.more_horiz),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
id: widget.diet.id,
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -153,6 +141,19 @@ class _DietsWidgetState extends State<DietsWidget> {
|
||||
),
|
||||
),
|
||||
],
|
||||
if (widget.diet.details.length > 200)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 16, top: 8),
|
||||
child: Text(
|
||||
'Показать ещё',
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: Color(0xFF8B8B8B),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
|
||||
@@ -3,10 +3,10 @@ import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
@@ -16,7 +16,6 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
@@ -24,6 +23,7 @@ import 'package:share_plus/share_plus.dart';
|
||||
class PlanWidget extends StatefulWidget {
|
||||
final PlanModel plan;
|
||||
final int index;
|
||||
|
||||
const PlanWidget({
|
||||
super.key,
|
||||
required this.plan,
|
||||
@@ -87,28 +87,18 @@ class _PlanWidgetState extends State<PlanWidget> {
|
||||
Positioned(
|
||||
right: 12,
|
||||
top: 12,
|
||||
child: PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
path: 'plan/${widget.plan.id}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
id: widget.plan.id,
|
||||
),
|
||||
anchor: const Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: const Icon(Icons.more_horiz),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
id: widget.plan.id,
|
||||
slug: widget.plan.slug,
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -156,6 +146,19 @@ class _PlanWidgetState extends State<PlanWidget> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.plan.details.length > 200)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 16, top: 8),
|
||||
child: Text(
|
||||
'Показать ещё',
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: Color(0xFF8B8B8B),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -6,8 +6,8 @@ import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
@@ -16,7 +16,6 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
@@ -113,31 +112,21 @@ class _RecipesWidgetState extends State<RecipesWidget> {
|
||||
size: 19,
|
||||
),
|
||||
),
|
||||
// Testing Issue 329
|
||||
Positioned(
|
||||
right: 12,
|
||||
top: 12,
|
||||
child: PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
complainedContentType: ComplainedContent.recipe,
|
||||
path: 'recipe/${widget.recipe.slug}',
|
||||
slug: widget.recipe.slug,
|
||||
),
|
||||
anchor: const Aligned(shiftToWithinBound: AxisFlag(x: true, y: true), follower: Alignment.topRight, target: Alignment.bottomRight),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: const Icon(Icons.more_horiz),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 32,
|
||||
height: 24,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CustomPopup(
|
||||
isAuthor: widget.recipe.author.authorIsMe,
|
||||
path: 'recipe/${widget.recipe.slug}',
|
||||
slug: widget.recipe.slug,
|
||||
complainedContentType: ComplainedContent.recipe,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -187,7 +176,7 @@ class _RecipesWidgetState extends State<RecipesWidget> {
|
||||
),
|
||||
if (widget.recipe.description.length > 200)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
padding: EdgeInsets.only(left: 16, top: 8),
|
||||
child: Text(
|
||||
'Показать ещё',
|
||||
style: TextStyle(
|
||||
|
||||
@@ -68,7 +68,7 @@ class _InternetConnectionCheckerScreenState extends State<InternetConnectionChec
|
||||
final uris = [
|
||||
Uri.parse('https://google.com'),
|
||||
Uri.parse('https://yandex.ru'),
|
||||
Uri.parse('https://dev2.eatvqqwewqeio.com'),
|
||||
Uri.parse('https://dev2.eatvio.com'),
|
||||
Uri.parse('https://eatvio.ru'),
|
||||
];
|
||||
for (final uri in uris) {
|
||||
|
||||
@@ -118,7 +118,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
if (!context.mounted) return;
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(title: widget.diet.name),
|
||||
child: SuccessPublishedDietOrPlanBottomSheet(title: widget.diet.name),
|
||||
);
|
||||
await context.read<MyDietsCubit>().loadAllDiets();
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
enum ConsultationStatus {
|
||||
completed,
|
||||
canceled,
|
||||
inProgress
|
||||
}
|
||||
|
||||
class ConsultantFinanceEntity {
|
||||
|
||||
@@ -5,7 +5,6 @@ part 'card_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class CardModel with _$CardModel {
|
||||
|
||||
factory CardModel({
|
||||
required int id,
|
||||
@JsonKey(name: 'bank_pan') required String cardNumber,
|
||||
@@ -16,7 +15,7 @@ class CardModel with _$CardModel {
|
||||
}
|
||||
|
||||
bool parseBool(json) {
|
||||
if (json == 1 || json == true) {
|
||||
if (json == 1 || json == true || json == '1') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -28,20 +28,19 @@ class UserCardsCubit extends Cubit<UserCardsState> {
|
||||
emit(state.copyWith(cards: cards, state: BaseState.success));
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
emit(state.copyWith(state: BaseState.error, error: e.toString()));
|
||||
emit(state.copyWith(state: BaseState.error, error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> markAsDefault({required int id}) async {
|
||||
final oldCards = [...state.cards];
|
||||
if (isClosed) return;
|
||||
final cards =
|
||||
oldCards.map((card) {
|
||||
if (card.id == id) {
|
||||
return card.copyWith(isDefault: true);
|
||||
}
|
||||
return card.copyWith(isDefault: false);
|
||||
}).toList();
|
||||
final cards = oldCards.map((card) {
|
||||
if (card.id == id) {
|
||||
return card.copyWith(isDefault: true);
|
||||
}
|
||||
return card.copyWith(isDefault: false);
|
||||
}).toList();
|
||||
emit(state.copyWith(cards: cards));
|
||||
|
||||
EasyDebounce.debounce('markAsDefault', Duration(milliseconds: id), () async {
|
||||
@@ -66,4 +65,14 @@ class UserCardsCubit extends Cubit<UserCardsState> {
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> collectCharge({required int chosenPlaId}) async {
|
||||
try {
|
||||
await cardsRepository.collectCharge(chosenPlaId: chosenPlaId);
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/enums/base_state.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart';
|
||||
@@ -11,104 +15,221 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class CardSettingsScreen extends StatelessWidget {
|
||||
static const path = '/card-settings-screen';
|
||||
static const name = 'cardSettingsScreen';
|
||||
const CardSettingsScreen({super.key});
|
||||
|
||||
const CardSettingsScreen({super.key, this.chosenPlanId});
|
||||
final int? chosenPlanId;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(create: (context) => sl<UserCardsCubit>()..getCards(), child: const CardsSettingsContent());
|
||||
return BlocProvider(
|
||||
create: (context) => sl<UserCardsCubit>()..getCards(),
|
||||
child: CardsSettingsContent(
|
||||
chosenPlanId: chosenPlanId,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class CardsSettingsContent extends StatelessWidget {
|
||||
const CardsSettingsContent({super.key});
|
||||
const CardsSettingsContent({super.key, this.chosenPlanId});
|
||||
final int? chosenPlanId;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))),
|
||||
title: Text(s.my_cards),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white),
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text('Привязанные карты', style: TextStyle(color: Color(0xFF323F4B), fontSize: 18, fontWeight: FontWeight.w600, height: 1)),
|
||||
return BlocBuilder<UserCardsCubit, UserCardsState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))),
|
||||
title: Text(s.my_cards),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white),
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text('Привязанные карты', style: TextStyle(color: Color(0xFF323F4B), fontSize: 18, fontWeight: FontWeight.w600, height: 1)),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final defaultCardNumber = state.cards.firstWhereOrNull((element) => element.isDefault)?.cardNumber;
|
||||
if (defaultCardNumber != null) {
|
||||
return Text(
|
||||
'Выплату будут производиться\nна карту ${defaultCardNumber.substring(defaultCardNumber.length - 7)}',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w500, height: 1),
|
||||
);
|
||||
}
|
||||
return Text(s.no_default_cards, style: TextStyles.textMMedium.copyWith(color: appTheme.black));
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
switch (state.state) {
|
||||
case BaseState.error:
|
||||
return SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
child: Center(
|
||||
child: DataErrorWidget(
|
||||
onReload: () async {
|
||||
context.read<UserCardsCubit>().getCards();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
case BaseState.success:
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
spacing: 12,
|
||||
children: List.generate(state.cards.length + 1, (index) {
|
||||
if (index < state.cards.length) {
|
||||
final cardsNumber = state.cards[index].cardNumber.substring(state.cards[index].cardNumber.length - 7);
|
||||
return CardWidget(isSelected: state.cards[index].isDefault, cardId: state.cards[index].id, cardNumber: cardsNumber);
|
||||
}
|
||||
return const CardWidget(enabledAddCard: true);
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
default:
|
||||
return SizedBox(width: MediaQuery.sizeOf(context).width, height: 200, child: const Center(child: Loader()));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
),
|
||||
if (chosenPlanId != null && state.cards.isNotEmpty) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: BlocBuilder<UserCardsCubit, UserCardsState>(
|
||||
builder: (context, state) {
|
||||
child: CustomOutlinedButton(
|
||||
text: s.collectCharge,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)),
|
||||
onPressed: () async {
|
||||
final defaultCardNumber = state.cards.firstWhereOrNull((element) => element.isDefault)?.cardNumber;
|
||||
if (defaultCardNumber != null) {
|
||||
return Text(
|
||||
'Выплату будут производиться\nна карту ${defaultCardNumber.substring(defaultCardNumber.length - 7)}',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w500, height: 1),
|
||||
final result = await context.read<UserCardsCubit>().collectCharge(chosenPlaId: chosenPlanId!);
|
||||
if (context.mounted) {
|
||||
if (!result) {
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
s.chargeCollectionFailed,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Text(
|
||||
s.contactSupport,
|
||||
style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
},
|
||||
text: s.ok,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
s.chargeApproved,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Text(
|
||||
'${s.moneySentToCard} ${defaultCardNumber?.substring(defaultCardNumber.length - 7)}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
},
|
||||
text: s.ok,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return Text(s.no_default_cards, style: TextStyles.textMMedium.copyWith(color: appTheme.black));
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: BlocBuilder<UserCardsCubit, UserCardsState>(
|
||||
builder: (context, state) {
|
||||
switch (state.state) {
|
||||
case BaseState.error:
|
||||
return SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
child: Center(
|
||||
child: DataErrorWidget(
|
||||
onReload: () async {
|
||||
context.read<UserCardsCubit>().getCards();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
case BaseState.success:
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
spacing: 12,
|
||||
children: List.generate(state.cards.length + 1, (index) {
|
||||
if (index < state.cards.length) {
|
||||
final cardsNumber = state.cards[index].cardNumber.substring(state.cards[index].cardNumber.length - 7);
|
||||
return CardWidget(isSelected: state.cards[index].isDefault, cardId: state.cards[index].id, cardNumber: cardsNumber);
|
||||
}
|
||||
return const CardWidget(enabledAddCard: true);
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
default:
|
||||
return SizedBox(width: MediaQuery.sizeOf(context).width, height: 200, child: const Center(child: Loader()));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
|
||||
import 'package:eatvio_app/features/my_finance/entities/consultant_finance_entity.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class UserFinanceScreen extends StatefulWidget {
|
||||
@@ -20,162 +23,179 @@ class _UserFinanceScreenState extends State<UserFinanceScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadiusDirectional.vertical(bottom: Radius.circular(12))),
|
||||
title: const Text('Финансы'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(CardSettingsScreen.name);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: appTheme.blueA400),
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
child: const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text('Управление картами', style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
),
|
||||
),
|
||||
return BlocBuilder<ProfileAvatarCubit, ProfileAvatarState>(
|
||||
builder: (BuildContext context, ProfileAvatarState state) {
|
||||
if (state is ProfileAvatarStateLoaded) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadiusDirectional.vertical(bottom: Radius.circular(12))),
|
||||
title: const Text('Финансы'),
|
||||
centerTitle: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
child: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomDropDownButton(
|
||||
items: periods
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: periods[index],
|
||||
child: Text(
|
||||
periods[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {},
|
||||
value: periods.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => Material(
|
||||
color: const Color(0xFFF6F6F6),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
if (state.profile.roles.contains('consultant')) ...[
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(CardSettingsScreen.name);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: appTheme.blueA400),
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
child: const Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: testFinanceEntity.consultationsList[index].id,
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
textStyle: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha((255 * 0.2).toInt()),
|
||||
blurRadius: 32,
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
testFinanceEntity.consultationsList[index].id,
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].date.format('dd.MM.yyy', 'RU'),
|
||||
style: const TextStyle(color: Color(0xFF6D6F71), height: 1, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].title,
|
||||
style: TextStyle(color: appTheme.blueA400, height: 1, fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Покупатель: ${testFinanceEntity.consultationsList[index].clientName}',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].planDuration} дней',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDEDEDF),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].price} ₽',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
Material(
|
||||
color: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
testFinanceEntity.consultationsList[index].status.name,
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xFF0BB450), height: 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text('Управление картами', style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600)),
|
||||
),
|
||||
),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemCount: testFinanceEntity.consultationsList.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
child: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomDropDownButton(
|
||||
items: periods
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: periods[index],
|
||||
child: Text(
|
||||
periods[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {},
|
||||
value: periods.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => Material(
|
||||
color: const Color(0xFFF6F6F6),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: testFinanceEntity.consultationsList[index].id,
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
textStyle: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha((255 * 0.2).toInt()),
|
||||
blurRadius: 32,
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
testFinanceEntity.consultationsList[index].id,
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].date.format('dd.MM.yyy', 'RU'),
|
||||
style: const TextStyle(color: Color(0xFF6D6F71), height: 1, fontWeight: FontWeight.w500),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].title,
|
||||
style: TextStyle(color: appTheme.blueA400, height: 1, fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Покупатель: ${testFinanceEntity.consultationsList[index].clientName}',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].planDuration} дней',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDEDEDF),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].price} ₽',
|
||||
style: const TextStyle(color: Color(0xFF323F4B), height: 1, fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
Material(
|
||||
color: testFinanceEntity.consultationsList[index].status == ConsultationStatus.canceled
|
||||
? const Color(0xFDD01717).withAlpha((255 * 0.1).toInt())
|
||||
: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
testFinanceEntity.consultationsList[index].status.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: testFinanceEntity.consultationsList[index].status == ConsultationStatus.canceled
|
||||
? const Color(0xFDD01717)
|
||||
: const Color(0xFF0BB450),
|
||||
height: 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemCount: testFinanceEntity.consultationsList.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,12 @@ class CardsRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> collectCharge({required int chosenPlaId}) async {
|
||||
try {
|
||||
await cardsService.collectCharge(chosenPlanId: chosenPlaId);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,10 @@ abstract class CardsService {
|
||||
Future<void> deleteCard({
|
||||
@Path('id') required int id,
|
||||
});
|
||||
|
||||
@POST('/api/chosen_plans/{id}/take_payin')
|
||||
Future<void> collectCharge({
|
||||
@Path('id') required int chosenPlanId,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -204,4 +204,13 @@ class MyPlansCubit extends Cubit<MyPlansState> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> unpublish(String slug) async {
|
||||
try {
|
||||
await myPlansRepository.unpublish(slug);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,5 +35,8 @@ class MyPlansRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> unpublish(String slug) async {
|
||||
return await myPlansService.unpublish(slug: slug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ part 'my_plans_service.g.dart';
|
||||
|
||||
@RestApi()
|
||||
abstract class MyPlansService {
|
||||
|
||||
factory MyPlansService(Dio dio, {String baseUrl}) = _MyPlansService;
|
||||
factory MyPlansService(Dio dio, {String baseUrl}) = _MyPlansService;
|
||||
|
||||
@GET('/api/plans/index')
|
||||
Future<PlanPaginationModel> getPlans({
|
||||
@@ -24,5 +23,8 @@ abstract class MyPlansService {
|
||||
@Path() required String slug,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
@POST('/api/plans/draft/{slug}')
|
||||
Future<void> unpublish({
|
||||
@Path() required String slug,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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 'notification_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
NotificationModel _$NotificationModelFromJson(Map<String, dynamic> json) {
|
||||
return _NotificationModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$NotificationModel {
|
||||
NotificationType get type => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this NotificationModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of NotificationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$NotificationModelCopyWith<NotificationModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $NotificationModelCopyWith<$Res> {
|
||||
factory $NotificationModelCopyWith(
|
||||
NotificationModel value, $Res Function(NotificationModel) then) =
|
||||
_$NotificationModelCopyWithImpl<$Res, NotificationModel>;
|
||||
@useResult
|
||||
$Res call({NotificationType type});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$NotificationModelCopyWithImpl<$Res, $Val extends NotificationModel>
|
||||
implements $NotificationModelCopyWith<$Res> {
|
||||
_$NotificationModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of NotificationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? type = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as NotificationType,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$NotificationModelImplCopyWith<$Res>
|
||||
implements $NotificationModelCopyWith<$Res> {
|
||||
factory _$$NotificationModelImplCopyWith(_$NotificationModelImpl value,
|
||||
$Res Function(_$NotificationModelImpl) then) =
|
||||
__$$NotificationModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({NotificationType type});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$NotificationModelImplCopyWithImpl<$Res>
|
||||
extends _$NotificationModelCopyWithImpl<$Res, _$NotificationModelImpl>
|
||||
implements _$$NotificationModelImplCopyWith<$Res> {
|
||||
__$$NotificationModelImplCopyWithImpl(_$NotificationModelImpl _value,
|
||||
$Res Function(_$NotificationModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of NotificationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? type = null,
|
||||
}) {
|
||||
return _then(_$NotificationModelImpl(
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as NotificationType,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$NotificationModelImpl implements _NotificationModel {
|
||||
_$NotificationModelImpl({required this.type});
|
||||
|
||||
factory _$NotificationModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$NotificationModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final NotificationType type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NotificationModel(type: $type)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$NotificationModelImpl &&
|
||||
(identical(other.type, type) || other.type == type));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, type);
|
||||
|
||||
/// Create a copy of NotificationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$NotificationModelImplCopyWith<_$NotificationModelImpl> get copyWith =>
|
||||
__$$NotificationModelImplCopyWithImpl<_$NotificationModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$NotificationModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _NotificationModel implements NotificationModel {
|
||||
factory _NotificationModel({required final NotificationType type}) =
|
||||
_$NotificationModelImpl;
|
||||
|
||||
factory _NotificationModel.fromJson(Map<String, dynamic> json) =
|
||||
_$NotificationModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
NotificationType get type;
|
||||
|
||||
/// Create a copy of NotificationModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$NotificationModelImplCopyWith<_$NotificationModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'notification_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$NotificationModelImpl _$$NotificationModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$NotificationModelImpl(
|
||||
type: $enumDecode(_$NotificationTypeEnumMap, json['type']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$NotificationModelImplToJson(
|
||||
_$NotificationModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'type': _$NotificationTypeEnumMap[instance.type]!,
|
||||
};
|
||||
|
||||
const _$NotificationTypeEnumMap = {
|
||||
NotificationType.userSubscribedNotification:
|
||||
'App\\Notifications\\UserSubscribedNotification',
|
||||
NotificationType.planSubscriptionStartedToAuthor:
|
||||
'App\\Notifications\\Plan\\PlanSubscriptionStartedToAuthor',
|
||||
NotificationType.planSubscriptionCanceledToAuthor:
|
||||
'App\\Notifications\\Plan\\PlanSubscriptionCanceledToAuthor',
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart'
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_state.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/collect_charge_banner.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/payment_banner.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_info.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_props.dart';
|
||||
@@ -61,7 +62,7 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
builder: (context, state) {
|
||||
final plan = state.chosenPlan;
|
||||
if (state.isLoading) {
|
||||
Scaffold(
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
s.infoAboutOrder,
|
||||
@@ -113,7 +114,7 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
planStatus = PlanStatusValues.paid;
|
||||
} else if (widget.successfulPayment == false) {
|
||||
planStatus = PlanStatusValues.paymentFailed;
|
||||
} else if (plan.chosenPlanState == ChosenPlanStateEnum.statePaid) {
|
||||
} else if (plan.chosenPlanState.isStateAfterPaidState()) {
|
||||
planStatus = PlanStatusValues.paid;
|
||||
} else {
|
||||
planStatus = PlanStatusValues.pendingPayment;
|
||||
@@ -134,6 +135,12 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
if (plan.chosenPlanState == ChosenPlanStateEnum.stateDone) ...[
|
||||
CollectChargeBanner(
|
||||
chosenPlan: plan,
|
||||
price: chosenOption?.price ?? 0,
|
||||
)
|
||||
],
|
||||
if (widget.successfulPayment != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
PaymentBanner(
|
||||
@@ -148,7 +155,10 @@ class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
PlanProps(planDuration: plan.plan.duration, planPrice: chosenOption?.price.toDouble() ?? 0, planStatus: planStatus),
|
||||
PlanProps(
|
||||
planDuration: plan.plan.duration,
|
||||
planPrice: chosenOption?.price.toDouble() ?? 0,
|
||||
planStatus: planStatus),
|
||||
const SizedBox(height: 8),
|
||||
PlanInfo(
|
||||
title: plan.plan.name,
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class CollectChargeBanner extends StatelessWidget {
|
||||
const CollectChargeBanner({super.key, required this.chosenPlan, required this.price});
|
||||
final ChosenPlanModel chosenPlan;
|
||||
final double price;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return MainBackgroundBouble(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400, borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20))),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 80),
|
||||
child: Text(
|
||||
'${s.congratsYouHaveFinishedPlan} «${chosenPlan.plan.name}»',
|
||||
style: TextStyles.textMSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 80),
|
||||
child: Text(
|
||||
'${s.userConfirmedPlanCompletion} $price₽',
|
||||
style: TextStyles.textSMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomOutlinedButton(
|
||||
text: s.collectCharge,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)),
|
||||
onPressed: () async {
|
||||
GoRouter.of(context).push(CardSettingsScreen.path, extra: chosenPlan.id);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ class PaymentBanner extends StatefulWidget {
|
||||
const PaymentBanner({
|
||||
super.key,
|
||||
required this.successfulPayment,
|
||||
|
||||
});
|
||||
final bool successfulPayment;
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ enum ChosenPlanStateEnum {
|
||||
|
||||
bool isStateAfterPaidState() {
|
||||
switch (this) {
|
||||
case ChosenPlanStateEnum.stateCanceledByTheInitiator:
|
||||
case ChosenPlanStateEnum.stateInited:
|
||||
case ChosenPlanStateEnum.stateInCoordination:
|
||||
case ChosenPlanStateEnum.stateStartDateHasBeenSet:
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/enums/product_type.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
@@ -14,7 +15,6 @@ import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart'
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart';
|
||||
@@ -29,7 +29,6 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -112,31 +111,13 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: const Loader(),
|
||||
@@ -160,31 +141,13 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: DataErrorWidget(onReload: () => context.read<AboutPlanCubit>().getPlan(widget.plan.slug)),
|
||||
@@ -237,6 +200,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
'chatScreen',
|
||||
extra: {
|
||||
'chatId': chosenPlan.chatId,
|
||||
'sendInitialMessage': true,
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -396,31 +360,13 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
anchor: const Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
|
||||
@@ -21,8 +21,8 @@ class ProfileModel with _$ProfileModel {
|
||||
@JsonKey(name: "profile_photo_url") required String profilePhotoUrl,
|
||||
@JsonKey(name: "roles") required List<String> roles,
|
||||
@JsonKey(name: "badges") required List<BadgeModel> badges,
|
||||
@JsonKey(name: "subscriptions") required List<ProfilePreviewModel> subscriptions,
|
||||
@JsonKey(name: "subscribers") required List<ProfilePreviewModel> subscribers,
|
||||
@JsonKey(name: "subscriptions") required List<String> subscriptions,
|
||||
@JsonKey(name: "subscribers") required List<String> subscribers,
|
||||
@JsonKey(name: "education_resource") EducationModel? educationResource,
|
||||
@JsonKey(name: "cert_photos") List<DiplomasAndCertificatesModel>? diplomasAndCertificates,
|
||||
}) = _ProfileModel;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user