Compare commits
No commits in common. "126f499bd55d8800fd8acf3c0fad11015514edfa" and "250510c53d3a8a55940568af9404701f02026405" have entirely different histories.
126f499bd5
...
250510c53d
|
|
@ -1,6 +1,3 @@
|
|||
android/app/.cxx
|
||||
android/app/.cxx/Debug
|
||||
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@ android {
|
|||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
||||
coreLibraryDesugaringEnabled true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
|
|
@ -60,10 +58,10 @@ android {
|
|||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file("keystore.jks")
|
||||
storePassword "12799721"
|
||||
keyAlias "upload"
|
||||
keyPassword "12799721"
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
|
|
@ -71,7 +69,6 @@ android {
|
|||
signingConfig signingConfigs.release
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,5 +109,4 @@ dependencies {
|
|||
implementation "androidx.room:room-runtime:2.2.5"
|
||||
implementation "androidx.sqlite:sqlite-framework:2.1.0"
|
||||
implementation "androidx.sqlite:sqlite:2.1.0"
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ repositories {
|
|||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.2.1" apply false
|
||||
id "com.android.application" version "8.1.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.14592 0.145917C8.19236 0.0993539 8.24754 0.0624112 8.30828 0.0372047C8.36903 0.0119983 8.43415 -0.000976563 8.49992 -0.000976562C8.56568 -0.000976562 8.63081 0.0119983 8.69155 0.0372047C8.7523 0.0624112 8.80747 0.0993539 8.85392 0.145917L11.8539 3.14592C11.9005 3.19236 11.9374 3.24754 11.9626 3.30828C11.9878 3.36903 12.0008 3.43415 12.0008 3.49992C12.0008 3.56568 11.9878 3.63081 11.9626 3.69155C11.9374 3.7523 11.9005 3.80747 11.8539 3.85392L8.85392 6.85392C8.80743 6.9004 8.75224 6.93728 8.6915 6.96244C8.63076 6.9876 8.56566 7.00055 8.49992 7.00055C8.43417 7.00055 8.36907 6.9876 8.30833 6.96244C8.24759 6.93728 8.1924 6.9004 8.14592 6.85392C8.09943 6.80743 8.06255 6.75224 8.03739 6.6915C8.01223 6.63076 7.99929 6.56566 7.99929 6.49992C7.99929 6.43417 8.01223 6.36907 8.03739 6.30833C8.06255 6.24759 8.09943 6.1924 8.14592 6.14592L10.2929 3.99992H0.499917C0.367309 3.99992 0.240132 3.94724 0.146364 3.85347C0.0525958 3.7597 -8.27312e-05 3.63253 -8.27312e-05 3.49992C-8.27312e-05 3.36731 0.0525958 3.24013 0.146364 3.14636C0.240132 3.0526 0.367309 2.99992 0.499917 2.99992H10.2929L8.14592 0.853917C8.09935 0.807472 8.06241 0.752296 8.0372 0.691551C8.012 0.630806 7.99902 0.565685 7.99902 0.499917C7.99902 0.43415 8.012 0.369029 8.0372 0.308284C8.06241 0.247538 8.09935 0.192363 8.14592 0.145917ZM3.85392 7.14592C3.90048 7.19236 3.93742 7.24754 3.96263 7.30828C3.98784 7.36903 4.00081 7.43415 4.00081 7.49992C4.00081 7.56568 3.98784 7.63081 3.96263 7.69155C3.93742 7.7523 3.90048 7.80747 3.85392 7.85392L1.70692 9.99992H11.4999C11.6325 9.99992 11.7597 10.0526 11.8535 10.1464C11.9472 10.2401 11.9999 10.3673 11.9999 10.4999C11.9999 10.6325 11.9472 10.7597 11.8535 10.8535C11.7597 10.9472 11.6325 10.9999 11.4999 10.9999H1.70692L3.85392 13.1459C3.9478 13.2398 4.00055 13.3671 4.00055 13.4999C4.00055 13.6327 3.9478 13.76 3.85392 13.8539C3.76003 13.9478 3.63269 14.0005 3.49992 14.0005C3.36714 14.0005 3.2398 13.9478 3.14592 13.8539L0.145917 10.8539C0.0993539 10.8075 0.062411 10.7523 0.0372045 10.6916C0.0119981 10.6308 -0.000976562 10.5657 -0.000976562 10.4999C-0.000976562 10.4341 0.0119981 10.369 0.0372045 10.3083C0.062411 10.2475 0.0993539 10.1924 0.145917 10.1459L3.14592 7.14592C3.19236 7.09935 3.24754 7.06241 3.30828 7.0372C3.36903 7.012 3.43415 6.99902 3.49992 6.99902C3.56568 6.99902 3.63081 7.012 3.69155 7.0372C3.7523 7.06241 3.80747 7.09935 3.85392 7.14592Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="12" height="12" rx="6" fill="#2BB34A"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 156 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect y="0.5" width="12" height="12" rx="6" fill="#F00505"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 164 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 10C0 4.47715 4.47715 0 10 0H32V24H10C4.47715 24 0 19.5228 0 14V10Z" fill="#B30436"/>
|
||||
<path d="M10.375 9.875C10.1641 9.875 10 9.66406 10 9.5C10 9.3125 10.1641 9.125 10.375 9.125H18.25L18.2266 7.0625C18.2266 6.82812 18.3672 6.61719 18.5781 6.54688C18.7891 6.45312 19.0234 6.5 19.1875 6.64062L21.8125 9.07812C21.9297 9.19531 22 9.3125 22 9.5C22 9.66406 21.9297 9.80469 21.8125 9.92188L19.1875 12.3594C19.0234 12.5234 18.7891 12.5469 18.5781 12.4531C18.3672 12.3828 18.2266 12.1719 18.2266 11.9375L18.25 9.875H10.375ZM19 7.50781V11.5156L21.1562 9.5L19 7.50781ZM21.625 15.125C21.8125 15.125 22 15.3359 22 15.5C22 15.6875 21.8125 15.875 21.625 15.875H13.75V17.9375C13.75 18.1719 13.6094 18.3828 13.3984 18.4531C13.1875 18.5234 12.9531 18.5 12.7891 18.3359L10.1641 15.8984C10.0469 15.7812 10 15.6172 10 15.5C10 15.3594 10.0469 15.2188 10.1641 15.1016L12.7891 12.6641C12.9531 12.5 13.1875 12.4766 13.3984 12.5469C13.6094 12.6406 13.75 12.8516 13.75 13.0625V15.125H21.625ZM13 17.5156V13.5078L10.8203 15.5L13 17.5156Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.75391 1.16406C9.17578 0.707031 9.91406 0.707031 10.3359 1.16406C10.793 1.58594 10.793 2.32422 10.3359 2.74609L9.45703 3.625H14.625C16.4883 3.625 18 5.13672 18 7V8.125C18 8.75781 17.4727 9.25 16.875 9.25C16.2422 9.25 15.75 8.75781 15.75 8.125V7C15.75 6.40234 15.2227 5.875 14.625 5.875H9.45703L10.3359 6.78906C10.793 7.21094 10.793 7.94922 10.3359 8.37109C9.91406 8.82812 9.17578 8.82812 8.75391 8.37109L5.94141 5.55859C5.48438 5.13672 5.48438 4.39844 5.94141 3.97656L8.75391 1.16406ZM12.0234 12.9766C12.4805 13.3984 12.4805 14.1367 12.0234 14.5586L9.21094 17.3711C8.78906 17.8281 8.05078 17.8281 7.62891 17.3711C7.17188 16.9492 7.17188 16.2109 7.62891 15.7891L8.50781 14.875H3.375C2.74219 14.875 2.25 15.4023 2.25 16V17.125C2.25 17.7578 1.72266 18.25 1.125 18.25C0.492188 18.25 0 17.7578 0 17.125V16C0 14.1367 1.47656 12.625 3.375 12.625H8.50781L7.62891 11.7461C7.17188 11.3242 7.17188 10.5859 7.62891 10.1641C8.05078 9.70703 8.78906 9.70703 9.21094 10.1641L12.0234 12.9766ZM18 13.75C18 15.0156 16.9805 16 15.75 16C14.4844 16 13.5 15.0156 13.5 13.75C13.5 12.5195 14.4844 11.5 15.75 11.5C16.9805 11.5 18 12.5195 18 13.75ZM4.5 4.75C4.5 6.01562 3.48047 7 2.25 7C0.984375 7 0 6.01562 0 4.75C0 3.51953 0.984375 2.5 2.25 2.5C3.48047 2.5 4.5 3.51953 4.5 4.75Z" fill="#1B3C59"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.125 8.875C3.49219 8.875 3 8.3125 3 7.75C3 7.15234 3.49219 6.625 4.125 6.625H15.3398V4.09375C15.3398 3.77734 15.5508 3.46094 15.8672 3.32031C16.1836 3.21484 16.5352 3.25 16.7812 3.49609L20.7188 7.15234C21.0703 7.46875 21.0703 8.06641 20.7188 8.38281L16.7812 12.0391C16.5352 12.2852 16.1836 12.3203 15.8672 12.1797C15.5508 12.0742 15.3398 11.7578 15.3398 11.4062V8.875H4.125ZM19.875 15.625C20.4727 15.625 21 16.1523 21 16.75C21 17.3828 20.4727 17.875 19.875 17.875H8.625V20.4062C8.625 20.7578 8.41406 21.0742 8.09766 21.1797C7.78125 21.3203 7.42969 21.2852 7.18359 21.0391L3.24609 17.3828C2.89453 17.0664 2.89453 16.4688 3.24609 16.1523L7.18359 12.4961C7.42969 12.25 7.78125 12.2148 8.09766 12.3203C8.41406 12.4258 8.625 12.7422 8.625 13.0938V15.625H19.875Z" fill="#1B3C59"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 889 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.875 12.375H3.125V2.625C3.125 2.55625 3.06875 2.5 3 2.5H2.125C2.05625 2.5 2 2.55625 2 2.625V13.375C2 13.4438 2.05625 13.5 2.125 13.5H13.875C13.9438 13.5 14 13.4438 14 13.375V12.5C14 12.4312 13.9438 12.375 13.875 12.375ZM4.5 9.4375C4.5 9.70272 4.60536 9.95707 4.79289 10.1446C4.98043 10.3321 5.23478 10.4375 5.5 10.4375C5.76522 10.4375 6.01957 10.3321 6.20711 10.1446C6.39464 9.95707 6.5 9.70272 6.5 9.4375C6.5 9.17228 6.39464 8.91793 6.20711 8.73039C6.01957 8.54286 5.76522 8.4375 5.5 8.4375C5.23478 8.4375 4.98043 8.54286 4.79289 8.73039C4.60536 8.91793 4.5 9.17228 4.5 9.4375ZM6.34375 5.9375C6.34375 6.13641 6.42277 6.32718 6.56342 6.46783C6.70407 6.60848 6.89484 6.6875 7.09375 6.6875C7.29266 6.6875 7.48343 6.60848 7.62408 6.46783C7.76473 6.32718 7.84375 6.13641 7.84375 5.9375C7.84375 5.73859 7.76473 5.54782 7.62408 5.40717C7.48343 5.26652 7.29266 5.1875 7.09375 5.1875C6.89484 5.1875 6.70407 5.26652 6.56342 5.40717C6.42277 5.54782 6.34375 5.73859 6.34375 5.9375ZM8.8125 9.5C8.8125 9.89782 8.97054 10.2794 9.25184 10.5607C9.53314 10.842 9.91468 11 10.3125 11C10.7103 11 11.0919 10.842 11.3732 10.5607C11.6545 10.2794 11.8125 9.89782 11.8125 9.5C11.8125 9.10218 11.6545 8.72064 11.3732 8.43934C11.0919 8.15804 10.7103 8 10.3125 8C9.91468 8 9.53314 8.15804 9.25184 8.43934C8.97054 8.72064 8.8125 9.10218 8.8125 9.5ZM11.125 4.59375C11.125 4.82581 11.2172 5.04837 11.3813 5.21247C11.5454 5.37656 11.7679 5.46875 12 5.46875C12.2321 5.46875 12.4546 5.37656 12.6187 5.21247C12.7828 5.04837 12.875 4.82581 12.875 4.59375C12.875 4.36169 12.7828 4.13913 12.6187 3.97503C12.4546 3.81094 12.2321 3.71875 12 3.71875C11.7679 3.71875 11.5454 3.81094 11.3813 3.97503C11.2172 4.13913 11.125 4.36169 11.125 4.59375Z" fill="#666666"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.207 2.28998L19.207 6.28598C19.3793 6.45805 19.4829 6.68708 19.4984 6.93011C19.5139 7.17314 19.4401 7.41346 19.291 7.60598L19.208 7.69998L15.208 11.706C15.0285 11.8872 14.7864 11.993 14.5315 12.0017C14.2765 12.0103 14.0278 11.9212 13.8364 11.7525C13.645 11.5838 13.5253 11.3484 13.5018 11.0944C13.4783 10.8403 13.5528 10.5869 13.71 10.386L13.793 10.292L16.083 7.99998H5.5C5.25507 7.99995 5.01866 7.91003 4.83563 7.74727C4.65259 7.58451 4.53566 7.36023 4.507 7.11698L4.5 6.99898C4.50003 6.75405 4.58996 6.51765 4.75272 6.33461C4.91547 6.15158 5.13975 6.03464 5.383 6.00598L5.5 5.99898H16.09L13.794 3.70598C13.6217 3.53392 13.5181 3.30488 13.5026 3.06185C13.4871 2.81883 13.5609 2.5785 13.71 2.38598L13.793 2.29098C13.9651 2.11866 14.1941 2.01504 14.4371 1.99958C14.6802 1.98411 14.9205 2.05786 15.113 2.20698L15.207 2.28998ZM19.491 16.882L19.497 16.999C19.497 17.2439 19.407 17.4803 19.2443 17.6634C19.0815 17.8464 18.8573 17.9633 18.614 17.992L18.497 17.999H7.914L10.208 20.292C10.3802 20.4642 10.4836 20.6933 10.4989 20.9363C10.5142 21.1793 10.4403 21.4196 10.291 21.612L10.208 21.706C10.0359 21.8783 9.8069 21.9819 9.56387 21.9974C9.32084 22.0129 9.08052 21.9391 8.888 21.79L8.794 21.706L4.794 17.71C4.62168 17.5379 4.51806 17.3089 4.50259 17.0659C4.48713 16.8228 4.56088 16.5825 4.71 16.39L4.793 16.296L8.793 12.292C8.97254 12.1107 9.21457 12.005 9.46955 11.9963C9.72453 11.9876 9.97317 12.0768 10.1646 12.2454C10.356 12.4141 10.4757 12.6496 10.4992 12.9036C10.5227 13.1576 10.4482 13.4111 10.291 13.612L10.208 13.706L7.918 15.999H18.498C18.7429 15.999 18.9793 16.0889 19.1624 16.2517C19.3454 16.4145 19.4623 16.6387 19.491 16.882Z" fill="#195D80"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,20 +0,0 @@
|
|||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_8341_39661)">
|
||||
<rect x="8" y="8" width="56" height="56" rx="10" fill="#181B1F"/>
|
||||
<path d="M26.1502 40.9985C25.5013 39.5318 25.1663 37.9456 25.1668 36.3418C25.1668 30.1668 30.0168 25.1651 36.0002 25.1651C41.9835 25.1651 46.8335 30.1685 46.8335 36.3418C46.834 37.9456 46.4991 39.5318 45.8502 40.9985M36.0002 19.3318V20.9985M52.6668 35.9985H51.0002M21.0002 35.9985H19.3335M47.7835 24.2135L46.6052 25.3918M25.3952 25.3935L24.2168 24.2151M40.1952 48.1768C41.8785 47.6318 42.5552 46.0901 42.7452 44.5401C42.8018 44.0768 42.4202 43.6918 41.9535 43.6918H30.1285C30.0145 43.69 29.9015 43.7124 29.7968 43.7575C29.6922 43.8027 29.5983 43.8695 29.5214 43.9536C29.4445 44.0378 29.3864 44.1373 29.3508 44.2456C29.3153 44.3538 29.3031 44.4685 29.3152 44.5818C29.5018 46.1285 29.9718 47.2585 31.7552 48.1751M40.1952 48.1768L31.7552 48.1751M40.1952 48.1768C39.9935 51.4185 39.0568 52.7018 36.0118 52.6651C32.7552 52.7251 32.0052 51.1368 31.7552 48.1751" stroke="#B8B8B8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M31.2627 33.6231C33.3296 29.9575 34.363 28.125 36 28.125C37.637 28.125 38.6704 29.9575 40.7373 33.6231L40.9952 34.0792C42.7129 37.1251 43.5721 38.648 42.7958 39.7615C42.0194 40.875 40.0984 40.875 36.2578 40.875H35.7422C31.9016 40.875 29.9806 40.875 29.2043 39.7615C28.4279 38.648 29.2871 37.1251 31.0048 34.0792L31.2627 33.6231Z" stroke="#007EA7" stroke-width="0.944444"/>
|
||||
<path d="M36 31.6667V35.2084" stroke="#007EA7" stroke-width="0.944444" stroke-linecap="round"/>
|
||||
<path d="M35.9998 38.0417C36.391 38.0417 36.7082 37.7245 36.7082 37.3333C36.7082 36.9421 36.391 36.625 35.9998 36.625C35.6086 36.625 35.2915 36.9421 35.2915 37.3333C35.2915 37.7245 35.6086 38.0417 35.9998 38.0417Z" fill="#007EA7"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_8341_39661" x="0" y="0" width="72" height="72" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="4"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.301961 0 0 0 0 0.301961 0 0 0 0 0.301961 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_8341_39661"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_8341_39661" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB |
|
|
@ -1,6 +0,0 @@
|
|||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.1502 24.9985C9.50126 23.5318 9.16631 21.9456 9.16683 20.3418C9.16683 14.1668 14.0168 9.16512 20.0002 9.16512C25.9835 9.16512 30.8335 14.1685 30.8335 20.3418C30.834 21.9456 30.4991 23.5318 29.8502 24.9985M20.0002 3.33179V4.99845M36.6668 19.9985H35.0002M5.00016 19.9985H3.3335M31.7835 8.21345L30.6052 9.39179M9.39516 9.39345L8.21683 8.21512M24.1952 32.1768C25.8785 31.6318 26.5552 30.0901 26.7452 28.5401C26.8018 28.0768 26.4202 27.6918 25.9535 27.6918H14.1285C14.0145 27.69 13.9015 27.7124 13.7968 27.7575C13.6922 27.8027 13.5983 27.8695 13.5214 27.9536C13.4445 28.0378 13.3864 28.1373 13.3508 28.2456C13.3153 28.3538 13.3031 28.4685 13.3152 28.5818C13.5018 30.1285 13.9718 31.2585 15.7552 32.1751M24.1952 32.1768L15.7552 32.1751M24.1952 32.1768C23.9935 35.4185 23.0568 36.7018 20.0118 36.6651C16.7552 36.7251 16.0052 35.1368 15.7552 32.1751" stroke="#1B3C59" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.2627 17.6231C17.3296 13.9575 18.363 12.125 20 12.125C21.637 12.125 22.6704 13.9575 24.7373 17.6231L24.9952 18.0792C26.7129 21.1251 27.5721 22.648 26.7958 23.7615C26.0194 24.875 24.0984 24.875 20.2578 24.875H19.7422C15.9016 24.875 13.9806 24.875 13.2043 23.7615C12.4279 22.648 13.2871 21.1251 15.0048 18.0792L15.2627 17.6231Z" stroke="#B30436" stroke-width="0.944444"/>
|
||||
<path d="M20 15.6667V19.2084" stroke="#B30436" stroke-width="0.944444" stroke-linecap="round"/>
|
||||
<path d="M19.9998 22.0417C20.391 22.0417 20.7082 21.7245 20.7082 21.3333C20.7082 20.9421 20.391 20.625 19.9998 20.625C19.6086 20.625 19.2915 20.9421 19.2915 21.3333C19.2915 21.7245 19.6086 22.0417 19.9998 22.0417Z" fill="#B30436"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -84,7 +84,6 @@ class Assets {
|
|||
static String get risk => '$_baseFeaturesPath/risk-$_themeSuffix.svg';
|
||||
static String get saha => '$_baseFeaturesPath/saha-$_themeSuffix.svg';
|
||||
static String get ai => '$_baseFeaturesPath/ai-$_themeSuffix.svg';
|
||||
static String get hugeideas => '$_baseFeaturesPath/hugeicons_idea-$_themeSuffix.svg';
|
||||
static String get startup => '$_baseFeaturesPath/startup-$_themeSuffix.svg';
|
||||
static String get stats => '$_baseFeaturesPath/stats-$_themeSuffix.svg';
|
||||
static String get tech => '$_baseFeaturesPath/tech-$_themeSuffix.svg';
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
class SwotItem {
|
||||
final int id;
|
||||
final String title;
|
||||
final String description;
|
||||
final String category;
|
||||
final String type;
|
||||
final String imageUrl;
|
||||
final double x1;
|
||||
final double y1;
|
||||
final String createdAt;
|
||||
|
||||
SwotItem({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.category,
|
||||
required this.type,
|
||||
required this.imageUrl,
|
||||
required this.x1,
|
||||
required this.y1,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory SwotItem.fromJson(Map<String, dynamic> json) {
|
||||
return SwotItem(
|
||||
id: json['id'],
|
||||
title: json['title'],
|
||||
description: json['description'],
|
||||
category: json['category'],
|
||||
type: json['type'],
|
||||
imageUrl: json["url"],
|
||||
x1: json["scoreX1"],
|
||||
y1: json["scoreY1"],
|
||||
createdAt: json["createdAt"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
class Note {
|
||||
final int postId;
|
||||
final String content;
|
||||
|
||||
Note({required this.postId, required this.content});
|
||||
|
||||
factory Note.fromJson(Map<String, dynamic> json) {
|
||||
return Note(
|
||||
postId: json['postId'],
|
||||
content: json['content'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'postId': postId,
|
||||
'content': content,
|
||||
};
|
||||
}
|
||||
|
|
@ -299,19 +299,14 @@ class RouteGenerator {
|
|||
),
|
||||
);
|
||||
case Routes.filteredBookmarks:
|
||||
final args = settings.arguments as Map<String, dynamic>;
|
||||
final type = args['type'] as int;
|
||||
final onDeleted = args['onDeleted'] as void Function(int id)?;
|
||||
|
||||
return _createRoute(
|
||||
ChangeNotifierProvider<FilteredBookmarksState>(
|
||||
create: (context) => FilteredBookmarksState(
|
||||
type,
|
||||
(settings.arguments as Map<String, dynamic>)['type'],
|
||||
),
|
||||
child: FilteredBookmarks(
|
||||
onDeleted: onDeleted,
|
||||
type: type,
|
||||
),
|
||||
onDeleted:
|
||||
(settings.arguments as Map<String, dynamic>)['onDeleted']),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import 'package:didvan/models/requests/studio.dart';
|
|||
|
||||
class RequestHelper {
|
||||
static const String baseUrl = 'https://api.didvan.app';
|
||||
static const String baseUrl2 = 'http://opportunity-threat.didvan.com';
|
||||
static const String _baseUserUrl = '$baseUrl/user';
|
||||
static const String _baseRadarUrl = '$baseUrl/radar';
|
||||
static const String _baseNewsUrl = '$baseUrl/news';
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:didvan/models/note.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:http/http.dart' as RequestServices;
|
||||
|
||||
class NoteService {
|
||||
static Future<Note?> getNoteByPostId(int postId) async {
|
||||
try {
|
||||
final response = await RequestServices.get(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/notes'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
},
|
||||
);
|
||||
print(
|
||||
'Get note - PostId: $postId, Status: ${response.statusCode}, Body: ${response.body}');
|
||||
if (response.statusCode == 200) {
|
||||
final List data = jsonDecode(response.body);
|
||||
print('Notes list: $data');
|
||||
final note = data.firstWhere(
|
||||
(e) => e['postId'] == postId,
|
||||
orElse: () => null,
|
||||
);
|
||||
print('Found note for PostId $postId: $note');
|
||||
return note != null ? Note.fromJson(note) : null;
|
||||
}
|
||||
print('Failed to get note: ${response.statusCode}, ${response.body}');
|
||||
return null;
|
||||
} catch (e) {
|
||||
print('Error in getNoteByPostId: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> saveNote(int postId, String content) async {
|
||||
try {
|
||||
final response = await RequestServices.post(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/notes'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: jsonEncode({
|
||||
'postId': postId,
|
||||
'content': content,
|
||||
}),
|
||||
);
|
||||
print(
|
||||
'Save note - PostId: $postId, Status: ${response.statusCode}, Body: ${response.body}');
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
try {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
if (responseBody['postId'] == postId &&
|
||||
responseBody['content'] == content) {
|
||||
return true;
|
||||
} else {
|
||||
print(
|
||||
'Server returned success status but data mismatch: ${response.body}');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error parsing response body: $e');
|
||||
return response.statusCode == 200 || response.statusCode == 201;
|
||||
}
|
||||
} else {
|
||||
print('Failed to save note: ${response.statusCode}, ${response.body}');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error in saveNote: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> deleteNote(int postId) async {
|
||||
final response = await RequestServices.delete(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/notes/post/$postId'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
},
|
||||
);
|
||||
return response.statusCode == 200;
|
||||
}
|
||||
|
||||
static Future<bool> updateNote(int postId, String content) async {
|
||||
try {
|
||||
final response = await RequestServices.put(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/notes/post/$postId'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'postId': postId,
|
||||
'content': content,
|
||||
}),
|
||||
);
|
||||
print(
|
||||
'Update note - PostId: $postId, Status: ${response.statusCode}, Body: ${response.body}');
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
try {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
if (responseBody['postId'] == postId &&
|
||||
responseBody['content'] == content) {
|
||||
return true;
|
||||
} else {
|
||||
print(
|
||||
'Server returned success status but data mismatch: ${response.body}');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error parsing response body: $e');
|
||||
return response.statusCode == 200 || response.statusCode == 201;
|
||||
}
|
||||
} else {
|
||||
print('Failed to update note: ${response.statusCode}, ${response.body}');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error in updateNote: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class SwotService {
|
||||
static Future<List<SwotItem>> fetchSwotItems() async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/swot'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
},
|
||||
);
|
||||
|
||||
print("Status Code: ${response.statusCode}");
|
||||
|
||||
// decode manually using utf8.decode on bodyBytes
|
||||
final decodedBody = utf8.decode(response.bodyBytes);
|
||||
print("Decoded Response Body: $decodedBody");
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final jsonData = json.decode(decodedBody);
|
||||
|
||||
if (jsonData['content'] == null || jsonData['content'] is! List) {
|
||||
throw Exception('The data structure is wrong.');
|
||||
}
|
||||
|
||||
final List<dynamic> items = jsonData['content'];
|
||||
return items.map((e) => SwotItem.fromJson(e)).toList();
|
||||
} else {
|
||||
throw Exception('Error receiving data - statusCode: ${response.statusCode}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart' as RequestServicess;
|
||||
|
||||
class BookmarkService {
|
||||
static Future<List<int>> fetchBookmarks() async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/bookmarks'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
},
|
||||
);
|
||||
print("fetchBookmarks: ${response.statusCode} - ${response.body}");
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as List;
|
||||
return data.map<int>((e) => e['postId'] as int).toList();
|
||||
} else {
|
||||
throw Exception("Failed to fetch bookmarks");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<int>> fetchSwotBookmarks() async {
|
||||
final response = await http.get(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/swot_bookmarks'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
print("fetchSwotBookmarks: ${response.statusCode} - ${response.body}");
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as List;
|
||||
return data.map<int>((e) => e['swotId'] as int).toList();
|
||||
} else {
|
||||
throw Exception("Failed to fetch swot bookmarks");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> addSwotBookmark(int swotId) async {
|
||||
final response = await http.post(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/swot_bookmarks'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({'swotId': swotId}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 201) {
|
||||
throw Exception("Failed to add swot bookmark");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> removeSwotBookmark(int swotId) async {
|
||||
final response = await http.delete(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/swot_bookmarks/swot/$swotId'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
||||
throw Exception("Failed to remove swot bookmark");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<SwotItem>> fetchBookmarkedSwotItems() async {
|
||||
final postIds = await fetchBookmarks(); // استفاده از همان لیست بوکمارکها
|
||||
final List<SwotItem> items = [];
|
||||
|
||||
for (final postId in postIds) {
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse("${RequestHelper.baseUrl2}/api/swot_items/$postId"),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final postData = jsonDecode(response.body);
|
||||
items.add(SwotItem.fromJson(postData));
|
||||
} else {
|
||||
print('Error fetching swot item $postId: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching swot item $postId: $e');
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static Future<void> addBookmark(int postId) async {
|
||||
final response = await http.post(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/bookmarks'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode({'postId': postId}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 201) {
|
||||
throw Exception("Failed to add bookmark");
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> removeBookmark(int postId) async {
|
||||
final response = await http.delete(
|
||||
Uri.parse('${RequestHelper.baseUrl2}/api/bookmarks/post/$postId'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
||||
throw Exception("Failed to remove bookmark");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +1,29 @@
|
|||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/overview_data.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/providers/core.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||||
import 'package:didvan/services/swot_service.dart';
|
||||
|
||||
class BookmarksState extends CoreProvier {
|
||||
final List<OverviewData> bookmarks = [];
|
||||
List<SwotItem> bookmarkedSwotItems = [];
|
||||
|
||||
String search = '';
|
||||
String lastSearch = '';
|
||||
int page = 1;
|
||||
int lastPage = 1;
|
||||
|
||||
bool _swotItemsLoading = false;
|
||||
bool get searching => search.isNotEmpty;
|
||||
bool get swotItemsLoading => _swotItemsLoading;
|
||||
bool get searching => search != '';
|
||||
|
||||
Future<void> loadInitialData() async {
|
||||
appState = AppState.busy;
|
||||
_swotItemsLoading = true;
|
||||
Future<void> getBookmarks({required int page}) async {
|
||||
if (search != '') {
|
||||
lastSearch = search;
|
||||
}
|
||||
if (page == 1) {
|
||||
bookmarks.clear();
|
||||
bookmarkedSwotItems.clear();
|
||||
notifyListeners();
|
||||
|
||||
await Future.wait([
|
||||
_fetchGeneralBookmarks(page: 1),
|
||||
_fetchSwotBookmarks(),
|
||||
]);
|
||||
|
||||
|
||||
if (appState != AppState.failed && !searching) {
|
||||
appState = AppState.idle;
|
||||
} else if (appState != AppState.failed && searching && bookmarks.isEmpty && bookmarkedSwotItems.isEmpty) {
|
||||
|
||||
appState = AppState.idle;
|
||||
}
|
||||
_swotItemsLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _fetchGeneralBookmarks({required int page}) async {
|
||||
if (page == 1) bookmarks.clear();
|
||||
this.page = page;
|
||||
if (!searching) lastSearch = search;
|
||||
|
||||
appState = AppState.busy;
|
||||
final service = RequestService(
|
||||
RequestHelper.searchMarks(page: page, search: search.isNotEmpty ? search : null),
|
||||
RequestHelper.searchMarks(page: page, search: search),
|
||||
);
|
||||
await service.httpGet();
|
||||
if (service.isSuccess) {
|
||||
|
|
@ -58,56 +32,15 @@ class BookmarksState extends CoreProvier {
|
|||
for (var i = 0; i < marks.length; i++) {
|
||||
bookmarks.add(OverviewData.fromJson(marks[i]));
|
||||
}
|
||||
} else {
|
||||
appState = AppState.failed;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> searchAndLoadData({required int page}) async {
|
||||
appState = AppState.busy;
|
||||
_swotItemsLoading = true;
|
||||
bookmarks.clear();
|
||||
notifyListeners();
|
||||
|
||||
await Future.wait([
|
||||
_fetchGeneralBookmarks(page: page),
|
||||
_fetchSwotBookmarks(),
|
||||
]);
|
||||
|
||||
if (appState != AppState.failed) {
|
||||
appState = AppState.idle;
|
||||
return;
|
||||
}
|
||||
_swotItemsLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
Future<void> _fetchSwotBookmarks() async {
|
||||
try {
|
||||
final postIds = await BookmarkService.fetchBookmarks();
|
||||
if (postIds.isNotEmpty) {
|
||||
final allSwots = await SwotService.fetchSwotItems();
|
||||
|
||||
bookmarkedSwotItems = allSwots.where((swot) {
|
||||
final isBookmarked = postIds.contains(swot.id);
|
||||
if (search.isEmpty) return isBookmarked;
|
||||
return isBookmarked && swot.title.toLowerCase().contains(search.toLowerCase());
|
||||
}).toList();
|
||||
} else {
|
||||
bookmarkedSwotItems = [];
|
||||
}
|
||||
} catch (e) {
|
||||
bookmarkedSwotItems = [];
|
||||
}
|
||||
appState = AppState.failed;
|
||||
}
|
||||
|
||||
void onMarkChanged(int id, bool value) {
|
||||
if (value) return;
|
||||
bookmarks.removeWhere((element) => element.id == id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void onSwotMarkChanged(int swotId) {
|
||||
bookmarkedSwotItems.removeWhere((element) => element.id == swotId);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,15 +4,14 @@ import 'package:didvan/config/design_config.dart';
|
|||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_state.dart';
|
||||
import 'package:didvan/views/home/main/widgets/swot_bookmark.dart';
|
||||
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/menu_item.dart';
|
||||
import 'package:didvan/views/widgets/overview/multitype.dart';
|
||||
// import 'package:didvan/views/widgets/search_field.dart';
|
||||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
|
|
@ -20,7 +19,6 @@ import 'package:didvan/views/widgets/item_title.dart';
|
|||
import 'package:didvan/views/widgets/state_handlers/empty_result.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class Bookmarks extends StatefulWidget {
|
||||
|
|
@ -30,36 +28,16 @@ class Bookmarks extends StatefulWidget {
|
|||
State<Bookmarks> createState() => _BookmarksState();
|
||||
}
|
||||
|
||||
|
||||
class _BookmarksState extends State<Bookmarks> {
|
||||
final _focuseNode = FocusNode();
|
||||
Timer? _timer;
|
||||
// Timer? _timer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
Future.delayed(Duration.zero, () {
|
||||
context.read<BookmarksState>().getBookmarks(page: 1);
|
||||
});
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
context.read<BookmarksState>().loadInitialData();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void _onSearchChanged(String value) {
|
||||
final state = context.read<BookmarksState>();
|
||||
if (value.length < 3 && value.isNotEmpty) {
|
||||
if (state.search.isNotEmpty && value.isEmpty) {
|
||||
state.search = value;
|
||||
state.loadInitialData();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (state.lastSearch == value && value.isNotEmpty) return;
|
||||
|
||||
_timer?.cancel();
|
||||
_timer = Timer(const Duration(milliseconds: 700), () {
|
||||
state.search = value;
|
||||
state.searchAndLoadData(page: 1);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -76,6 +54,7 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
sliver: SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
AnimatedVisibility(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
isVisible: !state.searching,
|
||||
|
|
@ -130,18 +109,10 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
icon: DidvanIcons.infography_regular,
|
||||
iconSize: 24,
|
||||
),
|
||||
const DidvanDivider(),
|
||||
MenuOption(
|
||||
onTap: () => _onCategorySelected(8),
|
||||
title: 'فرصت و تهدید',
|
||||
iconWidget: SvgPicture.asset("lib/assets/images/features/Saha Solid.svg",width: 24,),
|
||||
iconSize: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!state.searching || (state.bookmarks.isNotEmpty || state.bookmarkedSwotItems.isNotEmpty))
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: AnimatedVisibility(
|
||||
|
|
@ -154,13 +125,33 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
),
|
||||
),
|
||||
),
|
||||
|
||||
SliverStateHandler<BookmarksState>(
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
),
|
||||
sliver: SliverStateHandler<BookmarksState>(
|
||||
state: state,
|
||||
enableEmptyState: state.bookmarks.isEmpty && state.bookmarkedSwotItems.isEmpty && !state.searching && !state.swotItemsLoading,
|
||||
emptyState: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
centerEmptyState: state.searching,
|
||||
builder: (context, state, index) {
|
||||
index++;
|
||||
if (index % 15 == 0 && state.lastPage != state.page) {
|
||||
state.getBookmarks(page: state.page + 1);
|
||||
}
|
||||
index--;
|
||||
return MultitypeOverview(
|
||||
item: state.bookmarks[index],
|
||||
onMarkChanged: state.onMarkChanged,
|
||||
hasUnmarkConfirmation: true,
|
||||
enableCaption: true,
|
||||
enableBookmark: true,
|
||||
);
|
||||
},
|
||||
placeholder: MultitypeOverview.placeholder,
|
||||
itemPadding: const EdgeInsets.only(bottom: 8),
|
||||
paddingEmptyState: 0,
|
||||
emptyState: state.searching
|
||||
? EmptyResult(onNewSearch: _focuseNode.requestFocus)
|
||||
: Column(
|
||||
children: [
|
||||
DidvanText(
|
||||
'در قسمت رصدخانه من، تمامی مطالبی که در قسمتهای مختلف سوپراپلیکیشن دیدوان، بوکمارک (نشاندار) کردهاید، به تفکیک نمایش داده میشوند. همچنین امکان درج یادداشت شخصی بصورت ضمیمه برای هر محتوا وجود دارد.',
|
||||
|
|
@ -175,76 +166,28 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
),
|
||||
],
|
||||
),
|
||||
placeholder: state.searching && state.bookmarks.isEmpty && state.bookmarkedSwotItems.isEmpty && !state.swotItemsLoading
|
||||
? EmptyResult(onNewSearch: _focuseNode.requestFocus)
|
||||
: MultitypeOverview.placeholder,
|
||||
builder: (context, state, index) {
|
||||
|
||||
if (index >= state.bookmarks.length) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return MultitypeOverview(
|
||||
item: state.bookmarks[index],
|
||||
onMarkChanged: state.onMarkChanged,
|
||||
hasUnmarkConfirmation: true,
|
||||
enableCaption: true,
|
||||
enableBookmark: true,
|
||||
);
|
||||
},
|
||||
itemPadding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
childCount: state.bookmarks.length + (state.page != state.lastPage && state.bookmarks.isNotEmpty ? 1 : 0),
|
||||
onRetry: () => state.loadInitialData(),
|
||||
enableEmptyState: state.bookmarks.isEmpty,
|
||||
childCount:
|
||||
state.bookmarks.length + (state.page != state.lastPage ? 1 : 0),
|
||||
onRetry: () => state.getBookmarks(page: state.page),
|
||||
),
|
||||
|
||||
if (state.appState == AppState.idle && state.bookmarkedSwotItems.isNotEmpty)
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final item = state.bookmarkedSwotItems[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: SwotBookmark(
|
||||
item: item,
|
||||
onSwotUnbookmarked: (postId) {
|
||||
state.onSwotMarkChanged(postId);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: state.bookmarkedSwotItems.length,
|
||||
),
|
||||
)
|
||||
else if (state.swotItemsLoading)
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(child: MultitypeOverview.placeholder),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onCategorySelected(int type) {
|
||||
FocusScope.of(context).unfocus();
|
||||
final state = context.read<BookmarksState>();
|
||||
|
||||
Navigator.of(context).pushNamed(Routes.filteredBookmarks, arguments: {
|
||||
'type': type,
|
||||
'onDeleted': (int id) {
|
||||
final state = context.read<BookmarksState>();
|
||||
state.bookmarks.removeWhere(
|
||||
(element) => element.id == id && element.typeInteger == type);
|
||||
|
||||
if (type == 8) {
|
||||
state.bookmarkedSwotItems.removeWhere((element) => element.id == id);
|
||||
}
|
||||
state.update();
|
||||
},
|
||||
}).then((_) {
|
||||
state.loadInitialData();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// void _onChanged(String value) {
|
||||
// final state = context.read<BookmarksState>();
|
||||
|
|
@ -257,4 +200,4 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
// state.getBookmarks(page: 1);
|
||||
// });
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/views/home/bookmarks/filtered_bookmark/filtered_bookmarks_state.dart';
|
||||
import 'package:didvan/views/widgets/overview/multitype.dart';
|
||||
import 'package:didvan/views/widgets/overview/radar.dart';
|
||||
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/empty_list.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:didvan/views/home/main/widgets/swot_bookmark.dart';
|
||||
|
||||
class FilteredBookmarks extends StatefulWidget {
|
||||
final void Function(int id)? onDeleted;
|
||||
final int type;
|
||||
const FilteredBookmarks({Key? key, this.onDeleted, required this.type}) : super(key: key);
|
||||
const FilteredBookmarks({Key? key, this.onDeleted}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<FilteredBookmarks> createState() => _FilteredBookmarksState();
|
||||
|
|
@ -20,18 +19,15 @@ class FilteredBookmarks extends StatefulWidget {
|
|||
class _FilteredBookmarksState extends State<FilteredBookmarks> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
final state = context.read<FilteredBookmarksState>();
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => state.getBookmarks(page: 1),
|
||||
() => context.read<FilteredBookmarksState>().getBookmarks(page: 1),
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
String get _appBarTitle {
|
||||
|
||||
switch (widget.type) {
|
||||
switch (context.read<FilteredBookmarksState>().type) {
|
||||
case 1:
|
||||
return 'پویش افق';
|
||||
case 2:
|
||||
|
|
@ -46,83 +42,85 @@ class _FilteredBookmarksState extends State<FilteredBookmarks> {
|
|||
return 'سها';
|
||||
case 7:
|
||||
return 'اینفوگرافی';
|
||||
case 8:
|
||||
return 'فرصت و تهدید';
|
||||
default:
|
||||
return 'پویش';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onBookmarkChanged(int id, bool value, bool shouldUpdate, String itemType) async {
|
||||
if (value) return;
|
||||
widget.onDeleted?.call(id);
|
||||
|
||||
if (itemType == "swot") {
|
||||
context.read<FilteredBookmarksState>().onSwotMarkChanged(id);
|
||||
} else {
|
||||
context.read<FilteredBookmarksState>().onMarkChanged(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final state = context.watch<FilteredBookmarksState>();
|
||||
|
||||
return DidvanScaffold(
|
||||
appBarData: AppBarData(title: _appBarTitle, hasBack: true),
|
||||
appBarData: AppBarData(title: _appBarTitle),
|
||||
padding: const EdgeInsets.all(16),
|
||||
slivers: [
|
||||
if (widget.type == 8)
|
||||
SliverStateHandler<FilteredBookmarksState>(
|
||||
state: state,
|
||||
enableEmptyState: state.bookmarkedSwotItems.isEmpty && !state.swotItemsLoading,
|
||||
emptyState: const EmptyList(),
|
||||
placeholder: MultitypeOverview.placeholder,
|
||||
builder: (context, state, index) {
|
||||
final item = state.bookmarkedSwotItems[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: SwotBookmark(
|
||||
item: item,
|
||||
onSwotUnbookmarked: (postId) {
|
||||
_onBookmarkChanged(postId, false, true, "swot");
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
itemPadding: EdgeInsets.zero,
|
||||
childCount: state.bookmarkedSwotItems.length,
|
||||
onRetry: () => state.getBookmarks(page: 1),
|
||||
)
|
||||
else
|
||||
Consumer<FilteredBookmarksState>(
|
||||
builder: (context, state, child) =>
|
||||
SliverStateHandler<FilteredBookmarksState>(
|
||||
state: state,
|
||||
enableEmptyState: state.bookmarks.isEmpty,
|
||||
itemPadding: const EdgeInsets.only(bottom: 8),
|
||||
placeholder: MultitypeOverview.placeholder,
|
||||
placeholder: RadarOverview.placeholder,
|
||||
emptyState: const EmptyList(),
|
||||
builder: (context, state, index) {
|
||||
if (index >= state.bookmarks.length) {
|
||||
if (state.page < state.lastPage) {
|
||||
index++;
|
||||
if (index % 15 == 0 && state.lastPage != state.page) {
|
||||
state.getBookmarks(page: state.page + 1);
|
||||
return MultitypeOverview.placeholder;
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final item = state.bookmarks[index];
|
||||
index--;
|
||||
return MultitypeOverview(
|
||||
item: item,
|
||||
item: state.bookmarks[index],
|
||||
enableCaption: true,
|
||||
onMarkChanged: (id, value) => _onBookmarkChanged(id, value, true, item.type),
|
||||
onMarkChanged: (id, value) => _onBookmarkChanged(
|
||||
id,
|
||||
value,
|
||||
true,
|
||||
),
|
||||
enableBookmark: true,
|
||||
);
|
||||
// if (state.type == 'radar') {
|
||||
// return RadarOverview(
|
||||
// radar: state.bookmarks[index],
|
||||
// onMarkChanged: _onBookmarkChanged,
|
||||
// onCommentsChanged: state.onCommentsChanged,
|
||||
// hasUnmarkConfirmation: true,
|
||||
// );
|
||||
// }
|
||||
// if (state.type == 'news') {
|
||||
// return NewsOverview(
|
||||
// news: state.bookmarks[index],
|
||||
// onMarkChanged: _onBookmarkChanged,
|
||||
// hasUnmarkConfirmation: true,
|
||||
// );
|
||||
// }
|
||||
// if (state.type == 'podcast') {
|
||||
// return PodcastOverview(
|
||||
// studioRequestArgs:
|
||||
// const StudioRequestArgs(page: 0, type: 'podcast'),
|
||||
// podcast: state.bookmarks[index],
|
||||
// onMarkChanged: _onBookmarkChanged,
|
||||
// hasUnmarkConfirmation: true,
|
||||
// );
|
||||
// }
|
||||
// return VideoOverview(
|
||||
// studioRequestArgs:
|
||||
// const StudioRequestArgs(page: 0, type: 'video'),
|
||||
// video: state.bookmarks[index],
|
||||
// onMarkChanged: _onBookmarkChanged,
|
||||
// hasUnmarkConfirmation: true,
|
||||
// );
|
||||
},
|
||||
childCount: state.bookmarks.length + (state.page < state.lastPage ? 1: 0),
|
||||
childCount: state.bookmarks.length,
|
||||
onRetry: () => state.getBookmarks(page: state.page),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onBookmarkChanged(int id, bool value, bool shouldUpdate) async {
|
||||
if (value) return;
|
||||
final state = context.read<FilteredBookmarksState>();
|
||||
state.onMarkChanged(id, false);
|
||||
widget.onDeleted?.call(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +1,19 @@
|
|||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/overview_data.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/providers/core.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||||
import 'package:didvan/services/swot_service.dart';
|
||||
|
||||
class FilteredBookmarksState extends CoreProvier {
|
||||
final List<OverviewData> bookmarks = [];
|
||||
List<SwotItem> bookmarkedSwotItems = [];
|
||||
final int type;
|
||||
int page = 1;
|
||||
int lastPage = 1;
|
||||
bool _swotItemsLoading = false;
|
||||
bool get swotItemsLoading => _swotItemsLoading;
|
||||
|
||||
FilteredBookmarksState(this.type);
|
||||
|
||||
Future<void> getBookmarks({required int page}) async {
|
||||
if (type == 8) {
|
||||
await _fetchSwotBookmarksFiltered();
|
||||
} else {
|
||||
await _fetchGeneralBookmarks(page: page);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _fetchGeneralBookmarks({required int page}) async {
|
||||
this.page = page;
|
||||
appState = AppState.busy;
|
||||
notifyListeners();
|
||||
|
||||
final service = RequestService(
|
||||
RequestHelper.searchMarks(
|
||||
types: [type],
|
||||
|
|
@ -42,63 +25,22 @@ class FilteredBookmarksState extends CoreProvier {
|
|||
if (service.isSuccess) {
|
||||
lastPage = service.result['lastPage'];
|
||||
final marks = service.result['contents'];
|
||||
bookmarks.clear();
|
||||
for (var i = 0; i < marks.length; i++) {
|
||||
bookmarks.add(OverviewData.fromJson(marks[i]));
|
||||
}
|
||||
appState = AppState.idle;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
appState = AppState.failed;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _fetchSwotBookmarksFiltered() async {
|
||||
appState = AppState.busy;
|
||||
_swotItemsLoading = true;
|
||||
bookmarkedSwotItems.clear();
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final bookmarkedPostIds = await BookmarkService.fetchBookmarks();
|
||||
if (bookmarkedPostIds.isNotEmpty) {
|
||||
final allSwotItems = await SwotService.fetchSwotItems();
|
||||
bookmarkedSwotItems = allSwotItems.where((swot) => bookmarkedPostIds.contains(swot.id)).toList();
|
||||
} else {
|
||||
bookmarkedSwotItems = [];
|
||||
}
|
||||
appState = AppState.idle;
|
||||
} catch (e) {
|
||||
appState = AppState.failed;
|
||||
bookmarkedSwotItems = [];
|
||||
} finally {
|
||||
_swotItemsLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void onMarkChanged(int id, bool value) {
|
||||
|
||||
if (type != 8) {
|
||||
bookmarks.removeWhere((element) => element.id == id);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void onSwotMarkChanged(int id) {
|
||||
bookmarkedSwotItems.removeWhere((element) => element.id == id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
void onCommentsChanged(int id, int value) {
|
||||
|
||||
if (type != 8) {
|
||||
final item = bookmarks.firstWhere((radar) => radar.id == id, orElse: () => OverviewData(id: -1, title: '', image: '', description: '', createdAt: '', type: '', marked: false, liked: false, likes: 0, comments: 0, forManagers: false) );
|
||||
if(item.id != -1) {
|
||||
item.comments = value;
|
||||
bookmarks.firstWhere((radar) => radar.id == id).comments = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -202,11 +202,6 @@ class HomeState extends CoreProvier {
|
|||
asset: Assets.ai,
|
||||
link: 'tab-2',
|
||||
),
|
||||
MenuItemType(
|
||||
label: 'فرصت و تهدید',
|
||||
asset: Assets.hugeideas,
|
||||
link: 'http://opportunity-threat.didvan.com/?accessToken=${RequestService.token}',
|
||||
),
|
||||
];
|
||||
|
||||
categories = [
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/main.dart';
|
||||
import 'package:didvan/models/home_page_content/home_page_list.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/swot_service.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/views/home/main/main_page_state.dart';
|
||||
|
|
@ -15,16 +12,13 @@ import 'package:didvan/views/widgets/didvan/slider.dart';
|
|||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
// import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:didvan/views/home/main/widgets/swot_item_card.dart';
|
||||
|
||||
class MainPage extends StatefulWidget {
|
||||
const MainPage({
|
||||
super.key,
|
||||
});
|
||||
const MainPage({super.key});
|
||||
|
||||
@override
|
||||
State<MainPage> createState() => _MainPageState();
|
||||
|
|
@ -42,14 +36,13 @@ class _MainPageState extends State<MainPage> {
|
|||
return StateHandler<MainPageState>(
|
||||
onRetry: context.read<MainPageState>().init,
|
||||
state: context.watch<MainPageState>(),
|
||||
builder: (context, state) => ListView(
|
||||
builder: (context, state) => ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
children: [
|
||||
// محتوای اصلی صفحه
|
||||
const MainPageMainContent(),
|
||||
|
||||
// آیتمهای لیستها
|
||||
...List.generate(state.content.lists.length + 1, (index) {
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return const MainPageMainContent();
|
||||
}
|
||||
index--;
|
||||
if (index == 4) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 32),
|
||||
|
|
@ -93,112 +86,16 @@ class _MainPageState extends State<MainPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
int listIndex = index > 4 ? index - 1 : index;
|
||||
if (listIndex >= state.content.lists.length) {
|
||||
return const SizedBox.shrink();
|
||||
if (index > 3) {
|
||||
index--;
|
||||
}
|
||||
final list = state.content.lists[index];
|
||||
return _MainPageSection(
|
||||
list: state.content.lists[listIndex],
|
||||
isLast: listIndex == state.content.lists.length - 1,
|
||||
);
|
||||
}),
|
||||
|
||||
// کانتینر زیر کل لیستها
|
||||
FutureBuilder<List<SwotItem>>(
|
||||
future: SwotService.fetchSwotItems(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const SizedBox(
|
||||
height: 10,
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const SizedBox(
|
||||
height: 10,
|
||||
);
|
||||
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||
return const SizedBox(
|
||||
height: 10,
|
||||
);
|
||||
}
|
||||
|
||||
final items = snapshot.data!;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
/// Title Row
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20, top: 30),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
"lib/assets/images/features/Saha Solid.svg",
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
DidvanText(
|
||||
"ماژول فرصت و تهدید",
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
color: Theme.of(context).colorScheme.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
AppInitializer.openWebLink(
|
||||
navigatorKey.currentContext!,
|
||||
'http://opportunity-threat.didvan.com/?accessToken=${RequestService.token}',
|
||||
mode: LaunchMode.inAppWebView,
|
||||
list: list,
|
||||
isLast: index == state.content.lists.length - 1,
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
DidvanText(
|
||||
"همه",
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
Icon(
|
||||
DidvanIcons.angle_left_light,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
/// Swot Items Slider
|
||||
DidvanSlider(
|
||||
height: 300,
|
||||
itemCount: items.length,
|
||||
viewportFraction: 0.65,
|
||||
itemBuilder: (context, index, realIndex) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SwotItemCard(item: items[index]),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
itemCount: state.content.lists.length + 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -226,7 +123,6 @@ class InfoTitle extends StatelessWidget {
|
|||
class _MainPageSection extends StatelessWidget {
|
||||
final MainPageList list;
|
||||
final bool isLast;
|
||||
|
||||
const _MainPageSection({required this.list, required this.isLast});
|
||||
|
||||
void _moreHandler(BuildContext context) {
|
||||
|
|
@ -279,11 +175,6 @@ class _MainPageSection extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final icon = _generateIcon();
|
||||
|
||||
if (list.contents.isEmpty) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BookmarkIcon extends StatefulWidget {
|
||||
final int postId;
|
||||
|
||||
const BookmarkIcon({super.key, required this.postId});
|
||||
|
||||
@override
|
||||
State<BookmarkIcon> createState() => _BookmarkIconState();
|
||||
}
|
||||
|
||||
class _BookmarkIconState extends State<BookmarkIcon> {
|
||||
bool _bookmarked = false;
|
||||
bool _loading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadStatus();
|
||||
}
|
||||
|
||||
Future<void> _loadStatus() async {
|
||||
final bookmarks = await BookmarkService.fetchBookmarks();
|
||||
setState(() => _bookmarked = bookmarks.contains(widget.postId));
|
||||
}
|
||||
|
||||
Future<void> _toggleBookmark() async {
|
||||
setState(() => _loading = true);
|
||||
try {
|
||||
if (_bookmarked) {
|
||||
await BookmarkService.removeBookmark(widget.postId);
|
||||
print("Bookmark removed for post ${widget.postId}");
|
||||
} else {
|
||||
await BookmarkService.addBookmark(widget.postId);
|
||||
print("Bookmark added for post ${widget.postId}");
|
||||
}
|
||||
setState(() {
|
||||
_bookmarked = !_bookmarked;
|
||||
_loading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
print("Error toggling bookmark for post ${widget.postId}: $e");
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: _loading ? null : _toggleBookmark,
|
||||
icon: Icon(
|
||||
_bookmarked ? DidvanIcons.bookmark_solid : DidvanIcons.bookmark_regular,
|
||||
color: _bookmarked
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/models/view/action_sheet_data.dart'; // Ensure this is used or remove if not
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BookmarkedIcon extends StatefulWidget {
|
||||
final int postId;
|
||||
final void Function(bool isBookmarked)? onBookmarkChanged;
|
||||
|
||||
const BookmarkedIcon({
|
||||
super.key,
|
||||
required this.postId,
|
||||
this.onBookmarkChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BookmarkedIcon> createState() => _BookmarkedIconState();
|
||||
}
|
||||
|
||||
class _BookmarkedIconState extends State<BookmarkedIcon> {
|
||||
bool _bookmarked = false;
|
||||
bool _loading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadStatus();
|
||||
}
|
||||
|
||||
Future<void> _loadStatus() async {
|
||||
// setState(() => _loading = true);
|
||||
final bookmarks = await BookmarkService.fetchBookmarks();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_bookmarked = bookmarks.contains(widget.postId);
|
||||
// _loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _toggleBookmark() async {
|
||||
if (_loading) return;
|
||||
|
||||
if (_bookmarked) {
|
||||
bool confirmAction = false;
|
||||
|
||||
await ActionSheetUtils(context).openDialog(
|
||||
data: ActionSheetData(
|
||||
content: const DidvanText(
|
||||
'آیا میخواهید این محتوا از نشان شدهها حذف شود؟',
|
||||
),
|
||||
titleIcon: DidvanIcons.bookmark_regular,
|
||||
titleColor: Theme.of(context).colorScheme.secondary,
|
||||
title: 'تایید عملیات',
|
||||
onConfirmed: () => confirmAction = true,
|
||||
),
|
||||
);
|
||||
|
||||
if (!confirmAction) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setState(() => _loading = true);
|
||||
try {
|
||||
if (_bookmarked) {
|
||||
await BookmarkService.removeBookmark(widget.postId);
|
||||
} else {
|
||||
await BookmarkService.addBookmark(widget.postId);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
final newBookmarkStatus = !_bookmarked;
|
||||
setState(() {
|
||||
_bookmarked = newBookmarkStatus;
|
||||
});
|
||||
widget.onBookmarkChanged?.call(newBookmarkStatus);
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error toggling bookmark for post ${widget.postId}: $e");
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: _loading ? null : _toggleBookmark,
|
||||
icon: Icon(
|
||||
_bookmarked ? DidvanIcons.bookmark_solid : DidvanIcons.bookmark_regular,
|
||||
color: _bookmarked
|
||||
? const Color.fromARGB(255, 0, 126, 167)
|
||||
: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/note_service.dart';
|
||||
import 'package:didvan/views/home/main/widgets/bookmarked_icon.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text_field.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:persian_number_utility/persian_number_utility.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SwotBookmark extends StatefulWidget {
|
||||
final SwotItem item;
|
||||
final void Function(int postId)? onSwotUnbookmarked;
|
||||
|
||||
const SwotBookmark({
|
||||
super.key,
|
||||
required this.item, this.onSwotUnbookmarked,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SwotBookmark> createState() => _SwotBookmark();
|
||||
}
|
||||
|
||||
class _SwotBookmark extends State<SwotBookmark> {
|
||||
ValueNotifier<bool> myBookmarkStatus = ValueNotifier(true);
|
||||
String noteText = '';
|
||||
String tempNoteText = '';
|
||||
bool isLoading = true;
|
||||
bool hasExistingNote = false; // Track if a note exists
|
||||
Timer? _debounce;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
loadNote();
|
||||
}
|
||||
|
||||
Future<void> loadNote() async {
|
||||
final note = await NoteService.getNoteByPostId(widget.item.id);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
noteText = note?.content ?? '';
|
||||
tempNoteText = noteText;
|
||||
hasExistingNote = note != null; // Set flag if note exists
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void saveOrUpdateNote(String content) async {
|
||||
print('Processing note for PostId: ${widget.item.id}, Content: $content');
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
bool success;
|
||||
if (hasExistingNote) {
|
||||
// Update existing note
|
||||
success = await NoteService.updateNote(widget.item.id, content);
|
||||
} else {
|
||||
// Save new note
|
||||
success = await NoteService.saveNote(widget.item.id, content);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
await loadNote(); // Reload note from server
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('خطا در ذخیره یادداشت: سرور پاسخ ناموفق داد')),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('خطا در ذخیره یادداشت: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onNoteChanged(String value) {
|
||||
setState(() {
|
||||
tempNoteText = value;
|
||||
});
|
||||
|
||||
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
||||
|
||||
_debounce = Timer(const Duration(milliseconds: 500), () {
|
||||
saveOrUpdateNote(value);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_debounce?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
AppInitializer.openWebLink(
|
||||
context,
|
||||
'http://opportunity-threat.didvan.com/posts/${widget.item.id}/?accessToken=${RequestService.token}',
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(bottom: 10, right: 2, left: 2),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// ... (Row with image and text details for SwotItem) ...
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8, top: 8),
|
||||
child: Stack(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.item.imageUrl,
|
||||
width: 80,
|
||||
height: 80,
|
||||
fit: BoxFit.cover,
|
||||
httpHeaders: {
|
||||
'Authorization': 'Bearer ${RequestService.token}',
|
||||
},
|
||||
imageRenderMethodForWeb:
|
||||
ImageRenderMethodForWeb.HttpGet,
|
||||
placeholder: (context, _) => const ShimmerPlaceholder(
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.disabledBackground,
|
||||
child:
|
||||
const Icon(Icons.image_not_supported_outlined),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
borderRadius: const BorderRadius.horizontal(
|
||||
left: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
child: SvgPicture.asset("lib/assets/images/categories/Vector.svg",height: 14,)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.item.title,
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 18,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(
|
||||
DidvanIcons.calendar_day_light,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
DidvanText(
|
||||
DateTime.parse(widget.item.createdAt)
|
||||
.toPersianDateStr(),
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Notes Title Column
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.edit_outlined,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
DidvanText(
|
||||
'یادداشتهای من',
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// Row for (Divider + TextField) and BookmarkIcon
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.border,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
isLoading
|
||||
? const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: DidvanTextField(
|
||||
disableBorders: true,
|
||||
initialValue: tempNoteText,
|
||||
hintText: 'برای اضافه کردن یادداشت لمس کنید.',
|
||||
onChanged: onNoteChanged,
|
||||
isSmall: true,
|
||||
textInputAction: TextInputAction.done,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
BookmarkedIcon(
|
||||
postId: widget.item.id,
|
||||
onBookmarkChanged: (isBookmarked) {
|
||||
if (!isBookmarked) {
|
||||
widget.onSwotUnbookmarked?.call(widget.item.id);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/views/home/main/widgets/bookmark.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SwotItemCard extends StatefulWidget {
|
||||
final SwotItem item;
|
||||
|
||||
const SwotItemCard({super.key, required this.item, this.onBookmarkChangedInList});
|
||||
final void Function(int postId, bool isBookmarked)? onBookmarkChangedInList;
|
||||
|
||||
@override
|
||||
State<SwotItemCard> createState() => _SwotItemCardState();
|
||||
}
|
||||
|
||||
class _SwotItemCardState extends State<SwotItemCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
AppInitializer.openWebLink(
|
||||
context,
|
||||
'http://opportunity-threat.didvan.com/posts/${widget.item.id}/?accessToken=${RequestService.token}',
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: 250,
|
||||
height: 50,
|
||||
margin: const EdgeInsets.only(right: 0),
|
||||
padding: const EdgeInsets.all(0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
),
|
||||
child: CachedNetworkImage(
|
||||
errorWidget: (context, url, error) {
|
||||
if (kDebugMode) {
|
||||
print('image fetch complete with Error: $error');
|
||||
}
|
||||
return Container(
|
||||
height: 150,
|
||||
width: 300,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).colorScheme.disabledBackground,
|
||||
),
|
||||
child: const Icon(Icons.image_not_supported_outlined),
|
||||
);
|
||||
},
|
||||
errorListener: (value) {},
|
||||
fit: BoxFit.cover,
|
||||
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||
httpHeaders: {
|
||||
'Authorization': 'Bearer ${RequestService.token}'
|
||||
},
|
||||
width: 300,
|
||||
height: 150,
|
||||
imageUrl: widget.item.imageUrl,
|
||||
placeholder: (context, _) => const ShimmerPlaceholder(
|
||||
width: 300,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
widget.item.title,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
widget.item.type == "THREAT"
|
||||
? SvgPicture.asset(
|
||||
"lib/assets/images/features/Badge.svg")
|
||||
: SvgPicture.asset(
|
||||
"lib/assets/images/features/Badge-Green.svg"),
|
||||
const SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
widget.item.type == "THREAT" ? "تهدید" : "فرصت",
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
"lib/assets/images/features/ant-design_dot-chart-outlined.svg"),
|
||||
const SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
'عدد ${widget.item.type == "THREAT" ? "تهدید" : "فرصت"}: ${((widget.item.x1 ?? 0.0) * (widget.item.y1 ?? 0.0)).toStringAsFixed(1)}',
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
)
|
||||
],
|
||||
),
|
||||
// GestureDetector(
|
||||
// onTap: () {}, child: Icon(DidvanIcons.bookmark_solid)
|
||||
// // Icon(
|
||||
// // widget.item.marked
|
||||
// // ? DidvanIcons.bookmark_solid
|
||||
// // : DidvanIcons.bookmark_regular,
|
||||
// // color: widget.item.marked
|
||||
// // ? Theme.of(context).colorScheme.secondary
|
||||
// // : Theme.of(context).colorScheme.caption,
|
||||
// // ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
child: BookmarkIcon(postId: widget.item.id),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ class MainCategories extends StatelessWidget {
|
|||
'$link?accessToken=${RequestService.token}',
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
print("your goddamn token is :${RequestService.token}");
|
||||
} else if (link.startsWith('tab-')) {
|
||||
final state = context.read<HomeState>();
|
||||
int index = int.parse(link.replaceAll('tab-', ''));
|
||||
|
|
@ -34,14 +33,13 @@ class MainCategories extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final state = context.read<HomeState>();
|
||||
return Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
alignment: WrapAlignment.center,
|
||||
children: state.menuItems
|
||||
.map(
|
||||
(e) => GestureDetector(
|
||||
onTap: () => _onTap(e.link, context),
|
||||
child: SizedBox(
|
||||
width: (MediaQuery.of(context).size.width) / 4,
|
||||
// (MediaQuery.of(context).size.width - 40) / 3,
|
||||
width: (MediaQuery.of(context).size.width - 40) / 3,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
// import 'package:didvan/models/home_page_content/risk.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
|
||||
// class RiskCard extends StatelessWidget {
|
||||
// final Swot risk;
|
||||
|
||||
// const RiskCard({Key? key, required this.risk}) : super(key: key);
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Container(
|
||||
// height: 100,
|
||||
// margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
// padding: const EdgeInsets.all(12),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.green[100],
|
||||
// borderRadius: BorderRadius.circular(12),
|
||||
// border: Border.all(color: Colors.green, width: 1),
|
||||
// ),
|
||||
// child: Text(
|
||||
// risk.title,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Colors.black87,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import 'package:chewie/chewie.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
|
||||
|
|
@ -26,26 +25,9 @@ class StudioDetails extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _StudioDetailsState extends State<StudioDetails> {
|
||||
// ignore: unused_field
|
||||
int _currentlyPlayingId = 0;
|
||||
late VideoPlayerController _videoPlayerController;
|
||||
ChewieController? _chewieController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final state = context.read<StudioDetailsState>();
|
||||
state.args = widget.pageData['args'];
|
||||
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => state.getStudioDetails(widget.pageData['id']).then((_) {
|
||||
if (!mounted) return;
|
||||
_videoPlayerController = VideoPlayerController.network(
|
||||
state.studio.link,
|
||||
);
|
||||
_videoPlayerController.initialize().then((_) {
|
||||
_chewieController = ChewieController(
|
||||
late final ChewieController _chewieController = ChewieController(
|
||||
videoPlayerController: _videoPlayerController,
|
||||
customControls: const PrimaryControls(),
|
||||
autoPlay: true,
|
||||
|
|
@ -53,14 +35,15 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
aspectRatio: 16 / 9,
|
||||
materialProgressColors: ChewieProgressColors(
|
||||
playedColor: Theme.of(context).colorScheme.title,
|
||||
handleColor: Theme.of(context).colorScheme.title,
|
||||
),
|
||||
);
|
||||
setState(() {
|
||||
_currentlyPlayingId = state.studio.id;
|
||||
});
|
||||
});
|
||||
}),
|
||||
handleColor: Theme.of(context).colorScheme.title));
|
||||
@override
|
||||
void initState() {
|
||||
final state = context.read<StudioDetailsState>();
|
||||
state.args = widget.pageData['args'];
|
||||
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => state.getStudioDetails(widget.pageData['id']),
|
||||
);
|
||||
|
||||
if (widget.pageData['goToComment'] != null) {
|
||||
|
|
@ -80,6 +63,7 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
);
|
||||
}
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -96,14 +80,8 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (!state.isStudioLoaded) {
|
||||
return Center(
|
||||
child: Image.asset(
|
||||
Assets.loadingAnimation,
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
);
|
||||
if (_currentlyPlayingId != state.studio.id) {
|
||||
_handleVideoPlayback(state);
|
||||
}
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
|
|
@ -142,14 +120,8 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: _chewieController != null
|
||||
? Chewie(controller: _chewieController!)
|
||||
: Center(
|
||||
child: Image.asset(
|
||||
Assets.loadingAnimation,
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
child: Chewie(
|
||||
controller: _chewieController,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
|
@ -170,11 +142,18 @@ class _StudioDetailsState extends State<StudioDetails> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _handleVideoPlayback(state) async {
|
||||
_videoPlayerController = VideoPlayerController.network(
|
||||
state.studio.link,
|
||||
)..initialize().then((value) async {});
|
||||
_currentlyPlayingId = state.studio.id;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_videoPlayerController.pause();
|
||||
_videoPlayerController.dispose();
|
||||
_chewieController?.dispose();
|
||||
_chewieController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import 'package:didvan/services/network/request_helper.dart';
|
|||
|
||||
class StudioDetailsState extends CoreProvier {
|
||||
late StudioDetailsData studio;
|
||||
bool isStudioLoaded = false;
|
||||
StudioDetailsData? nextStudio;
|
||||
StudioDetailsData? prevStudio;
|
||||
late int initialIndex;
|
||||
|
|
@ -67,7 +66,6 @@ class StudioDetailsState extends CoreProvier {
|
|||
studio = prevStudio!;
|
||||
prevStudio = null;
|
||||
}
|
||||
isStudioLoaded = true;
|
||||
notifyListeners();
|
||||
_handlePodcastPlayback(studio);
|
||||
}
|
||||
|
|
@ -100,11 +98,9 @@ class StudioDetailsState extends CoreProvier {
|
|||
}
|
||||
final result = service.result;
|
||||
studio = StudioDetailsData.fromJson(result['studio']);
|
||||
isStudioLoaded = true;
|
||||
if (args?.page == 0) {
|
||||
initialIndex = 0;
|
||||
appState = AppState.idle;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
if (result['nextStudio'].isNotEmpty && this.args?.page != 0) {
|
||||
|
|
@ -118,7 +114,6 @@ class StudioDetailsState extends CoreProvier {
|
|||
}
|
||||
alongSideState = AppState.idle;
|
||||
appState = AppState.idle;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
if (isForward == null) {
|
||||
|
|
@ -128,8 +123,10 @@ class StudioDetailsState extends CoreProvier {
|
|||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
// MediaService.resetAudioPlayer();
|
||||
update();
|
||||
appState = AppState.idle;
|
||||
// rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,6 +165,7 @@ class StudioDetailsState extends CoreProvier {
|
|||
}
|
||||
} else {
|
||||
MediaService.audioPlayer.pause();
|
||||
// MediaService.audioPlayer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,26 +39,24 @@ class _PlayerNavBarState extends State<PlayerNavBar> {
|
|||
return StreamBuilder<bool>(
|
||||
stream: MediaService.audioPlayer.playingStream,
|
||||
builder: (context, isPlaying) => GestureDetector(
|
||||
onTap: () {
|
||||
// (MediaService.currentPodcast == null &&
|
||||
// (MediaService.audioPlayerTag ?? '')
|
||||
// .split('-')[1]
|
||||
// .isNotEmpty) ||
|
||||
// MediaService.currentPodcast?.description == 'radar'
|
||||
// ? Navigator.of(context).pushNamed(
|
||||
// Routes.radarDetails,
|
||||
// arguments: {
|
||||
// 'onMarkChanged': (id, value) {},
|
||||
// 'onCommentsChanged': (id, value) {},
|
||||
// 'id': MediaService.currentPodcast?.id,
|
||||
// 'args': const RadarRequestArgs(page: 0),
|
||||
// 'hasUnmarkConfirmation': false,
|
||||
// },
|
||||
// )
|
||||
// : (MediaService.audioPlayerTag ?? '').split('-')[1].isNotEmpty
|
||||
// ? _showPlayerBottomSheet(context)
|
||||
// : null;
|
||||
onTap: () => (MediaService.currentPodcast == null &&
|
||||
(MediaService.audioPlayerTag ?? '')
|
||||
.split('-')[1]
|
||||
.isNotEmpty) ||
|
||||
MediaService.currentPodcast?.description == 'radar'
|
||||
? Navigator.of(context).pushNamed(
|
||||
Routes.radarDetails,
|
||||
arguments: {
|
||||
'onMarkChanged': (id, value) {},
|
||||
'onCommentsChanged': (id, value) {},
|
||||
'id': MediaService.currentPodcast?.id,
|
||||
'args': const RadarRequestArgs(page: 0),
|
||||
'hasUnmarkConfirmation': false,
|
||||
},
|
||||
)
|
||||
: (MediaService.audioPlayerTag ?? '').split('-')[1].isNotEmpty
|
||||
? _showPlayerBottomSheet(context)
|
||||
: null,
|
||||
child: Consumer<StudioDetailsState>(
|
||||
builder: (context, state, child) => AnimatedContainer(
|
||||
height: widget.inHome
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class _DidvanScaffoldState extends State<DidvanScaffold> {
|
|||
if (widget.slivers != null)
|
||||
for (var i = 0; i < widget.slivers!.length; i++)
|
||||
SliverPadding(
|
||||
padding: widget.padding.copyWith(bottom: 0),
|
||||
padding: widget.padding,
|
||||
sliver: widget.slivers![i],
|
||||
),
|
||||
if (widget.children != null && widget.showSliversFirst)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ class DidvanTextField extends StatefulWidget {
|
|||
final bool acceptSpace;
|
||||
final String? Function(String value)? validator;
|
||||
final TextInputType? textInputType;
|
||||
final TextInputAction? textInputAction; // پارامتر جدید
|
||||
final bool disableBorders;
|
||||
final bool isSmall;
|
||||
final int? maxLine;
|
||||
|
|
@ -38,7 +37,6 @@ class DidvanTextField extends StatefulWidget {
|
|||
this.initialValue,
|
||||
this.validator,
|
||||
this.textInputType,
|
||||
this.textInputAction, // اضافه کردن به سازنده
|
||||
this.textAlign,
|
||||
this.obsecureText = false,
|
||||
this.autoFocus = false,
|
||||
|
|
@ -117,7 +115,6 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
obscureText: _hideContent,
|
||||
textAlign: widget.textAlign ?? TextAlign.start,
|
||||
keyboardType: widget.textInputType,
|
||||
textInputAction: widget.textInputAction, // پاس دادن به TextFormField
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
onFieldSubmitted: widget.onSubmitted,
|
||||
|
|
@ -238,6 +235,7 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
setState(() {
|
||||
_error = null;
|
||||
});
|
||||
// value = value.toEnglishDigit();
|
||||
widget.onChanged?.call(value);
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +259,6 @@ class _DidvanTextFieldState extends State<DidvanTextField> {
|
|||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,19 +7,16 @@ class MenuOption extends StatelessWidget {
|
|||
final String? title;
|
||||
final Widget? titleWidget;
|
||||
final IconData? icon;
|
||||
final Widget? iconWidget;
|
||||
final double iconSize;
|
||||
final String? suffix;
|
||||
final VoidCallback onTap;
|
||||
final Widget? trailing;
|
||||
final Color? color;
|
||||
|
||||
MenuOption({
|
||||
Key? key,
|
||||
required this.onTap,
|
||||
this.title,
|
||||
this.icon,
|
||||
this.iconWidget,
|
||||
this.suffix,
|
||||
this.color,
|
||||
this.trailing,
|
||||
|
|
@ -27,55 +24,46 @@ class MenuOption extends StatelessWidget {
|
|||
this.iconSize = 18,
|
||||
}) : super(key: key) {
|
||||
if (title == null && titleWidget == null) {
|
||||
throw Exception("MenuOption must have a title or titleWidget");
|
||||
throw Exception;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final Color effectiveTitleColor = color ?? theme.colorScheme.title;
|
||||
|
||||
Widget? displayIcon;
|
||||
if (iconWidget != null) {
|
||||
displayIcon = iconWidget;
|
||||
} else if (icon != null) {
|
||||
displayIcon = Icon(icon, size: iconSize, color: effectiveTitleColor);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: const EdgeInsets.symmetric(vertical: 0.0),
|
||||
child: Row(
|
||||
children: [
|
||||
if (displayIcon != null) displayIcon,
|
||||
if (displayIcon != null) const SizedBox(width: 4),
|
||||
|
||||
if (titleWidget != null) titleWidget!
|
||||
else DidvanText(
|
||||
if (icon != null)
|
||||
Icon(
|
||||
icon,
|
||||
size: iconSize,
|
||||
color: color ?? Theme.of(context).colorScheme.title,
|
||||
),
|
||||
if (icon != null) const SizedBox(width: 4),
|
||||
if (titleWidget != null) titleWidget!,
|
||||
if (titleWidget == null)
|
||||
DidvanText(
|
||||
title!,
|
||||
color: effectiveTitleColor,
|
||||
color: color ?? Theme.of(context).colorScheme.title,
|
||||
),
|
||||
const Spacer(),
|
||||
|
||||
if (suffix != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: DidvanText(
|
||||
DidvanText(
|
||||
suffix!,
|
||||
style: theme.textTheme.titleSmall!
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.copyWith(fontWeight: FontWeight.w400),
|
||||
color: theme.colorScheme.primary,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
|
||||
trailing ??
|
||||
Icon(
|
||||
DidvanIcons.angle_left_regular,
|
||||
size: 18,
|
||||
color: effectiveTitleColor,
|
||||
color: color ?? Theme.of(context).colorScheme.title,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
64
pubspec.lock
|
|
@ -422,70 +422,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
flutter_inappwebview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_inappwebview
|
||||
sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
flutter_inappwebview_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_android
|
||||
sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
flutter_inappwebview_internal_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_internal_annotations
|
||||
sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
flutter_inappwebview_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_ios
|
||||
sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_inappwebview_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_macos
|
||||
sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_inappwebview_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_platform_interface
|
||||
sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0+1"
|
||||
flutter_inappwebview_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_web
|
||||
sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_inappwebview_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_windows
|
||||
sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ dependencies:
|
|||
image_cropper: ^9.0.0
|
||||
package_info_plus: ^8.3.0
|
||||
flutter_local_notifications: ^19.1.0
|
||||
flutter_inappwebview: ^6.1.5
|
||||
# fading_edge_scrollview: ^4.1.1
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||