change leaderboard

This commit is contained in:
mohamadmahdi jebeli 2025-09-15 14:23:17 +03:30
parent a6814dfb5e
commit 2c0133dff7
21 changed files with 1782 additions and 298 deletions

8
assets/icons/cup.svg Normal file
View File

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.1504 19.35C11.7404 19.35 11.4004 19.01 11.4004 18.6V16.5C11.4004 16.09 11.7404 15.75 12.1504 15.75C12.5604 15.75 12.9004 16.09 12.9004 16.5V18.6C12.9004 19.01 12.5604 19.35 12.1504 19.35Z" fill="#292D32"/>
<path d="M17.9004 22.75H6.40039V21C6.40039 19.48 7.63039 18.25 9.15039 18.25H15.1504C16.6704 18.25 17.9004 19.48 17.9004 21V22.75ZM7.90039 21.25H16.4004V21C16.4004 20.31 15.8404 19.75 15.1504 19.75H9.15039C8.46039 19.75 7.90039 20.31 7.90039 21V21.25Z" fill="#292D32"/>
<path d="M18.1504 22.75H6.15039C5.74039 22.75 5.40039 22.41 5.40039 22C5.40039 21.59 5.74039 21.25 6.15039 21.25H18.1504C18.5604 21.25 18.9004 21.59 18.9004 22C18.9004 22.41 18.5604 22.75 18.1504 22.75Z" fill="#292D32"/>
<path d="M18.4297 12.4401C18.2197 12.4401 18.0097 12.3501 17.8597 12.1801C17.6697 11.9601 17.6197 11.6501 17.7397 11.3901C18.0797 10.6101 18.2497 9.78006 18.2497 8.91006V5.91006C18.2497 5.56006 18.1897 5.22006 18.0697 4.86006C18.0597 4.83006 18.0497 4.79006 18.0397 4.75006C18.0097 4.60006 17.9997 4.45006 17.9997 4.31006C17.9997 3.90006 18.3397 3.56006 18.7497 3.56006H19.3497C21.1397 3.56006 22.5997 5.06006 22.5997 6.91006C22.5997 8.44006 21.9697 9.95006 20.8797 11.0401C20.8597 11.0601 20.7997 11.1101 20.7897 11.1201C20.1997 11.6101 19.5297 12.1601 18.6297 12.4101C18.5597 12.4301 18.4997 12.4401 18.4297 12.4401ZM19.6797 5.09006C19.7297 5.36006 19.7497 5.64006 19.7497 5.91006V8.91006C19.7497 9.32006 19.7197 9.71006 19.6597 10.1101C19.7197 10.0601 19.7697 10.0201 19.8297 9.97006C20.6297 9.17006 21.0997 8.05006 21.0997 6.91006C21.0997 6.01006 20.4897 5.25006 19.6797 5.09006Z" fill="#292D32"/>
<path d="M5.58039 12.4C5.50039 12.4 5.43039 12.39 5.35039 12.36C4.53039 12.1 3.76039 11.62 3.12039 10.98C1.97039 9.70998 1.40039 8.31998 1.40039 6.84998C1.40039 5.02998 2.83039 3.59998 4.65039 3.59998H5.30039C5.55039 3.59998 5.79039 3.72998 5.93039 3.93998C6.07039 4.14998 6.09039 4.41998 5.99039 4.64998C5.83039 5.00998 5.75039 5.41998 5.75039 5.84998V8.84998C5.75039 9.70998 5.92039 10.55 6.27039 11.35C6.39039 11.62 6.33039 11.93 6.14039 12.15C5.99039 12.31 5.79039 12.4 5.58039 12.4ZM4.30039 5.12998C3.49039 5.28998 2.90039 5.98998 2.90039 6.84998C2.90039 7.93998 3.34039 8.98998 4.21039 9.94998C4.25039 9.99998 4.30039 10.04 4.35039 10.08C4.28039 9.66998 4.25039 9.25998 4.25039 8.84998V5.84998C4.25039 5.60998 4.27039 5.36998 4.30039 5.12998Z" fill="#292D32"/>
<path d="M12 16.75C7.73 16.75 4.25 13.27 4.25 9V6C4.25 3.38 6.38 1.25 9 1.25H15C17.62 1.25 19.75 3.38 19.75 6V9C19.75 13.27 16.27 16.75 12 16.75ZM9 2.75C7.21 2.75 5.75 4.21 5.75 6V9C5.75 12.45 8.55 15.25 12 15.25C15.45 15.25 18.25 12.45 18.25 9V6C18.25 4.21 16.79 2.75 15 2.75H9Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,5 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.5 16.5C13.625 16.5 17 13.125 17 9C17 4.875 13.625 1.5 9.5 1.5C5.375 1.5 2 4.875 2 9C2 13.125 5.375 16.5 9.5 16.5Z" stroke="#A1A0A0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.5 6V9.75" stroke="#A1A0A0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.49585 12H9.50259" stroke="#A1A0A0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 535 B

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.0002 22.76C10.5202 22.76 9.03018 22.2 7.87018 21.09C4.92018 18.25 1.66018 13.72 2.89018 8.33C4.00018 3.44 8.27018 1.25 12.0002 1.25C12.0002 1.25 12.0002 1.25 12.0102 1.25C15.7402 1.25 20.0102 3.44 21.1202 8.34C22.3402 13.73 19.0802 18.25 16.1302 21.09C14.9702 22.2 13.4802 22.76 12.0002 22.76ZM12.0002 2.75C9.09018 2.75 5.35018 4.3 4.36018 8.66C3.28018 13.37 6.24018 17.43 8.92018 20C10.6502 21.67 13.3602 21.67 15.0902 20C17.7602 17.43 20.7202 13.37 19.6602 8.66C18.6602 4.3 14.9102 2.75 12.0002 2.75Z" fill="#292D32"/>
<path d="M10.7499 13.75C10.5599 13.75 10.3699 13.68 10.2199 13.53L8.71994 12.03C8.42994 11.74 8.42994 11.26 8.71994 10.97C9.00994 10.68 9.48994 10.68 9.77994 10.97L10.7499 11.94L14.2199 8.47C14.5099 8.18 14.9899 8.18 15.2799 8.47C15.5699 8.76 15.5699 9.24 15.2799 9.53L11.2799 13.53C11.1299 13.68 10.9399 13.75 10.7499 13.75Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 981 B

View File

@ -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="M12 16.75C11.6 16.75 11.2 16.72 10.82 16.65C8.7 16.34 6.77 15.12 5.55 13.31C4.7 12.03 4.25 10.54 4.25 9C4.25 4.73 7.73 1.25 12 1.25C16.27 1.25 19.75 4.73 19.75 9C19.75 10.54 19.3 12.03 18.45 13.31C17.22 15.13 15.29 16.34 13.15 16.66C12.8 16.72 12.4 16.75 12 16.75ZM12 2.75C8.55 2.75 5.75 5.55 5.75 9C5.75 10.25 6.11 11.45 6.79 12.47C7.78 13.93 9.33 14.91 11.05 15.16C11.69 15.27 12.32 15.27 12.91 15.16C14.66 14.91 16.21 13.92 17.2 12.46C17.88 11.44 18.24 10.24 18.24 8.98999C18.25 5.54999 15.45 2.75 12 2.75Z" fill="#292D32"/>
<path d="M6.46933 22.59C6.32933 22.59 6.19933 22.57 6.05933 22.54C5.40933 22.39 4.90933 21.89 4.75933 21.24L4.40933 19.77C4.38933 19.68 4.31933 19.61 4.21933 19.58L2.56933 19.19C1.94933 19.04 1.45933 18.58 1.28933 17.97C1.11933 17.36 1.28933 16.7 1.73933 16.25L5.63933 12.35C5.79933 12.19 6.01933 12.11 6.23933 12.13C6.45933 12.15 6.65933 12.27 6.78933 12.46C7.77933 13.92 9.32933 14.91 11.0593 15.16C11.6993 15.27 12.3293 15.27 12.9193 15.16C14.6693 14.91 16.2193 13.92 17.2093 12.46C17.3293 12.27 17.5393 12.15 17.7593 12.13C17.9793 12.11 18.1993 12.19 18.3593 12.35L22.2593 16.25C22.7093 16.7 22.8793 17.36 22.7093 17.97C22.5393 18.58 22.0393 19.05 21.4293 19.19L19.7793 19.58C19.6893 19.6 19.6193 19.67 19.5893 19.77L19.2393 21.24C19.0893 21.89 18.5893 22.39 17.9393 22.54C17.2893 22.7 16.6193 22.47 16.1993 21.96L11.9993 17.13L7.79933 21.97C7.45933 22.37 6.97933 22.59 6.46933 22.59ZM6.08933 14.03L2.79933 17.32C2.70933 17.41 2.71933 17.51 2.73933 17.57C2.74933 17.62 2.79933 17.72 2.91933 17.74L4.56933 18.13C5.21933 18.28 5.71933 18.78 5.86933 19.43L6.21933 20.9C6.24933 21.03 6.34933 21.07 6.40933 21.09C6.46933 21.1 6.56933 21.11 6.65933 21.01L10.4893 16.6C8.78933 16.27 7.22933 15.36 6.08933 14.03ZM13.5093 16.59L17.3393 20.99C17.4293 21.1 17.5393 21.1 17.5993 21.08C17.6593 21.07 17.7493 21.02 17.7893 20.89L18.1393 19.42C18.2893 18.77 18.7893 18.27 19.4393 18.12L21.0893 17.73C21.2093 17.7 21.2593 17.61 21.2693 17.56C21.2893 17.51 21.2993 17.4 21.2093 17.31L17.9193 14.02C16.7693 15.35 15.2193 16.26 13.5093 16.59Z" fill="#292D32"/>
<path d="M13.8901 12.89C13.6301 12.89 13.3201 12.82 12.9501 12.6L12.0001 12.03L11.0501 12.59C10.1801 13.11 9.61014 12.81 9.40014 12.66C9.19014 12.51 8.74014 12.06 8.97014 11.07L9.21014 10.04L8.41014 9.29999C7.97014 8.85999 7.81014 8.33001 7.96014 7.85001C8.11014 7.37001 8.55014 7.02999 9.17014 6.92999L10.2401 6.75L10.7501 5.63C11.0401 5.06 11.4901 4.73999 12.0001 4.73999C12.5101 4.73999 12.9701 5.07001 13.2501 5.64001L13.8401 6.82001L14.8301 6.94C15.4401 7.04 15.8801 7.37999 16.0401 7.85999C16.1901 8.33999 16.0301 8.87 15.5901 9.31L14.7601 10.14L15.0201 11.07C15.2501 12.06 14.8001 12.51 14.5901 12.66C14.4801 12.75 14.2401 12.89 13.8901 12.89ZM9.61014 8.39001L10.3001 9.07999C10.6201 9.39999 10.7801 9.94 10.6801 10.38L10.4901 11.18L11.2901 10.71C11.7201 10.46 12.3001 10.46 12.7201 10.71L13.5201 11.18L13.3401 10.38C13.2401 9.93001 13.3901 9.39999 13.7101 9.07999L14.4001 8.39001L13.5301 8.23999C13.1101 8.16999 12.6901 7.86001 12.5001 7.48001L12.0001 6.5L11.5001 7.5C11.3201 7.87 10.9001 8.19001 10.4801 8.26001L9.61014 8.39001Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

4
assets/icons/radar-2.svg Normal file
View File

@ -0,0 +1,4 @@
<svg width="53" height="53" viewBox="0 0 53 53" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.4" d="M26.8099 48.4764C38.776 48.4764 48.4765 38.7759 48.4765 26.8097C48.4765 14.8436 38.776 5.14307 26.8099 5.14307C14.8437 5.14307 5.14319 14.8436 5.14319 26.8097C5.14319 38.7759 14.8437 48.4764 26.8099 48.4764Z" fill="#176BAD"/>
<path d="M26.8098 10.0181C23.1481 10.0181 19.6598 11.1881 16.7348 13.3764C16.0198 13.9181 15.8682 14.9364 16.4098 15.6514C16.9515 16.3664 17.9698 16.5181 18.6848 15.9764C21.0465 14.1997 23.8415 13.2681 26.8098 13.2681C34.2848 13.2681 40.3515 19.3347 40.3515 26.8097C40.3515 34.2847 34.2848 40.3514 26.8098 40.3514C19.3348 40.3514 13.2681 34.2847 13.2681 26.8097C13.2681 24.9897 13.6365 23.1914 14.3298 21.5231L16.7998 22.9314C16.3232 24.1664 16.0632 25.4664 16.0632 26.8097C16.0632 32.7247 20.8731 37.5347 26.7881 37.5347C32.7031 37.5347 37.5132 32.7247 37.5132 26.8097C37.5132 20.8947 32.7031 16.0847 26.7881 16.0847C25.1848 16.0847 23.6465 16.4314 22.2165 17.1031C21.4148 17.4931 21.0465 18.4464 21.4365 19.2697C21.8265 20.0714 22.7798 20.4181 23.6031 20.0497C24.5998 19.5731 25.6615 19.3347 26.7881 19.3347C30.9048 19.3347 34.2632 22.6931 34.2632 26.8097C34.2632 30.9264 30.9048 34.2847 26.7881 34.2847C22.6715 34.2847 19.3132 30.9264 19.3132 26.8097C19.3132 26.0514 19.4648 25.3147 19.6815 24.5997L25.9865 28.2181C26.7665 28.6731 27.7632 28.3914 28.1965 27.6114C28.6515 26.8314 28.3698 25.8347 27.5898 25.4014L14.4382 17.8397C13.6582 17.3847 12.6615 17.6664 12.2281 18.4464C10.7765 20.9814 9.99646 23.8631 9.99646 26.8097C9.99646 36.0614 17.5365 43.6014 26.7881 43.6014C36.0398 43.6014 43.5798 36.0614 43.5798 26.8097C43.5798 17.5581 36.0615 10.0181 26.8098 10.0181Z" fill="#176BAD"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

6
assets/icons/ranking.svg Normal file
View File

@ -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="M8.67 22.75H2C1.59 22.75 1.25 22.41 1.25 22V16C1.25 14.48 2.48 13.25 4 13.25H8.67C9.08 13.25 9.42 13.59 9.42 14V22C9.42 22.41 9.08 22.75 8.67 22.75ZM2.75 21.25H7.92V14.75H4C3.31 14.75 2.75 15.31 2.75 16V21.25Z" fill="#292D32"/>
<path d="M15.3302 22.75H8.66016C8.25016 22.75 7.91016 22.41 7.91016 22V12C7.91016 10.48 9.14016 9.25 10.6602 9.25H13.3302C14.8502 9.25 16.0802 10.48 16.0802 12V22C16.0802 22.41 15.7502 22.75 15.3302 22.75ZM9.42015 21.25H14.5902V12C14.5902 11.31 14.0302 10.75 13.3402 10.75H10.6702C9.98015 10.75 9.42015 11.31 9.42015 12V21.25Z" fill="#292D32"/>
<path d="M22.0001 22.75H15.3301C14.9201 22.75 14.5801 22.41 14.5801 22V17C14.5801 16.59 14.9201 16.25 15.3301 16.25H20.0001C21.5201 16.25 22.7501 17.48 22.7501 19V22C22.7501 22.41 22.4101 22.75 22.0001 22.75ZM16.0801 21.25H21.2501V19C21.2501 18.31 20.6901 17.75 20.0001 17.75H16.0801V21.25Z" fill="#292D32"/>
<path d="M13.6999 8.34999C13.4599 8.34999 13.1599 8.27997 12.8199 8.07997L11.9999 7.58998L11.1899 8.06999C10.3699 8.55999 9.82989 8.26998 9.62989 8.12998C9.42989 7.98998 8.99989 7.54998 9.20989 6.62998L9.39989 5.79997L8.71989 5.11997C8.29989 4.69997 8.14989 4.19997 8.29989 3.73997C8.44989 3.27997 8.85989 2.95996 9.43989 2.85996L10.3099 2.70997L10.7999 1.72999C11.3399 0.65999 12.6499 0.65999 13.1799 1.72999L13.6699 2.70997L14.5399 2.85996C15.1199 2.95996 15.5399 3.27997 15.6799 3.73997C15.8299 4.19997 15.6699 4.69997 15.2599 5.11997L14.5799 5.79997L14.7699 6.62998C14.9799 7.55998 14.5499 7.98999 14.3499 8.13999C14.2599 8.21999 14.0299 8.34999 13.6999 8.34999ZM11.9999 6.07997C12.2399 6.07997 12.4799 6.13999 12.6799 6.25999L13.2399 6.58998L13.1199 6.04997C13.0199 5.62997 13.1699 5.11998 13.4799 4.80998L13.9899 4.29997L13.3599 4.18998C12.9599 4.11998 12.5699 3.82998 12.3899 3.46998L11.9999 2.71998L11.6199 3.46998C11.4399 3.82998 11.0499 4.11998 10.6499 4.18998L10.0199 4.28999L10.5299 4.79997C10.8399 5.10997 10.9799 5.61999 10.8899 6.03999L10.7699 6.57997L11.3299 6.24998C11.5199 6.12998 11.7599 6.07997 11.9999 6.07997Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 20.75C5.62 20.75 1.25 16.38 1.25 11C1.25 5.62 5.62 1.25 11 1.25C16.38 1.25 20.75 5.62 20.75 11C20.75 16.38 16.38 20.75 11 20.75ZM11 2.75C6.45 2.75 2.75 6.45 2.75 11C2.75 15.55 6.45 19.25 11 19.25C15.55 19.25 19.25 15.55 19.25 11C19.25 6.45 15.55 2.75 11 2.75Z" fill="#292D32"/>
<path d="M20.1601 22.79C20.0801 22.79 20.0001 22.78 19.9301 22.77C19.4601 22.71 18.6101 22.39 18.1301 20.96C17.8801 20.21 17.9701 19.46 18.3801 18.89C18.7901 18.32 19.4801 18 20.2701 18C21.2901 18 22.0901 18.39 22.4501 19.08C22.8101 19.77 22.7101 20.65 22.1401 21.5C21.4301 22.57 20.6601 22.79 20.1601 22.79ZM19.5601 20.49C19.7301 21.01 19.9701 21.27 20.1301 21.29C20.2901 21.31 20.5901 21.12 20.9001 20.67C21.1901 20.24 21.2101 19.93 21.1401 19.79C21.0701 19.65 20.7901 19.5 20.2701 19.5C19.9601 19.5 19.7301 19.6 19.6001 19.77C19.4801 19.94 19.4601 20.2 19.5601 20.49Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 983 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.2398 22.75H8.75982C6.86982 22.75 5.48982 21.96 4.95982 20.6C4.40982 19.18 4.91982 17.42 6.23982 16.23L10.8798 12L6.23982 7.77C4.91982 6.58 4.40982 4.82 4.95982 3.4C5.48982 2.03 6.86982 1.25 8.75982 1.25H15.2398C17.1298 1.25 18.5098 2.04 19.0398 3.4C19.5898 4.82 19.0798 6.58 17.7598 7.77L13.1198 12L17.7698 16.23C19.0798 17.42 19.5998 19.18 19.0498 20.6C18.5098 21.96 17.1298 22.75 15.2398 22.75ZM11.9998 13.01L7.24982 17.33C6.40982 18.1 6.03982 19.22 6.35982 20.05C6.65982 20.82 7.50982 21.25 8.75982 21.25H15.2398C16.4898 21.25 17.3398 20.83 17.6398 20.05C17.9598 19.22 17.5998 18.1 16.7498 17.33L11.9998 13.01ZM8.75982 2.75C7.50982 2.75 6.65982 3.17 6.35982 3.95C6.03982 4.78 6.39982 5.9 7.24982 6.67L11.9998 10.99L16.7498 6.67C17.5898 5.9 17.9598 4.78 17.6398 3.95C17.3398 3.18 16.4898 2.75 15.2398 2.75H8.75982Z" fill="#292D32"/>
</svg>

After

Width:  |  Height:  |  Size: 951 B

View File

@ -135,6 +135,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/coin.svg /// File path: assets/icons/coin.svg
SvgGenImage get coin => const SvgGenImage('assets/icons/coin.svg'); SvgGenImage get coin => const SvgGenImage('assets/icons/coin.svg');
/// File path: assets/icons/cup.svg
SvgGenImage get cup => const SvgGenImage('assets/icons/cup.svg');
/// File path: assets/icons/current loc.svg /// File path: assets/icons/current loc.svg
SvgGenImage get currentLoc => SvgGenImage get currentLoc =>
const SvgGenImage('assets/icons/current loc.svg'); const SvgGenImage('assets/icons/current loc.svg');
@ -227,6 +230,10 @@ class $AssetsIconsGen {
SvgGenImage get icRoundLocalOffer => SvgGenImage get icRoundLocalOffer =>
const SvgGenImage('assets/icons/ic_round-local-offer.svg'); const SvgGenImage('assets/icons/ic_round-local-offer.svg');
/// File path: assets/icons/info-circle.svg
SvgGenImage get infoCircle =>
const SvgGenImage('assets/icons/info-circle.svg');
/// File path: assets/icons/infoPic.svg /// File path: assets/icons/infoPic.svg
SvgGenImage get infoPic => const SvgGenImage('assets/icons/infoPic.svg'); SvgGenImage get infoPic => const SvgGenImage('assets/icons/infoPic.svg');
@ -251,6 +258,10 @@ class $AssetsIconsGen {
/// File path: assets/icons/list.svg /// File path: assets/icons/list.svg
SvgGenImage get list => const SvgGenImage('assets/icons/list.svg'); SvgGenImage get list => const SvgGenImage('assets/icons/list.svg');
/// File path: assets/icons/location-tick.svg
SvgGenImage get locationTick =>
const SvgGenImage('assets/icons/location-tick.svg');
/// File path: assets/icons/location.svg /// File path: assets/icons/location.svg
SvgGenImage get location => const SvgGenImage('assets/icons/location.svg'); SvgGenImage get location => const SvgGenImage('assets/icons/location.svg');
@ -296,6 +307,9 @@ class $AssetsIconsGen {
SvgGenImage get materialSymbolsLocationWork => SvgGenImage get materialSymbolsLocationWork =>
const SvgGenImage('assets/icons/material-symbols_location-work.svg'); const SvgGenImage('assets/icons/material-symbols_location-work.svg');
/// File path: assets/icons/medal-star.svg
SvgGenImage get medalStar => const SvgGenImage('assets/icons/medal-star.svg');
/// File path: assets/icons/message-question.svg /// File path: assets/icons/message-question.svg
SvgGenImage get messageQuestion => SvgGenImage get messageQuestion =>
const SvgGenImage('assets/icons/message-question.svg'); const SvgGenImage('assets/icons/message-question.svg');
@ -344,6 +358,12 @@ class $AssetsIconsGen {
/// File path: assets/icons/profile.svg /// File path: assets/icons/profile.svg
SvgGenImage get profile => const SvgGenImage('assets/icons/profile.svg'); SvgGenImage get profile => const SvgGenImage('assets/icons/profile.svg');
/// File path: assets/icons/radar-2.svg
SvgGenImage get radar2 => const SvgGenImage('assets/icons/radar-2.svg');
/// File path: assets/icons/ranking.svg
SvgGenImage get ranking => const SvgGenImage('assets/icons/ranking.svg');
/// File path: assets/icons/receipt-discount 2.svg /// File path: assets/icons/receipt-discount 2.svg
SvgGenImage get receiptDiscount2 => SvgGenImage get receiptDiscount2 =>
const SvgGenImage('assets/icons/receipt-discount 2.svg'); const SvgGenImage('assets/icons/receipt-discount 2.svg');
@ -365,6 +385,10 @@ class $AssetsIconsGen {
/// File path: assets/icons/routing.svg /// File path: assets/icons/routing.svg
SvgGenImage get routing => const SvgGenImage('assets/icons/routing.svg'); SvgGenImage get routing => const SvgGenImage('assets/icons/routing.svg');
/// File path: assets/icons/search-normal.svg
SvgGenImage get searchNormal =>
const SvgGenImage('assets/icons/search-normal.svg');
/// File path: assets/icons/selected list.svg /// File path: assets/icons/selected list.svg
SvgGenImage get selectedList => SvgGenImage get selectedList =>
const SvgGenImage('assets/icons/selected list.svg'); const SvgGenImage('assets/icons/selected list.svg');
@ -427,6 +451,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/timer.svg /// File path: assets/icons/timer.svg
SvgGenImage get timer => const SvgGenImage('assets/icons/timer.svg'); SvgGenImage get timer => const SvgGenImage('assets/icons/timer.svg');
/// File path: assets/icons/timer_Hunt.svg
SvgGenImage get timerHunt => const SvgGenImage('assets/icons/timer_Hunt.svg');
/// File path: assets/icons/usa circle.svg /// File path: assets/icons/usa circle.svg
SvgGenImage get usaCircle => const SvgGenImage('assets/icons/usa circle.svg'); SvgGenImage get usaCircle => const SvgGenImage('assets/icons/usa circle.svg');
@ -467,6 +494,7 @@ class $AssetsIconsGen {
clander, clander,
clock, clock,
coin, coin,
cup,
currentLoc, currentLoc,
deliveryOff, deliveryOff,
deliveryOn, deliveryOn,
@ -492,6 +520,7 @@ class $AssetsIconsGen {
hugeiconsBabyBoyDress, hugeiconsBabyBoyDress,
hugeiconsCheeseCake01, hugeiconsCheeseCake01,
icRoundLocalOffer, icRoundLocalOffer,
infoCircle,
infoPic, infoPic,
ionFastFoodOutline, ionFastFoodOutline,
iranCircle, iranCircle,
@ -499,6 +528,7 @@ class $AssetsIconsGen {
like, like,
link2, link2,
list, list,
locationTick,
location, location,
locationPopup, locationPopup,
logout, logout,
@ -511,6 +541,7 @@ class $AssetsIconsGen {
materialSymbolsLocationOn, materialSymbolsLocationOn,
materialSymbolsLocationOnn, materialSymbolsLocationOnn,
materialSymbolsLocationWork, materialSymbolsLocationWork,
medalStar,
messageQuestion, messageQuestion,
microphone2, microphone2,
nearby, nearby,
@ -525,12 +556,15 @@ class $AssetsIconsGen {
pickupOn, pickupOn,
profile2, profile2,
profile, profile,
radar2,
ranking,
receiptDiscount2, receiptDiscount2,
receiptDiscount, receiptDiscount,
recenter, recenter,
riSearch2Line, riSearch2Line,
routing2, routing2,
routing, routing,
searchNormal,
selectedList, selectedList,
shield, shield,
shoppingCart, shoppingCart,
@ -549,6 +583,7 @@ class $AssetsIconsGen {
timerPause, timerPause,
timerStart, timerStart,
timer, timer,
timerHunt,
usaCircle, usaCircle,
]; ];
} }

View File

@ -0,0 +1,208 @@
# 🏆 Hunt Leaderboard - Enhanced UI Documentation
## Overview
The Hunt Leaderboard has been completely redesigned with a modern, engaging, and visually attractive interface that provides an exceptional user experience for the Rank Hunt feature.
## 🎨 Key Visual Enhancements
### 1. **Modern Design System**
- **Gradient Backgrounds**: Beautiful gradient overlays with depth and dimension
- **Enhanced Shadows**: Multi-layered shadows with proper opacity and spread
- **Rounded Corners**: Consistent 16-32px border radius for modern feel
- **Improved Typography**: Better font weights, sizes, and letter spacing
### 2. **Advanced Animations**
- **Elastic Entry Animations**: Items bounce in with elastic curves
- **Particle Background Effect**: Animated floating particles for dynamic background
- **Trophy Glow Effects**: Pulsing glow animations for top 3 positions
- **Smooth Transitions**: 600-1200ms duration with proper easing curves
### 3. **Enhanced Visual Hierarchy**
#### **Header Section**
- Gradient icon container with shadow effects
- Improved title typography with better spacing
- Enhanced close button with card-style background
#### **Statistics Overview**
- Interactive stats cards showing:
- Total number of hunters
- Total points accumulated
- User's current rank
- Color-coded icons and gradient backgrounds
- Professional dividers between stats
#### **Champion Podium (Top 3)**
- **3D Podium Effect**: Different heights for 1st, 2nd, 3rd place
- **Dynamic Trophy System**:
- Gold (1st): Animated glow with golden gradient
- Silver (2nd): Silver gradient with medium glow
- Bronze (3rd): Bronze gradient with subtle glow
- **Real-time Rank Colors**: Dynamic color assignment based on performance
- **Avatar Integration**: Circular avatars with border effects
### 4. **Participant List Enhancements**
- **Smart Categorization**: Top 3 in podium, others in scrollable list
- **Current User Highlighting**: Special gradient background and borders
- **Achievement Badges**: Fire icons for high performers (500+ points)
- **Enhanced Card Design**: Gradient backgrounds with professional shadows
- **Interactive Elements**: Hover effects and touch responses
## 🎯 Technical Features
### **Performance Optimizations**
- **Efficient Animations**: Multiple animation controllers with proper disposal
- **Smooth Scrolling**: Optimized ListView with proper item building
- **Memory Management**: Proper controller lifecycle management
### **Responsive Design**
- **Adaptive Heights**: 85% screen height for optimal viewing
- **Flexible Layouts**: Responsive to different screen sizes
- **Safe Area Handling**: Proper padding and margins
### **Accessibility Features**
- **High Contrast**: Proper color contrast ratios
- **Readable Typography**: Appropriate font sizes and weights
- **Touch Targets**: Proper button sizes for easy interaction
## 🎪 Additional Components Created
### 1. **CelebrationOverlay** (`celebration_overlay.dart`)
- **Confetti Animation**: 30 animated particles with different shapes
- **Burst Effects**: Expanding circle effects from center
- **Color Variety**: 8 different celebration colors
- **Star Particles**: Mixed circle and star-shaped confetti
- **Fade Out Effect**: Smooth opacity transitions
### 2. **AnimatedRankBadge** (`animated_rank_badge.dart`)
- **Pulse Animation**: Breathing effect for active badges
- **Shimmer Effect**: Metallic shine for top 3 ranks
- **Dynamic Colors**: Rank-based color schemes
- **Icon System**: Different icons for different rank levels
- **Point Display**: Integrated point counter with star icon
## 🎨 Color Scheme & Theming
### **Rank-Based Colors**
- **1st Place**: Gold (#FFD700) with warm gradients
- **2nd Place**: Silver (#C0C0C0) with cool gradients
- **3rd Place**: Bronze (#CD7F32) with earth tones
- **Top 10**: Primary blue with professional gradients
- **Others**: Subtle gray tones with accent highlights
### **Background Effects**
- **Primary Gradient**: Surface to card background transition
- **Particle Colors**: Primary color with 10% opacity
- **Shadow System**: Multi-layered shadows with proper falloff
## 🚀 Usage Examples
### **Basic Implementation**
```dart
LeaderboardWidget(
entries: leaderboardEntries,
userPoints: currentUserPoints,
onClose: () => Navigator.pop(context),
)
```
### **With Celebration**
```dart
CelebrationOverlay(
showCelebration: userAchievedNewRank,
onCelebrationComplete: () => _showLeaderboard(),
child: YourHuntScreen(),
)
```
### **Rank Badge Usage**
```dart
AnimatedRankBadge(
rank: userRank,
totalPoints: userPoints,
userName: currentUser.name,
showAnimation: true,
onTap: () => _showFullLeaderboard(),
)
```
## 🎯 Benefits of Enhanced UI
### **User Engagement**
- **Visual Appeal**: Modern gradients and animations attract attention
- **Gamification**: Trophy systems and celebrations motivate participation
- **Recognition**: Clear visual hierarchy emphasizes achievements
### **User Experience**
- **Intuitive Navigation**: Clear close buttons and smooth transitions
- **Information Density**: Optimal balance of data and visual elements
- **Performance**: Smooth 60fps animations with proper optimization
### **Competitive Spirit**
- **Clear Rankings**: Easy to understand position and progress
- **Achievement Visibility**: Badges and effects highlight success
- **Social Comparison**: Easy comparison with other participants
## 🎪 Animation Details
### **Entry Sequence**
1. **Slide Up**: Main container slides from bottom (600ms)
2. **Statistics Fade**: Stats cards fade in with stagger
3. **Podium Rise**: Top 3 podium rises with elastic curve
4. **List Items**: Participants animate in with 80ms intervals
5. **Background**: Particles start floating immediately
### **Interactive Feedback**
- **Button Hover**: Subtle scale and shadow changes
- **Card Tap**: Brief scale down with shadow adjustment
- **Trophy Glow**: Continuous pulse for top 3 positions
## 📱 Mobile Optimization
### **Touch Interactions**
- **Swipe to Close**: Gesture-based closing mechanism
- **Large Touch Targets**: Minimum 44px touch areas
- **Haptic Feedback**: Proper vibration responses
### **Performance**
- **Efficient Rendering**: Only necessary repaints
- **Memory Management**: Proper animation disposal
- **Battery Optimization**: Controlled animation refresh rates
## 🚀 Latest Updates & Fixes
### **Navigation & Layout Optimizations**
- **Fixed Navigation Overflow**: Content no longer falls under navigation bar
- **Dynamic Height Calculation**: Adapts to different screen sizes and safe areas
- **Compact Design**: Optimized spacing for better content density
- **Mobile-First**: Responsive design that works perfectly on all devices
### **Podium Enhancement**
- **Fixed Name Truncation**: Smart name shortening with first name + last initial
- **Improved Text Layout**: Better spacing prevents overflow issues
- **Interactive Podium**: Tap to see full participant details
- **Optimized Heights**: Adjusted podium heights for better proportion
### **Advanced Features**
- **Smart Search**: Quick search functionality for large participant lists
- **Live Counter Animation**: Animated participant count in statistics
- **Pull-to-Refresh**: Swipe down to refresh leaderboard data
- **Real-time Indicators**: Live status indicators throughout the UI
### **Performance Optimizations**
- **Fixed Item Heights**: Improved scrolling performance
- **Efficient Filtering**: Smart filtering for search functionality
- **Memory Management**: Proper animation controller disposal
- **Smooth Animations**: 60fps animations with optimized refresh rates
This enhanced Hunt Leaderboard transforms a simple ranking display into an engaging, beautiful, and highly interactive experience that motivates users to participate more actively in the Hunt challenges! 🎉
### **Usage with New Features**
```dart
LeaderboardWidget(
entries: leaderboardEntries,
userPoints: currentUserPoints,
onClose: () => Navigator.pop(context),
onRefresh: () => _refreshLeaderboardData(), // New refresh callback
)
```

View File

@ -1,10 +1,3 @@
/*
* Hunt Feature Usage Examples
*
* This file demonstrates how to use the Hunt feature components
* and integrate them into your app.
*/
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:lba/screens/mains/hunt/hunt.dart'; import 'package:lba/screens/mains/hunt/hunt.dart';
@ -13,7 +6,6 @@ import 'package:lba/screens/mains/hunt/models/hunt_card.dart';
import 'package:lba/screens/mains/hunt/widgets/hunt_card_widget.dart'; import 'package:lba/screens/mains/hunt/widgets/hunt_card_widget.dart';
import 'package:lba/screens/mains/hunt/widgets/leaderboard_widget.dart'; import 'package:lba/screens/mains/hunt/widgets/leaderboard_widget.dart';
// Example 1: Basic Hunt Screen Integration
class ExampleHuntIntegration extends StatelessWidget { class ExampleHuntIntegration extends StatelessWidget {
const ExampleHuntIntegration({super.key}); const ExampleHuntIntegration({super.key});
@ -26,7 +18,6 @@ class ExampleHuntIntegration extends StatelessWidget {
} }
} }
// Example 2: Custom Hunt Card Widget Usage
class ExampleHuntCard extends StatelessWidget { class ExampleHuntCard extends StatelessWidget {
const ExampleHuntCard({super.key}); const ExampleHuntCard({super.key});
@ -52,7 +43,6 @@ class ExampleHuntCard extends StatelessWidget {
child: HuntCardWidget( child: HuntCardWidget(
card: exampleCard, card: exampleCard,
onTap: () { onTap: () {
// Handle card selection
print('Card ${exampleCard.id} selected!'); print('Card ${exampleCard.id} selected!');
}, },
isSelected: false, isSelected: false,
@ -63,7 +53,6 @@ class ExampleHuntCard extends StatelessWidget {
} }
} }
// Example 3: Leaderboard Widget Usage
class ExampleLeaderboard extends StatelessWidget { class ExampleLeaderboard extends StatelessWidget {
const ExampleLeaderboard({super.key}); const ExampleLeaderboard({super.key});
@ -106,7 +95,6 @@ class ExampleLeaderboard extends StatelessWidget {
} }
} }
// Example 4: Custom Hunt State Management
class ExampleHuntStateUsage extends StatefulWidget { class ExampleHuntStateUsage extends StatefulWidget {
const ExampleHuntStateUsage({super.key}); const ExampleHuntStateUsage({super.key});
@ -140,12 +128,10 @@ class _ExampleHuntStateUsageState extends State<ExampleHuntStateUsage> {
builder: (context, state, child) { builder: (context, state, child) {
return Column( return Column(
children: [ children: [
// Display current game state
Text('Current State: ${state.gameState}'), Text('Current State: ${state.gameState}'),
Text('User Points: ${state.userPoints}'), Text('User Points: ${state.userPoints}'),
Text('Cards Available: ${state.cards.length}'), Text('Cards Available: ${state.cards.length}'),
// Control buttons
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
@ -170,7 +156,6 @@ class _ExampleHuntStateUsageState extends State<ExampleHuntStateUsage> {
], ],
), ),
// Display selected card info
if (state.selectedCard != null) ...[ if (state.selectedCard != null) ...[
const SizedBox(height: 20), const SizedBox(height: 20),
Text('Selected Card: ${state.selectedCard!.category}'), Text('Selected Card: ${state.selectedCard!.category}'),
@ -178,7 +163,6 @@ class _ExampleHuntStateUsageState extends State<ExampleHuntStateUsage> {
Text('Question: ${state.selectedCard!.question}'), Text('Question: ${state.selectedCard!.question}'),
], ],
// Time remaining display
if (state.gameState == HuntGameState.huntingActive) ...[ if (state.gameState == HuntGameState.huntingActive) ...[
const SizedBox(height: 20), const SizedBox(height: 20),
Text('Time Remaining: ${_formatDuration(state.timeRemaining)}'), Text('Time Remaining: ${_formatDuration(state.timeRemaining)}'),
@ -201,7 +185,6 @@ class _ExampleHuntStateUsageState extends State<ExampleHuntStateUsage> {
} }
} }
// Example 5: Custom Hunt Integration with Navigation
class ExampleHuntNavigation extends StatelessWidget { class ExampleHuntNavigation extends StatelessWidget {
const ExampleHuntNavigation({super.key}); const ExampleHuntNavigation({super.key});
@ -253,15 +236,4 @@ class ExampleHuntNavigation extends StatelessWidget {
), ),
); );
} }
} }
/*
* Integration Notes:
*
* 1. Always wrap Hunt components with ChangeNotifierProvider<HuntState>
* 2. Initialize the game state with huntState.initializeGame()
* 3. Handle permissions properly before starting hunts
* 4. Clean up resources in dispose methods
* 5. Use Consumer widgets to react to state changes
* 6. Test on physical devices for location and camera features
*/

View File

@ -2,6 +2,8 @@ import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:vibration/vibration.dart'; import 'package:vibration/vibration.dart';
import 'package:lba/res/colors.dart'; import 'package:lba/res/colors.dart';
@ -95,7 +97,6 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
} }
void _initializeGame() { void _initializeGame() {
// Initialization is handled in provider creation
} }
@override @override
@ -278,7 +279,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white.withOpacity(0.05) ? Colors.white.withOpacity(0.05)
: Colors.white.withOpacity(0.4), // Liquid Glass effect : Colors.white.withOpacity(0.4),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all( border: Border.all(
color: AppColors.isDarkMode color: AppColors.isDarkMode
@ -306,12 +307,11 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
: const Color(0xFF1976D2).withOpacity(0.1), : const Color(0xFF1976D2).withOpacity(0.1),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Icon( child: SvgPicture.asset(
Icons.search_rounded, Assets.icons.searchNormal.path,
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white ? Colors.white
: const Color(0xFF1976D2), : const Color(0xFF1976D2),
size: 20,
), ),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
@ -357,12 +357,11 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( SvgPicture.asset(
Icons.leaderboard_rounded, Assets.icons.ranking.path,
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white ? Colors.white
: const Color(0xFF1976D2), : const Color(0xFF1976D2),
size: 16,
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
@ -371,7 +370,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white ? Colors.white
: const Color(0xFF1976D2), : const Color(0xFF1976D2),
fontSize: 12, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@ -393,7 +392,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white.withOpacity(0.10) ? Colors.white.withOpacity(0.10)
: Colors.white.withOpacity(0.6), // More transparent : Colors.white.withOpacity(0.6),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all( border: Border.all(
color: AppColors.isDarkMode color: AppColors.isDarkMode
@ -413,7 +412,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
_buildStatItem( _buildStatItem(
icon: Icons.stars_rounded, icon: Assets.icons.medalStar.path,
label: 'Total Points', label: 'Total Points',
value: '${huntProvider.userPoints}', value: '${huntProvider.userPoints}',
color: AppColors.isDarkMode color: AppColors.isDarkMode
@ -436,7 +435,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
), ),
), ),
_buildStatItem( _buildStatItem(
icon: Icons.emoji_events, icon: Assets.icons.cup.path,
label: 'Rank', label: 'Rank',
value: '#${huntProvider.currentUserRank}', value: '#${huntProvider.currentUserRank}',
color: AppColors.isDarkMode color: AppColors.isDarkMode
@ -449,7 +448,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
} }
Widget _buildStatItem({ Widget _buildStatItem({
required IconData icon, required String icon,
required String label, required String label,
required String value, required String value,
required Color color, required Color color,
@ -463,7 +462,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
color: color.withOpacity(0.15), color: color.withOpacity(0.15),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Icon(icon, color: color, size: 24), child: SvgPicture.asset(icon, color: color,),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
@ -494,7 +493,7 @@ class _HuntContentState extends State<_HuntContent> with TickerProviderStateMixi
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.white.withOpacity(0.08) ? Colors.white.withOpacity(0.08)
: Colors.white.withOpacity(0.7), // More transparent : Colors.white.withOpacity(0.7),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all( border: Border.all(
color: AppColors.isDarkMode color: AppColors.isDarkMode

View File

@ -19,7 +19,6 @@ class HuntState extends ChangeNotifier {
bool _isCameraPermissionGranted = false; bool _isCameraPermissionGranted = false;
DateTime? _huntStartTime; DateTime? _huntStartTime;
// Getters
List<HuntCard> get cards => _cards; List<HuntCard> get cards => _cards;
HuntCard? get selectedCard => _selectedCard; HuntCard? get selectedCard => _selectedCard;
HuntGameState get gameState => _gameState; HuntGameState get gameState => _gameState;
@ -60,7 +59,6 @@ class HuntState extends ChangeNotifier {
void selectCard(HuntCard card) { void selectCard(HuntCard card) {
_selectedCard = card; _selectedCard = card;
// Don't change game state, keep it as cardSelection so cards just flip
notifyListeners(); notifyListeners();
} }
@ -105,7 +103,6 @@ class HuntState extends ChangeNotifier {
} }
void _updateLeaderboard() { void _updateLeaderboard() {
// Update user's position in leaderboard
for (int i = 0; i < _leaderboard.length; i++) { for (int i = 0; i < _leaderboard.length; i++) {
if (_leaderboard[i].isCurrentUser) { if (_leaderboard[i].isCurrentUser) {
_leaderboard[i] = _leaderboard[i].copyWith(totalPoints: _userPoints); _leaderboard[i] = _leaderboard[i].copyWith(totalPoints: _userPoints);
@ -113,10 +110,8 @@ class HuntState extends ChangeNotifier {
} }
} }
// Sort leaderboard by points
_leaderboard.sort((a, b) => b.totalPoints.compareTo(a.totalPoints)); _leaderboard.sort((a, b) => b.totalPoints.compareTo(a.totalPoints));
// Update ranks
for (int i = 0; i < _leaderboard.length; i++) { for (int i = 0; i < _leaderboard.length; i++) {
_leaderboard[i] = _leaderboard[i].copyWith(rank: i + 1); _leaderboard[i] = _leaderboard[i].copyWith(rank: i + 1);
} }

View File

@ -8,8 +8,8 @@ class LocationService {
if (permission == LocationPermission.denied) { if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission(); permission = await Geolocator.requestPermission();
} }
return permission == LocationPermission.whileInUse || return permission == LocationPermission.whileInUse ||
permission == LocationPermission.always; permission == LocationPermission.always;
} }
static Future<bool> checkCameraPermission() async { static Future<bool> checkCameraPermission() async {
@ -34,24 +34,35 @@ class LocationService {
} }
static double calculateDistance( static double calculateDistance(
double lat1, double lon1, double lat1,
double lat2, double lon2, double lon1,
double lat2,
double lon2,
) { ) {
return Geolocator.distanceBetween(lat1, lon1, lat2, lon2); return Geolocator.distanceBetween(lat1, lon1, lat2, lon2);
} }
static bool isWithinRange( static bool isWithinRange(
double currentLat, double currentLon, double currentLat,
double targetLat, double targetLon, double currentLon,
{double rangeInMeters = 50.0} double targetLat,
) { double targetLon, {
double distance = calculateDistance(currentLat, currentLon, targetLat, targetLon); double rangeInMeters = 50.0,
}) {
double distance = calculateDistance(
currentLat,
currentLon,
targetLat,
targetLon,
);
return distance <= rangeInMeters; return distance <= rangeInMeters;
} }
static double getBearing( static double getBearing(
double startLat, double startLng, double startLat,
double endLat, double endLng, double startLng,
double endLat,
double endLng,
) { ) {
final startLatRad = startLat * (math.pi / 180); final startLatRad = startLat * (math.pi / 180);
final startLngRad = startLng * (math.pi / 180); final startLngRad = startLng * (math.pi / 180);
@ -61,10 +72,11 @@ class LocationService {
double dLng = endLngRad - startLngRad; double dLng = endLngRad - startLngRad;
double y = math.sin(dLng) * math.cos(endLatRad); double y = math.sin(dLng) * math.cos(endLatRad);
double x = math.cos(startLatRad) * math.sin(endLatRad) - double x =
math.cos(startLatRad) * math.sin(endLatRad) -
math.sin(startLatRad) * math.cos(endLatRad) * math.cos(dLng); math.sin(startLatRad) * math.cos(endLatRad) * math.cos(dLng);
double bearing = math.atan2(y, x); double bearing = math.atan2(y, x);
return (bearing * (180 / math.pi) + 360) % 360; // Convert to degrees return (bearing * (180 / math.pi) + 360) % 360;
} }
} }

View File

@ -1,28 +0,0 @@
// Quick test to verify Hunt feature works
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../hunt.dart';
class HuntTestApp extends StatelessWidget {
const HuntTestApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hunt Feature Test',
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
),
darkTheme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.dark,
),
home: const Hunt(), // This now properly creates its own provider
);
}
}
void main() {
runApp(const HuntTestApp());
}

View File

@ -0,0 +1,306 @@
import 'package:flutter/material.dart';
import 'package:lba/res/colors.dart';
class AnimatedRankBadge extends StatefulWidget {
final int rank;
final int totalPoints;
final String userName;
final bool showAnimation;
final VoidCallback? onTap;
const AnimatedRankBadge({
super.key,
required this.rank,
required this.totalPoints,
required this.userName,
this.showAnimation = true,
this.onTap,
});
@override
State<AnimatedRankBadge> createState() => _AnimatedRankBadgeState();
}
class _AnimatedRankBadgeState extends State<AnimatedRankBadge>
with TickerProviderStateMixin {
late AnimationController _pulseController;
late AnimationController _shimmerController;
late Animation<double> _pulseAnimation;
late Animation<double> _shimmerAnimation;
@override
void initState() {
super.initState();
_pulseController = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
);
_shimmerController = AnimationController(
duration: const Duration(milliseconds: 2000),
vsync: this,
);
_pulseAnimation = Tween<double>(
begin: 1.0,
end: 1.1,
).animate(CurvedAnimation(
parent: _pulseController,
curve: Curves.easeInOut,
));
_shimmerAnimation = Tween<double>(
begin: -1.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _shimmerController,
curve: Curves.easeInOut,
));
if (widget.showAnimation) {
_pulseController.repeat(reverse: true);
_shimmerController.repeat();
}
}
@override
void dispose() {
_pulseController.dispose();
_shimmerController.dispose();
super.dispose();
}
Color _getRankColor() {
switch (widget.rank) {
case 1:
return const Color(0xFFFFD700);
case 2:
return const Color(0xFFC0C0C0);
case 3:
return const Color(0xFFCD7F32);
default:
if (widget.rank <= 10) {
return AppColors.primary;
} else {
return AppColors.textSecondary;
}
}
}
IconData _getRankIcon() {
switch (widget.rank) {
case 1:
return Icons.emoji_events_rounded;
case 2:
return Icons.emoji_events_outlined;
case 3:
return Icons.emoji_events_outlined;
default:
if (widget.rank <= 10) {
return Icons.military_tech_rounded;
} else {
return Icons.person_rounded;
}
}
}
String _getRankSuffix() {
if (widget.rank == 1) return 'st';
if (widget.rank == 2) return 'nd';
if (widget.rank == 3) return 'rd';
return 'th';
}
@override
Widget build(BuildContext context) {
final isTopThree = widget.rank <= 3;
final rankColor = _getRankColor();
return GestureDetector(
onTap: widget.onTap,
child: AnimatedBuilder(
animation: widget.showAnimation ? _pulseAnimation : AlwaysStoppedAnimation(1.0),
builder: (context, child) {
return Transform.scale(
scale: widget.showAnimation ? _pulseAnimation.value : 1.0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: isTopThree
? [
rankColor,
rankColor.withOpacity(0.8),
]
: [
AppColors.cardBackground,
AppColors.cardBackground.withOpacity(0.8),
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: rankColor.withOpacity(0.3),
width: 1.5,
),
boxShadow: [
BoxShadow(
color: rankColor.withOpacity(0.3),
blurRadius: isTopThree ? 12 : 6,
offset: const Offset(0, 4),
spreadRadius: isTopThree ? 2 : 0,
),
],
),
child: Stack(
children: [
if (isTopThree && widget.showAnimation)
AnimatedBuilder(
animation: _shimmerAnimation,
builder: (context, child) {
return Positioned.fill(
child: ClipRRect(
borderRadius: BorderRadius.circular(18),
child: CustomPaint(
painter: ShimmerPainter(
progress: _shimmerAnimation.value,
color: Colors.white.withOpacity(0.3),
),
size: Size.infinite,
),
),
);
},
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isTopThree
? Colors.white.withOpacity(0.2)
: rankColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
_getRankIcon(),
color: isTopThree ? Colors.white : rankColor,
size: 20,
),
),
const SizedBox(width: 12),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'${widget.rank}${_getRankSuffix()}',
style: TextStyle(
color: isTopThree ? Colors.white : AppColors.textPrimary,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 4),
Text(
'Place',
style: TextStyle(
color: isTopThree ? Colors.white70 : AppColors.textSecondary,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 2),
Row(
children: [
Text(
widget.userName,
style: TextStyle(
color: isTopThree ? Colors.white70 : AppColors.textSecondary,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: isTopThree
? Colors.white.withOpacity(0.2)
: AppColors.confirmButton.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.stars_rounded,
color: isTopThree ? Colors.white : AppColors.confirmButton,
size: 12,
),
const SizedBox(width: 2),
Text(
'${widget.totalPoints}',
style: TextStyle(
color: isTopThree ? Colors.white : AppColors.confirmButton,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
],
),
],
),
],
),
),
);
},
),
);
}
}
class ShimmerPainter extends CustomPainter {
final double progress;
final Color color;
ShimmerPainter({required this.progress, required this.color});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..shader = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.transparent,
color,
Colors.transparent,
],
stops: const [0.0, 0.5, 1.0],
).createShader(Rect.fromLTWH(
size.width * progress - size.width * 0.3,
0,
size.width * 0.6,
size.height,
));
canvas.drawRect(Offset.zero & size, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

View File

@ -0,0 +1,240 @@
import 'package:flutter/material.dart';
import 'dart:math' as math;
class CelebrationOverlay extends StatefulWidget {
final Widget child;
final bool showCelebration;
final VoidCallback? onCelebrationComplete;
const CelebrationOverlay({
super.key,
required this.child,
this.showCelebration = false,
this.onCelebrationComplete,
});
@override
State<CelebrationOverlay> createState() => _CelebrationOverlayState();
}
class _CelebrationOverlayState extends State<CelebrationOverlay>
with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
late List<Particle> _particles;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 2500),
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.3, curve: Curves.easeOut),
));
_scaleAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.6, curve: Curves.elasticOut),
));
_particles = _generateParticles();
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
widget.onCelebrationComplete?.call();
}
});
}
@override
void didUpdateWidget(CelebrationOverlay oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.showCelebration && !oldWidget.showCelebration) {
_startCelebration();
}
}
void _startCelebration() {
_controller.reset();
_particles = _generateParticles();
_controller.forward();
}
List<Particle> _generateParticles() {
final random = math.Random();
return List.generate(30, (index) {
return Particle(
x: random.nextDouble(),
y: random.nextDouble(),
color: _getRandomColor(random),
size: 3.0 + random.nextDouble() * 5.0,
speedX: (random.nextDouble() - 0.5) * 2.0,
speedY: random.nextDouble() * -2.0 - 1.0,
);
});
}
Color _getRandomColor(math.Random random) {
final colors = [
const Color(0xFFFFD700), // Gold
const Color(0xFFFF6B35), // Orange
const Color(0xFF4ECDC4), // Teal
const Color(0xFF45B7D1), // Blue
const Color(0xFF96CEB4), // Green
const Color(0xFFFECEA8), // Peach
const Color(0xFFFF9FF3), // Pink
const Color(0xFFF9CA24), // Yellow
];
return colors[random.nextInt(colors.length)];
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
widget.child,
if (widget.showCelebration)
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Positioned.fill(
child: Opacity(
opacity: _fadeAnimation.value,
child: CustomPaint(
painter: CelebrationPainter(
particles: _particles,
progress: _controller.value,
scale: _scaleAnimation.value,
),
size: Size.infinite,
),
),
);
},
),
],
);
}
}
class Particle {
final double x;
final double y;
final Color color;
final double size;
final double speedX;
final double speedY;
Particle({
required this.x,
required this.y,
required this.color,
required this.size,
required this.speedX,
required this.speedY,
});
}
class CelebrationPainter extends CustomPainter {
final List<Particle> particles;
final double progress;
final double scale;
CelebrationPainter({
required this.particles,
required this.progress,
required this.scale,
});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..style = PaintingStyle.fill;
for (final particle in particles) {
final currentX = particle.x * size.width + particle.speedX * progress * size.width * 0.5;
final currentY = particle.y * size.height + particle.speedY * progress * size.height * 0.5;
final opacity = (1.0 - progress).clamp(0.0, 1.0);
paint.color = particle.color.withOpacity(opacity);
final rotation = progress * math.pi * 4;
canvas.save();
canvas.translate(currentX, currentY);
canvas.rotate(rotation);
if (particle.size > 6) {
_drawStar(canvas, paint, particle.size * scale);
} else {
canvas.drawCircle(Offset.zero, particle.size * scale, paint);
}
canvas.restore();
}
if (progress < 0.3 && scale > 0) {
_drawBurstEffect(canvas, size, progress, scale);
}
}
void _drawStar(Canvas canvas, Paint paint, double size) {
final path = Path();
final angleStep = (math.pi * 2) / 5;
final innerRadius = size * 0.4;
final outerRadius = size;
for (int i = 0; i < 10; i++) {
final angle = i * angleStep / 2;
final radius = i % 2 == 0 ? outerRadius : innerRadius;
final x = math.cos(angle) * radius;
final y = math.sin(angle) * radius;
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
path.close();
canvas.drawPath(path, paint);
}
void _drawBurstEffect(Canvas canvas, Size size, double progress, double scale) {
final center = Offset(size.width / 2, size.height / 2);
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 3.0;
final colors = [
const Color(0xFFFFD700),
const Color(0xFFFF6B35),
const Color(0xFF4ECDC4),
];
for (int i = 0; i < colors.length; i++) {
final radius = (progress * 150.0 * (i + 1)) * scale;
final opacity = (1.0 - progress).clamp(0.0, 1.0);
paint.color = colors[i].withOpacity(opacity * 0.5);
canvas.drawCircle(center, radius, paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

View File

@ -562,14 +562,12 @@ class AdvancedTargetPainter extends CustomPainter {
final primaryColor = isNear ? const Color(0xFF00E676) : const Color(0xFF2196F3); final primaryColor = isNear ? const Color(0xFF00E676) : const Color(0xFF2196F3);
final baseRadius = math.max(60.0, math.min(85.0, 100 - (distance / 2))); final baseRadius = math.max(60.0, math.min(85.0, 100 - (distance / 2)));
// Outer glow
paint paint
..color = primaryColor.withOpacity(0.1 * pulseValue) ..color = primaryColor.withOpacity(0.1 * pulseValue)
..strokeWidth = 20.0 ..strokeWidth = 20.0
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10); ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 10);
canvas.drawCircle(center, baseRadius, paint); canvas.drawCircle(center, baseRadius, paint);
// Main rotating rings
paint paint
..color = primaryColor.withOpacity(0.8) ..color = primaryColor.withOpacity(0.8)
..strokeWidth = 2.5 ..strokeWidth = 2.5
@ -580,13 +578,11 @@ class AdvancedTargetPainter extends CustomPainter {
canvas.drawArc(Rect.fromCircle(center: center, radius: baseRadius), canvas.drawArc(Rect.fromCircle(center: center, radius: baseRadius),
rotationValue * 2 * math.pi + 3, 2.5, false, paint); rotationValue * 2 * math.pi + 3, 2.5, false, paint);
// Inner static ring
paint paint
..color = primaryColor.withOpacity(0.4) ..color = primaryColor.withOpacity(0.4)
..strokeWidth = 1.5; ..strokeWidth = 1.5;
canvas.drawCircle(center, baseRadius - 15, paint); canvas.drawCircle(center, baseRadius - 15, paint);
// Scanning arc
if (!isNear) { if (!isNear) {
final sweepAngle = scanValue * 2 * math.pi; final sweepAngle = scanValue * 2 * math.pi;
paint paint
@ -601,7 +597,6 @@ class AdvancedTargetPainter extends CustomPainter {
); );
} }
// Success animation
if (isNear) { if (isNear) {
paint paint
..color = primaryColor.withOpacity(1.0 - pulseValue) ..color = primaryColor.withOpacity(1.0 - pulseValue)

View File

@ -1,4 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart'; import 'package:lba/res/colors.dart';
import '../models/hunt_card.dart'; import '../models/hunt_card.dart';
import 'hunt_timer_widget.dart'; import 'hunt_timer_widget.dart';
@ -98,7 +100,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
} }
void _openARHint() { void _openARHint() {
// Navigate to AR camera for location-based hints
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -367,7 +368,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Gaming-style icon container with floating effect
Container( Container(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -414,7 +414,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
), ),
), ),
const SizedBox(height: 15), const SizedBox(height: 15),
// Gaming-style mystery text with holographic effect
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -491,7 +490,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
), ),
), ),
), ),
// Gaming-style difficulty indicator with glow
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) { children: List.generate(3, (index) {
@ -557,7 +555,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Header with title and timer
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -607,7 +604,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
), ),
], ],
), ),
// Enhanced Timer
HuntTimerWidget( HuntTimerWidget(
timeRemaining: const Duration(hours: 12), timeRemaining: const Duration(hours: 12),
isActive: true, isActive: true,
@ -619,7 +615,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
const SizedBox(height: 10), const SizedBox(height: 10),
// Riddle section
Expanded( Expanded(
flex: 4, flex: 4,
child: Container( child: Container(
@ -694,7 +689,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
const SizedBox(height: 8), const SizedBox(height: 8),
// AR Hint section
Expanded( Expanded(
flex: 1, flex: 1,
child: GestureDetector( child: GestureDetector(
@ -732,14 +726,13 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon( SvgPicture.asset(
Icons.help, Assets.icons.infoCircle.path,
color: AppColors.isDarkMode color: AppColors.isDarkMode
? Colors.yellow.shade600 ? Colors.yellow.shade600
: const Color(0xFFE65100), : const Color(0xFFE65100),
size: 14,
), ),
const SizedBox(width: 6), const SizedBox(width: 3),
Text( Text(
'AR Smart Hint', 'AR Smart Hint',
style: TextStyle( style: TextStyle(
@ -758,7 +751,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
const SizedBox(height: 6), const SizedBox(height: 6),
// Action button
Container( Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 6), padding: const EdgeInsets.symmetric(vertical: 6),
@ -790,10 +782,10 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon( SvgPicture.asset(
Icons.location_on_rounded, Assets.icons.locationTick.path,
color: Colors.white, color: Colors.white,
size: 12, width: 14,
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
@ -819,7 +811,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
final pi = 3.14159; final pi = 3.14159;
if (isShowingFront) { if (isShowingFront) {
// Front side animated gradient
return LinearGradient( return LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
@ -863,7 +854,6 @@ class _HuntCardWidgetState extends State<HuntCardWidget>
], ],
); );
} else { } else {
// Back side animated gradient
return LinearGradient( return LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,

View File

@ -1,5 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart'; import 'package:lba/res/colors.dart';
class HuntTimerWidget extends StatefulWidget { class HuntTimerWidget extends StatefulWidget {
@ -75,7 +77,6 @@ class _HuntTimerWidgetState extends State<HuntTimerWidget>
if (_currentTime.inSeconds > 0) { if (_currentTime.inSeconds > 0) {
_currentTime = Duration(seconds: _currentTime.inSeconds - 1); _currentTime = Duration(seconds: _currentTime.inSeconds - 1);
// Pulse animation when time is running low
if (_currentTime.inMinutes < 5) { if (_currentTime.inMinutes < 5) {
_pulseController.forward().then((_) { _pulseController.forward().then((_) {
_pulseController.reverse(); _pulseController.reverse();
@ -158,14 +159,14 @@ class _HuntTimerWidgetState extends State<HuntTimerWidget>
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon( SvgPicture.asset(
isExpired isExpired
? Icons.timer_off_outlined ? Assets.icons.timerHunt.path
: _currentTime.inMinutes < 2 : _currentTime.inMinutes < 2
? Icons.timer_outlined ? Assets.icons.timerHunt.path
: Icons.timer_rounded, : Assets.icons.timerHunt.path,
color: timerColor, color: timerColor,
size: widget.fontSize != null ? widget.fontSize! + 2 : 14, width: widget.fontSize != null ? widget.fontSize! + 4 : 16,
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(

File diff suppressed because it is too large Load Diff