houshan base models

This commit is contained in:
mohamadmahdi jebeli 2025-10-30 10:51:50 +03:30
parent 7c51bdd435
commit e2c46a07c1
22 changed files with 1431 additions and 680 deletions

View File

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_11306_3525)">
<path d="M13.3333 9.3335H10.6667C10.4899 9.3335 10.3203 9.40373 10.1953 9.52876C10.0702 9.65378 10 9.82335 10 10.0002V14.0002C10 14.177 10.0702 14.3465 10.1953 14.4716C10.3203 14.5966 10.4899 14.6668 10.6667 14.6668H13.3333C13.5101 14.6668 13.6797 14.5966 13.8047 14.4716C13.9298 14.3465 14 14.177 14 14.0002V10.0002C14 9.82335 13.9298 9.65378 13.8047 9.52876C13.6797 9.40373 13.5101 9.3335 13.3333 9.3335ZM13.0667 13.7335H10.9333V10.2668H13.0667V13.7335Z" fill="#007EA7"/>
<path d="M22.4734 8.25317L19.7467 5.5265C19.6225 5.40334 19.4549 5.33391 19.2801 5.33317H15.9467V4.03317C15.9558 3.68287 15.8265 3.3431 15.587 3.08734C15.3475 2.83158 15.0169 2.6804 14.6667 2.6665H9.22672C9.05561 2.67324 8.8876 2.71423 8.73262 2.78707C8.57764 2.8599 8.43886 2.96309 8.32448 3.09052C8.2101 3.21796 8.12245 3.36705 8.06672 3.52896C8.011 3.69088 7.98833 3.86233 8.00005 4.03317V5.33317H4.72005C4.63231 5.33266 4.54534 5.34948 4.46411 5.38266C4.38289 5.41583 4.30901 5.46472 4.24672 5.5265L1.52672 8.25317C1.46493 8.31546 1.41605 8.38934 1.38287 8.47057C1.34969 8.55179 1.33288 8.63877 1.33339 8.7265V18.6665C1.33339 19.0201 1.47386 19.3593 1.72391 19.6093C1.97396 19.8594 2.3131 19.9998 2.66672 19.9998H21.3334C21.687 19.9998 22.0261 19.8594 22.2762 19.6093C22.5262 19.3593 22.6667 19.0201 22.6667 18.6665V8.71984C22.666 8.54494 22.5965 8.37734 22.4734 8.25317ZM9.33339 3.99984H14.6667V5.33317H9.33339V3.99984ZM21.3334 11.3332H14.6667V12.6198H21.3334V18.6665H2.66672V12.6198H9.33339V11.3332H2.66672V8.99984L5.00005 6.6665H19.0001L21.3334 8.99984V11.3332Z" fill="#007EA7"/>
</g>
<defs>
<clipPath id="clip0_11306_3525">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,6 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 24C0 12.6863 0 7.02944 3.51472 3.51472C7.02944 0 12.6863 0 24 0C35.3137 0 40.9706 0 44.4853 3.51472C48 7.02944 48 12.6863 48 24C48 35.3137 48 40.9706 44.4853 44.4853C40.9706 48 35.3137 48 24 48C12.6863 48 7.02944 48 3.51472 44.4853C0 40.9706 0 35.3137 0 24Z" fill="#B0D7E4"/>
<path d="M28.845 20.5642C29.7377 20.267 30.7026 20.267 31.5953 20.5642C32.1779 20.7589 32.6593 21.0993 33.1264 21.5078C33.5729 21.9005 34.0795 22.4246 34.6859 23.0516C35.4101 23.8042 36.1352 24.5557 36.8614 25.3062C37.5708 26.0377 37.8558 26.8104 37.8526 27.8427C37.8431 30.4695 37.7877 32.2713 37.034 33.7486C36.3127 35.1633 35.1621 36.3133 33.747 37.034C31.6174 38.1202 28.8941 37.8542 26.5856 37.8542H21.4144C19.6854 37.8542 18.3143 37.8542 17.2107 37.7639C16.0802 37.6721 15.1254 37.4789 14.253 37.0356C12.8377 36.3145 11.6871 35.1639 10.966 33.7486C10.4989 32.8318 10.3169 31.8343 10.2219 30.6199C10.0825 28.7832 11.6405 27.2965 12.8391 26.0884C13.3252 25.5976 13.8382 25.1859 14.4747 24.9516C15.4404 24.5984 16.4999 24.5984 17.4656 24.9516C18.1021 25.1859 18.6151 25.5976 19.1012 26.0884C19.573 26.5634 20.1019 27.1967 20.7415 27.9647C20.7969 28.0327 20.884 28.0961 20.9648 28.0122L25.7544 23.0516C26.3624 22.4246 26.8674 21.9005 27.3139 21.5078C27.781 21.0993 28.2639 20.7589 28.845 20.5642ZM28.8814 23.2922C28.5173 23.6121 28.0787 24.0649 27.4295 24.7378L22.6732 29.662C22.4292 29.9149 22.1346 30.1135 21.8087 30.2449C21.4827 30.3764 21.1328 30.4377 20.7816 30.4248C20.4304 30.412 20.0859 30.3253 19.7704 30.1704C19.455 30.0155 19.1757 29.7959 18.9508 29.5258C18.2684 28.7088 17.8044 28.1531 17.4149 27.762C17.0349 27.3772 16.8133 27.2427 16.6502 27.1825C16.2111 27.0218 15.7292 27.0218 15.2901 27.1825C15.127 27.2427 14.9069 27.3772 14.5254 27.762C13.9395 28.351 13.4218 29.0081 12.8914 29.6462C12.6364 29.9517 12.5668 30.1132 12.5953 30.5012C12.6744 31.5398 12.828 32.1716 13.0814 32.6703C13.5747 33.6383 14.3617 34.4254 15.3297 34.9187C15.8126 35.1641 16.4222 35.3161 17.4039 35.3968C18.4014 35.4776 19.6744 35.4792 21.4667 35.4792H26.5334C28.4207 35.4792 30.9113 35.8148 32.6704 34.9187C33.6384 34.4254 34.4254 33.6383 34.9187 32.6703C35.3652 31.7916 35.4665 30.6072 35.4776 27.8348C35.4792 27.401 35.4127 27.2237 35.1008 26.9022L33.0108 24.7378C32.3616 24.0649 31.9246 23.6137 31.5589 23.2922C30.7434 22.5766 29.7317 22.5449 28.8814 23.2922Z" fill="#007EA7"/>
<path d="M21.4144 10.146H26.5856C28.3146 10.146 29.6857 10.146 30.7893 10.2362C31.9198 10.3281 32.8746 10.5212 33.7486 10.9646C35.1635 11.6863 36.3136 12.8375 37.034 14.2532C37.4789 15.124 37.6721 16.0803 37.7639 17.2108C37.8541 18.3144 37.8541 19.6856 37.8541 21.4146V26.5857C37.8541 28.3147 37.8541 29.6859 37.7639 30.7895C37.6721 31.92 37.4789 32.8747 37.0356 33.7487C36.3138 35.1637 35.1626 36.3138 33.747 37.0342C32.8761 37.4791 31.9198 37.6722 30.7893 37.7641C29.6857 37.8543 28.3146 37.8543 26.5856 37.8543H21.4144C19.6854 37.8543 18.3142 37.8543 17.2106 37.7641C16.0801 37.6722 15.1254 37.4791 14.253 37.0357C12.8377 36.3147 11.6871 35.164 10.966 33.7487C10.5211 32.8747 10.3279 31.92 10.2361 30.7895C10.1458 29.6859 10.1458 28.3147 10.1458 26.5857V21.4146C10.1458 19.6856 10.1458 18.3144 10.2361 17.2108C10.3279 16.0803 10.5211 15.1256 10.9644 14.2532C11.6859 12.8376 12.8371 11.687 14.253 10.9662C15.1238 10.5212 16.0801 10.3281 17.2106 10.2362C18.3142 10.146 19.6854 10.146 21.4144 10.146ZM17.4038 12.6033C16.4221 12.6825 15.8126 12.8361 15.3296 13.0815C14.3616 13.5748 13.5746 14.3618 13.0813 15.3298C12.8359 15.8127 12.6839 16.4223 12.6031 17.404C12.5224 18.4015 12.5208 19.6745 12.5208 21.4668V26.5335C12.5208 28.3274 12.5208 29.6004 12.6031 30.5963C12.6823 31.578 12.8359 32.1876 13.0813 32.6705C13.5746 33.6385 14.3616 34.4255 15.3296 34.9188C15.8126 35.1642 16.4221 35.3162 17.4038 35.397C18.4013 35.4777 19.6743 35.4793 21.4666 35.4793H26.5333C28.3272 35.4793 29.6002 35.4793 30.5961 35.397C31.5778 35.3178 32.1874 35.1642 32.6703 34.9188C33.6383 34.4255 34.4253 33.6385 34.9186 32.6705C35.1641 32.1876 35.3161 31.578 35.3968 30.5963C35.4776 29.5988 35.4791 28.3258 35.4791 26.5335V21.4668C35.4791 19.6745 35.4791 18.3999 35.3968 17.404C35.3176 16.4223 35.1641 15.8127 34.9186 15.3298C34.4253 14.3618 33.6383 13.5748 32.6703 13.0815C32.1874 12.8361 31.5778 12.6841 30.5961 12.6033C29.5986 12.5226 28.3256 12.521 26.5333 12.521H21.4666C19.6743 12.521 18.3997 12.521 17.4038 12.6033Z" fill="#007EA7"/>
<path d="M20.8334 17.271C20.3084 17.271 19.805 17.4795 19.4339 17.8507C19.0627 18.2218 18.8542 18.7253 18.8542 19.2502C18.8542 19.7751 19.0627 20.2785 19.4339 20.6496C19.805 21.0208 20.3084 21.2293 20.8334 21.2293C21.3583 21.2293 21.8617 21.0208 22.2328 20.6496C22.604 20.2785 22.8125 19.7751 22.8125 19.2502C22.8125 18.7253 22.604 18.2218 22.2328 17.8507C21.8617 17.4795 21.3583 17.271 20.8334 17.271ZM16.4792 19.2502C16.4792 18.0954 16.9379 16.9879 17.7545 16.1713C18.5711 15.3547 19.6786 14.896 20.8334 14.896C21.9882 14.896 23.0957 15.3547 23.9122 16.1713C24.7288 16.9879 25.1875 18.0954 25.1875 19.2502C25.1875 20.405 24.7288 21.5125 23.9122 22.329C23.0957 23.1456 21.9882 23.6043 20.8334 23.6043C19.6786 23.6043 18.5711 23.1456 17.7545 22.329C16.9379 21.5125 16.4792 20.405 16.4792 19.2502Z" fill="#007EA7"/>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,9 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.3334 15.9998C29.3334 8.63984 23.3601 2.6665 16.0001 2.6665C8.64008 2.6665 2.66675 8.63984 2.66675 15.9998C2.66675 23.3598 8.64008 29.3332 16.0001 29.3332" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6667 4H12C9.40005 11.7867 9.40005 20.2133 12 28H10.6667" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 4C21.2933 7.89333 21.9467 11.9467 21.9467 16" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 21.3333V20C7.89333 21.2933 11.9467 21.9467 16 21.9467" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 11.9998C11.7867 9.3998 20.2133 9.3998 28 11.9998" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M24.2667 28.5334C26.6231 28.5334 28.5333 26.6231 28.5333 24.2667C28.5333 21.9103 26.6231 20 24.2667 20C21.9102 20 20 21.9103 20 24.2667C20 26.6231 21.9102 28.5334 24.2667 28.5334Z" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M29.3333 29.3333L28 28" stroke="#007EA7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 16.7399C5.79 16.7399 5.57249 16.6874 5.37749 16.5824C4.94999 16.3574 4.6875 15.9074 4.6875 15.4274V14.3625C2.4225 14.13 0.9375 12.4649 0.9375 10.0799V5.57996C0.9375 2.99996 2.67 1.26746 5.25 1.26746H12.75C15.33 1.26746 17.0625 2.99996 17.0625 5.57996V10.0799C17.0625 12.6599 15.33 14.3924 12.75 14.3924H9.92249L6.72748 16.5225C6.50998 16.665 6.255 16.7399 6 16.7399ZM5.25 2.38495C3.315 2.38495 2.0625 3.63745 2.0625 5.57245V10.0725C2.0625 12.0075 3.315 13.26 5.25 13.26C5.5575 13.26 5.8125 13.515 5.8125 13.8225V15.42C5.8125 15.5175 5.8725 15.5625 5.91 15.585C5.9475 15.6075 6.02251 15.63 6.10501 15.5775L9.44252 13.3575C9.53252 13.2975 9.64501 13.26 9.75751 13.26H12.7575C14.6925 13.26 15.945 12.0075 15.945 10.0725V5.57245C15.945 3.63745 14.6925 2.38495 12.7575 2.38495H5.25Z" fill="#2196F3"/>
<path d="M8.99986 9.08252C8.69236 9.08252 8.43736 8.82752 8.43736 8.52002V8.36255C8.43736 7.49255 9.07485 7.06504 9.31485 6.90004C9.59235 6.71254 9.68234 6.58505 9.68234 6.39005C9.68234 6.01505 9.37486 5.70752 8.99986 5.70752C8.62486 5.70752 8.31738 6.01505 8.31738 6.39005C8.31738 6.69755 8.06238 6.95255 7.75488 6.95255C7.44738 6.95255 7.19238 6.69755 7.19238 6.39005C7.19238 5.39255 8.00236 4.58252 8.99986 4.58252C9.99736 4.58252 10.8073 5.39255 10.8073 6.39005C10.8073 7.24505 10.1774 7.67253 9.94487 7.83003C9.65237 8.02503 9.56236 8.15255 9.56236 8.36255V8.52002C9.56236 8.83502 9.30736 9.08252 8.99986 9.08252Z" fill="#2196F3"/>
<path d="M9 10.95C8.685 10.95 8.4375 10.695 8.4375 10.3875C8.4375 10.08 8.6925 9.82495 9 9.82495C9.3075 9.82495 9.5625 10.08 9.5625 10.3875C9.5625 10.695 9.315 10.95 9 10.95Z" fill="#2196F3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,8 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="20" fill="#007EA7"/>
<path d="M19.9998 25.938C16.7248 25.938 14.0623 23.2755 14.0623 20.0005V13.1255C14.0623 9.85049 16.7248 7.18799 19.9998 7.18799C23.2748 7.18799 25.9373 9.85049 25.9373 13.1255V20.0005C25.9373 23.2755 23.2748 25.938 19.9998 25.938ZM19.9998 9.06299C17.7623 9.06299 15.9373 10.888 15.9373 13.1255V20.0005C15.9373 22.238 17.7623 24.063 19.9998 24.063C22.2373 24.063 24.0623 22.238 24.0623 20.0005V13.1255C24.0623 10.888 22.2373 9.06299 19.9998 9.06299Z" fill="#FCFCFC"/>
<path d="M19.9998 30.312C14.2123 30.312 9.49976 25.5995 9.49976 19.812V17.687C9.49976 17.1745 9.92476 16.7495 10.4373 16.7495C10.9498 16.7495 11.3748 17.1745 11.3748 17.687V19.812C11.3748 24.562 15.2498 28.437 19.9998 28.437C24.7498 28.437 28.6248 24.562 28.6248 19.812V17.687C28.6248 17.1745 29.0498 16.7495 29.5623 16.7495C30.0748 16.7495 30.4998 17.1745 30.4998 17.687V19.812C30.4998 25.5995 25.7873 30.312 19.9998 30.312Z" fill="#FCFCFC"/>
<path d="M21.7376 14.5999C21.6376 14.5999 21.5251 14.5874 21.4126 14.5499C20.5001 14.2124 19.5001 14.2124 18.5876 14.5499C18.1001 14.7249 17.5626 14.4749 17.3876 13.9874C17.2126 13.4999 17.4626 12.9624 17.9501 12.7874C19.2751 12.3124 20.7376 12.3124 22.0626 12.7874C22.5501 12.9624 22.8001 13.4999 22.6251 13.9874C22.4751 14.3624 22.1126 14.5999 21.7376 14.5999Z" fill="#FCFCFC"/>
<path d="M20.9999 17.2499C20.9124 17.2499 20.8374 17.2374 20.7499 17.2124C20.2499 17.0749 19.7374 17.0749 19.2374 17.2124C18.7374 17.3499 18.2249 17.0499 18.0874 16.5499C17.9499 16.0624 18.2499 15.5499 18.7499 15.4124C19.5624 15.1874 20.4374 15.1874 21.2499 15.4124C21.7499 15.5499 22.0499 16.0624 21.9124 16.5624C21.7999 16.9749 21.4124 17.2499 20.9999 17.2499Z" fill="#FCFCFC"/>
<path d="M20 34.062C19.4875 34.062 19.0625 33.637 19.0625 33.1245V29.3745C19.0625 28.862 19.4875 28.437 20 28.437C20.5125 28.437 20.9375 28.862 20.9375 29.3745V33.1245C20.9375 33.637 20.5125 34.062 20 34.062Z" fill="#FCFCFC"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.0698 8.51013L9.50978 4.23013C3.75978 1.35013 1.39978 3.71013 4.27978 9.46013L5.14978 11.2001C5.39978 11.7101 5.39978 12.3001 5.14978 12.8101L4.27978 14.5401C1.39978 20.2901 3.74978 22.6501 9.50978 19.7701L18.0698 15.4901C21.9098 13.5701 21.9098 10.4301 18.0698 8.51013ZM14.8398 12.7501H9.43977C9.02978 12.7501 8.68977 12.4101 8.68977 12.0001C8.68977 11.5901 9.02978 11.2501 9.43977 11.2501H14.8398C15.2498 11.2501 15.5898 11.5901 15.5898 12.0001C15.5898 12.4101 15.2498 12.7501 14.8398 12.7501Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 629 B

View File

@ -0,0 +1,5 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 24C0 12.6863 0 7.02944 3.51472 3.51472C7.02944 0 12.6863 0 24 0C35.3137 0 40.9706 0 44.4853 3.51472C48 7.02944 48 12.6863 48 24C48 35.3137 48 40.9706 44.4853 44.4853C40.9706 48 35.3137 48 24 48C12.6863 48 7.02944 48 3.51472 44.4853C0 40.9706 0 35.3137 0 24Z" fill="#B0D7E4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.9414 10.4747C29.524 9.91601 28.1547 10.2947 27.1854 11.1573C26.2387 11.9973 25.6667 13.2933 25.6667 14.6667V20C25.6667 21.2893 26.712 22.3333 28 22.3333H33.3334C34.7067 22.3333 36.0027 21.76 36.844 20.8147C37.7054 19.8453 38.084 18.476 37.524 17.0587C36.9355 15.5694 36.0476 14.2166 34.9154 13.0841C33.7831 11.9517 32.4306 11.0635 30.9414 10.4747ZM27.6667 20V14.6667C27.6667 13.8307 28.02 13.0907 28.5147 12.6507C28.9854 12.232 29.5694 12.084 30.208 12.336C31.4421 12.8241 32.563 13.5602 33.5014 14.4986C34.4399 15.437 35.1759 16.5579 35.664 17.792C35.916 18.4307 35.768 19.0147 35.3494 19.4853C34.9094 19.98 34.1694 20.3333 33.3334 20.3333H28C27.9116 20.3333 27.8268 20.2982 27.7643 20.2357C27.7018 20.1732 27.6667 20.0884 27.6667 20Z" fill="#007EA7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.66 11.8266C21.8467 11.2986 21.06 11.1466 20.1934 11.2986C19.46 11.4266 18.6734 11.7786 17.8374 12.1533L17.748 12.1933C15.7268 13.0985 13.9559 14.4814 12.5877 16.2228C11.2195 17.9643 10.295 20.0121 9.89376 22.1901C9.49254 24.3681 9.62661 26.611 10.2845 28.7257C10.9423 30.8404 12.1042 32.7635 13.6701 34.3295C15.2361 35.8956 17.1591 37.0576 19.2737 37.7156C21.3884 38.3736 23.6312 38.5079 25.8093 38.1068C27.9873 37.7057 30.0352 36.7814 31.7768 35.4133C33.5183 34.0452 34.9013 32.2744 35.8067 30.2533L35.8467 30.1626C36.2214 29.3266 36.5734 28.5399 36.7014 27.8053C36.852 26.9413 36.7014 26.1533 36.1734 25.3386C35.6054 24.4626 34.8267 24.0333 33.8747 23.8386C33.0294 23.6653 31.9734 23.6653 30.7627 23.6666H28.6667C27.3814 23.6666 26.5174 23.6639 25.8734 23.5786C25.2587 23.4946 24.9947 23.3519 24.8214 23.1786C24.648 23.0053 24.5054 22.7413 24.4214 22.1253C24.336 21.4826 24.3334 20.6186 24.3334 19.3333V17.2373C24.3334 16.0266 24.3334 14.9706 24.16 14.1253C23.9667 13.1733 23.5374 12.3946 22.66 11.8266ZM18.5654 14.0186C19.524 13.5893 20.08 13.3479 20.5387 13.2679C20.892 13.2066 21.1707 13.2439 21.5734 13.5053C21.912 13.7253 22.092 13.9866 22.2014 14.5253C22.328 15.1479 22.3334 15.9973 22.3334 17.3333V19.4026C22.3334 20.5999 22.3334 21.5999 22.44 22.3919C22.552 23.2293 22.8 23.9853 23.408 24.5919C24.0147 25.1999 24.7707 25.4479 25.608 25.5599C26.4 25.6666 27.4 25.6666 28.5974 25.6666H30.6667C32.0027 25.6666 32.852 25.6719 33.4747 25.7986C34.0134 25.9079 34.2747 26.0879 34.4947 26.4266C34.756 26.8293 34.7934 27.1079 34.732 27.4626C34.652 27.9199 34.4107 28.4759 33.9814 29.4359C32.762 32.1545 30.5497 34.3042 27.7974 35.4453C24.9653 36.6175 21.7856 36.6282 18.9457 35.4749C16.1058 34.3216 13.8339 32.097 12.621 29.282C11.4081 26.4671 11.3518 23.2879 12.4641 20.4317C13.5765 17.5755 15.7681 15.2718 18.5654 14.0186Z" fill="#007EA7"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,7 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 24C0 12.6863 0 7.02944 3.51472 3.51472C7.02944 0 12.6863 0 24 0C35.3137 0 40.9706 0 44.4853 3.51472C48 7.02944 48 12.6863 48 24C48 35.3137 48 40.9706 44.4853 44.4853C40.9706 48 35.3137 48 24 48C12.6863 48 7.02944 48 3.51472 44.4853C0 40.9706 0 35.3137 0 24Z" fill="#B0D7E4"/>
<path d="M14.6667 15.7705H18.2667M18.2667 15.7705H20.6667M18.2667 15.7705V14.6665M22.6667 15.7705H20.6667M20.6667 15.7705C20.2454 17.2785 19.36 18.7052 18.352 19.9585L19.8947 21.5625M15.7814 22.6665C16.7036 21.8287 17.5629 20.924 18.352 19.9598C17.8387 19.3558 17.1187 18.3812 16.912 17.9398M26 33.3332L27.1107 30.6665M27.1107 30.6665L29.3334 25.3332L31.556 30.6665M27.1107 30.6665H31.556M32.6667 33.3332L31.556 30.6665" stroke="#007EA7" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26.6667 21.3332V18.6665C26.6667 14.8958 26.6667 13.0092 25.4947 11.8385C24.324 10.6665 22.4374 10.6665 18.6667 10.6665C14.896 10.6665 13.0094 10.6665 11.8387 11.8385C10.6667 13.0092 10.6667 14.8958 10.6667 18.6665C10.6667 22.4372 10.6667 24.3238 11.8387 25.4945C13.0094 26.6665 14.896 26.6665 18.6667 26.6665H21.3334" stroke="#007EA7" stroke-width="1.5" stroke-linecap="round"/>
<path d="M21.3334 29.333C21.3334 25.5623 21.3334 23.6757 22.5054 22.505C23.676 21.333 25.5627 21.333 29.3334 21.333C33.104 21.333 34.9907 21.333 36.1614 22.505C37.3334 23.6757 37.3334 25.5623 37.3334 29.333C37.3334 33.1037 37.3334 34.9903 36.1614 36.161C34.9907 37.333 33.104 37.333 29.3334 37.333C25.5627 37.333 23.676 37.333 22.5054 36.161C21.3334 34.9903 21.3334 33.1037 21.3334 29.333Z" stroke="#007EA7" stroke-width="1.5"/>
<path d="M13.3334 29.9997C13.3334 31.8717 13.3334 32.809 13.7827 33.481C13.9773 33.7723 14.2274 34.0224 14.5187 34.217C15.1907 34.6663 16.128 34.6663 18 34.6663M34.6667 17.9997C34.6667 16.1277 34.6667 15.1903 34.2174 14.5183C34.0228 14.227 33.7727 13.9769 33.4814 13.7823C32.8094 13.333 31.872 13.333 30 13.333" stroke="#007EA7" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -50,7 +50,7 @@ Future<void> _backgroundCallbackHomeWidget(Uri? uri) async {
void main() async {
runZonedGuarded(
() async {
() async {
WidgetsFlutterBinding.ensureInitialized();
try {
if (!kIsWeb) {
@ -73,7 +73,7 @@ void main() async {
}
await SentryFlutter.init(
(options) {
(options) {
options.dsn = 'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048';
options.tracesSampleRate = 1.0;
options.profilesSampleRate = 1.0;
@ -81,7 +81,7 @@ void main() async {
appRunner: () => runApp(const Didvan()),
);
},
(error, stack) {
(error, stack) {
Sentry.captureException(error, stackTrace: stack);
},
);
@ -178,7 +178,10 @@ class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
providers: [
ChangeNotifierProvider<PodcastsState>(create: (context) => PodcastsState()),
ChangeNotifierProvider<MediaProvider>(create: (context) => MediaProvider()),
// --- MODIFIED ---
// حذف ..fetchWelcomeMessage()
ChangeNotifierProvider<UserProvider>(create: (context) => UserProvider()),
// --- END MODIFIED ---
ChangeNotifierProvider<ThemeProvider>(create: (context) => ThemeProvider()),
ChangeNotifierProvider<StudioDetailsState>(create: (context) => StudioDetailsState()),
ChangeNotifierProvider<HistoryAiChatState>(create: (context) => HistoryAiChatState()),
@ -190,42 +193,43 @@ class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
builder: (context, themeProvider, child) => Container(
color: Theme.of(context).colorScheme.surface,
child: SafeArea(
child: MaterialApp(
scrollBehavior: MyCustomScrollBehavior(),
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
title: 'Didvan',
theme: LightThemeConfig.themeData.copyWith(
bottomSheetTheme: const BottomSheetThemeData(
surfaceTintColor: Colors.transparent,
backgroundColor: Colors.transparent),
textTheme: LightThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
darkTheme: DarkThemeConfig.themeData.copyWith(
bottomSheetTheme: const BottomSheetThemeData(
surfaceTintColor: Colors.transparent,
backgroundColor: Colors.transparent),
textTheme: DarkThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
color: LightThemeConfig.themeData.primaryColor,
themeMode: themeProvider.themeMode,
onGenerateRoute: (settings) =>
RouteGenerator.generateRoute(settings),
builder: BotToastInit(),
navigatorObservers: [BotToastNavigatorObserver()],
initialRoute: "/",
localizationsDelegates: const [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale("fa", "IR"),
],
locale: const Locale("fa", "IR"),
)),
child: MaterialApp(
scrollBehavior: MyCustomScrollBehavior(),
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
title: 'Didvan',
theme: LightThemeConfig.themeData.copyWith(
bottomSheetTheme: const BottomSheetThemeData(
surfaceTintColor: Colors.transparent,
backgroundColor: Colors.transparent),
textTheme: LightThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
darkTheme: DarkThemeConfig.themeData.copyWith(
bottomSheetTheme: const BottomSheetThemeData(
surfaceTintColor: Colors.transparent,
backgroundColor: Colors.transparent),
textTheme: DarkThemeConfig.themeData.textTheme.apply(
fontFamily: themeProvider.fontFamily,
)),
color: LightThemeConfig.themeData.primaryColor,
themeMode: themeProvider.themeMode,
onGenerateRoute: (settings) =>
RouteGenerator.generateRoute(settings),
builder: BotToastInit(),
navigatorObservers: [BotToastNavigatorObserver()],
initialRoute: "/",
localizationsDelegates: const [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale("fa", "IR"),
],
locale: const Locale("fa", "IR"),
),
),
),
),
);

View File

@ -0,0 +1,7 @@
// lib/models/ai/ai_model_enum.dart
enum AiModel {
chatGPT,
gemini,
grok
}

View File

@ -16,6 +16,14 @@ class UserProvider extends CoreProvier {
bool isAuthenticated = false;
int _unreadMessageCount = 0;
// --- ADDED ---
String? _welcomeMessage;
bool _isLoadingWelcome = true;
String? get welcomeMessage => _welcomeMessage;
bool get isLoadingWelcome => _isLoadingWelcome;
// --- END ADDED ---
set unreadMessageCount(int value) {
if (value < 0) {
return;
@ -32,6 +40,55 @@ class UserProvider extends CoreProvier {
static final List<MapEntry> _statisticMarkQueue = [];
static final List<Map> _itemMarkQueue = [];
// --- ADDED ---
Future<void> fetchWelcomeMessage() async {
if (!_isLoadingWelcome) {
_isLoadingWelcome = true;
notifyListeners(); // برای نمایش لودینگ اگر قبلا مخفی شده بود
}
try {
const String url = 'https://api.didvan.app/ai/aiwellcom';
// اطمینان از اینکه توکن وجود دارد قبل از ارسال درخواست
if (RequestService.token == null) {
print("UserProvider: fetchWelcomeMessage skipped, token is null.");
_isLoadingWelcome = false; // توکن نیست، لودینگ تمام
notifyListeners();
return;
}
print("UserProvider: Fetching welcome message..."); // Log start
final service = RequestService(url, useAutherization: true);
await service.post();
if (service.isSuccess) {
print("UserProvider: Welcome message API success."); // Log success
final period = service.data('period');
final userData = service.data('user'); // Rename to avoid conflict with class member 'user'
if (period != null && userData is Map && userData.containsKey('fullName')) {
final fullName = userData['fullName'];
_welcomeMessage = '$period بخیر $fullName 👋';
print("UserProvider: Welcome message set: $_welcomeMessage"); // Log message content
} else {
print("UserProvider: Welcome message API success but data format unexpected.");
_welcomeMessage = null; // Clear if data format is wrong
}
} else {
print("UserProvider: Welcome message API failed. Status: ${service.statusCode}, Error: ${service.errorMessage}"); // Log failure
_welcomeMessage = null; // Clear on API error
}
} catch (e) {
print("UserProvider: Exception fetching welcome message: $e"); // Log exception
_welcomeMessage = null; // Clear on exception
} finally {
// همیشه لودینگ رو false کن و UI رو آپدیت کن
_isLoadingWelcome = false;
print("UserProvider: fetchWelcomeMessage finished. isLoadingWelcome: $_isLoadingWelcome"); // Log end
notifyListeners();
}
}
// --- END ADDED ---
Future<String?> setAndGetToken({String? newToken}) async {
try {
if (newToken == null) {
@ -46,15 +103,25 @@ class UserProvider extends CoreProvier {
}
Future<bool> getUserInfo() async {
isAuthenticated = true;
isAuthenticated = true; // Assume authenticated until proven otherwise
print("UserProvider: Getting user info..."); // Log start
final RequestService service = RequestService(RequestHelper.userInfo);
await service.httpGet();
if (service.statusCode == 401 ||
(service.isSuccess && service.result['user'] == null)) {
if (service.statusCode == 401) {
print("UserProvider: getUserInfo failed - Unauthorized (401).");
isAuthenticated = false; // Not authenticated
return false;
}
if (service.isSuccess) {
if (service.result['user'] == null) {
print("UserProvider: getUserInfo success but user data is null.");
isAuthenticated = false; // Treat as not authenticated if user data is null
return false;
}
try {
print("UserProvider: User info fetched successfully."); // Log success
user = User.fromJson(service.result['user']);
await StorageService.setValue(
key: 'notificationTimeRangeStart',
@ -65,17 +132,30 @@ class UserProvider extends CoreProvier {
value: service.result['user']['end'],
);
// توکن فایربیس رو ثبت کن
await _registerFirebaseToken();
notifyListeners();
notifyListeners(); // اول اطلاعات کاربر رو آپدیت کن
// --- ADDED ---
// حالا که اطلاعات کاربر و توکن لود شده، پیام خوشامدگویی رو بگیر
await fetchWelcomeMessage();
// --- END ADDED ---
return true;
} catch (e) {
print("UserProvider: Exception processing user info: $e");
isAuthenticated = false; // Error processing, assume not authenticated
return false;
}
}
throw 'Getting user from API failed!';
// If service failed for reasons other than 401
print("UserProvider: getUserInfo failed. Status: ${service.statusCode}, Error: ${service.errorMessage}");
isAuthenticated = false; // Failed to get user info
// Consider throwing an error or handling it based on app logic
// throw 'Getting user from API failed!'; // Or return false
return false;
}
Future<void> _registerFirebaseToken() async {
@ -221,51 +301,53 @@ class UserProvider extends CoreProvier {
}
// static Future<void> changeRadarMark(int id, bool value) async {
// _radarMarkQueue.add(MapEntry(id, value));
// Future.delayed(const Duration(milliseconds: 500), () async {
// final MapEntry? lastChange =
// _radarMarkQueue.lastWhereOrNull((item) => item.key == id);
// if (lastChange == null) return;
// final service = RequestService(RequestHelper.mark(id, 'radar'));
// if (lastChange.value) {
// await service.post();
// } else {
// await service.delete();
// }
// _radarMarkQueue.removeWhere((element) => element.key == id);
// });
//   _radarMarkQueue.add(MapEntry(id, value));
//   Future.delayed(const Duration(milliseconds: 500), () async {
//     final MapEntry? lastChange =
//         _radarMarkQueue.lastWhereOrNull((item) => item.key == id);
//     if (lastChange == null) return;
//     final service = RequestService(RequestHelper.mark(id, 'radar'));
//     if (lastChange.value) {
//       await service.post();
//     } else {
//       await service.delete();
//     }
//     _radarMarkQueue.removeWhere((element) => element.key == id);
//   });
// }
// static Future<void> changeStudioMark(int id, bool value) async {
// _studioMarkQueue.add(MapEntry(id, value));
// Future.delayed(const Duration(milliseconds: 500), () async {
// final MapEntry? lastChange =
// _studioMarkQueue.lastWhereOrNull((item) => item.key == id);
// if (lastChange == null) return;
// final service = RequestService(RequestHelper.mark(id, 'studio'));
// if (lastChange.value) {
// await service.post();
// } else {
// await service.delete();
// }
// _studioMarkQueue.removeWhere((element) => element.key == id);
// });
//   _studioMarkQueue.add(MapEntry(id, value));
//   Future.delayed(const Duration(milliseconds: 500), () async {
//     final MapEntry? lastChange =
//         _studioMarkQueue.lastWhereOrNull((item) => item.key == id);
//     if (lastChange == null) return;
//     final service = RequestService(RequestHelper.mark(id, 'studio'));
//     if (lastChange.value) {
//       await service.post();
//     } else {
//       await service.delete();
//     }
//     _studioMarkQueue.removeWhere((element) => element.key == id);
//   });
// }
// static Future<void> changeNewsMark(int id, bool value) async {
// _newsMarkQueue.add(MapEntry(id, value));
// Future.delayed(const Duration(milliseconds: 500), () async {
// final MapEntry? lastChange =
// _newsMarkQueue.lastWhereOrNull((item) => item.key == id);
// if (lastChange == null) return;
// final service = RequestService(RequestHelper.mark(id, 'news'));
// if (lastChange.value) {
// await service.post();
// } else {
// await service.delete();
// }
// _newsMarkQueue.removeWhere((element) => element.key == id);
// });
//   _newsMarkQueue.add(MapEntry(id, value));
//   Future.delayed(const Duration(milliseconds: 500), () async {
//     final MapEntry? lastChange =
//         _newsMarkQueue.lastWhereOrNull((item) => item.key == id);
//     if (lastChange == null) return;
//     final service = RequestService(RequestHelper.mark(id, 'news'));
//     if (lastChange.value) {
//       await service.post();
//     } else {
//       await service.delete();
//   ----------------------------------------------------------------
//   }
//     _newsMarkQueue.removeWhere((element) => element.key == id);
//   });
// }
static Future<void> changeStatisticMark(int id, bool value) async {
@ -285,10 +367,10 @@ class UserProvider extends CoreProvier {
}
// Future<void> getUnreadMessageCount() async {
// final RequestService service = RequestService(RequestHelper.directs);
// await service.httpGet();
// if (service.isSuccess) {
// _unreadMessageCount = service.result['unread'] ?? 0;
// }
//   final RequestService service = RequestService(RequestHelper.directs);
//   await service.httpGet();
//   if (service.isSuccess) {
//     _unreadMessageCount = service.result['unread'] ?? 0;
//   }
// }
}
}

View File

@ -119,7 +119,7 @@ class MediaService {
try {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
allowedExtensions: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv'],
allowMultiple: false,
);
return result;

View File

@ -3,6 +3,7 @@ import 'package:didvan/models/requests/news.dart';
import 'package:didvan/models/requests/newstats_general.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/models/requests/studio.dart';
import 'package:get/get_connect/http/src/request/request.dart';
class RequestHelper {
static const String baseUrl = 'https://api.didvan.app';
@ -233,6 +234,7 @@ class RequestHelper {
static String deleteAllChats() => '$baseUrl/ai/chat/all';
static String archivedChat(int id) => '$baseUrl/ai/chat/$id/archive';
static String placeholder(int id) => '$baseUrl/ai/chat/$id/placeholder';
static String aiSummery() => '$baseUrl/ai/aisummery';
static String tools() => '$baseUrl/ai/tool';
static String info() => '$baseUrl/ai/video';
static String usersAssistants({final bool personal = false}) =>
@ -278,4 +280,9 @@ class RequestHelper {
}
return null;
}
static String aiSuggestedQuestions() {
return '$baseUrl/ai/aiquestion';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
// lib/views/ai/ai_chat_state.dart
// ignore_for_file: body_might_complete_normally_catch_error, avoid_print
import 'dart:async';
@ -37,6 +39,11 @@ class AiChatState extends CoreProvier {
bool isRecorded = false;
TextEditingController message = TextEditingController();
// --- ADDED ---
List<String> suggestedQuestions = [];
bool isLoadingQuestions = true;
// --- END ADDED ---
Future<void> _scrolledEnd() async {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await scrollController.animateTo(
@ -73,6 +80,38 @@ class AiChatState extends CoreProvier {
return service;
}
// --- ADDED ---
Future<void> fetchSuggestedQuestions() async {
isLoadingQuestions = true;
suggestedQuestions.clear();
update();
// 1. RequestHelper فقط URL string را برمیگرداند
final service = RequestService(
RequestHelper.aiSuggestedQuestions(),
// 2. بدنه درخواست خالی است و هدر Authorization خودکار اضافه میشود
);
// 3. متد post() را (به جای httpPost) فراخوانی میکنیم
await service.post();
if (service.isSuccess) {
// 4. از متد data() برای خواندن نتیجه استفاده میکنیم
final List<dynamic> questionsList = service.data('Questions');
if (questionsList.isNotEmpty) {
suggestedQuestions = questionsList.map((q) => q.toString()).toList();
}
isLoadingQuestions = false;
update();
} else {
// 5. از errorMessage برای نمایش خطا استفاده میکنیم
print("Error fetching suggested questions: ${service.errorMessage}");
isLoadingQuestions = false;
update();
}
}
// --- END ADDED ---
Future<void> getAllMessages(int chatId) async {
loading = true;
onResponsing = true;
@ -151,16 +190,20 @@ class AiChatState extends CoreProvier {
.toIso8601String()));
update();
await _scrolledEnd();
// if (file != null) {
// html.AnchorElement anchorElement = html.AnchorElement(href: file!.path);
// anchorElement.download = '${file!.path}.m4a';
// anchorElement.click();
// }
// تعیین URL بر اساس bot ID
String url;
if (bot.id == 100) {
// برای Aisummery از endpoint خاص استفاده میکنیم
url = '/100/aisummery';
} else {
// برای بقیه bot ها از endpoint عادی استفاده میکنیم
url = '${isAssistants ? '/user/${bot.responseType}' : ''}/${bot.id}/${bot.name}'
.toLowerCase();
}
final req = await AiApiService.initial(
url:
'${isAssistants ? '/user/${bot.responseType}' : ''}/${bot.id}/${bot.name}'
.toLowerCase(),
url: url,
message: message,
chatId: chatId,
file: uploadedFile,
@ -290,6 +333,7 @@ class AiChatState extends CoreProvier {
message: 'خطا در برقراری ارتباط', aLertType: ALertType.error));
update();
}
Future<void> clearChat() async {
messages.clear();
chatId = null;
@ -302,4 +346,4 @@ class AiChatState extends CoreProvier {
notifyListeners();
await Future.delayed(const Duration(milliseconds: 10));
}
}
}

View File

@ -1,7 +1,10 @@
// lib/views/ai/widgets/ai_message_bar.dart
// ignore_for_file: library_private_types_in_public_api, avoid_web_libraries_in_flutter, deprecated_member_use
import 'dart:async';
import 'package:didvan/utils/extension.dart';
import 'package:record/record.dart';
import 'package:universal_html/html.dart' as html;
import 'dart:io';
@ -13,6 +16,7 @@ import 'package:didvan/models/ai/bots_model.dart';
import 'package:didvan/models/ai/chats_model.dart';
import 'package:didvan/models/ai/files_model.dart';
import 'package:didvan/models/ai/messages_model.dart';
import 'package:didvan/models/ai/ai_model_enum.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/utils/date_time.dart';
@ -34,6 +38,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
import 'package:provider/provider.dart';
import 'package:flutter_svg/flutter_svg.dart'; // <-- ایمپورت SVG
typedef _Fn = void Function();
@ -41,9 +46,29 @@ class AiMessageBar extends StatefulWidget {
final BotsModel bot;
final String? assistantsName;
final bool? attch;
const AiMessageBar(
{Key? key, required this.bot, this.attch, this.assistantsName})
: super(key: key);
// --- ADDED ---
final bool showSearchToggle;
final bool isSearchMode;
final ValueChanged<bool>? onSearchModeToggled;
final bool showModelSelector;
final AiModel selectedModel;
final ValueChanged<AiModel>? onModelChanged;
// --- END ADDED ---
const AiMessageBar({
Key? key,
required this.bot,
this.attch,
this.assistantsName,
// --- ADDED ---
this.showSearchToggle = false,
this.isSearchMode = false,
this.onSearchModeToggled,
this.showModelSelector = false,
this.selectedModel = AiModel.chatGPT,
this.onModelChanged,
// --- END ADDED ---
}) : super(key: key);
@override
_AiMessageBarState createState() => _AiMessageBarState();
@ -231,11 +256,14 @@ class _AiMessageBarState extends State<AiMessageBar> {
@override
Widget build(BuildContext context) {
return Consumer<AiChatState>(builder: (context, state, child) {
// --- MODIFIED: Theme definition moved here to be accessible by new toggle ---
final theme = Theme.of(context);
return Container(
padding: const EdgeInsets.fromLTRB(12, 24, 12, 0).copyWith(
top: (state.file != null && !state.file!.isRecorded) ? 0 : 24),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: theme.colorScheme.background,
),
child: Column(
children: [
@ -245,40 +273,233 @@ class _AiMessageBarState extends State<AiMessageBar> {
children: [
Container(
decoration: BoxDecoration(
boxShadow: DesignConfig.defaultShadow,
color: Theme.of(context).colorScheme.surface,
color: const Color.fromARGB(255, 245, 245, 245),
border: Border.all(
color: const Color.fromARGB(255, 0, 126, 167),
width: 1.5),
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(16),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
// --- MODIFIED: Changed Row to Column ---
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
recorderAndSendButton(state),
if (!(_mRecorder!.isStopped))
ValueListenableBuilder(
valueListenable: _countTimer,
builder: (context, value, child) => Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: SizedBox(
width: 50,
child: Center(
child: DidvanText(
DateTimeUtils.normalizeTimeDuration(value)),
// --- MODIFIED: Added new Web Search Toggle ---
// --- MODIFIED: This is the original Row, now inside the Column ---
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
recorderAndSendButton(state),
if (!(_mRecorder!.isStopped))
ValueListenableBuilder(
valueListenable: _countTimer,
builder: (context, value, child) => Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: SizedBox(
width: 50,
child: Center(
child: DidvanText(
DateTimeUtils.normalizeTimeDuration(
value)),
),
),
),
),
Expanded(
child: Padding(
padding: _mRecorder!.isPaused ||
_mRecorder!.isRecording
? const EdgeInsets.fromLTRB(12, 8, 0, 8)
// --- MODIFIED: Adjusted padding when search toggle or model selector is visible ---
: (widget.showSearchToggle ||
widget.showModelSelector)
? EdgeInsets.zero.copyWith(top: 4.0)
: EdgeInsets.zero,
child:
recorderAndTextMessageHandler(context, state),
),
),
],
),
if (widget.showSearchToggle || widget.showModelSelector)
Padding(
padding: const EdgeInsets.only(
top: 4.0, left: 12.0, right: 12.0, bottom: 8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// Model Selector Dropdown (3 options)
if (widget.showModelSelector)
Builder(
builder: (context) {
String icon;
String label;
switch (widget.selectedModel) {
case AiModel.gemini:
icon = '';
label = 'Gemini';
break;
case AiModel.grok:
icon = 'assets/icons/grok.svg';
label = 'Grok';
break;
case AiModel.chatGPT:
default:
icon = 'assets/icons/chat_gpt.svg';
label = 'ChatGPT';
}
return PopupMenuButton<AiModel>(
onSelected: (AiModel model) {
widget.onModelChanged?.call(model);
},
offset: const Offset(0, 40),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(12.0),
),
itemBuilder: (BuildContext context) => [
PopupMenuItem<AiModel>(
value: AiModel.chatGPT,
child: Row(
children: [
Icon(
Icons.chat_bubble_outline,
size: 20,
),
const SizedBox(width: 12.0),
const DidvanText(
'ChatGPT',
fontSize: 14,
),
],
),
),
const PopupMenuItem<AiModel>(
value: AiModel.gemini,
child: Row(
children: [
Icon(
Icons.auto_awesome,
size: 20,
),
SizedBox(width: 12.0),
DidvanText(
'Gemini',
fontSize: 14,
),
],
),
),
const PopupMenuItem<AiModel>(
value: AiModel.grok,
child: Row(
children: [
Icon(
Icons.bolt,
size: 20,
),
SizedBox(width: 12.0),
DidvanText(
'Grok',
fontSize: 14,
),
],
),
),
],
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10.0, vertical: 6.0),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(100.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
icon,
height: 20,
),
const SizedBox(width: 8.0),
DidvanText(
label,
fontSize: 14,
color: const Color.fromARGB(
255, 61, 61, 61),
),
const SizedBox(width: 4.0),
const Icon(
Icons.arrow_drop_down,
size: 20,
color: Color.fromARGB(
255, 61, 61, 61),
),
],
),
),
);
},
),
// Spacer between toggles
if (widget.showSearchToggle &&
widget.showModelSelector)
const SizedBox(width: 8.0),
// Search Toggle
if (widget.showSearchToggle)
Builder(
builder: (context) {
final Color activeColor =
const Color.fromARGB(255, 0, 126, 167);
final bool isSearchMode =
widget.isSearchMode;
final Color backgroundColor = isSearchMode
? activeColor.withOpacity(0.1)
: theme.colorScheme.surface;
return InkWell(
onTap: () {
widget.onSearchModeToggled
?.call(!widget.isSearchMode);
},
borderRadius:
BorderRadius.circular(100.0),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10.0, vertical: 6.0),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius:
BorderRadius.circular(100.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
'lib/assets/icons/global-search 2.svg',
height: 25,
),
const SizedBox(width: 8.0),
const DidvanText(
'جستجو در وب',
fontSize: 14,
color: Color.fromARGB(
255, 61, 61, 61),
),
],
),
),
);
},
),
],
),
),
Expanded(
child: Padding(
padding:
_mRecorder!.isPaused || _mRecorder!.isRecording
? const EdgeInsets.fromLTRB(12, 8, 0, 8)
: EdgeInsets.zero,
child: recorderAndTextMessageHandler(context, state),
),
),
],
),
),
@ -286,23 +507,24 @@ class _AiMessageBarState extends State<AiMessageBar> {
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.focused
.withOpacity(0.5)),
color: theme.colorScheme.focused.withOpacity(0.5)),
),
)
],
),
// --- MODIFIED: Search Toggle UI removed from here ---
// The original Checkbox block that was here has been deleted.
MediaQuery.of(context).viewInsets.bottom == 0
? const Padding(
? const Padding(
padding: EdgeInsets.fromLTRB(3, 8, 3, 4),
child: SizedBox(height: 12,)
// DidvanText(
// 'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
// fontSize: 11,
// fontWeight: FontWeight.bold,
// ),
child: DidvanText(
'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید.',
fontSize: 10,
fontWeight: FontWeight.normal,
color: Color.fromARGB(255, 95, 95, 95),
),
)
: const SizedBox(
height: 12,
@ -407,7 +629,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
Padding(
padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
child: MessageBarBtn(
enable: false,
enable: true, // <-- فعال کردن دکمه
icon: openAttach || state.file != null
? DidvanIcons.close_regular
: Icons.add,
@ -441,13 +663,14 @@ class _AiMessageBarState extends State<AiMessageBar> {
enabled: !(state.file != null && widget.bot.attachment == 1),
decoration: InputDecoration(
contentPadding: const EdgeInsets.fromLTRB(12, 12, 12, 12),
contentPadding: const EdgeInsets.fromLTRB(12, 12, 0, 15),
border: InputBorder.none,
// --- MODIFIED: Hint Text is now always the same ---
hintText: 'بنویسید...',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Theme.of(context).colorScheme.disabledText),
.copyWith(color: const Color.fromARGB(255, 95, 95, 95)),
suffixIcon: state.isEdite
? InkWell(
onTap: () {
@ -472,16 +695,30 @@ class _AiMessageBarState extends State<AiMessageBar> {
widget.bot.attachment != 0
? MessageBarBtn(
enable: true,
icon: _mRecorder!.isRecording || _mRecorder!.isPaused
? Icons.stop_rounded
: DidvanIcons.mic_regular,
iconWidget: _mRecorder!.isRecording || _mRecorder!.isPaused
? SvgPicture.asset(
'lib/assets/icons/microphone-3.svg',
width: 24,
height: 24,
)
: SvgPicture.asset(
'lib/assets/icons/microphone-3.svg',
width: 29,
height: 29,
),
click: getRecorderFn(),
)
// --- MODIFIED BLOCK: استفاده از iconWidget برای SVG ---
: MessageBarBtn(
enable: (state.file != null && state.file!.isRecorded) ||
(widget.bot.attachment == 1) ||
message.text.isNotEmpty,
icon: DidvanIcons.send_light,
iconWidget: SvgPicture.asset(
'lib/assets/icons/send3.svg', // <-- مسیر SVG شما
width: 24, // اندازه دلخواه
height: 24,
color: const Color.fromARGB(255, 0, 126, 167),
),
click: () async {
if ((state.file == null || !state.file!.isRecorded) &&
(widget.bot.attachment != 1) &&
@ -531,10 +768,12 @@ class _AiMessageBarState extends State<AiMessageBar> {
state.message.clear();
openAttach = false;
state.update();
// --- MODIFIED: postMessage uses widget.bot, which is now stateful (normal or search)
await state.postMessage(
widget.bot, widget.assistantsName != null);
},
),
// --- END MODIFIED BLOCK ---
),
);
}
@ -560,8 +799,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
String? name = result.files.single.name;
if (kIsWeb) {
Uint8List? bytes = result
.files.first.bytes;
Uint8List? bytes = result.files.first.bytes;
state.file = FilesModel(
'',
@ -691,6 +929,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
));
}
// --- MODIFIED BLOCK: کد صحیح تابع ---
Widget audioContainer() {
final state = context.watch<AiChatState>();
@ -698,11 +937,12 @@ class _AiMessageBarState extends State<AiMessageBar> {
width: MediaQuery.sizeOf(context).width,
child: AudioWave(
file: state.file!.path,
loadingPaddingSize: 8.0,
loadingPaddingSize: 8.0, // <-- این پارامتر درست است
totalDuration: _countTimer.value,
),
);
}
// --- END MODIFIED BLOCK ---
Widget fileContainer() {
final state = context.watch<AiChatState>();

View File

@ -98,7 +98,6 @@ class _AudioWaveState extends State<AudioWave> {
click: () async {
await VoiceService.resetVoicePlayer();
},
loading: true,
);
}
return MessageBarBtn(

View File

@ -1,54 +1,55 @@
import 'package:didvan/config/theme_data.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class MessageBarBtn extends StatelessWidget {
final bool enable;
final IconData icon;
final IconData? icon;
final Widget? iconWidget; // برای پذیرش ویجتهای سفارشی
final Function()? click;
final Color? color;
final bool loading;
const MessageBarBtn(
{Key? key,
required this.enable,
required this.icon,
this.click,
this.color,
this.loading = false})
: super(key: key);
const MessageBarBtn({
Key? key,
this.icon,
this.iconWidget,
this.click,
required this.enable,
}) : assert(icon != null || iconWidget != null,
'Either icon or iconWidget must be provided'), // اطمینان از اینکه یکی از آیکنها ارائه شده
super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: 32,
height: 32,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: enable
? color ?? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.border),
child: InkWell(
onTap: click,
child: Stack(
children: [
Positioned.fill(
child: Icon(
icon,
size: 18,
color: enable ? Theme.of(context).colorScheme.white : null,
),
),
if (loading)
const Positioned.fill(
child: Padding(
padding: EdgeInsets.all(8.0),
child: SpinKitCircle(
color: Colors.white,
),
))
],
),
// --- BLOCK MODIFIED ---
// ویجت آیکن نهایی را مشخص میکنیم
Widget finalIconWidget;
if (iconWidget != null) {
// اگر ویجت سفارشی (SVG) داریم، رنگ اصلیاش را حفظ میکنیم
// و فقط برای حالت غیرفعال، آن را کمرنگ میکنیم
finalIconWidget = Opacity(
opacity: enable ? 1.0 : 0.5, // شفافیت بر اساس فعال بودن
child: iconWidget,
);
} else {
// اگر آیکن معمولی (IconData) داریم، از رنگ تم استفاده میکنیم
final color = enable
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.disabledText;
finalIconWidget = Icon(
icon,
size: 24,
color: color, // رنگ بر اساس فعال/غیرفعال بودن
);
}
// --- END MODIFIED BLOCK ---
return InkWell(
onTap: click,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: finalIconWidget, // نمایش ویجت آیکن نهایی
),
);
}
}
}

View File

@ -1,7 +1,6 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/views/ai/ai.dart';
import 'package:didvan/models/ai/bots_model.dart';
import 'package:didvan/views/ai/ai_chat_page.dart';
import 'package:didvan/views/ai/ai_chat_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
@ -22,11 +21,13 @@ class AiSectionPage extends StatefulWidget {
class _AiSectionGridItem {
final String title;
final String description; // فیلد جدید اضافه شد
final String iconPath;
final void Function(BuildContext context) onTap;
_AiSectionGridItem({
required this.title,
required this.description, // به سازنده اضافه شد
required this.iconPath,
required this.onTap,
});
@ -59,8 +60,9 @@ class _AiSectionPageState extends State<AiSectionPage> {
_gridItems = [
_AiSectionGridItem(
title: 'تصویرساز',
iconPath: 'lib/assets/icons/houshanNav/imagegeneratorU.svg',
title: 'ساخت عکس',
description: 'ایجاد تصاویر خلاقانه با هوش مصنوعی', // توضیحات اضافه شد
iconPath: 'lib/assets/icons/create image.svg',
onTap: (context) {
final aiState = context.read<AiState>();
aiState.endChat();
@ -76,55 +78,10 @@ class _AiSectionPageState extends State<AiSectionPage> {
}
},
),
_AiSectionGridItem(
title: 'چت صوتی',
iconPath: 'lib/assets/icons/houshanNav/aichatU.svg',
onTap: (context) {
final aiState = context.read<AiState>();
aiState.endChat();
if (aiState.tools != null && aiState.tools!.isNotEmpty) {
try {
final tool = aiState.tools!.last;
if (tool.bots != null && tool.bots!.isNotEmpty) {
aiState.startChat(AiChatArgs(bot: tool.bots!.first));
}
} catch (e) {
debugPrint('خطا در یافتن ابزار چت صوتی: $e');
}
}
},
),
_AiSectionGridItem(
title: 'گفت‌وگو',
iconPath:
'lib/assets/icons/houshanNav/streamline-flex_ai-scanner-robot.svg',
onTap: (context) {
context.read<AiState>().endChat();
Navigator.push(
context, MaterialPageRoute(builder: (context) => const Ai()));
},
),
_AiSectionGridItem(
title: 'جست‌وجو',
iconPath: 'lib/assets/icons/houshanNav/searchU.svg',
onTap: (context) {
final aiState = context.read<AiState>();
aiState.endChat();
if (aiState.tools != null && aiState.tools!.length > 1) {
try {
final tool = aiState.tools![1];
if (tool.bots != null && tool.bots!.isNotEmpty) {
aiState.startChat(AiChatArgs(bot: tool.bots!.first));
}
} catch (e) {
debugPrint('خطا در یافتن ابزار جست‌وجو: $e');
}
}
},
),
_AiSectionGridItem(
title: 'ترجمه',
iconPath: 'lib/assets/icons/houshanNav/translateU.svg',
description: 'ترجمه متون به زبان‌های مختلف', // توضیحات اضافه شد
iconPath: 'lib/assets/icons/translate.svg',
onTap: (context) {
final aiState = context.read<AiState>();
aiState.endChat();
@ -140,6 +97,26 @@ class _AiSectionPageState extends State<AiSectionPage> {
}
},
),
_AiSectionGridItem(
title: 'خلاصه‌ساز',
description: 'ساخت نمودار با تحلیل هوشمند',
iconPath: 'lib/assets/icons/summary.svg',
onTap: (context) {
final aiState = context.read<AiState>();
aiState.endChat();
// ساخت BotsModel برای Aisummery
final aisummeryBot = BotsModel(
id: 100,
name: 'Aisummery',
responseType: 'text',
attachmentType: ['pdf', 'image', 'audio'],
attachment: 1,
);
aiState.startChat(AiChatArgs(bot: aisummeryBot));
},
),
];
}
@ -154,7 +131,32 @@ class _AiSectionPageState extends State<AiSectionPage> {
Expanded(
child: aiState.isChatting
? AiChatPage(args: aiState.currentChatArgs!)
: _buildAiGrid(context, aiState),
: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: Row(
children: [
SvgPicture.asset('lib/assets/icons/clarity_tools-line.svg'),
const SizedBox(width: 8,),
DidvanText(
'جعبه ابزار استراتژیک هوشان',
style: Theme.of(context).textTheme.titleMedium,
color: Theme.of(context).colorScheme.title,
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height - 200,
child: _buildAiGrid(context, aiState),
),
],
),
),
),
],
);
@ -169,18 +171,42 @@ class _AiSectionPageState extends State<AiSectionPage> {
child: DidvanText('لیست ابزارها هنوز بارگذاری نشده یا خالی است.'));
}
return GridView.builder(
padding: const EdgeInsets.all(16.0),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16.0,
mainAxisSpacing: 16.0,
childAspectRatio: 3 / 2.2,
),
itemCount: _gridItems.length,
itemBuilder: (context, index) {
final item = _gridItems[index];
return _buildGridItemCard(context, item);
return ListView.builder(
scrollDirection: Axis.horizontal,
reverse: true,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
itemCount: (_gridItems.length / 2).ceil(),
itemBuilder: (context, columnIndex) {
return Padding(
padding: EdgeInsets.only(
left: columnIndex == (_gridItems.length / 2).ceil() - 1 ? 0 : 16.0,
right: 16.0,
),
child: SizedBox(
width: 180,
height: 340, // ارتفاع افزایش یافت (قبلا 300)
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (columnIndex * 2 < _gridItems.length)
SizedBox(
width: 180,
height: 160, // ارتفاع کارت افزایش یافت (قبلا 140)
child: _buildGridItemCard(context, _gridItems[columnIndex * 2]),
),
if (columnIndex * 2 + 1 < _gridItems.length)
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: SizedBox(
width: 180,
height: 160, // ارتفاع کارت افزایش یافت (قبلا 140)
child: _buildGridItemCard(context, _gridItems[columnIndex * 2 + 1]),
),
),
],
),
),
);
},
);
}
@ -188,35 +214,45 @@ class _AiSectionPageState extends State<AiSectionPage> {
Widget _buildGridItemCard(BuildContext context, _AiSectionGridItem item) {
return InkWell(
onTap: () => item.onTap(context),
borderRadius: DesignConfig.mediumBorderRadius,
borderRadius: BorderRadius.circular(25),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: DesignConfig.mediumBorderRadius,
boxShadow: DesignConfig.defaultShadow,
color: const Color.fromARGB(255, 245, 245, 245),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: const Color.fromARGB(255, 184, 184, 184),
width: 1,
),
),
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset(
item.iconPath,
width: 48,
height: 48,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.title,
BlendMode.srcIn,
),
),
const SizedBox(height: 12),
const SizedBox(height: 8),
DidvanText(
item.title,
style: Theme.of(context).textTheme.titleSmall,
color: Theme.of(context).colorScheme.title,
color: const Color.fromARGB(255, 0, 126, 167),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4), // فاصله برای توضیحات
Expanded( // برای مدیریت بهتر فضا و جلوگیری از overflow
child: DidvanText(
item.description, // نمایش توضیحات
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: Theme.of(context).colorScheme.caption,
),
maxLines: 2, // حداکثر 2 خط
overflow: TextOverflow.ellipsis,
),
),
],
),
),

View File

@ -249,7 +249,6 @@ class _RecordChecking extends StatelessWidget {
MessageBarBtn(
enable: true,
icon: DidvanIcons.trash_solid,
color: Theme.of(context).colorScheme.error,
click: () => state.deleteRecordedFile()),
const SizedBox(
width: 12,

View File

@ -1,13 +1,19 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/hoshan_home_app_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
final Function()? onBack;
final bool withInfo;
final bool withActions;
const HoshanAppBar(
{Key? key, this.onBack, this.withActions = true, this.withInfo = true})
: super(key: key);
@ -15,37 +21,23 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)),
color: Theme.of(context).colorScheme.surface,
boxShadow: [
BoxShadow(
color: const Color(0XFF1B3C59).withValues(alpha: 0.15),
blurRadius: 8,
spreadRadius: 0,
offset: const Offset(0, 8),
)
],
),
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
DidvanIcons.ai_solid,
size: 40,
color: Theme.of(context).colorScheme.title,
),
DidvanText(
'هوشان',
fontSize: 14,
color: Theme.of(context).colorScheme.title,
fontWeight: FontWeight.bold,
),
SvgPicture.asset(
Assets.horizontalLogoWithText,
height: 60,
width: 60,
)
// DidvanText(
// 'هوشان',
// fontSize: 14,
// color: Theme.of(context).colorScheme.title,
// fontWeight: FontWeight.bold,
// ),
],
),
Row(
@ -58,37 +50,80 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
// Navigator.pushNamed(context, Routes.info);
// }),
// if (withActions)
// Stack(
// children: [
// DidvanIconButton(
// icon: DidvanIcons.ai_regular,
// size: 32,
// onPressed: () {
// context.read<BotAssistantsState>().getMyAssissmant();
// Stack(
// children: [
// DidvanIconButton(
// icon: DidvanIcons.ai_regular,
// size: 32,
// onPressed: () {
// context.read<BotAssistantsState>().getMyAssissmant();
// Navigator.pushNamed(context, Routes.botAssistants);
// },
// ),
// Icon(
// CupertinoIcons.plus,
// color: Theme.of(context).colorScheme.primary,
// size: 16,
// )
// ],
// ),
// Navigator.pushNamed(context, Routes.botAssistants);
// },
// ),
// Icon(
// CupertinoIcons.plus,
// color: Theme.of(context).colorScheme.primary,
// size: 16,
// )
// ],
// ),
GestureDetector(
onTap: () {
print('history bottom tapped');
final historyState = context.read<HistoryAiChatState>();
if (historyState.chats.isEmpty) {
historyState.getChats();
}
showHistoryDrawer(context);
},
child: Container(
padding: const EdgeInsets.all(8),
child: SvgPicture.asset(
'lib/assets/icons/history.svg',
height: 24,
),
),
),
const SizedBox(width: 5,),
if (withInfo)
DidvanIconButton(
icon: DidvanIcons.angle_left_light,
size: 32,
onPressed: () => onBack?.call(),
),
],
)
],
));
}
void showHistoryDrawer(BuildContext context) {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration: const Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation) {
return const HistoryDrawerContent();
},
transitionBuilder: (context, animation, secondaryAnimation, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation,
curve: Curves.easeInOut,
)),
child: child,
);
},
);
}
@override
Size get preferredSize => const Size(double.infinity, 144);
}
}

View File

@ -1,6 +1,7 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/providers/user.dart'; // --- ADDED ---
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
@ -8,7 +9,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:didvan/routes/routes.dart';
import 'package:shamsi_date/shamsi_date.dart';
import 'package:didvan/services/network/request.dart';
// import 'package:didvan/services/network/request.dart'; // --- REMOVED --- (دیگه نیازی نیست)
class HoshanHomeAppBar extends StatefulWidget {
const HoshanHomeAppBar({super.key});
@ -18,58 +19,20 @@ class HoshanHomeAppBar extends StatefulWidget {
}
class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
String? _welcomeMessage;
bool _isLoadingWelcome = true;
// --- REMOVED ---
// String? _welcomeMessage;
// bool _isLoadingWelcome = true;
@override
void initState() {
super.initState();
_fetchWelcomeMessage();
}
// @override
// void initState() {
// super.initState();
// fetchWelcomeMessage();
// }
Future<void> _fetchWelcomeMessage() async {
try {
const String url = 'https://api.didvan.app/ai/aiwellcom';
// Future<void> fetchWelcomeMessage() async { ... }
// --- END REMOVED ---
final service = RequestService(url, useAutherization: true);
await service.post();
if (service.isSuccess) {
final period = service.data('period');
final user = service.data('user');
if (period != null && user is Map && user.containsKey('fullName')) {
final fullName = user['fullName'];
if (mounted) {
setState(() {
_welcomeMessage = '$period بخیر $fullName 👋';
_isLoadingWelcome = false;
});
}
} else {
if (mounted) {
setState(() {
_isLoadingWelcome = false;
});
}
}
} else {
if (mounted) {
setState(() {
_isLoadingWelcome = false;
});
}
}
} catch (e) {
if (mounted) {
setState(() {
_isLoadingWelcome = false;
});
}
}
}
void _showHistoryDrawer(BuildContext context) {
void showHistoryDrawer(BuildContext context) {
showGeneralDialog(
context: context,
barrierDismissible: true,
@ -77,7 +40,7 @@ class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
barrierColor: Colors.black54,
transitionDuration: const Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation) {
return const _HistoryDrawerContent();
return const HistoryDrawerContent();
},
transitionBuilder: (context, animation, secondaryAnimation, child) {
return SlideTransition(
@ -119,6 +82,10 @@ class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
@override
Widget build(BuildContext context) {
// --- ADDED ---
final userProvider = context.watch<UserProvider>();
// --- END ADDED ---
return Container(
decoration: const BoxDecoration(
color: Color.fromRGBO(230, 242, 246, 1),
@ -150,7 +117,7 @@ class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
if (historyState.chats.isEmpty) {
historyState.getChats();
}
_showHistoryDrawer(context);
showHistoryDrawer(context);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -165,16 +132,18 @@ class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
Container(
padding: const EdgeInsets.fromLTRB(8, 35, 8, 35),
alignment: Alignment.center,
child: _isLoadingWelcome
// --- MODIFIED ---
child: userProvider.isLoadingWelcome
? const SizedBox(height: 20)
: _welcomeMessage != null
: userProvider.welcomeMessage != null
? DidvanText(
_welcomeMessage!,
userProvider.welcomeMessage!,
fontSize: 21,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.title,
)
: const SizedBox(height: 20),
// --- END MODIFIED ---
),
GestureDetector(
onTap: () {
@ -262,14 +231,14 @@ class _HoshanHomeAppBarState extends State<HoshanHomeAppBar> {
}
}
class _HistoryDrawerContent extends StatefulWidget {
const _HistoryDrawerContent();
class HistoryDrawerContent extends StatefulWidget {
const HistoryDrawerContent();
@override
State<_HistoryDrawerContent> createState() => _HistoryDrawerContentState();
State<HistoryDrawerContent> createState() => _HistoryDrawerContentState();
}
class _HistoryDrawerContentState extends State<_HistoryDrawerContent> {
class _HistoryDrawerContentState extends State<HistoryDrawerContent> {
final TextEditingController _searchController = TextEditingController();
String _searchQuery = '';
@ -796,4 +765,4 @@ class _HistoryDrawerContentState extends State<_HistoryDrawerContent> {
),
);
}
}
}