calling in progress

ui_ux_rollout_merge_audio_video_call
WaseemAbbasi22 1 month ago
parent eead2ebb84
commit a5d129970b

@ -0,0 +1,4 @@
<svg width="58" height="58" viewBox="0 0 58 58" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M28.3018 3.01044C21.3189 3.01044 15.6581 8.67122 15.6581 15.6542C15.6581 22.6371 21.3189 28.2979 28.3018 28.2979C35.2847 28.2979 40.9455 22.6371 40.9455 15.6542C40.9455 8.67122 35.2847 3.01044 28.3018 3.01044Z" fill="white"/>
<path d="M43.2934 36.3107C42.9057 36.0918 42.563 35.8983 42.2852 35.733C33.7257 30.6362 22.8782 30.6362 14.3189 35.733C14.0388 35.8997 13.6927 36.095 13.301 36.3161C11.5843 37.2845 8.9893 38.7485 7.21154 40.4885C6.09968 41.5768 5.04327 43.011 4.8512 44.7681C4.64698 46.6365 5.4621 48.39 7.09741 49.9479C9.91865 52.6356 13.3042 54.7897 17.6833 54.7897H38.9207C43.2998 54.7897 46.6854 52.6356 49.5066 49.9479C51.1418 48.39 51.957 46.6365 51.7528 44.7681C51.5606 43.011 50.5043 41.5768 49.3924 40.4885C47.6146 38.7485 45.0196 37.2845 43.3029 36.3161L43.2934 36.3107Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 918 B

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.8065 1.16447C14.2759 1.01134 13.7216 1.31736 13.5685 1.84799C13.4154 2.37863 13.7214 2.93292 14.252 3.08605C17.4591 4.01154 19.9889 6.54122 20.9145 9.74819C21.0676 10.2788 21.6219 10.5848 22.1526 10.4317C22.6832 10.2785 22.9892 9.72421 22.836 9.19358C21.7199 5.32634 18.6739 2.28049 14.8065 1.16447Z" fill="#3B3D4A"/>
<path d="M14.2661 6.03666C13.7578 5.82079 13.1707 6.05789 12.9548 6.56624C12.7389 7.07459 12.976 7.66169 13.4844 7.87756C14.6692 8.38068 15.6199 9.33137 16.123 10.5161C16.3389 11.0245 16.926 11.2616 17.4343 11.0457C17.9427 10.8298 18.1798 10.2427 17.9639 9.73438C17.2582 8.07269 15.9278 6.74231 14.2661 6.03666Z" fill="#3B3D4A"/>
<path d="M6.49064 2.4124C6.21024 1.90937 5.75895 1.52863 5.19226 1.41151C4.61966 1.29316 4.04411 1.46773 3.57108 1.85327C1.85471 3.25218 0.76188 5.49346 1.23618 7.84468C1.52772 9.28994 2.01343 10.7159 3.00255 12.4406C4.98763 15.902 8.0947 19.0108 11.5601 20.9981C13.2848 21.9873 14.7108 22.473 16.156 22.7645C18.5072 23.2388 20.7485 22.146 22.1474 20.4296C22.533 19.9566 22.7075 19.381 22.5892 18.8084C22.4721 18.2417 22.0913 17.7904 21.5883 17.5101L19.9857 16.6168C19.3956 16.2878 18.8989 16.0109 18.4672 15.8301C18.0092 15.6383 17.5575 15.5244 17.0581 15.5765C16.5588 15.6286 16.1403 15.8332 15.7318 16.1154C15.3466 16.3814 14.9177 16.7548 14.4081 17.1985L12.8998 18.5116C12.6296 18.7469 12.4944 18.8645 12.3255 18.8753C12.1566 18.886 12.0124 18.7896 11.7238 18.5967C9.26273 16.9518 7.04759 14.7358 5.404 12.2768C5.21116 11.9882 5.11474 11.844 5.12549 11.6751C5.13624 11.5062 5.25389 11.3711 5.48917 11.1008L6.80218 9.59261C7.24588 9.08298 7.61928 8.65411 7.88529 8.26893C8.16746 7.86034 8.37211 7.4419 8.42419 6.94254C8.47626 6.44318 8.36235 5.99152 8.17054 5.53351C7.98973 5.10174 7.71286 4.60505 7.38385 4.01485L6.49064 2.4124Z" fill="#3B3D4A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5368 4.99141C18.3737 3.89234 13.6254 3.89106 9.45743 4.99141C7.37923 5.54005 5.91035 6.24306 4.57538 7.10677C2.35643 8.54243 1.45543 11.0949 1.70423 13.473C1.77726 14.1709 2.11459 14.7881 2.69607 15.1604C3.2673 15.5262 3.95202 15.5781 4.5849 15.4029L6.48667 14.8765C7.17775 14.6852 7.7732 14.5204 8.24752 14.3312C8.75523 14.1286 9.21756 13.8638 9.58726 13.4198C9.95867 12.9739 10.1323 12.4724 10.2327 11.9384C10.3257 11.4435 10.3686 10.8386 10.418 10.1428L10.5712 7.98564C10.5919 7.69432 10.6022 7.54866 10.6933 7.44677C10.7843 7.34488 10.9247 7.31887 11.2056 7.26684C14.3271 6.68853 17.6695 6.68902 20.7886 7.26685C21.0694 7.31888 21.2099 7.34489 21.3009 7.44678C21.392 7.54867 21.4023 7.69433 21.423 7.98565L21.5762 10.1428C21.6256 10.8386 21.6685 11.4435 21.7615 11.9384C21.8619 12.4724 22.0355 12.9739 22.4069 13.4198C22.7766 13.8638 23.239 14.1286 23.7467 14.3312C24.221 14.5204 24.8165 14.6852 25.5076 14.8765L27.4093 15.4029C28.0422 15.5781 28.7269 15.5262 29.2981 15.1604C29.8796 14.7881 30.2169 14.1709 30.29 13.473C30.5388 11.0949 29.6378 8.54243 27.4188 7.10677C26.0838 6.24305 24.615 5.54005 22.5368 4.99141Z" fill="white"/>
<path d="M16.0036 14.5C16.74 14.5 17.3369 15.0969 17.3369 15.8333V21.8333L18.1136 21.8333C18.3478 21.8332 18.6354 21.8329 18.8706 21.8624L18.8751 21.8629C19.0437 21.884 19.8117 21.9797 20.1775 22.7339C20.5441 23.4896 20.1416 24.1565 20.0545 24.3008L20.0512 24.3061C19.9283 24.5102 19.7494 24.738 19.6023 24.9254L19.5706 24.9657C19.1778 25.4668 18.6685 26.1125 18.1613 26.6338C17.9082 26.8939 17.6185 27.1623 17.3106 27.3741C17.0369 27.5623 16.57 27.8333 15.9958 27.8333C15.4215 27.8333 14.9546 27.5623 14.6809 27.3741C14.3731 27.1623 14.0834 26.8939 13.8303 26.6338C13.323 26.1125 12.8137 25.4668 12.4209 24.9657L12.3893 24.9254C12.2421 24.738 12.0633 24.5102 11.9403 24.3061L11.9371 24.3008C11.85 24.1565 11.4474 23.4896 11.814 22.7339C12.1798 21.9797 12.9479 21.884 13.1165 21.8629L13.1209 21.8624C13.3562 21.8329 13.6437 21.8332 13.8779 21.8333L14.6702 21.8333V15.8333C14.6702 15.0969 15.2672 14.5 16.0036 14.5Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.29289 1.29289C1.68342 0.902369 2.31658 0.902369 2.70711 1.29289L22.7071 21.2929C23.0976 21.6834 23.0976 22.3166 22.7071 22.7071C22.3166 23.0976 21.6834 23.0976 21.2929 22.7071L16.9406 18.3549C15.7867 19.137 14.4337 19.6528 12.9722 19.8126V20.8269H14.9167C15.4536 20.8269 15.8889 21.2574 15.8889 21.7885C15.8889 22.3195 15.4536 22.75 14.9167 22.75H9.08333C8.54639 22.75 8.11111 22.3195 8.11111 21.7885C8.11111 21.2574 8.54639 20.8269 9.08333 20.8269H11.0278V19.8126C6.65283 19.3343 3.25 15.6659 3.25 11.2115C3.25 10.6805 3.68528 10.25 4.22222 10.25C4.75917 10.25 5.19444 10.6805 5.19444 11.2115C5.19444 14.9288 8.2414 17.9423 12 17.9423C13.2985 17.9423 14.512 17.5827 15.5444 16.9586L14.6763 16.0905C13.8769 16.5116 12.9663 16.75 12 16.75C8.82436 16.75 6.25 14.1756 6.25 11V7.66421L1.29289 2.70711C0.902369 2.31658 0.902369 1.68342 1.29289 1.29289Z" fill="#F4F6FC"/>
<path d="M12 1.25C15.1756 1.25 17.75 3.82436 17.75 7V11C17.75 11.641 17.6451 12.2575 17.4516 12.8333C17.3374 13.1729 17.2803 13.3428 17.1177 13.3809C16.9551 13.4191 16.819 13.283 16.5467 13.0107L7.62218 4.08618C7.44997 3.91397 7.36387 3.82786 7.35845 3.71186C7.35302 3.59585 7.42553 3.50835 7.57054 3.33337C8.62524 2.06068 10.2179 1.25 12 1.25Z" fill="#F4F6FC"/>
<path d="M19.7778 10.25C19.2408 10.25 18.8056 10.6805 18.8056 11.2115C18.8056 12.2201 18.5813 13.1769 18.1793 14.0357C18.0828 14.2418 18.0346 14.3448 18.051 14.4381C18.0674 14.5314 18.1428 14.6068 18.2935 14.7575L18.8612 15.3252C19.1075 15.5715 19.2306 15.6946 19.3804 15.672C19.5303 15.6493 19.6077 15.5026 19.7626 15.209C20.3934 14.0133 20.75 12.6536 20.75 11.2115C20.75 10.6805 20.3147 10.25 19.7778 10.25Z" fill="#F4F6FC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 1.25C8.82436 1.25 6.25 3.82436 6.25 7V11C6.25 14.1756 8.82436 16.75 12 16.75C15.1756 16.75 17.75 14.1756 17.75 11V7C17.75 3.82436 15.1756 1.25 12 1.25Z" fill="#F4F6FC"/>
<path d="M5.19444 11.2115C5.19444 10.6805 4.75917 10.25 4.22222 10.25C3.68528 10.25 3.25 10.6805 3.25 11.2115C3.25 15.6659 6.65283 19.3343 11.0278 19.8126V20.8269H9.08333C8.54639 20.8269 8.11111 21.2574 8.11111 21.7885C8.11111 22.3195 8.54639 22.75 9.08333 22.75H14.9167C15.4536 22.75 15.8889 22.3195 15.8889 21.7885C15.8889 21.2574 15.4536 20.8269 14.9167 20.8269H12.9722V19.8126C17.3472 19.3343 20.75 15.6659 20.75 11.2115C20.75 10.6805 20.3147 10.25 19.7778 10.25C19.2408 10.25 18.8056 10.6805 18.8056 11.2115C18.8056 14.9288 15.7586 17.9423 12 17.9423C8.2414 17.9423 5.19444 14.9288 5.19444 11.2115Z" fill="#F4F6FC"/>
</svg>

After

Width:  |  Height:  |  Size: 908 B

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9916 3.9756C11.6784 3.44801 12.4957 3.01957 13.367 3.38808C14.2302 3.75318 14.5076 4.63267 14.6274 5.49785C14.7502 6.38459 14.7502 7.60557 14.7502 9.12365V14.8794C14.7502 16.3975 14.7502 17.6185 14.6274 18.5052C14.5076 19.3704 14.2302 20.2499 13.367 20.615C12.4957 20.9835 11.6784 20.5551 10.9916 20.0275C10.2892 19.488 9.3966 18.5765 8.34667 17.5044C7.80721 16.9536 7.44921 16.6873 7.08663 16.5374C6.72221 16.3868 6.27914 16.3229 5.50619 16.3229C4.83768 16.3229 4.23963 16.3229 3.78679 16.2758C3.31184 16.2265 2.87088 16.1191 2.47421 15.8485C1.7184 15.3328 1.42917 14.5777 1.31957 13.8838C1.23785 13.3663 1.24723 12.7981 1.25479 12.3405V11.6626C1.24723 11.205 1.23785 10.6368 1.31957 10.1193C1.42917 9.42536 1.7184 8.67029 2.47421 8.15462C2.87088 7.88398 3.31184 7.77657 3.78679 7.72723C4.23963 7.68019 4.83768 7.68021 5.50619 7.68023C6.27914 7.68023 6.72221 7.61628 7.08663 7.46563C7.44922 7.31574 7.80717 7.04954 8.34663 6.49869C9.39658 5.42656 10.2892 4.51511 10.9916 3.9756Z" fill="#F4F6FC"/>
<path d="M16.3935 8.20504C16.8325 7.87003 17.4601 7.95439 17.7951 8.39347C18.5519 9.38539 19.0001 10.6418 19.0001 12.0001C19.0001 13.3583 18.5519 14.6147 17.7951 15.6066C17.4601 16.0457 16.8325 16.1301 16.3935 15.7951C15.9544 15.4601 15.87 14.8325 16.205 14.3935C16.699 13.746 17.0001 12.9149 17.0001 12.0001C17.0001 11.0852 16.699 10.2541 16.205 9.60664C15.87 9.16756 15.9544 8.54004 16.3935 8.20504Z" fill="#F4F6FC"/>
<path d="M20.7376 6.32472C20.3646 5.91738 19.7321 5.8895 19.3247 6.26245C18.9174 6.63541 18.8895 7.26796 19.2625 7.6753C20.3608 8.87497 21 10.379 21 12C21 13.621 20.3608 15.125 19.2625 16.3247C18.8895 16.7321 18.9174 17.3646 19.3247 17.7376C19.7321 18.1105 20.3646 18.0826 20.7376 17.6753C22.1408 16.1427 23 14.1675 23 12C23 9.83247 22.1408 7.8573 20.7376 6.32472Z" fill="#F4F6FC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.6949 2.4068C18.0224 1.96211 18.6484 1.86712 19.0931 2.19463L19.0969 2.19747C19.1724 2.25451 19.3861 2.41593 19.5059 2.50946C19.7487 2.69891 20.0757 2.96119 20.4057 3.24769C20.7307 3.52987 21.0815 3.85522 21.3588 4.16915C21.4965 4.32497 21.6373 4.50157 21.7491 4.68699C21.8443 4.84496 22.0001 5.13899 22.0001 5.49983C22.0001 5.86068 21.8443 6.15473 21.7491 6.3127C21.6373 6.49811 21.4965 6.67471 21.3588 6.83053C21.0814 7.14446 20.7307 7.46981 20.4057 7.75198C20.0757 8.03847 19.7487 8.30076 19.5059 8.4902C19.3859 8.58389 19.1718 8.74556 19.0966 8.80235L19.0932 8.8049C18.6485 9.13241 18.0224 9.03753 17.6949 8.59283C17.565 8.41644 17.5015 8.21152 17.5 8.00803V6.49988H9.5C6.3286 6.49988 4 8.74755 4 11.9999C4 12.5522 3.55228 12.9999 3 12.9999C2.44772 12.9999 2 12.5522 2 11.9999C2 7.62227 5.24485 4.49988 9.5 4.49988H17.5V2.99982C17.4999 2.79363 17.5632 2.58556 17.6949 2.4068Z" fill="#F4F6FC"/>
<path d="M22 11.9999C22 16.3775 18.7552 19.4999 14.5 19.4999H6.50005V20.9956C6.5011 21.2032 6.43777 21.4129 6.3052 21.5929C5.97769 22.0376 5.35169 22.1326 4.90699 21.8051L4.90343 21.8024C4.82806 21.7454 4.6141 21.5838 4.49415 21.4902C4.2514 21.3008 3.92436 21.0385 3.59439 20.752C3.26939 20.4699 2.91862 20.1445 2.64124 19.8306C2.50356 19.6748 2.36278 19.4982 2.251 19.3127C2.15577 19.1548 2 18.8607 2 18.4999C2 18.139 2.15578 17.845 2.25101 17.687C2.36278 17.5016 2.50356 17.325 2.64124 17.1692C2.91862 16.8553 3.26938 16.5299 3.59438 16.2477C3.92434 15.9612 4.25138 15.699 4.49412 15.5095C4.61412 15.4159 4.82805 15.2543 4.90333 15.1974L4.9068 15.1948C5.35149 14.8673 5.97765 14.9622 6.30517 15.4068C6.43683 15.5856 6.50021 15.7937 6.50005 15.9999V17.4999H14.5C17.6714 17.4999 20 15.2522 20 11.9999C20 11.4476 20.4477 10.9999 21 10.9999C21.5523 10.9999 22 11.4476 22 11.9999Z" fill="#F4F6FC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.072 3H8.92797C7.33935 2.99997 6.04614 2.99995 5.02631 3.13706C3.96232 3.28011 3.04736 3.58869 2.31802 4.31802C1.58869 5.04736 1.28011 5.96232 1.13706 7.02631C0.999949 8.04614 0.999972 9.33928 1 10.9279V13.072C0.999972 14.6607 0.999949 15.9539 1.13706 16.9737C1.28011 18.0377 1.58869 18.9527 2.31802 19.682C3.04736 20.4113 3.96232 20.7199 5.02631 20.8629C6.04616 21.0001 7.33933 21 8.928 21H10.072C11.6607 21 12.9538 21.0001 13.9737 20.8629C15.0377 20.7199 15.9527 20.4113 16.682 19.682C17.3875 18.9764 17.6993 18.0972 17.8484 17.0773C18.3063 17.4374 18.7206 17.7408 19.0944 17.9666C19.7947 18.3896 20.6822 18.7439 21.5929 18.2925C22.4895 17.848 22.7673 16.9371 22.8829 16.1198C22.9991 15.2982 22.9991 14.1926 22.999 12.8645V11.1382C22.9991 9.81011 22.9991 8.70445 22.8829 7.88282C22.7673 7.06553 22.4895 6.15463 21.5929 5.71019C20.6822 5.25874 19.7947 5.61301 19.0944 6.03609C18.7207 6.26185 18.3066 6.56515 17.8488 6.92504C17.6998 5.90419 17.3881 5.02411 16.682 4.31802C15.9527 3.58869 15.0377 3.28011 13.9737 3.13706C12.9539 2.99995 11.6607 2.99997 10.072 3ZM17.9943 9.3825C18 9.86282 18 10.3777 18 10.928V13.072C18 13.6233 18 14.1391 17.9943 14.6201C18.9515 15.4089 19.6126 15.943 20.1285 16.2547C20.3999 16.4186 20.5637 16.4778 20.6531 16.4955C20.6728 16.4994 20.6863 16.5007 20.6942 16.5012L20.6994 16.5013L20.7027 16.5013L20.7047 16.5005C20.7067 16.4995 20.7082 16.4986 20.7092 16.4979C20.7103 16.4971 20.7108 16.4966 20.7108 16.4966C20.7136 16.4936 20.7286 16.4774 20.7499 16.4358C20.7977 16.3422 20.8567 16.1641 20.9026 15.8397C20.9966 15.1754 20.999 14.2135 20.999 12.7832V11.2194C20.999 9.78915 20.9966 8.82725 20.9026 8.16294C20.8567 7.83855 20.7977 7.66044 20.7499 7.56691C20.7286 7.52522 20.714 7.50949 20.7112 7.50653C20.7112 7.50653 20.709 7.50427 20.7047 7.50211L20.7032 7.50139C20.7032 7.50139 20.6982 7.5013 20.6942 7.5015C20.6863 7.50191 20.6728 7.50322 20.6531 7.50713C20.5637 7.52483 20.3999 7.58402 20.1285 7.74796C19.6126 8.05966 18.9515 8.59379 17.9943 9.3825ZM13 9.5C13 10.3284 12.3284 11 11.5 11C10.6716 11 10 10.3284 10 9.5C10 8.67157 10.6716 8 11.5 8C12.3284 8 13 8.67157 13 9.5Z" fill="#3B3D4A"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.70711 1.29289C2.31658 0.902369 1.68342 0.902369 1.29289 1.29289C0.902369 1.68342 0.902369 2.31658 1.29289 2.70711L2.80516 4.21938C2.69757 4.30332 2.59413 4.39465 2.4948 4.49398C1.81966 5.16912 1.52415 6.02253 1.38483 7.0588C1.24997 8.06188 1.24998 9.34083 1.25 10.9434V13.0549C1.24998 14.6575 1.24997 15.9365 1.38483 16.9396C1.52415 17.9758 1.81966 18.8293 2.4948 19.5044C3.16994 20.1795 4.02335 20.475 5.05961 20.6144C6.0627 20.7492 7.34165 20.7492 8.94424 20.7492H10.0558C11.6583 20.7492 12.9373 20.7492 13.9404 20.6144C14.9767 20.475 15.8301 20.1795 16.5052 19.5044C16.7838 19.2258 16.9978 18.9168 17.1628 18.5771L21.2929 22.7071C21.6834 23.0976 22.3166 23.0976 22.7071 22.7071C23.0976 22.3166 23.0976 21.6834 22.7071 21.2929L2.70711 1.29289Z" fill="white"/>
<path d="M13.7062 5.11923C12.8353 5.00213 11.6772 5 9.99904 5H8.96752C8.43122 4.9829 8.00115 4.54335 8 4.00265C7.99882 3.45037 8.44558 3.0017 8.99787 3.00052L10.0711 3C11.6597 2.99997 12.9529 2.99994 13.9727 3.13706C15.0367 3.28011 15.9517 3.58869 16.681 4.31802C17.4103 5.04735 17.7189 5.96232 17.862 7.0263C17.8742 7.11687 17.8853 7.20959 17.8954 7.30449C18.3463 6.97574 18.7545 6.69858 19.1231 6.49173C19.8273 6.09659 20.6866 5.78411 21.5681 6.18995C22.4678 6.60419 22.762 7.47353 22.8824 8.26363C23.0002 9.03709 23.0001 10.073 23.0001 11.2982L23.0001 12.8993C23.0001 14.0331 23.0001 14.9981 22.9116 15.7394C22.8712 16.0774 22.8065 16.4355 22.6808 16.7737C22.2465 17.9425 20.3372 17.3376 20.8394 15.9064C20.8777 15.7971 20.9057 15.6698 20.9257 15.5022C20.9983 14.8939 21.0001 14.0493 21.0001 12.8357V11.3832C21.0001 10.0499 20.9972 9.16915 20.9052 8.56474C20.8606 8.27197 20.8048 8.12186 20.7653 8.05005C20.7565 8.03415 20.7496 8.0241 20.7453 8.01834L20.7414 8.01344L20.7384 8.01018L20.7371 8.00939L20.7349 8.00824L20.7316 8.00663C20.7285 8.00465 20.7123 7.99436 20.6408 8.00751C20.5417 8.02573 20.3729 8.08381 20.1018 8.2359C19.5905 8.52282 18.9376 9.01181 17.9965 9.73188C17.9991 10.1102 17.999 10.5087 17.999 10.9278V12C17.999 12.5523 17.5513 13 16.999 13C16.4467 13 15.999 12.5523 15.999 12L15.999 11C15.999 9.32182 15.9969 8.16377 15.8798 7.2928C15.7666 6.45059 15.5626 6.02803 15.2668 5.73223C14.971 5.43644 14.5485 5.23246 13.7062 5.11923Z" fill="white"/>
<path d="M8.96889 5.00004L8.93871 5.00002C8.91327 5 8.90978 5 8.96752 5L8.96889 5.00004Z" fill="white"/>
<path d="M9.00213 5.00052C9.13771 5.00023 9.0365 5.0001 8.96889 5.00004C8.97993 5.00038 8.99101 5.00054 9.00213 5.00052Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.072 3H8.92797C7.33935 2.99997 6.04614 2.99995 5.02631 3.13706C3.96232 3.28011 3.04736 3.58869 2.31802 4.31802C1.58869 5.04736 1.28011 5.96232 1.13706 7.02631C0.999949 8.04614 0.999972 9.33928 1 10.9279V13.072C0.999972 14.6607 0.999949 15.9539 1.13706 16.9737C1.28011 18.0377 1.58869 18.9527 2.31802 19.682C3.04736 20.4113 3.96232 20.7199 5.02631 20.8629C6.04616 21.0001 7.33933 21 8.928 21H10.072C11.6607 21 12.9538 21.0001 13.9737 20.8629C15.0377 20.7199 15.9527 20.4113 16.682 19.682C17.3875 18.9764 17.6993 18.0972 17.8484 17.0773C18.3063 17.4374 18.7206 17.7408 19.0944 17.9666C19.7947 18.3896 20.6822 18.7439 21.5929 18.2925C22.4895 17.848 22.7673 16.9371 22.8829 16.1198C22.9991 15.2982 22.9991 14.1926 22.999 12.8645V11.1382C22.9991 9.81011 22.9991 8.70445 22.8829 7.88282C22.7673 7.06553 22.4895 6.15463 21.5929 5.71019C20.6822 5.25874 19.7947 5.61301 19.0944 6.03609C18.7207 6.26185 18.3066 6.56515 17.8488 6.92504C17.6998 5.90419 17.3881 5.02411 16.682 4.31802C15.9527 3.58869 15.0377 3.28011 13.9737 3.13706C12.9539 2.99995 11.6607 2.99997 10.072 3ZM17.9943 9.3825C18 9.86282 18 10.3777 18 10.928V13.072C18 13.6233 18 14.1391 17.9943 14.6201C18.9515 15.4089 19.6126 15.943 20.1285 16.2547C20.3999 16.4186 20.5637 16.4778 20.6531 16.4955C20.6728 16.4994 20.6863 16.5007 20.6942 16.5012L20.6994 16.5013L20.7027 16.5013L20.7047 16.5005C20.7067 16.4995 20.7082 16.4986 20.7092 16.4979C20.7103 16.4971 20.7108 16.4966 20.7108 16.4966C20.7136 16.4936 20.7286 16.4774 20.7499 16.4358C20.7977 16.3422 20.8567 16.1641 20.9026 15.8397C20.9966 15.1754 20.999 14.2135 20.999 12.7832V11.2194C20.999 9.78915 20.9966 8.82725 20.9026 8.16294C20.8567 7.83855 20.7977 7.66044 20.7499 7.56691C20.7286 7.52522 20.714 7.50949 20.7112 7.50653C20.7112 7.50653 20.709 7.50427 20.7047 7.50211L20.7032 7.50139C20.7032 7.50139 20.6982 7.5013 20.6942 7.5015C20.6863 7.50191 20.6728 7.50322 20.6531 7.50713C20.5637 7.52483 20.3999 7.58402 20.1285 7.74796C19.6126 8.05966 18.9515 8.59379 17.9943 9.3825ZM13 9.5C13 10.3284 12.3284 11 11.5 11C10.6716 11 10 10.3284 10 9.5C10 8.67157 10.6716 8 11.5 8C12.3284 8 13 8.67157 13 9.5Z" fill="#F4F6FC"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -7,8 +7,8 @@ class URLs {
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/mobile"; // host local UAT
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v4/mobile"; // v4 for Demo module
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation

@ -114,6 +114,7 @@ extension WidgetExtensions on Widget {
BuildContext context, {
bool showShadow = true,
double borderRadius = 14,
double width = double.infinity,
bool withShadow = true,
Color? backgroundColor,
Color? borderColor,
@ -125,7 +126,7 @@ extension WidgetExtensions on Widget {
? Container(
padding: paddingObject ?? EdgeInsets.all(padding),
margin: margin,
width: double.infinity,
width: width,
decoration: ShapeDecoration(
color: backgroundColor ?? AppColor.background(context),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(borderRadius), side: BorderSide(color: borderColor ?? AppColor.borderColor(context))),

@ -0,0 +1,262 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/cx_module/chat/model/call_session.dart';
import 'package:test_sa/modules/cx_module/chat/call/video_call_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
class AudioCallPage extends StatefulWidget {
const AudioCallPage({Key? key}) : super(key: key);
@override
State<AudioCallPage> createState() => _AudioCallPageState();
}
class _AudioCallPageState extends State<AudioCallPage> {
@override
void initState() {
super.initState();
// Initialize call on page load
WidgetsBinding.instance.addPostFrameCallback((_) {
// Will be implemented when connecting to provider
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.backgroundTabBarDark,
appBar: const DefaultAppBar(
backgroundColor: Colors.transparent,
arrowBackColor: AppColor.white10,
),
body: SafeArea(
child: Selector<ChatProvider, CallSession?>(
selector: (_, provider) => provider.currentCall,
builder: (context, session, _) {
if (session == null) {
return const Center(child: Text('No active call'));
}
return Column(
children: [
const Spacer(flex: 2),
_buildContactInfo(context, session),
8.height,
_buildCallStatusOrDuration(context),
const Spacer(flex: 4),
_buildControls(context, session),
32.height,
],
);
},
),
),
);
}
Widget _buildContactInfo(BuildContext context, CallSession session) {
return Column(
children: [
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.whiteF8d,
//TODO need to check opacity
border: Border.all(color: AppColor.white10.withOpacity(0.2), width: 1),
),
child: ClipOval(
child: session.peerAvatar != null
? CachedNetworkImage(
imageUrl: session.peerAvatar!,
fit: BoxFit.cover,
placeholder: (context, url) => Center(
child: CircularProgressIndicator(
color: Colors.white.withOpacity(0.5),
),
),
errorWidget: (context, url, error) => 'call_user_avatar'.toSvgAsset(height: 48, width: 48),
)
: 'call_user_avatar'.toSvgAsset(height: 48, width: 48),
),
),
24.height,
Text(
session.peerName,
style: AppTextStyles.heading2.copyWith(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
],
);
}
Widget _buildCallStatusOrDuration(BuildContext context) {
return Selector<ChatProvider, CallStatus>(
selector: (_, provider) => provider.callStatus,
builder: (context, status, _) {
String statusText;
switch (status) {
case CallStatus.outgoingRinging:
statusText = 'Calling...';
break;
case CallStatus.incomingRinging:
statusText = 'Incoming call...';
break;
case CallStatus.connecting:
statusText = 'Connecting...';
break;
case CallStatus.connected:
return _buildDuration(context);
default:
statusText = '';
}
return Text(
statusText,
style: AppTextStyles.heading5.copyWith(
color: AppColor.neutral100,
),
);
},
);
}
Widget _buildDuration(BuildContext context) {
return Selector<ChatProvider, Duration>(
selector: (_, provider) => provider.callDuration,
builder: (context, duration, _) {
if (duration.inSeconds == 0) {
return const SizedBox.shrink();
}
String twoDigits(int n) => n.toString().padLeft(2, '0');
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.white.withAlpha(51),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'$minutes:$seconds',
style: AppTextStyles.heading5.copyWith(
color: AppColor.neutral100,
fontWeight: FontWeight.w400,
),
),
);
},
);
}
Widget _buildControls(BuildContext context, CallSession session) {
final chatProvider = context.read<ChatProvider>();
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isMuted,
builder: (context, isMuted, _) {
return _buildControlButton(
icon: isMuted ? 'mic_disable' : 'mic_enable',
label: isMuted ? 'Unmute' : 'Mute',
isActive: isMuted,
onPressed: () {
chatProvider.toggleMute();
},
);
},
),
_buildControlButton(
icon: 'video_call_icon',
label: 'Video',
isActive: false,
onPressed: () {
// Switch to video call view
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const VideoCallPage(),
),
);
},
),
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isSpeakerOn,
builder: (context, isSpeakerOn, _) {
return _buildControlButton(
icon: 'speaker_enable',
label: 'Speaker',
isActive: isSpeakerOn,
onPressed: () {
chatProvider.toggleSpeaker();
},
);
},
),
],
),
48.height,
_buildEndCallButton(context, chatProvider),
],
);
}
Widget _buildControlButton({
required String icon,
required String label,
required bool isActive,
required VoidCallback onPressed,
}) {
return Column(
children: [
Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(color: isActive ? AppColor.primary10 : AppColor.black2E, shape: BoxShape.circle, border: BoxBorder.all(color: AppColor.white10.withOpacity(0.2))),
child: icon.toSvgAsset(width: 24, height: 24, color: AppColor.white10),
).onPress(() {
onPressed();
}),
8.height,
Text(
label,
style: AppTextStyles.heading5.copyWith(color: AppColor.neutral100, fontWeight: FontWeight.w400),
),
],
);
}
Widget _buildEndCallButton(BuildContext context, ChatProvider provider) {
return Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: AppColor.red30,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
alignment: Alignment.center,
child: 'end_call'.toSvgAsset(height: 32, width: 32, color: AppColor.white10),
).onPress(() async {
await provider.hangUp();
if (mounted) {
Navigator.pop(context);
}
});
}
}

@ -0,0 +1,411 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/cx_module/chat/model/call_session.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/app_style/app_themes.dart';
import 'package:test_sa/modules/cx_module/chat/call/widgets/draggable_local_preview.dart';
class VideoCallPage extends StatefulWidget {
const VideoCallPage({Key? key}) : super(key: key);
@override
State<VideoCallPage> createState() => _VideoCallPageState();
}
class _VideoCallPageState extends State<VideoCallPage> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// Initialize video call
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.backgroundTabBarDark,
body: Selector<ChatProvider, CallSession?>(
selector: (_, provider) => provider.currentCall,
builder: (context, session, _) {
if (session == null) {
return const Center(
child: Text(
'No active call',
style: TextStyle(color: Colors.white),
),
);
}
return Stack(
children: [
_buildRemoteVideo(context),
_buildLocalVideo(context),
_buildTopBar(context, session),
_buildBottomControls(context, session),
],
);
},
),
);
}
Widget _buildRemoteVideo(BuildContext context) {
final chatProvider = context.read<ChatProvider>();
return Positioned.fill(
child: Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isPeerCameraOn,
builder: (context, isPeerCameraOn, _) {
if (!isPeerCameraOn) {
// Show avatar when peer camera is off
return _buildRemoteAvatarPlaceholder(context);
}
// TODO: Replace with actual RTCVideoView when WebRTC is wired
return Container(
color: Colors.black,
child: const Center(
child: Text(
'Remote Video',
style: TextStyle(color: Colors.white54),
),
),
);
/* Will be replaced with:
return RTCVideoView(
chatProvider.webrtcService.remoteRenderer,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
mirror: false,
);
*/
},
),
);
}
Widget _buildRemoteAvatarPlaceholder(BuildContext context) {
return Selector<ChatProvider, CallSession?>(
selector: (_, provider) => provider.currentCall,
builder: (context, session, _) {
if (session == null) return const SizedBox.shrink();
return Container(
color: AppColor.backgroundTabBarDark,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.whiteF8d,
border: Border.all(color: AppColor.white10.withAlpha(51), width: 1),
),
child: ClipOval(
child: session.peerAvatar != null
? CachedNetworkImage(
imageUrl: session.peerAvatar!,
fit: BoxFit.cover,
placeholder: (context, url) => Center(
child: CircularProgressIndicator(
color: Colors.white.withAlpha(128),
),
),
errorWidget: (context, url, error) => 'call_user_avatar'.toSvgAsset(height: 48, width: 48),
)
: 'call_user_avatar'.toSvgAsset(height: 48, width: 48),
),
),
24.height,
Text(
session.peerName,
style: AppTextStyles.heading2.copyWith(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
8.height,
Text(
'Camera is off',
style: AppTextStyles.heading5.copyWith(
color: AppColor.neutral100,
fontWeight: FontWeight.w400,
),
),
],
),
),
);
},
);
}
Widget _buildLocalVideo(BuildContext context) {
return Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isCameraOn,
builder: (context, isCameraOn, _) {
if (!isCameraOn) {
// Show avatar when local camera is off
return DraggableLocalPreview(
child: Container(
width: 120,
height: 160,
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white, width: 2),
),
child: const Icon(
Icons.videocam_off,
color: Colors.white,
size: 32,
),
),
);
}
// TODO: Replace with actual RTCVideoView when WebRTC is wired
return DraggableLocalPreview(
child: Container(
width: 120,
height: 160,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white, width: 2),
),
child: const Center(
child: Text(
'You',
style: TextStyle(color: Colors.white54),
),
),
),
);
/* Will be replaced with:
final chatProvider = context.read<ChatProvider>();
return DraggableLocalPreview(
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: RTCVideoView(
chatProvider.webrtcService.localRenderer,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
mirror: true,
),
),
);
*/
},
);
}
Widget _buildTopBar(BuildContext context, CallSession session) {
return Align(
alignment: AlignmentGeometry.topLeft,
child: Padding(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
),
child: IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: AppColor.white10,
),
onPressed: () => Navigator.pop(context),
),
),
);
}
Widget _buildBottomControls(BuildContext context, CallSession session) {
final chatProvider = context.read<ChatProvider>();
return Positioned(
bottom: 24,
left: 0,
right: 0,
//for now use these colors, later we can change to use the theme colors
child: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(65, 67, 82, 0.7),
Color.fromRGBO(105, 109, 133, 0.7),
Color.fromRGBO(65, 67, 82, 0.7),
],
stops: [0.0, 0.5, 1.0],
),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: AppColor.white10.withAlpha(51)),
),
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
session.peerName,
style: AppTextStyles.heading2.copyWith(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
16.height,
_buildCallStatusOrDuration(context),
16.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isMuted,
builder: (context, isMuted, _) {
return _buildVideoControlButton(
icon: isMuted ? 'mic_disable' : 'mic_enable',
isActive: isMuted,
onPressed: () => chatProvider.toggleMute(),
);
},
),
// Camera toggle
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isCameraOn,
builder: (context, isCameraOn, _) {
return _buildVideoControlButton(
icon: isCameraOn ? 'video_enable' : 'video_disable',
isActive: !isCameraOn,
onPressed: () => chatProvider.toggleCamera(),
);
},
),
// Switch camera
_buildVideoControlButton(
icon: 'toggle_camera',
isActive: false,
onPressed: () => chatProvider.switchCamera(),
),
// Speaker
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.isSpeakerOn,
builder: (context, isSpeakerOn, _) {
return _buildVideoControlButton(
icon: 'speaker_enable',
isActive: isSpeakerOn,
onPressed: () => chatProvider.toggleSpeaker(),
);
},
),
_buildVideoControlButton(
icon: 'end_call',
isHangUp: true,
showBorder: false,
onPressed: () {
chatProvider.hangUp();
if (mounted) {
Navigator.pop(context);
}
},
),
],
),
],
),
).paddingOnly(bottom: 16, start: 16, end: 16),
);
}
Widget _buildCallStatusOrDuration(BuildContext context) {
return Selector<ChatProvider, CallStatus>(
selector: (_, provider) => provider.callStatus,
builder: (context, status, _) {
String statusText;
switch (status) {
case CallStatus.outgoingRinging:
statusText = 'Calling...';
break;
case CallStatus.incomingRinging:
statusText = 'Incoming call...';
break;
case CallStatus.connecting:
statusText = 'Connecting...';
break;
case CallStatus.connected:
return _buildDuration(context);
default:
statusText = '';
}
return Text(
statusText,
style: AppTextStyles.heading5.copyWith(
color: AppColor.neutral100,
fontWeight: FontWeight.w400,
),
);
},
);
}
Widget _buildDuration(BuildContext context) {
return Selector<ChatProvider, Duration>(
selector: (_, provider) => provider.callDuration,
builder: (context, duration, _) {
if (duration.inSeconds == 0) {
return const SizedBox.shrink();
}
String twoDigits(int n) => n.toString().padLeft(2, '0');
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return Text(
'$minutes:$seconds',
style: AppTextStyles.heading5.copyWith(
color: AppColor.neutral100,
fontWeight: FontWeight.w400,
fontFeatures: [const FontFeature.tabularFigures()],
),
);
},
);
}
Widget _buildVideoControlButton({
required String icon,
bool? isActive,
bool isHangUp = false,
bool showBorder = true,
required VoidCallback onPressed,
}) {
return Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: isHangUp
? AppColor.red30
: isActive != null && isActive
? AppColor.primary10
: AppColor.black2E,
shape: BoxShape.circle,
border: showBorder ? BoxBorder.all(color: AppColor.white10.withOpacity(0.2)) : null),
child: icon.toSvgAsset(width: 24, height: 24, color: AppColor.white10),
).onPress(() {
onPressed();
});
}
}

@ -0,0 +1,82 @@
import 'package:flutter/material.dart';
/// Draggable widget for local video preview in video calls
/// Allows user to move the PiP (Picture-in-Picture) preview around the screen
class DraggableLocalPreview extends StatefulWidget {
final Widget child;
const DraggableLocalPreview({
Key? key,
required this.child,
}) : super(key: key);
@override
State<DraggableLocalPreview> createState() => _DraggableLocalPreviewState();
}
class _DraggableLocalPreviewState extends State<DraggableLocalPreview> {
Offset position = const Offset(20, 100); // Initial position (top-right area)
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return Positioned(
left: position.dx,
top: position.dy,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
// Update position while dragging
position = Offset(
(position.dx + details.delta.dx).clamp(
0.0,
screenSize.width - 120, // Subtract preview width
),
(position.dy + details.delta.dy).clamp(
0.0,
screenSize.height - 160, // Subtract preview height
),
);
});
},
onPanEnd: (details) {
// Snap to nearest edge for better UX
setState(() {
final middleX = screenSize.width / 2;
final middleY = screenSize.height / 2;
// Snap to left or right edge
if (position.dx < middleX) {
position = Offset(20, position.dy);
} else {
position = Offset(screenSize.width - 140, position.dy);
}
// Keep within vertical bounds
position = Offset(
position.dx,
position.dy.clamp(80.0, screenSize.height - 200),
);
});
},
child: Container(
width: 120,
height: 160,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: widget.child,
),
),
);
}
}

@ -16,8 +16,11 @@ import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/modules/cm_module/cm_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/cx_module/chat/call/audio_call_page.dart';
import 'package:test_sa/modules/cx_module/chat/call/video_call_page.dart';
import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/cx_module/chat/model/call_session.dart';
import 'package:test_sa/modules/cx_module/chat/view_all_attachment_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
@ -194,9 +197,57 @@ class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
final chatProvider = Provider.of<ChatProvider>(context, listen: false);
return Scaffold(
// backgroundColor: AppColor.white10,
appBar: DefaultAppBar(title: widget.title),
appBar: DefaultAppBar(
title: widget.title,
actions: [
Selector<ChatProvider, Participants?>(
selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton(
icon: "calling_icon".toSvgAsset(width: 24, height: 24),
onPressed: () {
log('recipient: ${recipient?.userName}');
if (recipient != null) {
chatProvider.startCall(recipient, CallType.audio);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AudioCallPage(),
),
);
}
},
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
),
Selector<ChatProvider, Participants?>(
selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton(
icon: "video_call_icon".toSvgAsset(
width: 24,
height: 24,
),
onPressed: () {
if (recipient != null) {
chatProvider.startCall(recipient, CallType.video);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const VideoCallPage(),
),
);
}
},
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
),
],
),
// OPTIMIZATION: Using Selector for connection state (rarely changes)
// This prevents rebuilding entire chat UI on every message/typing event
body: Selector<ChatProvider, _ChatConnectionState>(
@ -272,11 +323,7 @@ class _ChatPageState extends State<ChatPage> {
4.width,
Text(
"View All Documents",
style: AppTextStyles.bodyText.copyWith(
color: AppColor.white10,
decoration: TextDecoration.underline,
decorationColor: AppColor.white10
),
style: AppTextStyles.bodyText.copyWith(color: AppColor.white10, decoration: TextDecoration.underline, decorationColor: AppColor.white10),
).onPress(() {
Navigator.push(context, CupertinoPageRoute(builder: (context) => ViewAllAttachmentPage(moduleId: widget.moduleId, requestId: widget.requestId)));
}),
@ -396,7 +443,7 @@ class _ChatPageState extends State<ChatPage> {
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_attachment".toSvgAsset(width: 24, height: 24,color: AppColor.icon2Color(context)),
icon: "chat_attachment".toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)),
constraints: const BoxConstraints(),
),
IconButton(
@ -417,7 +464,7 @@ class _ChatPageState extends State<ChatPage> {
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_mic".toSvgAsset(width: 24, height: 24,color: AppColor.icon2Color(context)),
icon: "chat_mic".toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)),
constraints: const BoxConstraints(),
),
] else if (chatState == ChatState.voiceRecordingStarted) ...[

File diff suppressed because it is too large Load Diff

@ -0,0 +1,100 @@
/// Call session data model for audio/video calling
/// Stores all information about an active call
enum CallType { audio, video }
enum CallDirection { outgoing, incoming }
enum CallStatus {
idle,
checkingPermissions,
outgoingRinging,
incomingRinging,
connecting,
connected,
ended
}
class CallSession {
final String callId;
final CallType type;
final CallDirection direction;
final String peerId; // Employee number
final String peerName;
final String? peerAvatar;
final DateTime startTime;
String? sessionId; // For SDP/ICE correlation
String? sdpOffer;
String? sdpAnswer;
CallSession({
required this.callId,
required this.type,
required this.direction,
required this.peerId,
required this.peerName,
this.peerAvatar,
required this.startTime,
this.sessionId,
this.sdpOffer,
this.sdpAnswer,
});
Map<String, dynamic> toJson() => {
'callId': callId,
'type': type.name,
'direction': direction.name,
'peerId': peerId,
'peerName': peerName,
'peerAvatar': peerAvatar,
'startTime': startTime.toIso8601String(),
'sessionId': sessionId,
'sdpOffer': sdpOffer,
'sdpAnswer': sdpAnswer,
};
factory CallSession.fromJson(Map<String, dynamic> json) => CallSession(
callId: json['callId'],
type: CallType.values.firstWhere((e) => e.name == json['type']),
direction: CallDirection.values.firstWhere((e) => e.name == json['direction']),
peerId: json['peerId'],
peerName: json['peerName'],
peerAvatar: json['peerAvatar'],
startTime: DateTime.parse(json['startTime']),
sessionId: json['sessionId'],
sdpOffer: json['sdpOffer'],
sdpAnswer: json['sdpAnswer'],
);
CallSession copyWith({
String? callId,
CallType? type,
CallDirection? direction,
String? peerId,
String? peerName,
String? peerAvatar,
DateTime? startTime,
String? sessionId,
String? sdpOffer,
String? sdpAnswer,
}) {
return CallSession(
callId: callId ?? this.callId,
type: type ?? this.type,
direction: direction ?? this.direction,
peerId: peerId ?? this.peerId,
peerName: peerName ?? this.peerName,
peerAvatar: peerAvatar ?? this.peerAvatar,
startTime: startTime ?? this.startTime,
sessionId: sessionId ?? this.sessionId,
sdpOffer: sdpOffer ?? this.sdpOffer,
sdpAnswer: sdpAnswer ?? this.sdpAnswer,
);
}
bool get isVideo => type == CallType.video;
bool get isAudio => type == CallType.audio;
bool get isIncoming => direction == CallDirection.incoming;
bool get isOutgoing => direction == CallDirection.outgoing;
}

@ -47,8 +47,9 @@ class Participants {
String? employeeNumber;
String? role;
int? userStatus;
String? image;
Participants({this.userId, this.userName, this.employeeNumber, this.role, this.userStatus});
Participants({this.userId, this.userName, this.employeeNumber, this.role, this.image, this.userStatus});
Participants.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
@ -56,6 +57,7 @@ class Participants {
employeeNumber = json['employeeNumber'];
role = json['role'];
userStatus = json['userStatus'];
image = json['image'];
}
Map<String, dynamic> toJson() {
@ -65,6 +67,7 @@ class Participants {
data['employeeNumber'] = employeeNumber;
data['role'] = role;
data['userStatus'] = userStatus;
data['image'] = image;
return data;
}
}

@ -35,6 +35,7 @@ class AppColor {
static const Color neutral150 = Color(0xffA1A1A1);
static const Color neutral160 = Color(0xffE5E5E5);
static const Color neutral170 = Color(0xff6E6E6E);
static const Color neutral180 = Color(0xff414352);
static const Color disableDark = Color(0xff444756);
static const Color switchBgColor = Color(0xff5A5E79);
@ -59,12 +60,15 @@ class AppColor {
static const Color white90 = Color(0xffBFD1E4);
static const Color white936 = Color(0xff212936);
static const Color whiteF3 = Color(0xffF1F1F3);
static const Color whiteF33 = Color(0xffF3F3F3);
static const Color whiteF8d = Color(0xff8d96a3);
//black
static const Color black10 = Color(0xff3B3D4A);
static const Color black20 = Color(0xff212936);
static const Color black35 = Color(0xff222A36);
static const Color black1E = Color(0xff1E1F20);
static const Color black2E = Color(0xff2E2E2E);
static const Color black92 = Color(0xff929292);
//red

@ -16,8 +16,21 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
final bool showBackButton;
final VoidCallback? onWillPopScope;
final TextStyle? titleStyle;
final Color? backgroundColor;
final Color? arrowBackColor;
const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions, this.titleStyle, this.showHomeActionButton = false, this.showBackButton = true, Key? key}) : super(key: key);
const DefaultAppBar(
{this.title,
this.onBackPress,
this.arrowBackColor,
this.onWillPopScope,
this.actions,
this.titleStyle,
this.backgroundColor,
this.showHomeActionButton = false,
this.showBackButton = true,
Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -39,12 +52,16 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
_actions.addAll(actions!);
}
return AppBar(
backgroundColor: backgroundColor,
automaticallyImplyLeading: false,
titleSpacing: 16,
title: Row(
children: [
if (showBackButton)
const Icon(Icons.arrow_back_ios).onPress(() {
Icon(
Icons.arrow_back_ios,
color: arrowBackColor,
).onPress(() {
if (onWillPopScope != null) {
showDialog(
context: context,

@ -233,6 +233,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dart_webrtc:
dependency: transitive
description:
name: dart_webrtc
sha256: f6d615bddea5e458ce180a914f3055c234ffb52fb7397a51b3491e76d6d7edb2
url: "https://pub.dev"
source: hosted
version: "1.8.1"
date_picker_timeline:
dependency: "direct main"
description:
@ -423,6 +431,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_callkit_incoming:
dependency: "direct main"
description:
name: flutter_callkit_incoming
sha256: "0e418f2c7fdbddeebc0288ce0e10c17fd01c1a886731d5cb1048d86b72443b92"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
flutter_custom_month_picker:
dependency: "direct main"
description:
@ -590,6 +606,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_webrtc:
dependency: "direct main"
description:
name: flutter_webrtc
sha256: "0f89dee7f4c35dab5611f351c3897a3bfe9f7057720cc7da209b52455af4316e"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
fluttertoast:
dependency: "direct main"
description:
@ -854,6 +878,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.20.2"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation:
dependency: transitive
description:
@ -1828,7 +1860,7 @@ packages:
source: hosted
version: "3.1.5"
uuid:
dependency: transitive
dependency: "direct main"
description:
name: uuid
sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489"
@ -1899,6 +1931,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webrtc_interface:
dependency: transitive
description:
name: webrtc_interface
sha256: c6f100eac5057d9a817a60473126f9828c796d42884d498af4f339c97b21014f
url: "https://pub.dev"
source: hosted
version: "1.5.1"
wifi_iot:
dependency: "direct main"
description:

@ -108,6 +108,9 @@ dependencies:
local_auth_darwin: ^1.4.0
haptic_feedback: ^0.6.4+3
sn_progress_dialog: ^1.2.0
flutter_webrtc: ^1.5.2
flutter_callkit_incoming: ^3.1.3
uuid: ^4.5.3
dev_dependencies:

Loading…
Cancel
Save