This commit is contained in:
InsaneTrashRU 2025-06-06 15:16:47 +03:00
commit 923379a43b
238 changed files with 19285 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
Doctor

6
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

17
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\maksi\.android\avd\Pixel_5_API_29_2.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-11-30T18:27:18.890685800Z" />
</component>
</project>

10
.idea/deploymentTargetSelector.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

19
.idea/gradle.xml generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SameParameterValue" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

6
.idea/kotlinc.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.0" />
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

9
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

714
.idea/other.xml generated Normal file
View File

@ -0,0 +1,714 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="direct_access_persist.xml">
<option name="deviceSelectionList">
<list>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="Sony" />
<option name="codename" value="A402SO" />
<option name="id" value="A402SO" />
<option name="manufacturer" value="Sony" />
<option name="name" value="Xperia 10" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2520" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="27" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="F01L" />
<option name="id" value="F01L" />
<option name="manufacturer" value="FUJITSU" />
<option name="name" value="F-01L" />
<option name="screenDensity" value="360" />
<option name="screenX" value="720" />
<option name="screenY" value="1280" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="OnePlus" />
<option name="codename" value="OP535DL1" />
<option name="id" value="OP535DL1" />
<option name="manufacturer" value="OnePlus" />
<option name="name" value="CPH2409" />
<option name="screenDensity" value="401" />
<option name="screenX" value="1080" />
<option name="screenY" value="2412" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="OnePlus" />
<option name="codename" value="OP5552L1" />
<option name="id" value="OP5552L1" />
<option name="manufacturer" value="OnePlus" />
<option name="name" value="CPH2415" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2412" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="OPPO" />
<option name="codename" value="OP573DL1" />
<option name="id" value="OP573DL1" />
<option name="manufacturer" value="OPPO" />
<option name="name" value="CPH2557" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="28" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="SH-01L" />
<option name="id" value="SH-01L" />
<option name="manufacturer" value="SHARP" />
<option name="name" value="AQUOS sense2 SH-01L" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="a15" />
<option name="id" value="a15" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="A15" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="a15x" />
<option name="id" value="a15x" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="A15 5G" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="a16x" />
<option name="id" value="a16x" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="A16 5G" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="a35x" />
<option name="id" value="a35x" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="A35" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />
<option name="codename" value="a51" />
<option name="id" value="a51" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy A51" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="akita" />
<option name="id" value="akita" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="motorola" />
<option name="codename" value="arcfox" />
<option name="id" value="arcfox" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="razr plus 2024" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1080" />
<option name="screenY" value="1272" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="motorola" />
<option name="codename" value="austin" />
<option name="id" value="austin" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="moto g 5G (2022)" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="b0q" />
<option name="id" value="b0q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S22 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="b6q" />
<option name="id" value="b6q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Flip 6" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1080" />
<option name="screenY" value="2640" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="32" />
<option name="brand" value="google" />
<option name="codename" value="bluejay" />
<option name="id" value="bluejay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="caiman" />
<option name="id" value="caiman" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro" />
<option name="screenDensity" value="360" />
<option name="screenX" value="960" />
<option name="screenY" value="2142" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="google" />
<option name="codename" value="caiman" />
<option name="id" value="caiman" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro" />
<option name="screenDensity" value="360" />
<option name="screenX" value="960" />
<option name="screenY" value="2142" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="comet" />
<option name="id" value="comet" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="google" />
<option name="codename" value="comet" />
<option name="id" value="comet" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="29" />
<option name="brand" value="samsung" />
<option name="codename" value="crownqlteue" />
<option name="id" value="crownqlteue" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Note9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2220" />
<option name="screenY" value="1080" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="dm2q" />
<option name="id" value="dm2q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="S23 Plus" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="dm3q" />
<option name="id" value="dm3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S23 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="motorola" />
<option name="codename" value="dubai" />
<option name="id" value="dubai" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="edge 30" />
<option name="screenDensity" value="405" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="e1q" />
<option name="id" value="e1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S24" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="e3q" />
<option name="id" value="e3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S24 Ultra" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1440" />
<option name="screenY" value="3120" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="eos" />
<option name="id" value="eos" />
<option name="manufacturer" value="Google" />
<option name="name" value="Eos" />
<option name="screenDensity" value="320" />
<option name="screenX" value="384" />
<option name="screenY" value="384" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix_camera" />
<option name="id" value="felix_camera" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold (Camera-enabled)" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="motorola" />
<option name="codename" value="fogona" />
<option name="id" value="fogona" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="moto g play - 2024" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="motorola" />
<option name="codename" value="fogos" />
<option name="id" value="fogos" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="moto g34 5G" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="g0q" />
<option name="id" value="g0q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-S906U1" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="gta9pwifi" />
<option name="id" value="gta9pwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-X210" />
<option name="screenDensity" value="240" />
<option name="screenX" value="1200" />
<option name="screenY" value="1920" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="gts7lwifi" />
<option name="id" value="gts7lwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-T870" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="gts7xllite" />
<option name="id" value="gts7xllite" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-T738U" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="gts8uwifi" />
<option name="id" value="gts8uwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S8 Ultra" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1848" />
<option name="screenY" value="2960" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="gts8wifi" />
<option name="id" value="gts8wifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S8" />
<option name="screenDensity" value="274" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="gts9fe" />
<option name="id" value="gts9fe" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S9 FE 5G" />
<option name="screenDensity" value="280" />
<option name="screenX" value="1440" />
<option name="screenY" value="2304" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="gts9wifi" />
<option name="id" value="gts9wifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-X710" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="husky" />
<option name="id" value="husky" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8 Pro" />
<option name="screenDensity" value="390" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="motorola" />
<option name="codename" value="java" />
<option name="id" value="java" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="G20" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="komodo" />
<option name="id" value="komodo" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro XL" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="google" />
<option name="codename" value="komodo" />
<option name="id" value="komodo" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro XL" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="lynx" />
<option name="id" value="lynx" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="motorola" />
<option name="codename" value="manaus" />
<option name="id" value="manaus" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="edge 40 neo" />
<option name="screenDensity" value="400" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="motorola" />
<option name="codename" value="maui" />
<option name="id" value="maui" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="moto g play - 2023" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="o1q" />
<option name="id" value="o1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S21" />
<option name="screenDensity" value="421" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="google" />
<option name="codename" value="oriole" />
<option name="id" value="oriole" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="samsung" />
<option name="codename" value="pa3q" />
<option name="id" value="pa3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S25 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3120" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="panther" />
<option name="id" value="panther" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q5q" />
<option name="id" value="q5q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold5" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1812" />
<option name="screenY" value="2176" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q6q" />
<option name="id" value="q6q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1856" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="r11" />
<option name="id" value="r11" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Watch" />
<option name="screenDensity" value="320" />
<option name="screenX" value="384" />
<option name="screenY" value="384" />
<option name="type" value="WEAR_OS" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="r11q" />
<option name="id" value="r11q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-S711U" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="redfin" />
<option name="id" value="redfin" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 5" />
<option name="screenDensity" value="440" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="shiba" />
<option name="id" value="shiba" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="t2q" />
<option name="id" value="t2q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S21 Plus" />
<option name="screenDensity" value="394" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="tangorpro" />
<option name="id" value="tangorpro" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Tablet" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="google" />
<option name="codename" value="tegu" />
<option name="id" value="tegu" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="tokay" />
<option name="id" value="tokay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="google" />
<option name="codename" value="tokay" />
<option name="id" value="tokay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="xcover7" />
<option name="id" value="xcover7" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-G556B" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2408" />
</PersistentDeviceSelectionData>
</list>
</option>
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

102
app/build.gradle Normal file
View File

@ -0,0 +1,102 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.example.doctor'
compileSdk 33
defaultConfig {
applicationId "com.example.doctor"
minSdk 28
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures{
viewBinding true
}
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "com.mikepenz:materialdrawer:7.0.0"
implementation "com.mikepenz:materialdrawer-nav:7.0.0"
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.1.17'
implementation platform('com.google.firebase:firebase-bom:31.2.0')
implementation 'com.google.firebase:firebase-database-ktx:20.1.0'
implementation 'com.google.firebase:firebase-auth-ktx:21.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'androidx.fragment:fragment-ktx:1.5.5'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.test:core-ktx:1.4.0'
implementation 'androidx.games:games-activity:1.1.0'
implementation 'com.google.mlkit:common:18.1.0'
implementation 'com.google.firebase:firebase-messaging-ktx:23.1.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation 'com.kizitonwose.calendar:view:2.0.0'
//Lifecycle
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
//Retrofit
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
//OkHttp
implementation "com.squareup.okhttp3:logging-interceptor:4.7.2"
implementation "com.squareup.okhttp3:okhttp:4.7.2"
implementation 'com.squareup.picasso:picasso:2.71828'
//Свайп
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.work:work-runtime-ktx:2.8.1"
// // Kotlin
// implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
// implementation "androidx.navigation:navigation-ui-ktx:2.5.2"
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,24 @@
package com.example.doctor
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.doctor", appContext.packageName)
}
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission
android:name="android.permission.CALL_PHONE"
tools:ignore="PermissionImpliesUnsupportedChromeOsHardware" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Doctor"
android:usesCleartextTraffic="true"
tools:targetApi="31" >
<activity
android:name=".CodeError.Code500Activity"
android:exported="false" />
<activity
android:name=".CodeError.Code429Activity"
android:exported="false" />
<activity
android:name=".Enternet.EnternetActivity"
android:exported="false" />
<activity
android:name=".Setting.Courses.CoursesActivity"
android:exported="false" />
<activity
android:name=".Appeals.AppealsCreateMessageActivity"
android:exported="false" />
<activity
android:name=".Patients.PatientActivity"
android:exported="false" />
<activity
android:name=".Auth.AuthActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustPan|stateAlwaysHidden" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application>
</manifest>

View File

@ -0,0 +1,18 @@
package com.example.doctor.Adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// Адаптер для ViewPager2, который управляет списком фрагментов
class VpAdapter(fr_act:FragmentActivity, private val list:List<Fragment>):FragmentStateAdapter(fr_act) {
// Возвращает количество фрагментов в списке
override fun getItemCount(): Int {
return list.size // возвращаем количество фрагментов
}
// Возвращает фрагмент по указанной позиции
override fun createFragment(position: Int): Fragment {
return list[position] // возвращаем фрагмент из списка по позиции
}
}

View File

@ -0,0 +1,18 @@
package com.example.doctor.Adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// Адаптер для ViewPager2, который управляет списком фрагментов пациентов
class VpAdapterPatientList(fr_act:FragmentActivity, private val list:List<Fragment>):FragmentStateAdapter(fr_act) {
// Возвращает количество фрагментов в списке
override fun getItemCount(): Int {
return list.size // возвращаем количество фрагментов
}
// Возвращает фрагмент по указанной позиции
override fun createFragment(position: Int): Fragment {
return list[position] // возвращаем фрагмент из списка по позиции
}
}

View File

@ -0,0 +1,18 @@
package com.example.doctor.Adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// Адаптер для ViewPager2, который управляет списком фрагментов для редактирования спортивных упражнений
class VpEditSportAdapter(fr_act:FragmentActivity, private val list: List<Any>):FragmentStateAdapter(fr_act) {
// Возвращает количество фрагментов в списке
override fun getItemCount(): Int {
return list.size // возвращаем количество фрагментов
}
// Возвращает фрагмент по указанной позиции (приведение типа к Fragment)
override fun createFragment(position: Int): Fragment {
return list[position] as Fragment // возвращаем фрагмент из списка по позиции
}
}

View File

@ -0,0 +1,20 @@
package com.example.doctor
// Модель данных для добавления спортивного курса пациенту
data class AddSportPatientModel(
val id: Int, // Идентификатор добавленного курса пациента
val status: String, // Статус операции добавления
val one: Int, // Поле 1 (вероятно, для хранения данных о выполнении упражнений по дням)
val two: Int, // Поле 2
val three: Int, // Поле 3
val four: Int, // Поле 4
val five: Int, // Поле 5
val six: Int, // Поле 6
val seven: Int, // Поле 7
val eight: Int, // Поле 8
val nine: Int, // Поле 9
val ten: Int, // Поле 10
val eleven: Int, // Поле 11
val twelve: Int, // Поле 12
)

View File

@ -0,0 +1,20 @@
package com.example.doctor.Appeals
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.doctor.R
import com.example.doctor.databinding.ActivityAppealsBinding
// Активити для создания нового обращения (сообщения)
class AppealsCreateMessageActivity : AppCompatActivity() {
private lateinit var binding: ActivityAppealsBinding
// Функция жизненного цикла Activity, инициализирует интерфейс и запускает фрагмент создания сообщения
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAppealsBinding.inflate(layoutInflater)
setContentView(binding.root)
// Заменяем контейнер на фрагмент создания сообщения
supportFragmentManager.beginTransaction().replace(R.id.CLAppealsActivity, CreateMessageFragment.newInstance()).commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}

View File

@ -0,0 +1,235 @@
package com.example.doctor.Appeals
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import com.example.doctor.Adapter.VpAdapter
import com.example.doctor.R
import com.example.doctor.Appeals.TabLayout.OldAppealsFragment
import com.example.doctor.Appeals.TabLayout.NewAppealsFragment
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentAppealsBinding
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
class AppealsFragment : Fragment() {
private lateinit var binding: FragmentAppealsBinding
private lateinit var doctorApi: DoctorApi
private lateinit var timer: Timer
private val model: DoctorViewModel by activityViewModels()
val prefDoctorConclusion = ConclusionPref()
private val dataModel: DataModel by activityViewModels()//Для передачи данных
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
private val tList = listOf(
"новые",
"обработанные",
)
//Список с фрагментами для переключения
private val flist = listOf(
NewAppealsFragment.newInstance(),
OldAppealsFragment.newInstance(),
)
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentAppealsBinding.inflate(layoutInflater, container, false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и обработчики
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init() // Инициализация ViewPager и TabLayout
binding.btnAddMessage.setOnClickListener {
val intetn = Intent(requireContext(), AppealsCreateMessageActivity::class.java)
startActivity(intetn)
}
}
// Получение обработанных обращений с сервера и обновление ViewModel
private fun getOldAppeals() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorOld("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if (List?.appeals_old != null) {
model.appealsOldList.value = List.appeals_old
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Получение новых (необработанных) обращений с сервера и обновление ViewModel
private fun getNewAppeals() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorNew("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if(List.appeals_new != null){
model.appealsNewList.value = List.appeals_new
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация ViewPager и TabLayout для переключения между вкладками обращений
private fun init() = with(binding) {
val adapter = VpAdapter(activity as FragmentActivity, flist)
vpProduct.adapter = adapter
//Переключения (связываем таблаяут(переключатель) с viewpager, чтобы переключать фрагменты)
TabLayoutMediator(tabLayoutProduct, vpProduct) { tab, pos ->
tab.text =
tList[pos]//tab - нажатая кнопка, pos - позиция кнопки, tList[pos] - передаем название по полученной позиции
}.attach()// attach() - чтобы все переключалось, а не вывадило постоянно один экран
//Изменения цвета в зависомости на каком из tabLayout вы находитесь
binding.tabLayoutProduct.setTabTextColors(
getResources().getColor(R.color.black),
getResources().getColor(R.color.white)
);
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
companion object {
// Фабричный метод для создания экземпляра AppealsFragment
fun newInstance() = AppealsFragment()
}
// Функция жизненного цикла, запускает таймер для периодического обновления обращений
override fun onStart() {
super.onStart()
checkForUpdates(true)
}
// Функция жизненного цикла, останавливает таймер при остановке фрагмента
override fun onStop() {
super.onStop()
timer.cancel()
timer.purge()
}
// Запускает таймер, который каждые 10 секунд обновляет списки обращений
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 10000) {
activity?.runOnUiThread {
getOldAppeals()
getNewAppeals()
}
}
}
}

View File

@ -0,0 +1,109 @@
package com.example.doctor.Appeals
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.Appeals.TabLayout.Model.AppealsNewModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldModel
import com.example.doctor.R
import com.example.doctor.databinding.ItemAppealsNewBinding
class AppealsNewAdapter(val listener_check_apeals: Listener, val listener_patient_apeals: Listener2) :
ListAdapter<AppealsNewModel, AppealsNewAdapter.Holder>(
Comparator()
) {//Productitem - по этой форме будем заполнять.//ProductAdapter.holder - это создаваемый holder который хранит логику как нужно заполнять карточку
// ViewHolder для элемента списка обращений
class Holder(view: View, val listener_check_apeals: Listener, val listener_patient_apeals: Listener2) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding =
ItemAppealsNewBinding.bind(view)
var itemTemp: AppealsNewModel? =
null//Глобальная переменная для нашего item, чтобы можно было передать данные для нажатия
// Инициализация обработчиков нажатий на кнопки в карточке
init {
binding.btnAdd.setOnClickListener {
itemTemp?.let { it1 -> listener_check_apeals.onClickAppeals(it1) }
}
binding.btnPatient.setOnClickListener {
itemTemp?.let { it2 -> listener_patient_apeals.onClickAppealsPatient(it2) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: AppealsNewModel) = with(binding) {
itemTemp = item
txtNumber.text = item.number.toString()+"."
txtAppeals.text = item.text
txtLoginPatient.text = item.login
if (item.expand) {
txtAppeals.maxLines = 30
} else {
txtAppeals.maxLines = 1
}
CardViewNew.setOnClickListener {
if (item.expand == false) {
txtAppeals.maxLines = 100
item.expand = true
} else {
txtAppeals.maxLines = 1
item.expand = false
}
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_appeals_new, parent, false)
return Holder(view, listener_check_apeals,listener_patient_apeals)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый список и новый, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<AppealsNewModel>() {
override fun areItemsTheSame(
oldItem: AppealsNewModel,
newItem: AppealsNewModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: AppealsNewModel,
newItem: AppealsNewModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на кнопку "Обработать обращение"
interface Listener {
fun onClickAppeals(item: AppealsNewModel)
}
// Интерфейс для обработки нажатия на кнопку "Открыть пациента"
interface Listener2 {
fun onClickAppealsPatient(item: AppealsNewModel)
}
}

View File

@ -0,0 +1,109 @@
package com.example.doctor.Appeals
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldModel
import com.example.doctor.Appeals.TabLayout.OldAppealsFragment
import com.example.doctor.R
import com.example.doctor.databinding.ItemAppealsOldBinding
class AppealsOldAdapter(val listener_appeal: Listener, val listener_patient_apeals: OldAppealsFragment) :
ListAdapter<AppealsOldModel, AppealsOldAdapter.Holder>(
Comparator()
) {
// Адаптер для отображения обработанных обращений в RecyclerView
// ViewHolder для элемента списка обработанных обращений
class Holder(view: View, val listener_appeal: Listener, val listener_patient_apeals: OldAppealsFragment) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding =
ItemAppealsOldBinding.bind(view)
var itemTemp: AppealsOldModel? =
null // Глобальная переменная для текущего элемента, чтобы можно было передать данные при нажатии
// Инициализация обработчиков нажатий на карточку и кнопку пациента
init {
itemView.setOnClickListener {
itemTemp?.let { it1 -> listener_appeal.onClickAppeals(it1) }
}
binding.btnPatient.setOnClickListener {
itemTemp?.let { it2 -> listener_patient_apeals.onClickAppealsPatient(it2) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: AppealsOldModel) = with(binding) {
itemTemp = item
txtNumber.text = item.number.toString()+"."
txtAppeals.text = item.text
txtLoginPatient.text = item.login
if (item.expand) {
binding.txtAppeals.maxLines = 100
} else {
binding.txtAppeals.maxLines = 1
}
binding.CardViewOld.setOnClickListener {
if (item.expand == false) {
binding.txtAppeals.maxLines = 100
item.expand = true
} else {
binding.txtAppeals.maxLines = 1
item.expand = false
}
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_appeals_old, parent, false)
return Holder(view, listener_appeal,listener_patient_apeals)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<AppealsOldModel>() {
override fun areItemsTheSame(
oldItem: AppealsOldModel,
newItem: AppealsOldModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: AppealsOldModel,
newItem: AppealsOldModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на карточку обращения
interface Listener {
fun onClickAppeals(item: AppealsOldModel)
}
// Интерфейс для обработки нажатия на кнопку "Открыть пациента"
interface Listener2 {
fun onClickAppealsPatient(item: AppealsOldModel)
}
}

View File

@ -0,0 +1,281 @@
package com.example.doctor.Appeals
import android.content.Intent
import android.os.Bundle
import android.transition.TransitionInflater
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentCreateMessageBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
class CreateMessageFragment : Fragment() {
private lateinit var binding: FragmentCreateMessageBinding
private val dataModel: DataModel by activityViewModels()//Для передачи данных
private val modelDoctor: DoctorViewModel by activityViewModels()
private lateinit var doctorApi: DoctorApi
private lateinit var timer: Timer
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
var patientList:List<PatientAllModel>?=null
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCreateMessageBinding.inflate(layoutInflater,container,false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R.transition.slide_right)
exitTransition = inflater.inflateTransition(R.transition.slide_right)
GetPatientList() // Загрузка списка пациентов
binding.btnAddMessagePatient.setOnClickListener{
val login = binding.searchPatient.text.toString()
val text = binding.edTextMessagePatient.text.toString()
if(login!="" && text!=""){
AddMessageDoctor() // Отправка сообщения
}
else{
Toast(requireContext()).showCustomInfoToast("Не все данные заполнены", requireActivity())
}
}
// binding.btnExit.setOnClickListener{
// dataModel.patientAppeal.value = 1
// }
binding.btnExit.setOnClickListener{
activity?.finish()
}
modelDoctor.patientListSearch.observe(viewLifecycleOwner){
if(patientList!=it){
patientList =it
addPatientLogin(it) // Обновление автодополнения по пациентам
}
}
// fixedRateTimer("timer", false, 0, 10000) {
// activity?.runOnUiThread {
//
// }
// }
}
// Добавляет автодополнение по логинам пациентов
private fun addPatientLogin(patient: List<PatientAllModel>) {
val listPatient = arrayListOf("")
for(i in 0 .. patient.count()-1){
listPatient.add(patient[i].login.toString())
}
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, listPatient)
binding.searchPatient.threshold = 1
binding.searchPatient.setAdapter(adapter)
binding.searchPatient.setOnItemClickListener { parent, arg1, pos, id ->
//val list = ArrayList<PatientModel>()
val serpat = binding.searchPatient.text.toString()
binding.searchPatient.setText(serpat)
}
}
// Получение списка всех пациентов с сервера и обновление ViewModel
fun GetPatientList() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientAll("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
//Если нету ошибок
if (List != null) {
modelDoctor.patientListSearch.value = List.patient
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Отправка сообщения врачу (POST-запрос)
fun AddMessageDoctor() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.AddMessageDoctor("Bearer $Tokens",binding.searchPatient.text.toString(),binding.edTextMessagePatient.text.toString())
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
if (Nice) {
if (List != null) {
//Если нету ошибок
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
binding.edTextMessagePatient.setText("")
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
companion object {
fun newInstance() = CreateMessageFragment()
}
// Функция жизненного цикла, запускает таймер для периодического обновления списка пациентов
override fun onResume() {
super.onResume()
checkForUpdates(true)
}
// Функция жизненного цикла, останавливает таймер при остановке фрагмента
override fun onStop() {
super.onStop()
timer.cancel()
timer.purge()
}
// Запускает таймер, который каждые 10 секунд обновляет список пациентов
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 10000) {
activity?.runOnUiThread {
GetPatientList()
}
}
}
}

View File

@ -0,0 +1,7 @@
package com.example.doctor.Appeals.TabLayout.Model
// Модель данных для списка новых обращений (необработанных)
data class AppealsNewListModel(
val appeals_new: List<AppealsNewModel> // Список новых обращений
)

View File

@ -0,0 +1,16 @@
package com.example.doctor.Appeals.TabLayout.Model
// Модель данных для нового обращения (необработанного)
data class AppealsNewModel(
val id: Int, // Уникальный идентификатор обращения
val number: Int, // Порядковый номер обращения
val text: String, // Текст обращения
val id_patient: Int, // ID пациента
val id_doctor: Int, // ID доктора
val check: Int, // Статус проверки обращения
val login: String, // Логин пациента
val created_at: String, // Дата создания
val updated_at: String, // Дата обновления
var expand : Boolean = false, // Флаг для раскрытия текста обращения в UI
)

View File

@ -0,0 +1,7 @@
package com.example.doctor.Appeals.TabLayout.Model
// Модель данных для списка обработанных обращений
data class AppealsOldListModel(
val appeals_old: List<AppealsOldModel> // Список обработанных обращений
)

View File

@ -0,0 +1,16 @@
package com.example.doctor.Appeals.TabLayout.Model
// Модель данных для обработанного обращения
data class AppealsOldModel(
val id: Int, // Уникальный идентификатор обращения
val number: Int, // Порядковый номер обращения
val text: String, // Текст обращения
val id_patient: Int, // ID пациента
val id_doctor: Int, // ID доктора
val check: Int, // Статус проверки обращения
val login: String, // Логин пациента
val created_at: String, // Дата создания
val updated_at: String, // Дата обновления
var expand : Boolean = false, // Флаг для раскрытия текста обращения в UI
)

View File

@ -0,0 +1,257 @@
package com.example.doctor.Appeals.TabLayout
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Appeals.AppealsNewAdapter
import com.example.doctor.Appeals.TabLayout.Model.AppealsNewModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldModel
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Model.PatientIdModel
import com.example.doctor.Patients.PatientActivity
import com.example.doctor.Patients.PatientsListFragment
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentNewAppealsBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
// Фрагмент для отображения списка новых (необработанных) обращений
class NewAppealsFragment : Fragment(), AppealsNewAdapter.Listener,AppealsNewAdapter.Listener2 {
private lateinit var binding:FragmentNewAppealsBinding
private val model: DoctorViewModel by activityViewModels()
private val dataModel: DataModel by activityViewModels()//Для передачи данных между фрагментами
lateinit var adapter: AppealsNewAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
val prefDoctorSave = SavePref()
// Класс для проверки наличия интернета
val enternetCheck = EnternetCheck()
// Список новых обращений
var newAppeals: List<AppealsNewModel>? = null
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentNewAppealsBinding.inflate(layoutInflater,container,false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewAppeals() // Инициализация списка обращений (RecyclerView)
patientListCurrent() // (зарезервировано для будущего)
// Подписка на обновление списка обращений
model.appealsNewList.observe(viewLifecycleOwner) {
if(newAppeals != it){
newAppeals = it
adapter.submitList(it)
if(newAppeals !=null){
binding.CLNull.visibility = View.GONE
binding.txtNull.visibility = View.GONE
}
}
}
getNewAppeals() // Загрузка новых обращений с сервера
}
// Получение необработанных обращений с сервера и обновление ViewModel
private fun getNewAppeals() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorNew("Bearer $Tokens")
requireActivity().runOnUiThread {
// Обработка ответа сервера
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
if (Nice) {
if(List?.appeals_new != null){
binding.txtNull.visibility = View.GONE
model.appealsNewList.value = List.appeals_new
}
else{
binding.txtNull.visibility = View.VISIBLE
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Получение обработанных обращений с сервера и обновление ViewModel (для синхронизации)
private fun getOldAppeals() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorOld("Bearer $Tokens")
requireActivity().runOnUiThread {
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
if (Nice) {
if(List?.appeals_old != null){
model.appealsOldList.value = List.appeals_old
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Отметить обращение как обработанное (отправка на сервер)
private fun addCheckAppeals(id:Int,id_patient:Int) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.UpdateMessageDoctor("Bearer $Tokens",id,id_patient)
requireActivity().runOnUiThread {
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
}
}
getNewAppeals()
getOldAppeals()
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
// (Зарезервировано для будущего, например, для вывода прогресса)
private fun patientListCurrent() = with(binding) {
// model.appealsAllCurrent.observe(viewLifecycleOwner) {//viewLifecycleOwner - следит за циклом жизни fragment
//
// }
}
// Инициализация списка обращений (RecyclerView)
private fun initRcViewAppeals() = with(binding) {
rcView.layoutManager = GridLayoutManager(requireContext(),1)
adapter = AppealsNewAdapter(this@NewAppealsFragment,this@NewAppealsFragment)
rcView.adapter = adapter
}
companion object {
// Фабричный метод для создания экземпляра NewAppealsFragment
fun newInstance() = NewAppealsFragment()
}
// Обработчик нажатия на кнопку "Обработать обращение"
override fun onClickAppeals(item: AppealsNewModel) {
addCheckAppeals(item.id,item.id_patient)
}
// Обработчик нажатия на кнопку "Открыть пациента"
override fun onClickAppealsPatient(item: AppealsNewModel) {
prefDoctorSave.saveIdPatient(requireContext(),item.id_patient)
prefDoctorSave.saveViewPatient(requireContext(),1)
model.patientId.value = PatientIdModel(item.id)
val intetn = Intent(requireContext(), PatientActivity::class.java)
startActivity(intetn)
}
}

View File

@ -0,0 +1,176 @@
package com.example.doctor.Appeals.TabLayout
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Appeals.AppealsOldAdapter
import com.example.doctor.Appeals.TabLayout.Model.AppealsNewModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldModel
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Model.PatientIdModel
import com.example.doctor.Patients.PatientActivity
import com.example.doctor.Patients.PatientsListFragment
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.FragmentOldAppealsBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import kotlin.concurrent.fixedRateTimer
// Фрагмент для отображения списка обработанных обращений
class OldAppealsFragment : Fragment(), AppealsOldAdapter.Listener,AppealsOldAdapter.Listener2 {
private lateinit var binding:FragmentOldAppealsBinding
private val model: DoctorViewModel by activityViewModels()
private val dataModel: DataModel by activityViewModels()//Для передачи данных между фрагментами
lateinit var adapter: AppealsOldAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
val prefDoctorSave = SavePref()
// Класс для проверки наличия интернета
val enternetCheck = EnternetCheck()
// Список обработанных обращений
var oldAppeals: List<AppealsOldModel>? = null
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentOldAppealsBinding.inflate(layoutInflater,container,false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewAppeals() // Инициализация списка обращений (RecyclerView)
appealsAllCurrent() // (зарезервировано для будущего)
// Подписка на обновление списка обработанных обращений
model.appealsOldList.observe(viewLifecycleOwner) {
if(oldAppeals != it){
oldAppeals = it
adapter.submitList(it)
if(oldAppeals !=null){
binding.CLNull.visibility = View.GONE
binding.txtNull.visibility = View.GONE
}
}
}
getOldAppeals() // Загрузка обработанных обращений с сервера
}
// Получение обработанных обращений с сервера и обновление ViewModel
private fun getOldAppeals() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorOld("Bearer $Tokens")
requireActivity().runOnUiThread {
val List = listAppeals.body()
val Nice = listAppeals.isSuccessful
val Code = listAppeals.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
if (Nice) {
if (List != null) {
if(List.appeals_old != null){
binding.txtNull.visibility = View.GONE
model.appealsOldList.value = List.appeals_old
}
else{
binding.txtNull.visibility = View.VISIBLE
}
}else{
binding.txtNull.visibility = View.VISIBLE
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
// (Зарезервировано для будущего, например, для вывода прогресса)
private fun appealsAllCurrent() = with(binding) {
// model.appealsAllCurrent.observe(viewLifecycleOwner) {//viewLifecycleOwner - следит за циклом жизни fragment
//
// }
}
// Инициализация списка обращений (RecyclerView)
private fun initRcViewAppeals() = with(binding) {
rcView.layoutManager = GridLayoutManager(requireContext(),1)
adapter = AppealsOldAdapter(this@OldAppealsFragment,this@OldAppealsFragment)
rcView.adapter = adapter
}
companion object {
// Фабричный метод для создания экземпляра OldAppealsFragment
fun newInstance() = OldAppealsFragment()
}
// Обработчик нажатия на обращение (пустой, можно реализовать при необходимости)
override fun onClickAppeals(item: AppealsOldModel) {
// Здесь можно реализовать дополнительную логику при нажатии на обращение
}
// Обработчик нажатия на кнопку "Открыть пациента"
override fun onClickAppealsPatient(item: AppealsOldModel) {
model.patientId.value = PatientIdModel(item.id)
val intetn = Intent(requireContext(), PatientActivity::class.java)
startActivity(intetn)
}
}

View File

@ -0,0 +1,24 @@
package com.example.doctor.Auth
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.doctor.R
import com.example.doctor.databinding.ActivityAuthBinding
// Активити для аутентификации пользователя (доктора)
class AuthActivity : AppCompatActivity() {
private lateinit var binding:ActivityAuthBinding
// Функция жизненного цикла Activity: инициализация интерфейса и отображение фрагмента аутентификации
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAuthBinding.inflate(layoutInflater)
setContentView(binding.root)
// Отображение фрагмента аутентификации при создании активити
supportFragmentManager.beginTransaction()
.replace(R.id.CLAuth, AuthFragment.newInstance())
.commit()
}
}

View File

@ -0,0 +1,200 @@
package com.example.doctor.Auth
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import com.example.doctor.Auth.Model.AuthModel
import com.example.doctor.Auth.Model.UserModel
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.MainActivity
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Pref.SavePref
import com.example.doctor.Toast.showCustomDangerToast
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentAuthBinding
import com.squareup.picasso.Picasso
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
// Фрагмент для аутентификации пользователя (доктора)
class AuthFragment : Fragment() {
private lateinit var binding: FragmentAuthBinding
private lateinit var doctorApi: DoctorApi
private val DoctorviewModel: DoctorViewModel by activityViewModels()
// Переменная для хранения токена
private var Token = ""
// Вспомогательные классы для работы с SharedPreferences
val prefDoctorSave = SavePref()
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
// Класс для проверки наличия интернета
val enternetCheck = EnternetCheck()
// Функция жизненного цикла Fragment: создание и возврат View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentAuthBinding.inflate(layoutInflater, container, false)
return binding.root
}
// Функция жизненного цикла Fragment: инициализация View и обработчиков
@SuppressLint("SuspiciousIndentation")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRetrofit() // Инициализация Retrofit клиента
prefDoctorClear.clearToken(requireContext()) // Очистка сохраненного токена
Token = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена (после очистки должен быть пустым)
binding.apply {
binding.textError.text = "" // Очистка текста ошибки
// Обработчик нажатия на кнопку "Авторизоваться"
binding.btnAuth.setOnClickListener {
// Проверка на заполненность полей логина и пароля
if(edLogin.text.toString() == ""||edPassword.text.toString() == ""){
Toast(requireContext()).showCustomInfoToast(
"Не все поля заполнены",
requireActivity()
)
}
else{
// Вызов функции аутентификации с введенными данными
Auth(
AuthModel(
edLogin.text.toString(),
edPassword.text.toString(),
)
)
}
}
}
}
// Функция для выполнения запроса аутентификации к серверу
private fun Auth(authModel: AuthModel) {
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Повторная инициализация Retrofit (возможно, избыточна здесь)
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val response = doctorApi.LoginDoctor(authModel) // Выполнение POST-запроса аутентификации
// Обработка сообщения об ошибке из тела ответа при его наличии
val errorMessage = response.errorBody()?.string()
?.let { JSONObject(it).getString("error") }
// Переключение на главный поток для обновления UI
requireActivity().runOnUiThread {
// Фиксируем полученные данные из ответа
val List = response.body()
val Nice = response.isSuccessful
val Code = response.code()
// Обработка различных кодов ответа сервера
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
// Если ответ успешный (код 200)
if (Nice) {
if (List != null) {
// Сохранение токена в ViewModel и SharedPreferences
DoctorviewModel.token.value = List.token
prefDoctorSave.saveToken(requireContext(), List.token)
// Переход на главный экран приложения
val intetn = Intent(requireContext(), MainActivity::class.java)
startActivity(intetn)
activity?.finish() // Закрытие текущей активити аутентификации
}
else{
// Отображение сообщения об ошибке, если пользователь не найден
Toast(requireContext()).showCustomInfoToast(
"Такого пользователя нету",
requireActivity()
)
}
}
}
else if (Code == 500) {
// Обработка внутренней ошибки сервера
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
// Обработка ошибки аутентификации (неверные учетные данные или истек токен)
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
companion object {
// Фабричный метод для создания экземпляра AuthFragment
fun newInstance() = AuthFragment()
}
}

View File

@ -0,0 +1,8 @@
package com.example.doctor.Auth.Model
// Модель данных для запроса аутентификации (логин и пароль)
data class AuthModel(
//val login:String,
val login:String, // Логин пользователя (доктора)
val password:String, // Пароль пользователя (доктора)
)

View File

@ -0,0 +1,6 @@
package com.example.doctor.Auth.Model
// Модель данных для проверки статуса токена
data class CheckTokenModel(
val status:String, // Статус токена (например, "active")
)

View File

@ -0,0 +1,8 @@
package com.example.doctor.Auth.Model
// Модель данных для ответа аутентификации (информация о пользователе)
data class UserModel(
val id:String, // Идентификатор пользователя (доктора)
val token:String, // Токен аутентификации
)

View File

@ -0,0 +1,173 @@
//package com.example.doctor.BottomSheetMenu
//
//import android.annotation.SuppressLint
//import android.app.Dialog
//import android.graphics.Color
//import android.os.Bundle
//import android.support.annotation.Nullable
//import android.view.KeyEvent
//import android.view.LayoutInflater
//import android.view.View
//import android.view.ViewGroup
//import android.widget.FrameLayout
//import android.widget.Toast
//import androidx.coordinatorlayout.widget.CoordinatorLayout
//import androidx.fragment.app.activityViewModels
//import com.example.doctor.DoctorViewModel
//import com.example.doctor.R
//import com.example.doctor.databinding.ItemButtomMenu2Binding
//import com.google.android.material.bottomsheet.BottomSheetBehavior
//import com.google.android.material.bottomsheet.BottomSheetDialogFragment
//
//// Этот класс представляет собой нижнее всплывающее меню (BottomSheet) для аккаунта.
//// В настоящее время весь код внутри класса закомментирован.
//class AccountBottomSheetMenu: BottomSheetDialogFragment() {
// private lateinit var binding: ItemButtomMenu2Binding
// private val model: DoctorViewModel by activityViewModels()//Инициализировали класс
//
// @SuppressLint("RestrictedApi")
// override fun setupDialog(dialog: Dialog, style: Int) {
// super.setupDialog(dialog, style)
//
// val view = LayoutInflater.from(context).inflate(R.layout.item_buttom_menu, null)
// dialog.setContentView(view)
//
// val param = (view.parent as View).layoutParams as CoordinatorLayout.LayoutParams
//
// val behavior = param.behavior
//
// if(behavior is BottomSheetBehavior<*>){
// behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
// override fun onStateChanged(bottomSheet: View, newState: Int) {
// var state = ""
// when(newState){
// BottomSheetBehavior.STATE_DRAGGING->{
// state = "DRAGGING"
// }
// BottomSheetBehavior.STATE_SETTLING->{
// state = "SETTLING"
// }
// BottomSheetBehavior.STATE_EXPANDED->{
// state = "EXPANDED"
// }
// BottomSheetBehavior.STATE_COLLAPSED->{
// state = "COLLAPSED"
// }
// BottomSheetBehavior.STATE_HIDDEN->{
// state = "HIDDEN"
// dismiss()
// behavior.state = BottomSheetBehavior.STATE_COLLAPSED
// }
//
// }
// }
//
// override fun onSlide(bottomSheet: View, slideOffset: Float) {
//
// }
//
// })
// }
// }
//
// //Данная функция необходима чтобы убрать белый фон в нижнем всплывающем меню
// override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//
// return super.onCreateDialog(savedInstanceState).apply {
// // window?.setDimAmount(0.2f) // Set dim amount here
// setOnShowListener {
// val bottomSheet = findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout
// bottomSheet.setBackgroundResource(android.R.color.transparent)
// }
// }
// }
//
//
// override fun onCreateView(
// inflater: LayoutInflater,
// container: ViewGroup?,
// savedInstanceState: Bundle?
// ): View? {
// binding = ItemButtomMenu2Binding.inflate(inflater,container,false)
// return binding.root
// }
//
//
//
//
// companion object {
//
// fun newInstance(): AccountBottomSheetMenu {
// val args = Bundle()
// val fragment = AccountBottomSheetMenu()
// fragment.arguments = args
// return fragment
// }
// }
//
//
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// super.onViewCreated(view, savedInstanceState)
//
// /* //Ввод адреса вручную
// binding.btnAdresAdd.setOnClickListener{
// binding.CardViewStart.visibility = View.GONE
// binding.CardView1.visibility = View.VISIBLE
// }
// //Вернутся из ввода адреса
// binding.btnBack.setOnClickListener{
// binding.CardViewStart.visibility = View.VISIBLE
// binding.CardView1.visibility = View.GONE
// }*/
// //Оформления заказа по введенному адресу
// /* binding.btnAddZakaz.setOnClickListener{
// setListener()
// }*/
// /*//Оформления заказа по адресу из профиля
// binding.btnZakazAdresUserProfile.setOnClickListener{
// setListener()
// }*/
// //Вызов фунции
// setListener()
//
//
// //binding.textView34.setText(binding.editTextAdres.getText().toString())
// }
//
// //Функция оформления заказа
// private fun setListener(){
// /* binding.btnAddZakaz.setOnClickListener{
// adresUser = binding.editTextAdres.text.toString()
// if(adresUser == ""){
// Toast.makeText(requireContext(), "Нужен адрес", Toast.LENGTH_SHORT).show()
// }
// else{
// //Данная модель нужна только для того чтобы передать сигнал для BasketFragmen и в случае если true, то он вызовет запрос и прогрузочный экран
// val itemStatus = StatusModel(true)
// model.addZakaz.value = itemStatus
// dismiss()//После нажатия закрываем
// }
// //requestWithSomeHttpHeadersZakaz(requireContext(), adresUser)
// }
// binding.editTextAdres.setOnKeyListener { v, keyCode, event ->
//
// when {
// //Проверяем нажалили мы на "ввод"
// //Check if it is the Enter-Key, Check if the Enter Key was pressed down
// ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.action == KeyEvent.ACTION_DOWN)) -> {
//
// //Если да, то выполняем нажати на кнопку отправки сообщения
// binding.btnAddZakaz.performClick()
//
// //return true
// return@setOnKeyListener true
// }
// else -> false
// }
//
//
// }*/
//
// }
//
//}

View File

@ -0,0 +1,182 @@
package com.example.user.BottomSheetMenu
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.os.Bundle
import android.support.annotation.Nullable
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.Toast
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.activityViewModels
import com.example.doctor.DoctorViewModel
import com.example.doctor.Patients.Model.CreatePatientModel
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.ItemButtomMenuBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
// Этот класс представляет собой нижнее всплывающее меню (BottomSheet) для добавления пациента.
class NoteBottomSheetMenu: BottomSheetDialogFragment() {
private lateinit var binding: ItemButtomMenuBinding
private lateinit var doctorApi: DoctorApi
// Класс для получения данных из SharedPreferences
val prefDoctorConclusion = ConclusionPref()
// Метод для настройки диалога BottomSheet
@SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.item_buttom_menu, null)
dialog.setContentView(view)
val param = (view.parent as View).layoutParams as CoordinatorLayout.LayoutParams
val behavior = param.behavior
if(behavior is BottomSheetBehavior<*>){
behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
// Обработчик изменения состояния BottomSheet
override fun onStateChanged(bottomSheet: View, newState: Int) {
var state = ""
when(newState){
BottomSheetBehavior.STATE_DRAGGING->{
state = "DRAGGING"
}
BottomSheetBehavior.STATE_SETTLING->{
state = "SETTLING"
}
BottomSheetBehavior.STATE_EXPANDED->{
state = "EXPANDED"
}
BottomSheetBehavior.STATE_COLLAPSED->{
state = "COLLAPSED"
}
BottomSheetBehavior.STATE_HIDDEN->{
state = "HIDDEN"
dismiss() // Закрыть диалог при скрытии
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
// Обработчик сдвига BottomSheet
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
}
}
// Данная функция необходима чтобы убрать белый фон в нижнем всплывающем меню
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
// window?.setDimAmount(0.2f) // Установка затемнения фона
setOnShowListener {
val bottomSheet = findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout
bottomSheet.setBackgroundResource(android.R.color.transparent) // Установка прозрачного фона
}
}
}
// Функция жизненного цикла Fragment: создание и возврат View
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = ItemButtomMenuBinding.inflate(inflater,container,false)
return binding.root
}
companion object {
// Фабричный метод для создания экземпляра NoteBottomSheetMenu
fun newInstance(): NoteBottomSheetMenu {
val args = Bundle()
val fragment = NoteBottomSheetMenu()
fragment.arguments = args
return fragment
}
}
// Функция жизненного цикла Fragment: инициализация View и обработчиков
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Обработчик нажатия на кнопку добавления пациента
binding.btnAddPatient.setOnClickListener{
// Проверка на заполненность полей email и пароля
if(binding.edEmail.text.toString() == "" && binding.edPassword.text.toString() == ""){
Toast(requireContext()).showCustomInfoToast("Не все поля заполнены", requireActivity())
}
else{
// Вызов функции создания аккаунта пациента
CreateAccountPatient(CreatePatientModel(binding.edEmail.text.toString(),binding.edPassword.text.toString()))
}
}
}
// Функция для создания аккаунта пациента через API
fun CreateAccountPatient(createPatientModel: CreatePatientModel) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.CreateAccountPatient("Bearer $Tokens",createPatientModel) // Выполнение POST-запроса создания пациента
// Переключение на главный поток для обновления UI
requireActivity().runOnUiThread {
// Фиксируем полученные данные из ответа
val patientList = listProduct.body()
// Обработка ответа сервера
if (patientList != null) {
Toast(requireContext()).showCustomInfoToast("Аккаунт для пациента создан", requireActivity())
dismiss()// Закрыть диалог после успешного создания
}
else{
Toast(requireContext()).showCustomInfoToast("Ошибка валидации", requireActivity())
}
}
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
}

View File

@ -0,0 +1,6 @@
package com.example.doctor.BottomSheetMenu
// Модель данных для передачи статуса (булево значение)
data class StatusModel(
val status: Boolean = false // Булево поле для индикации статуса (по умолчанию false)
)

View File

@ -0,0 +1,141 @@
package com.example.doctor.CodeError
import android.annotation.SuppressLint
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.MainActivity
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.ActivityCode429Binding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
// Активити для обработки ошибки с кодом 429 (слишком много запросов)
// При появлении этой ошибки пользователь перенаправляется на этот экран с ожиданием
class Code429Activity : AppCompatActivity() {
private lateinit var binding:ActivityCode429Binding // Объект привязки для доступа к элементам UI
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API
private lateinit var timer: Timer // Таймер для периодической проверки
// Вспомогательные классы для работы с SharedPreferences
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
// Класс для проверки наличия интернета
val enternetCheck = EnternetCheck()
// Функция жизненного цикла Activity: создание Activity и инициализация UI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCode429Binding.inflate(layoutInflater) // Надуваем макет
setContentView(binding.root) // Устанавливаем корневой View
}
// Функция для периодической проверки токена и состояния соединения
fun CheckToken(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(this@Code429Activity)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this@Code429Activity) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val list = doctorApi.CheckToken("Bearer $Tokens") // Запрос на проверку токена
// Переключение на главный поток для обновления UI и обработки ответа
runOnUiThread {
// Фиксируем полученные данные из ответа
val List = list.body()
val Nice = list.isSuccessful
val Code = list.code()
// Обработка различных кодов ответа сервера
if(Code==500){
// Переход на экран ошибки 500
val intetn = Intent(this@Code429Activity, Code500Activity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
else if(Code==200) {
// Если ответ успешный (код 200)
//Если нету ошибок
if (Nice) {
//Если нету ошибок
if (List != null) {
// Логируем успешную проверку токена
Log.i("clogon1231111","clogon1231111")
finish() // Закрываем текущую активити (ошибка устранена)
}
}
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401 (неавторизованный)
val intetn = Intent(this@Code429Activity, AuthActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(this, EnternetActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
// Функция жизненного цикла Activity: возобновление работы, запуск таймера
override fun onResume() {
super.onResume()
checkForUpdates(true) // Запускаем периодическую проверку
}
// Функция жизненного цикла Activity: остановка работы, отмена таймера
override fun onStop() {
super.onStop()
timer.cancel() // Отмена таймера
timer.purge() // Очистка задач таймера
}
// Запускает таймер, который периодически (каждые 15 секунд) вызывает CheckToken()
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 15000) { // Таймер с фиксированной задержкой и интервалом 15 секунд
this@Code429Activity.runOnUiThread { // Выполнение кода в основном потоке UI
CheckToken() // Вызываем проверку токена
}
}
}
}

View File

@ -0,0 +1,193 @@
package com.example.doctor.CodeError
import android.annotation.SuppressLint
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.core.content.ContentProviderCompat.requireContext
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.MainActivity
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.ActivityCode500Binding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
// Активити для обработки внутренней ошибки сервера с кодом 500
// Отображает пользователю экран с информацией об ошибке и таймером до перенаправления
class Code500Activity : AppCompatActivity() {
private lateinit var binding: ActivityCode500Binding // Объект привязки для доступа к элементам UI
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API
private lateinit var timer: Timer // Таймер для периодической проверки
// Вспомогательные классы для работы с SharedPreferences
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
// Класс для проверки наличия интернета
val enternetCheck = EnternetCheck()
var checkClose = false // Флаг для контроля закрытия активити (не используется в текущем коде)
// Функция жизненного цикла Activity: создание Activity и инициализация UI, запуск таймера обратного отсчета
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCode500Binding.inflate(layoutInflater) // Надуваем макет
setContentView(binding.root) // Устанавливаем корневой View
// val fixedRateTimer = fixedRateTimer("hello-timer",
// false,0,5000) {
//
// }
// try {
// this@Code500Activity.runOnUiThread {
// CheckToken()
// }
// }
// finally {
// fixedRateTimer.cancel();
// }
//ПОСТОЯННО ВЫЗЫВАЕТСЯ НУЖНО КАК-ТО ОТКЛЮЧАТЬ
// fixedRateTimer("timer", false, 0, 10000) {
// this@Code500Activity?.runOnUiThread {
// }
// }
binding.apply {
// Запуск таймера обратного отсчета на 30 секунд
val timer = object: CountDownTimer(30000, 1000) { // 30000 мс = 30 секунд, интервал 1000 мс = 1 секунда
override fun onTick(millisUntilFinished: Long) {
// Этот метод вызывается каждую секунду во время отсчета (логика не реализована)
}
override fun onFinish() {
// Этот метод вызывается по окончании таймера
// Переход на экран аутентификации
val intetn = Intent(this@Code500Activity, AuthActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
timer.start() // Запуск таймера
}
}
// Функция для периодической проверки токена и состояния соединения
fun CheckToken(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(this@Code500Activity)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this@Code500Activity) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val list = doctorApi.CheckToken("Bearer $Tokens") // Запрос на проверку токена
// Переключение на главный поток для обновления UI и обработки ответа
runOnUiThread {
// Фиксируем полученные данные из ответа
val List = list.body()
val Nice = list.isSuccessful
val Code = list.code()
// Обработка различных кодов ответа сервера
if(Code==429){
// Переход на экран ошибки 429
val intetn = Intent(this@Code500Activity, Code429Activity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
else if(Code==200) {
// Если ответ успешный (код 200)
//Если нету ошибок
if (Nice) {
//Если нету ошибок
if (List != null) {
// Логируем успешную проверку токена
Log.i("clogon1231111","clogon1231111")
finish() // Закрываем текущую активити (ошибка устранена)
}
}
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401 (неавторизованный)
val intetn = Intent(this@Code500Activity, AuthActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(this, EnternetActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
// Функция жизненного цикла Activity: возобновление работы, запуск таймера
override fun onResume() {
super.onResume()
checkForUpdates(true) // Запускаем периодическую проверку
}
// Функция жизненного цикла Activity: остановка работы, отмена таймера
override fun onStop() {
super.onStop()
timer.cancel() // Отмена таймера
timer.purge() // Очистка задач таймера
}
// Запускает таймер, который периодически (каждые 15 секунд) вызывает CheckToken()
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 15000) { // Таймер с фиксированной задержкой и интервалом 15 секунд
this@Code500Activity.runOnUiThread { // Выполнение кода в основном потоке UI
CheckToken() // Вызываем проверку токена
}
}
}
}

View File

@ -0,0 +1,30 @@
package com.example.doctor
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
//Ослеживание за обновлением подробной продуктовой карточкой
open class DataModel: ViewModel() {
/*//Для отлеживания обновлений активити
val messageForActivity: MutableLiveData<String> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<String>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}*/
//Для отлеживания обновлений фрагммента 1
val messageForFrag1: MutableLiveData<Int> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<Int>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}
val fragmentMenu: MutableLiveData<Int> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<Int>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}
val patientList: MutableLiveData<Int> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<Int>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}
val patientAppeal: MutableLiveData<Int> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<Int>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}
/*//Для отлеживания обновлений фрагммента 2
val messageForFrag2: MutableLiveData<String> by lazy{//by lazy - чтобы каждый раз не создавался MutableLiveData(MutableLiveData<String>()), а он один раз при загрузке создаться и дальше будет пользоваться уже созданным
MutableLiveData<String>()//LiveData - означает что будет обновляться в нужынй момент, не постоянна, а в зависимоти от жизни активити
}*/
}

View File

@ -0,0 +1,93 @@
package com.example.doctor
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsNewModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldModel
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Model.PatientIdModel
import com.example.doctor.Patients.Model.PatientModel
import com.example.doctor.Patients.Reports.Courses.SportCoursModel
import com.example.doctor.Patients.Reports.Edit.EditSportModel
import com.example.doctor.Patients.Reports.QBAModel
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Model.EditCoursesDoctorModel
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Model.CoursesDoctorCA
import com.example.doctor.Setting.Courses.Model.CoursesDoctorModel
//import com.example.retrofit.model.Product
class DoctorViewModel: ViewModel() {
//Токен
val token = MutableLiveData<String>()
//Пациенты
val patientId = MutableLiveData<PatientIdModel>()
val patientCurrent = MutableLiveData<PatientAllModel>()
val patientListList= MutableLiveData<PatientAllModel>()
//Обращения необработанные
val appealsNewCurrent = MutableLiveData<AppealsNewModel>()
val appealsNewList= MutableLiveData<List<AppealsNewModel>>()
//Обращения обработанные
val appealsOldCurrent = MutableLiveData<AppealsOldModel>()
val appealsOldList= MutableLiveData<List<AppealsOldModel>>()
//val productList = MutableLiveData<List<Product>>()
val patientOneCurrent = MutableLiveData<PatientModel>()
//Отчеты
val qbaCurrent = MutableLiveData<QBAModel>()
val qbaList= MutableLiveData<List<QBAModel>>()
//КУрсы
val SportCoursCurrent = MutableLiveData<SportCoursModel>()
val SportCoursList= MutableLiveData<List<SportCoursModel>>()
val SportCoursDoctorList= MutableLiveData<List<SportCoursModel>>()
val BtnSportCoursDoctorCurrent = MutableLiveData<Int>()
//Редактирование занятий
val EditSportCurrentYes = MutableLiveData<EditSportModel>()
val EditSportListYes= MutableLiveData<List<EditSportModel>>()
//Редактирование занятий
val EditSportCurrentNO = MutableLiveData<EditSportModel>()
val EditSportListNo= MutableLiveData<List<EditSportModel>>()
//Список пациентов
val PatientActiveCurrent = MutableLiveData<PatientAllModel>()
val PatientActiveList= MutableLiveData<List<PatientAllModel>>()
val PatientNotCurrent = MutableLiveData<PatientAllModel>()
val PatientNotList= MutableLiveData<List<PatientAllModel>>()
//Список со всеми пациентами
val PatientAllModel= MutableLiveData<List<PatientAllModel>>()
//id пациента
val id_patient = MutableLiveData<Int>()
//Курсы созданный доктором
val CoursesDoctorCurrent = MutableLiveData<CoursesDoctorModel>()
val CoursesDoctorList= MutableLiveData<List<CoursesDoctorModel>>()
//Упражнения не входяшие в курс доктора
val EditCoursesDoctorAllCurrent = MutableLiveData<EditCoursesDoctorModel>()
val EditCoursesDoctorAllList= MutableLiveData<List<EditCoursesDoctorModel>>()
//Упражнения входяшие в курс доктора
val EditCoursesDoctorYourCurrent = MutableLiveData<EditCoursesDoctorModel>()
val EditCoursesDoctorYourList= MutableLiveData<List<EditCoursesDoctorModel>>()
val CoursesDoctorCA = MutableLiveData<CoursesDoctorCA>()
//Список пациентов для поисковой строки
val patientListSearch= MutableLiveData<List<PatientAllModel>>()
//Для передачи данных редактируемого курса
val CoursesCustomDoctor = MutableLiveData<CoursesDoctorModel>()
}

View File

@ -0,0 +1,26 @@
package com.example.doctor.Enternet
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.doctor.R
import com.example.doctor.databinding.ActivityEnternetBinding
import com.example.doctor.databinding.FragmentEnternetBinding
// Активити для отображения экрана отсутствия интернет-соединения
class EnternetActivity : AppCompatActivity() {
private lateinit var binding: ActivityEnternetBinding // Объект привязки для доступа к элементам UI
// Функция жизненного цикла Activity: создание Activity и инициализация UI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEnternetBinding.inflate(layoutInflater) // Надуваем макет
setContentView(binding.root) // Устанавливаем корневой View
// Отображаем фрагмент отсутствия интернета при создании активити
supportFragmentManager.beginTransaction()
.replace(R.id.CLEnternet, EnternetFragment.newInstance())
.commit() // Заменяем контейнер на фрагмент
}
}

View File

@ -0,0 +1,42 @@
package com.example.doctor.Enternet
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
// Класс для проверки наличия интернет-соединения
class EnternetCheck() {
// Функция для проверки активного интернет-соединения
fun isOnline(context: Context): Boolean {
if (context == null) return false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
return true
}
}
}
} else {
val activeNetworkInfo = connectivityManager.activeNetworkInfo
if (activeNetworkInfo != null && activeNetworkInfo.isConnected) {
return true
}
}
return false // Интернет отсутствует
}
}

View File

@ -0,0 +1,43 @@
package com.example.doctor.Enternet
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.doctor.MainActivity
import com.example.doctor.databinding.FragmentEnternetBinding
// Фрагмент для отображения экрана отсутствия интернет-соединения
class EnternetFragment : Fragment() {
private lateinit var binding: FragmentEnternetBinding // Объект привязки для доступа к элементам UI макета фрагмента
// Функция жизненного цикла Fragment: создание и возврат View (надувание макета)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentEnternetBinding.inflate(layoutInflater,container,false)
return binding.root // Возвращаем корневой View фрагмента
}
// Функция жизненного цикла Fragment: инициализация View и обработчиков событий после создания View
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Установка обработчика нажатия на кнопку "Повторить" или "Проверить интернет"
binding.btnEnternet.setOnClickListener{
// Создание Intent для перехода к MainActivity (попытка вернуться в основное приложение)
val intetn = Intent(requireContext(), MainActivity::class.java)
activity?.finish() // Закрываем текущую активити (EnternetActivity)
startActivity(intetn) // Запускаем MainActivity
}
}
companion object {
// Фабричный метод для создания нового экземпляра EnternetFragment
fun newInstance() = EnternetFragment() // Создаем и возвращаем новый экземпляр фрагмента
}
}

View File

@ -0,0 +1,157 @@
package com.example.doctor.Home
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.FragmentHomeBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
// Фрагмент для отображения главной страницы приложения (статистика пациента и обращений)
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding // Объект привязки для доступа к элементам UI макета фрагмента
private val dataModel: DataModel by activityViewModels()// ViewModel для обмена данными между фрагментами (например, для навигации)
private var Token = "" // Переменная для хранения токена аутентификации
val prefDoctorClear= ClearPref() // Вспомогательный класс для очистки SharedPreferences
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API для сетевых запросов
val prefDoctorConclusion = ConclusionPref() // Вспомогательный класс для получения данных из SharedPreferences
private val modelDoctor: DoctorViewModel by activityViewModels() // ViewModel для хранения и управления данными приложения
// Класс проверки наличия интернета
val enternetCheck = EnternetCheck()
// Функция жизненного цикла, создаёт и возвращает view фрагмента (надувание макета)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(layoutInflater,container, false)
return binding.root // Возвращаем корневой View фрагмента
}
// Функция жизненного цикла, вызывается после создания view. Устанавливает обработчики нажатий и запускает загрузку данных
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Обработчик нажатия на карточку пациента: переход на экран списка пациентов
binding.CVPatinet.setOnClickListener {
dataModel.fragmentMenu.value = R.id.patient // Устанавливаем значение в ViewModel для навигации
}
// Обработчик нажатия на карточку обращений: переход на экран списка обращений
binding.CVAppeals.setOnClickListener {
dataModel.fragmentMenu.value = R.id.list_check // Устанавливаем значение в ViewModel для навигации
}
CountPatientAndAppeals() // Загружает и отображает статистику пациентов и обращений
}
// Получение данных для главной страницы: количества пациентов и обращений с сервера
fun CountPatientAndAppeals() = with(binding) {
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listHomeView = doctorApi.CountPatientAndAppeals("Bearer $Tokens") // Выполнение GET-запроса для получения статистики
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
// Фиксируем полученные данные из ответа
val List = listHomeView.body()
val Nice = listHomeView.isSuccessful
val Code = listHomeView.code()
// Обработка различных кодов ответа сервера
if(Code==429){
// Переход на экран ошибки 429
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
// Если ответ успешный (код 200)
//Если нету ошибок
if (Nice) {
if (List != null) {
// Обновление текстовых полей с количеством пациентов и обращений
txtCountPatient.text = List?.patient.toString()
txtCountAppealsNew.text = List?.appeals_check.toString()
txtCountAppealsAll.text = List?.appeals_all.toString()
CLLoad.visibility = View.GONE // Скрываем индикатор загрузки
}
}
}
else if (Code == 500) {
// Переход на экран ошибки 500
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401 (неавторизованный)
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
companion object {
// Фабричный метод для создания экземпляра HomeFragment
fun newInstance() = HomeFragment() // Создаем и возвращаем новый экземпляр фрагмента
}
}

View File

@ -0,0 +1,9 @@
package com.example.doctor.Home
// Модель данных для информации на главной странице (статистика)
data class HomeInfoModel(
val patient: Int, // Количество пациентов
val appeals_check: Int, // Количество проверенных обращений
val appeals_all: Int, // Общее количество обращений
)

View File

@ -0,0 +1,518 @@
package com.example.doctor
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.RemoteViews
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintSet.Constraint
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkRequest
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.Auth.AuthFragment
import com.example.doctor.Auth.Model.AuthModel
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.Worker.MyWorker
import com.example.doctor.databinding.ActivityMainBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import android.app.TaskStackBuilder
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.view.View
import androidx.activity.viewModels
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.test.core.app.ActivityScenario.launch
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Enternet.EnternetFragment
import kotlinx.coroutines.Job
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
// Главная Activity приложения, управляет отображением основного контента и аутентификацией
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding // Объект привязки для доступа к элементам UI макета активити
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API для сетевых запросов
private lateinit var timer: Timer // Таймер для периодических задач
//Токен
private var Token = "" // Переменная для хранения токена аутентификации
val prefDoctorSave = SavePref() // Вспомогательный класс для сохранения данных в SharedPreferences
val prefDoctorConclusion = ConclusionPref() // Вспомогательный класс для получения данных из SharedPreferences
var backPressedTime: Long = 0 // Время последнего нажатия кнопки "Назад"
// Переменные для работы с уведомлениями (закомментированы)
lateinit var notificationManager: NotificationManager
lateinit var notificationChannel: NotificationChannel
lateinit var builder: Notification.Builder
private val channelId = "i.apps.notifications"
private val description = "Test notification"
// Константы для каналов уведомлений (закомментированы)
val CHANNEL_ID = "channelID"
val CHANNEL_NAME = "channelName"
val NOTIF_ID = 0
//Класс проверки интеренета
val enternetCheck = EnternetCheck() // Класс для проверки наличия интернет-соединения
private val modelDoctor: DoctorViewModel by viewModels()// ViewModel для хранения и управления данными приложения
// Функция жизненного цикла Activity: создание Activity и инициализация UI
@SuppressLint("RemoteViewLayout", "MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) // Надуваем макет
setContentView(binding.root) // Устанавливаем корневой View
MainAndAuth() // Запуск процесса аутентификации или отображения основного контента
}
// Получение необработанных обращений с сервера и обновление ViewModel
private fun getNewAppeals() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorNew("Bearer $Tokens") // Выполнение GET-запроса для получения новых обращений
// Переключение на главный поток для обновления UI
runOnUiThread {
//Фиксируем полученные данные
val AppealsMes = listAppeals.body()
//Если нету ошибок
if (AppealsMes != null) {
if (AppealsMes.appeals_new != null) {
modelDoctor.appealsNewList.value = AppealsMes.appeals_new // Обновление списка новых обращений в ViewModel
}
}
}
}
} else {
// finish()
// val intetn = Intent(this, EnternetActivity::class.java)
// startActivity(intetn)
}
}
// Получение обработанных обращений с сервера и обновление ViewModel
private fun getOldAppeals() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listAppeals = doctorApi.GetAppealsDoctorOld("Bearer $Tokens") // Выполнение GET-запроса для получения обработанных обращений
// Переключение на главный поток для обновления UI
runOnUiThread {
//Фиксируем полученные данные
val AppealsMes = listAppeals.body()
//Если нету ошибок
if (AppealsMes != null) {
if (AppealsMes.appeals_old != null) {
modelDoctor.appealsOldList.value = AppealsMes.appeals_old // Обновление списка обработанных обращений в ViewModel
}
}
}
}
} else {
// finish()
// val intetn = Intent(this, EnternetActivity::class.java)
// startActivity(intetn)
}
}
// Получение списка всех пациентов для поиска с сервера и обновление ViewModel
fun GetPatientListSearch() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listPatientList = doctorApi.GetPatientAll("Bearer $Tokens") // Выполнение GET-запроса для получения всех пациентов
// Переключение на главный поток для обновления UI
runOnUiThread {
//Фиксируем полученные данные
val patientList = listPatientList.body()
//Если нету ошибок
if (patientList != null) {
modelDoctor.patientListSearch.value = patientList.patient // Обновление списка пациентов для поиска в ViewModel
}
}
}
} else {
// finish()
// val intetn = Intent(this, EnternetActivity::class.java)
// startActivity(intetn)
}
}
// Получение списка активных пациентов с сервера и обновление ViewModel
fun GetPatientListYes() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientAllActive("Bearer $Tokens") // Выполнение GET-запроса для получения активных пациентов
// Переключение на главный поток для обновления UI
runOnUiThread {
//Фиксируем полученные данные
val patientList = listProduct.body()
//Если нету ошибок
if (patientList != null) {
modelDoctor.PatientActiveList.value = patientList.patient // Обновление списка активных пациентов в ViewModel
}
}
}
} else {
// finish()
// val intetn = Intent(this, EnternetActivity::class.java)
// startActivity(intetn)
}
}
// Получение списка неактивных пациентов с сервера и обновление ViewModel
fun GetPatientListNo() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(this) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientAllNotActive("Bearer $Tokens") // Выполнение GET-запроса для получения неактивных пациентов
// Переключение на главный поток для обновления UI
runOnUiThread {
//Фиксируем полученные данные
val patientList = listProduct.body()
//Если нету ошибок
if (patientList != null) {
modelDoctor.PatientNotList.value = patientList.patient // Обновление списка неактивных пациентов в ViewModel
}
}
}
} else {
// finish()
// val intetn = Intent(this, EnternetActivity::class.java)
// startActivity(intetn)
}
}
// private fun createNotifChannel() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val channel = NotificationChannel(
// CHANNEL_ID,
// CHANNEL_NAME,
// NotificationManager.IMPORTANCE_DEFAULT
// ).apply {
// lightColor = Color.BLUE
// enableLights(true)
// }
// val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
// manager.createNotificationChannel(channel)
// }
// }
// //Одинарный
// fun myOneTimeWork() {
// val constraints = Constraints.Builder()
// .setRequiredNetworkType(NetworkType.NOT_REQUIRED)//Тут мы указыаем что сработает при наличие интернета
// .setRequiresCharging(true)
// .build()
//
// //Ограничение
// val myWorkRequest: WorkRequest =
// OneTimeWorkRequest.Builder(MyWorker::class.java)//OneTimeWorkRequest - разовая
// .setConstraints(constraints)
// .build()
//
// WorkManager.getInstance(this@MainActivity).enqueue(myWorkRequest)//Отправка запроса
// }
// //Повторяющийся
// fun myPriodicTimeWork() {
// val constraints = Constraints.Builder()
// .setRequiredNetworkType(NetworkType.NOT_REQUIRED)//Тут мы указыаем что сработает при наличие интернета
// .setRequiresCharging(true)
// .build()
//
// //Ограничение
// val myWorkRequest = PeriodicWorkRequest.Builder(
// MyWorker::class.java,
// 15,
// TimeUnit.MINUTES
// )//PeriodicWorkRequest - переодически, 15 - время интервала(минимальное 15 минут)
// .setConstraints(constraints)
// .addTag("my_id")//Уникальный индификатор для уведомления, для того чтобы можно было кпримеру обратиться и остановать данный менеджер
// .build()
//
// WorkManager.getInstance(this@MainActivity).enqueueUniquePeriodicWork(
// "my_id",
// ExistingPeriodicWorkPolicy.KEEP,
// myWorkRequest
// )//Отправка запроса
// }
// Функция для определения, отображать экран аутентификации или основной контент
fun MainAndAuth() {
Token = prefDoctorConclusion.conclusionToken(this@MainActivity) // Получение токена
//CheckTokenAuth(Token)
if (Token == "") { // Если токен пустой, переходим к аутентификации
Auth()
} else { // Иначе, проверяем токен
CheckTokenAuth(Token)
}
}
// Функция для отображения экрана аутентификации
fun Auth() {
binding.CLLoad.visibility = View.GONE // Скрываем индикатор загрузки
// Замена текущего фрагмента на фрагмент аутентификации
supportFragmentManager.beginTransaction()
.replace(R.id.CLMain, AuthFragment.newInstance())
.commit() // Применяем изменения
}
// Функция для отображения основного контента приложения
fun Main() {
binding.CLLoad.visibility = View.GONE // Скрываем индикатор загрузки
fragment_inicializ() // Инициализация главного фрагмента с нижним меню
// fixedRateTimer("timer", false, 0, 10000) {
// this@MainActivity.runOnUiThread {
// getNewAppeals()
// getOldAppeals()
// GetPatientListSearch()
// GetPatientListYes()
// GetPatientListNo()
// }
// }
}
// (Закомментированная функция для инициализации уведомлений и WorkManager)
@SuppressLint("MissingPermission")
private fun main() = with(binding) {
// btn11.setOnClickListener {
// myOneTimeWork()
// }
// btn22.setOnClickListener {
// myPriodicTimeWork()
// }
// createNotifChannel()
// notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// val intent = Intent(this@MainActivity, MainActivity::class.java)
// val pendingIntent = TaskStackBuilder.create(this@MainActivity).run {
// addNextIntentWithParentStack(intent)
// getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
// }
//
// val notif = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
// .setContentTitle("Sample Title")
// .setContentText("This is sample body notif")
// .setSmallIcon(R.drawable.door)
// .setPriority(NotificationCompat.PRIORITY_HIGH)
// .setContentIntent(pendingIntent)
// .build()
//
//
// val notifManger = NotificationManagerCompat.from(this@MainActivity)
// button3.setOnClickListener {
//
// notifManger.notify(NOTIF_ID, notif)
// }
//
//
}
// Функция для проверки валидности токена аутентификации на сервере
private fun CheckTokenAuth(token: String) {
// Проверка интернет-соединения
if (enternetCheck.isOnline(this)) {
initRetrofit() // Инициализация Retrofit
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val response = doctorApi.CheckToken("Bearer $token") // Выполнение GET-запроса для проверки токена
// Переключение на главный поток для обновления UI и обработки ответа
runOnUiThread {
//Фиксируем полученные данные
val List = response.body()
val Nice = response.isSuccessful
val Code = response.code()
// Обработка различных кодов ответа сервера
if(Code==429){
// Переход на экран ошибки 429
val intetn = Intent(this@MainActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (Code.toString() == "200") { // Если код 200, токен валиден, переходим на основной экран
Main()
} else { // Иначе, токен невалиден, переходим к аутентификации
Auth()
}
}
}
else if (Code == 500) {
// Переход на экран ошибки 500
val intetn = Intent(this@MainActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401 (неавторизованный)
val intetn = Intent(this@MainActivity, AuthActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(this, EnternetActivity::class.java)
finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
// Инициализация главного фрагмента (MainFragment) с нижним меню
private fun fragment_inicializ() {
//Вывод фрагмента на активити при первоначальной загрузке
supportFragmentManager.beginTransaction()
.replace(R.id.CLMain, MainFragment.newInstance())
.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
// override fun onBackPressed() {
// if (backPressedTime + 3000 > System.currentTimeMillis()) {
// super.onBackPressed()
// finish()
// } else {
// AlertDialog.Builder(this@MainActivity)
// .setTitle("Выйти")
// .setMessage("Вы точно хотите выйти из приложения?")
// .setPositiveButton("Да") { dialog, whichButton ->
// super.onBackPressed()
// }
// .setNegativeButton("Нет") { dialog, whichButton ->
//
// }
// .show()
// }
// backPressedTime = System.currentTimeMillis()
// }
// override fun onResume() {
// super.onResume()
// checkForUpdates(true)
// }
//
//
// override fun onStop() {
// super.onStop()
// timer.cancel()
// timer.purge()
// }
//
// private fun checkForUpdates(daemonIsTrue: Boolean) {
// Token = prefDoctorConclusion.conclusionToken(this@MainActivity)
// timer = fixedRateTimer("default", daemonIsTrue, 0, 5000) {
// this@MainActivity?.runOnUiThread {
//
// CheckTokenAuth(Token)
// }
// }
//
//}
}

View File

@ -0,0 +1,211 @@
package com.example.doctor
import android.annotation.SuppressLint
import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
//import androidx.navigation.fragment.findNavController
import com.example.doctor.Appeals.AppealsFragment
import com.example.doctor.Home.HomeFragment
import com.example.doctor.Patients.PatientsListFragment
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Setting.SettingFragment
import com.example.doctor.databinding.FragmentMainBinding
import java.util.Date
class MainFragment : Fragment() {
private lateinit var binding: FragmentMainBinding
private val dataModel: DataModel by activityViewModels()//Для передачи данных
val prefDoctorSave = SavePref()
val prefDoctorConclusion = ConclusionPref()
private var Token = ""
var sdf: SimpleDateFormat = SimpleDateFormat("EEEE")
var d: Date = Date()
var dayOfTheWeek: String = sdf.format(d)
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentMainBinding.inflate(layoutInflater, container, false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует наблюдателей и запускает начальные функции
@SuppressLint("ResourceType")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//MainAndAuth()
dataModel.fragmentMenu.observe(viewLifecycleOwner, Observer {
binding.buttonNavigation.selectedItemId = it
})
addDate() // Добавляет текущую дату на экран
fragment_inicializ() // Инициализирует первый фрагмент
}
// Добавляет текущую дату и день недели в текстовое поле на главном экране
private fun addDate() {
val calendar: Calendar = Calendar.getInstance()
val sdf: SimpleDateFormat = SimpleDateFormat("EEEE")
val d: Date = Date()
val DayOfTheWeek: String = sdf.format(d)
val Day = calendar.get(Calendar.DATE)
val Month = calendar.get(Calendar.MONTH).plus(1)
var day = Day.toString()
var month = ""
var date_of_the_week = ""
when (Month) {
1 -> month = "Январь"
2 -> month = "Февраль"
3 -> month = "Март"
4 -> month = "Апрель"
5 -> month = "Май"
6 -> month = "Июнь"
7 -> month = "Июль"
8 -> month = "Август"
9 -> month = "Сентябрь"
10 -> month = "Октябрь"
11 -> month = "Ноябрь"
12 -> month = "Декабрь"
else -> { // обратите внимание на блок
month = ""
}
}
when (dayOfTheWeek) {
"Monday" -> date_of_the_week = "Пн"
"Tuesday" -> date_of_the_week = "Вт"
"Wednesday" -> date_of_the_week = "Ср"
"Thursday" -> date_of_the_week = "Чт"
"Friday" -> date_of_the_week = "Пт"
"Saturday" -> date_of_the_week = "Сб"
"Sunday" -> date_of_the_week = "Вс"
"Понедельник" -> date_of_the_week = "Пн"
"Вторник" -> date_of_the_week = "Вт"
"Стреда" -> date_of_the_week = "Ср"
"Четверг" -> date_of_the_week = "Чт"
"Пятница" -> date_of_the_week = "Пт"
"Суббота" -> date_of_the_week = "Сб"
"Воскресенье" -> date_of_the_week = "Вс"
else -> {
date_of_the_week = ""
}
}
System.out.println(calendar.get(Calendar.DATE))
binding.txtDate.setText("${day}" + " " + "${month}")
}
// fun MainAndAuth(){
//
// //Token = prefDoctorConclusion.conclusionToken()
// if(Token == ""){
// Auth()
// }
// else{
// Main()
// }
// }
// fun Auth(){
// val intetn = Intent(requireContext(), AuthActivity::class.java)
// startActivity(intetn)
// activity?.finish()
// }
// fun Main(){
// fragment_inicializ()
// }
// Инициализация фрагментов и навигации по нижнему меню
fun fragment_inicializ() {
Token = prefDoctorConclusion.conclusionToken(requireContext())
//Вывод фрагмента на активити при первоначальной загрузке
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.CLMainFragment, HomeFragment.newInstance())
?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
//Эран который будет выбран по умолчанию(кнопка которая будет прожата по умолчанию)
binding.buttonNavigation.selectedItemId =
R.id.home//По умолчанию и так первая, но на всякий случай выберу еще програмным путем первую ячейку
//Нажатие на bottom navigation
binding.buttonNavigation.setOnItemSelectedListener {
when (it.itemId) {//it.itemId - это id нажатого элемента
R.id.home -> {
if (!isClickRecently()) {
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.CLMainFragment, HomeFragment.newInstance())
?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}
R.id.patient -> {
if (!isClickRecently()) {
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.CLMainFragment, PatientsListFragment.newInstance())
?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}
R.id.list_check -> {//Если вы не авторизованный пользваотель то вам не будет доступен доступ к данном фрагменту
if (!isClickRecently()) {
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.CLMainFragment, AppealsFragment.newInstance())
?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}
R.id.setting -> {//Если вы не авторизованный пользваотель то вам не будет доступен доступ к данном фрагменту
if (!isClickRecently()) {
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.CLMainFragment, SettingFragment.newInstance())
?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}
}
true
}
}
// Проверяет, было ли недавнее нажатие, чтобы избежать двойных кликов
var mLastClickTime = 0L
fun isClickRecently(): Boolean {
if (SystemClock.elapsedRealtime() - mLastClickTime < 500) {
return true
}
mLastClickTime = SystemClock.elapsedRealtime()
return false
}
companion object {
// Фабричный метод для создания экземпляра MainFragment
fun newInstance() = MainFragment()
}
}

View File

@ -0,0 +1,85 @@
package com.example.doctor.Patients.Adapter
import android.annotation.SuppressLint
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Model.PatientModel
import com.example.doctor.R
import com.example.doctor.databinding.ItemCardPatientBinding
// Адаптер для отображения списка пациентов в RecyclerView
class PatientListAdapter(val listener_patient: Listener) :
ListAdapter<PatientAllModel, PatientListAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента списка пациентов
class Holder(view: View, val listener_patient: Listener) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding =
ItemCardPatientBinding.bind(view)
var itemTemp: PatientAllModel? =
null // Глобальная переменная для текущего пациента, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на карточку пациента
init {
itemView.setOnClickListener {
itemTemp?.let { it1 -> listener_patient.onClickPatient(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation", "SetTextI18n")
fun bind(item: PatientAllModel) = with(binding) {
itemTemp = item
txtNumberCurds.text = item.number.toString() + "."
txtLoginPatient.text = item.login
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_card_patient, parent, false)
return Holder(view, listener_patient)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<PatientAllModel>() {
override fun areItemsTheSame(
oldItem: PatientAllModel,
newItem: PatientAllModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: PatientAllModel,
newItem: PatientAllModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на карточку пациента
interface Listener {
fun onClickPatient(item: PatientAllModel)
}
}

View File

@ -0,0 +1,7 @@
package com.example.doctor.Patients.Model
data class CreatePatientModel(
//val login:String,
val login:String,
val password:String,
)

View File

@ -0,0 +1,6 @@
package com.example.doctor.Patients.Model
data class MessageModel(
val message: String,
)

View File

@ -0,0 +1,6 @@
package com.example.doctor.Patients.Model
data class PatientAllListModel(
val patient: List<PatientAllModel>
)

View File

@ -0,0 +1,22 @@
package com.example.doctor.Patients.Model
import java.util.Date
data class PatientAllModel(
val number: Int? = null,
val id: Int? = null,
val login: String? = null,
val email: String? = null,
val loginDoctor: String? = null,
val emailDoctor: String? = null,
val pause: String? = null,
val block: String? = null,
val report7day: String? = null,
val report15day: String? = null,
val id_sport_patient: Int? = null,
val total_days_sports: Int? = null,
val now_days_sports: Int? = null,
val created_at: String? = null,
val updated_at: String? = null,
)

View File

@ -0,0 +1,9 @@
package com.example.doctor.Patients.Model
import java.util.Date
data class PatientIdModel(
val id: Int
)

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Model
data class PatientModel(
val id: Int,
val login: String,
//val email:String,
)

View File

@ -0,0 +1,6 @@
package com.example.doctor.Patients.Model
data class PauseModel(
val message: String,
)

View File

@ -0,0 +1,421 @@
package com.example.doctor.Patients
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.activity.viewModels
import androidx.core.content.ContentProviderCompat.requireContext
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.ActivityPatientBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
class PatientActivity : AppCompatActivity() {
private lateinit var binding: ActivityPatientBinding
private lateinit var doctorApi: DoctorApi
private lateinit var timer: Timer
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
private val modelDoctor: DoctorViewModel by viewModels()//Инициализировали класс
var idPatient = 0
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPatientBinding.inflate(layoutInflater)
setContentView(binding.root)
supportFragmentManager.beginTransaction().replace(R.id.CLPatientActivity, PatientFragment.newInstance()).commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
idPatient = prefDoctorConclusion.conclusionIdPatient(this)
}
//Получения списка анкет ДО и ПОСЛЕ для пациента
fun QBAPatientList(id:Int){
if (enternetCheck.isOnline(this@PatientActivity)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this@PatientActivity)
CoroutineScope(Dispatchers.IO).launch {
val list = doctorApi.GetPatientBAQiestionar("Bearer $Tokens",id)
runOnUiThread {
//Фиксируем полученные данные
val List = list.body()
val Nice = list.isSuccessful
val Code = list.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if(List?.questionnaire !=null){
modelDoctor.qbaList.value = List.questionnaire
}
}
}
//2
GetPatientID(idPatient)
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
finish()
val intetn = Intent(this, EnternetActivity::class.java)
startActivity(intetn)
}
}
private fun GetPatientID(idPatient: Int) {
if (enternetCheck.isOnline(this)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this)
CoroutineScope(Dispatchers.IO).launch {
val listPatient = doctorApi.GetPatientID("Bearer $Tokens", idPatient)
runOnUiThread {
//Фиксируем полученные данные
val List = listPatient.body()
val Nice = listPatient.isSuccessful
val Code = listPatient.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.patientCurrent.value = List
}
}
//3
GetCoursesAllSport(idPatient)
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity,Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(this, EnternetActivity::class.java)
finish()
startActivity(intetn)
}
}
//Вывод всех курсов
fun GetCoursesAllSport(idPatient: Int){
if (enternetCheck.isOnline(this)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this)
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetCoursAllPatient("Bearer $Tokens",idPatient)
runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.SportCoursList.value = List.courses
}
}
//4
GetCoursesYouSport(idPatient)
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(this@PatientActivity, EnternetActivity::class.java)
finish()
startActivity(intetn)
}
}
//Получения списка курсов созданных доктором
fun GetCoursesYouSport(idPatient:Int) {
if (enternetCheck.isOnline(this)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this)
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetCoursesDoctorPatient("Bearer $Tokens",idPatient)
runOnUiThread {
//Фиксируем полученные данные
val List = listCoursesDoctor.body()
val Nice = listCoursesDoctor.isSuccessful
val Code = listCoursesDoctor.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.SportCoursDoctorList.value = List.courses_doctor
}
}
//5
GetCoursesSportYes(idPatient)
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(this, EnternetActivity::class.java)
finish()
startActivity(intetn)
}
}
//Получения списка пациентов
fun GetCoursesSportYes(id_patient:Int) {
if (enternetCheck.isOnline(this)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this)
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportYes("Bearer $Tokens", id_patient)
runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.EditSportListYes.value = List.set_of_sports_exercises_yes
}
}
//6
GetCoursesSportNo(idPatient)
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(this, EnternetActivity::class.java)
finish()
startActivity(intetn)
}
}
//Получения списка пациентов
fun GetCoursesSportNo(id_patient:Int) {
if (enternetCheck.isOnline(this)) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(this)
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportNo("Bearer $Tokens",id_patient)
runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
val intetn = Intent(this@PatientActivity, Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.EditSportListNo.value = List.set_of_sports_exercises_no
}
}
}
else if (Code == 500) {
val intetn = Intent(this@PatientActivity, Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(this@PatientActivity, AuthActivity::class.java)
finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(this, EnternetActivity::class.java)
finish()
startActivity(intetn)
}
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
override fun onResume() {
super.onResume()
checkForUpdates(true)
}
override fun onStop() {
super.onStop()
timer.cancel()
timer.purge()
}
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 10000) {
this@PatientActivity?.runOnUiThread {
QBAPatientList(idPatient)
}
}
}
}

View File

@ -0,0 +1,263 @@
package com.example.doctor.Patients
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.fragment.app.activityViewModels
import com.example.doctor.DoctorViewModel
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.Pref.ConclusionPref
import android.R
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Handler
import android.util.Log
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
//import androidx.navigation.fragment.findNavController
import com.example.doctor.Adapter.VpAdapterPatientList
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.MainActivity
import com.example.doctor.Patients.TabLayoutPatient.ActiveCoursesPatientFragment
import com.example.doctor.Patients.TabLayoutPatient.NotActiveCoursesPatientFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.FragmentPatientsListBinding
import com.example.user.BottomSheetMenu.NoteBottomSheetMenu
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import kotlin.concurrent.fixedRateTimer
class PatientsListFragment : Fragment(){
private lateinit var binding: FragmentPatientsListBinding
private val modelDoctor: DoctorViewModel by activityViewModels()
private val dataModel: DataModel by activityViewModels()//Для передачи данных
private lateinit var doctorApi: DoctorApi
private lateinit var timer: Timer
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
var viewListPAtient = true
var patientListSearch:List<PatientAllModel>?=null
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
private val tList = listOf(
"Активные",
"Без курса",
)
//Список с фрагментами для переключения
private val flist = listOf(
ActiveCoursesPatientFragment.newInstance(),
NotActiveCoursesPatientFragment.newInstance(),
)
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentPatientsListBinding.inflate(layoutInflater, container, false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и обработчики
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Чтобы срабатывала команда 1 раз
if(viewListPAtient){
GetPatientList() // Загружает список пациентов
init() // Инициализация ViewPager и TabLayout
//Нажатие на кнопку для добавления пациента
binding.btnAddPatient.setOnClickListener {
val noteBottomSheetMenu = NoteBottomSheetMenu.newInstance()
noteBottomSheetMenu.show(
requireActivity().supportFragmentManager,
"Note Bottom Sheet Fragment"
)
}
}
// Наблюдение за изменением списка пациентов для поиска
modelDoctor.patientListSearch.observe(viewLifecycleOwner){
if(patientListSearch!=it){
patientListSearch = it
addListSerchPatient(it)
}
}
}
// Инициализация ViewPager и TabLayout для переключения между вкладками пациентов
private fun init() = with(binding) {
val adapter = VpAdapterPatientList(activity as FragmentActivity, flist as List<Fragment>)
vpPatient.adapter = adapter
//Переключения (связываем таблаяут(переключатель) с viewpager, чтобы переключать фрагменты)
TabLayoutMediator(tabLayoutPatient, vpPatient) { tab, pos ->
tab.text =
tList[pos]//tab - нажатая кнопка, pos - позиция кнопки, tList[pos] - передаем название по полученной позиции
}.attach()// attach() - чтобы все переключалось, а не вывадило постоянно один экран
//Изменения цвета в зависомости на каком из tabLayout вы находитесь
binding.tabLayoutPatient.setTabTextColors(getResources().getColor(com.example.doctor.R.color.black),
getResources().getColor(com.example.doctor.R.color.white));
}
// private fun viewPatient() {
// val viewPatient = prefDoctorConclusion.conclusionViewPatient(requireContext())
// val idPatient = prefDoctorConclusion.conclusionIdPatient(requireContext())
// Log.i("viewPatient1",viewPatient.toString())
// Log.i("idPatient1",viewPatient.toString())
// if(viewPatient ==1 && idPatient !=0){
// GetPatientID(idPatient)
// prefDoctorClear.clearIdPatient(requireContext())
// prefDoctorClear.clearViewPatient(requireContext())
// Log.i("viewPatient2",viewPatient.toString())
// Log.i("idPatient2",viewPatient.toString())
// }
// }
// Получение списка всех пациентов с сервера и обновление ViewModel
fun GetPatientList() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listPatientList = doctorApi.GetPatientAll("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listPatientList.body()
val Nice = listPatientList.isSuccessful
val Code = listPatientList.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.patientListSearch.value = List?.patient
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Добавляет автодополнение и обработку выбора пациента в поисковой строке
private fun addListSerchPatient(patient: List<PatientAllModel>) {
val listPatient = arrayListOf("")
for(i in 0 .. patient.count()-1){
listPatient.add(patient[i].login.toString())
}
val adapter = ArrayAdapter(requireContext(), R.layout.simple_list_item_1, listPatient)
binding.searchPatient.threshold = 1
binding.searchPatient.setAdapter(adapter)
binding.searchPatient.setOnItemClickListener { parent, arg1, pos, id ->
val serpat = binding.searchPatient.text.toString()
//Ищем пациента по логину
for(i in 0 ..patient.count()-1) {
if(patient[i].login == serpat){
modelDoctor.patientCurrent.value = patient[i]
prefDoctorSave.saveIdPatient(requireContext(),patient[i].id!!)
prefDoctorSave.saveViewPatient(requireContext(),1)
val intetn = Intent(requireContext(), PatientActivity::class.java)
startActivity(intetn)
}
}
}
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
companion object {
// Фабричный метод для создания экземпляра PatientsListFragment
fun newInstance() = PatientsListFragment()
}
// Функция жизненного цикла, запускает таймер для периодического обновления списка пациентов
override fun onResume() {
super.onResume()
checkForUpdates(true)
}
// Функция жизненного цикла, останавливает таймер при остановке фрагмента
override fun onStop() {
super.onStop()
timer.cancel()
timer.purge()
}
// Запускает таймер, который каждые 10 секунд обновляет список пациентов
private fun checkForUpdates(daemonIsTrue: Boolean) {
timer = fixedRateTimer("default", daemonIsTrue, 0, 10000) {
activity?.runOnUiThread {
GetPatientList()
}
}
}
}

View File

@ -0,0 +1,81 @@
package com.example.doctor.Patients.Reports.Courses
import android.annotation.SuppressLint
import android.graphics.Color
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemCardCoursesDoctorBinding
import com.example.doctor.databinding.ItemSportCourseBinding
// Адаптер для отображения всех курсов пациента в RecyclerView
class CoursesAllAdapter(val listener_courses: Listener) : ListAdapter<SportCoursModel, CoursesAllAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента списка курсов
class Holder(view: View, val listener_courses: Listener): RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding = ItemCardCoursesDoctorBinding.bind(view)
var itemTemp: SportCoursModel? =
null // Глобальная переменная для текущего курса, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на карточку курса
init {
itemView.setOnClickListener {
itemTemp?.let { it1 -> listener_courses.onClickSportCourses(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: SportCoursModel) = with(binding) {
itemTemp = item
txtNumberCurds.text = item.number.toString() + "."
txtNameCoursesDoctor.text = item.name
if (item.visibility == 100000) {
CVCours.setCardBackgroundColor(Color.parseColor("#83da83"))
Log.i("11111111111","sasdasdasdasdasadsdasda")
} else {
CVCours.setCardBackgroundColor(Color.parseColor("#b6b6b6"))
Log.i("2222222222222","sasdasdasdasdasadsdasda")
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_card_courses_doctor, parent, false)
return Holder(view, listener_courses)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<SportCoursModel>() {
override fun areItemsTheSame(oldItem: SportCoursModel, newItem: SportCoursModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: SportCoursModel, newItem: SportCoursModel): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на карточку курса
interface Listener {
fun onClickSportCourses(item: SportCoursModel)
}
}

View File

@ -0,0 +1,91 @@
package com.example.doctor.Patients.Reports.Courses
import android.annotation.SuppressLint
import android.graphics.Color
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.Setting.Courses.Model.CoursesDoctorModel
import com.example.doctor.databinding.ItemCardCoursesDoctorBinding
// Адаптер для отображения курсов, созданных доктором, в RecyclerView
class CoursesYouAdapter(val listener: Listener) :
ListAdapter<SportCoursModel, CoursesYouAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента списка курсов
class Holder(view: View, val listener: Listener) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding = ItemCardCoursesDoctorBinding.bind(view)
var itemTemp: SportCoursModel? =
null // Глобальная переменная для текущего курса, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на карточку курса
init {
itemView.setOnClickListener {
itemTemp?.let { it1 -> listener.onClickCourses(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation", "SetTextI18n")
fun bind(item: SportCoursModel) = with(binding) {
itemTemp = item
txtNumberCurds.text = item.number.toString() + "."
txtNameCoursesDoctor.text = item.name
if (item.visibility == 100000) {
CVCours.setCardBackgroundColor(Color.parseColor("#83da83"))
Log.i("11111111111","sasdasdasdasdasadsdasda")
} else {
CVCours.setCardBackgroundColor(Color.parseColor("#b6b6b6"))
Log.i("2222222222222","sasdasdasdasdasadsdasda")
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_card_courses_doctor, parent, false)
return Holder(view, listener)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<SportCoursModel>() {
override fun areItemsTheSame(
oldItem: SportCoursModel,
newItem: SportCoursModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: SportCoursModel,
newItem: SportCoursModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на карточку курса
interface Listener {
fun onClickCourses(item: SportCoursModel)
}
}

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Reports.Courses
// Модель данных для списка спортивных курсов, созданных доктором для пациента
// Этот класс используется для представления списка объектов SportCoursModel, связанных с врачом и пациентом.
data class SportCoursDoctorListModel(
val courses_doctor: List<SportCoursModel> // Список объектов SportCoursModel, представляющих спортивные курсы, созданные доктором
)

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Reports.Courses
// Модель данных для списка всех спортивных курсов пациента
// Этот класс используется для представления списка объектов SportCoursModel, связанных со всеми спортивными курсами пациента.
data class SportCoursListModel(
val courses: List<SportCoursModel> // Список объектов SportCoursModel, представляющих спортивные курсы пациента
)

View File

@ -0,0 +1,13 @@
package com.example.doctor.Patients.Reports.Courses
// Модель данных для спортивного курса пациента
// Этот класс представляет структуру данных одного спортивного курса, связанного с отчетами пациента.
data class SportCoursModel(
val number: Int, // Порядковый номер спортивного курса
val id: Int, // Уникальный идентификатор спортивного курса
val name: String, // Название спортивного курса
val description: String, // Описание спортивного курса
val visibility: Int, // Статус видимости спортивного курса (например, 0 - скрыт, 1 - виден)
val created_at: String, // Дата создания спортивного курса
val updated_at: String, // Дата последнего обновления спортивного курса
)

View File

@ -0,0 +1,217 @@
package com.example.doctor.Patients.Reports.Courses.TabLayout
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Reports.Courses.CoursesAllAdapter
import com.example.doctor.Patients.Reports.Courses.SportCoursModel
import com.example.doctor.Patients.Reports.CoursesListAdapter
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentCoursesAllBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
// Фрагмент для отображения ВСЕХ спортивных курсов для пациента
// Этот фрагмент используется в TabLayout на экране отчетов пациента для отображения всех доступных спортивных курсов.
class CoursesAllFragment : Fragment(),CoursesAllAdapter.Listener {
private lateinit var binding: FragmentCoursesAllBinding // Объект привязки для доступа к элементам UI макета фрагмента
private val modelDoctor: DoctorViewModel by activityViewModels() // ViewModel для хранения и управления данными приложения
lateinit var adapterCours: CoursesAllAdapter // Адаптер для списка всех курсов
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API для сетевых запросов
val prefDoctorConclusion = ConclusionPref() // Вспомогательный класс для получения данных из SharedPreferences
val prefDoctorClear = ClearPref() // Вспомогательный класс для очистки SharedPreferences
val prefDoctorSave = SavePref() // Вспомогательный класс для сохранения данных в SharedPreferences
var sportCourses:List<SportCoursModel>?=null // Список спортивных курсов
var id: Int? = null // Идентификатор пациента (получается из ViewModel)
//Класс проверки интеренета
val enternetCheck = EnternetCheck() // Класс для проверки наличия интернет-соединения
// Функция жизненного цикла, создаёт и возвращает view фрагмента (надувание макета)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCoursesAllBinding.inflate(layoutInflater,container,false)
return binding.root // Возвращаем корневой View фрагмента
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewCours() // Инициализация списка курсов (RecyclerView)
// Подписка на изменение id пациента в ViewModel
modelDoctor.id_patient.observe(viewLifecycleOwner){
id = it // Обновляем локальную переменную id пациента
GetAllCoursesSport() // Загрузка всех курсов пациента при получении id
}
// Подписка на изменение списка всех спортивных курсов в ViewModel
modelDoctor.SportCoursList.observe(viewLifecycleOwner) {//viewLifecycleOwner - следит за циклом жизни fragment
if(sportCourses != it){
sportCourses = it // Обновляем локальный список курсов
adapterCours.submitList(it)//Напрямую переадем созданный список в adapter(ProductAdapter) // Обновляем данные в адаптере RecyclerView
binding.txtNull.visibility = View.GONE // Скрываем текст о отсутствии курсов, если список не пустой
}
}
}
// Получение всех курсов пациента с сервера и обновление ViewModel
fun GetAllCoursesSport(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
binding.txtNull.visibility = View.VISIBLE // Показываем текст "Загрузка" или "Нет курсов" пока идет запрос
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена авторизации
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetCoursAllPatient("Bearer $Tokens",id!!) // Выполнение GET-запроса для получения всех курсов пациента
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body() // Тело ответа
val Nice = listProduct.isSuccessful // Флаг успешности запроса
val Code = listProduct.code() // Код ответа HTTP
// Обработка различных кодов ответа сервера
if(Code==429){
// Переход на экран ошибки 429 (слишком много запросов)
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок (код 200 - OK)
if (Nice) {
if (List != null) {
modelDoctor.SportCoursList.value = List.courses // Обновление списка всех курсов в ViewModel
binding.txtNull.visibility = View.GONE // Скрываем текст о отсутствии курсов
}
}
}
else if (Code == 500) {
// Переход на экран ошибки 500 (внутренняя ошибка сервера)
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401 (неавторизованный)
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor() // Создание перехватчика для логирования HTTP-запросов
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования: тело запроса и ответа
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor) // Добавление перехватчика к клиенту
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON для автоматической десериализации ответов
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API-сервиса
}
// Инициализация списка курсов (RecyclerView) с адаптером CoursesAllAdapter
private fun initRcViewCours() = with(binding) {
rcView.layoutManager = GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию // Установка LayoutManager для вертикального списка
adapterCours = CoursesAllAdapter(this@CoursesAllFragment) // Создание экземпляра адаптера, передавая текущий фрагмент как слушатель нажатий
rcView.adapter = adapterCours // Установка адаптера для RecyclerView
}
companion object {
// Фабричный метод для создания экземпляра CoursesAllFragment
fun newInstance() = CoursesAllFragment() // Создает и возвращает новый экземпляр фрагмента
}
// Обработчик нажатия на элемент спортивного курса в списке
override fun onClickSportCourses(item: SportCoursModel) {
AddSportPatient(id!!,item.id,14) // Вызов функции добавления выбранного курса пациенту (с id пациента, id курса и количеством дней 14)
// GetAllCoursesSport() // Закомментированный вызов обновления списка курсов (возможно, перенесено в AddSportPatient)
}
// Добавление выбранного спортивного курса пациенту через API
fun AddSportPatient(id_patient:Int,id_course:Int,all_day:Int){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена авторизации
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
// Выполнение POST-запроса для добавления спортивного курса пациенту
val updatePassword= doctorApi.AddSportPatient("Bearer $Tokens",id_patient,id_course,all_day)
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = updatePassword.body() // Тело ответа
val Nice = updatePassword.isSuccessful // Флаг успешности запроса
val Code = updatePassword.code() // Код ответа HTTP
// Обработка различных кодов ответа сервера
if(Code==429){
// Переход на экран ошибки 429
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок (код 200 - OK)
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity()) // Показываем сообщение об успешном добавлении курса
GetAllCoursesSport() // Обновляем список всех курсов после добавления
modelDoctor.BtnSportCoursDoctorCurrent.value = 2 // Обновляем состояние кнопки "Очистить спорт пациента" (вероятно, делаем ее зеленой, указывая на наличие курса)
}
}
}
else if (Code == 500) {
// Переход на экран ошибки 500
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
// Переход на экран аутентификации при ошибке 401
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
// Переход на экран отсутствия интернета
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}

View File

@ -0,0 +1,193 @@
package com.example.doctor.Patients.Reports.Courses.TabLayout
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Reports.Courses.CoursesYouAdapter
import com.example.doctor.Patients.Reports.Courses.SportCoursModel
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Setting.Courses.Model.CoursesDoctorModel
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentCoursesYouBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class CoursesYouFragment : Fragment(),CoursesYouAdapter.Listener {
private lateinit var binding:FragmentCoursesYouBinding
private val modelDoctor: DoctorViewModel by activityViewModels()
lateinit var adapterCours: CoursesYouAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
var sportCoursesDoctor:List<SportCoursModel>?=null
var id: Int? = null
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
// Функция жизненного цикла, создаёт и возвращает view фрагмента
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCoursesYouBinding.inflate(layoutInflater,container,false)
return binding.root
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewCours() // Инициализация списка курсов
modelDoctor.id_patient.observe(viewLifecycleOwner){
id = it
GetCoursesDoctor() // Загрузка курсов, созданных доктором
}
modelDoctor.SportCoursDoctorList.observe(viewLifecycleOwner){
if(sportCoursesDoctor!=it){
sportCoursesDoctor = it
adapterCours.submitList(it)
binding.txtNull.visibility = View.GONE
}
}
}
// Получение списка курсов, созданных доктором, с сервера и обновление ViewModel
fun GetCoursesDoctor() {
if (enternetCheck.isOnline(requireContext())) {
binding.txtNull.visibility = View.VISIBLE
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetCoursesDoctorPatient("Bearer $Tokens",id!!)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listCoursesDoctor.body()
val Nice = listCoursesDoctor.isSuccessful
val Code = listCoursesDoctor.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.SportCoursDoctorList.value = List.courses_doctor
binding.txtNull.visibility = View.GONE
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация клиента Retrofit для сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
// Инициализация списка курсов (RecyclerView)
private fun initRcViewCours() = with(binding) {
rcView.layoutManager = GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapterCours = CoursesYouAdapter(this@CoursesYouFragment)
rcView.adapter = adapterCours
}
companion object {
// Фабричный метод для создания экземпляра CoursesYouFragment
fun newInstance() = CoursesYouFragment()
}
// Обработчик нажатия на курс: добавляет курс пациенту и обновляет список
override fun onClickCourses(item: SportCoursModel) {
AddSportPatient(id!!,item.id,14)
GetCoursesDoctor()
}
// Добавление курса пациенту через API
fun AddSportPatient(id_patient:Int,id_course:Int,all_day:Int){
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val updatePassword= doctorApi.AddSportPatient("Bearer $Tokens",id_patient,id_course,all_day)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = updatePassword.body()
val Nice = updatePassword.isSuccessful
val Code = updatePassword.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
GetCoursesDoctor()
modelDoctor.BtnSportCoursDoctorCurrent.value = 2
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}

View File

@ -0,0 +1,81 @@
package com.example.doctor.Patients.Reports
import android.annotation.SuppressLint
import android.graphics.Color
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.Patients.Reports.Courses.SportCoursModel
import com.example.doctor.R
import com.example.doctor.databinding.ItemSportCourseBinding
// Адаптер для отображения списка спортивных курсов пациента в RecyclerView
class CoursesListAdapter(val listener_courses: Listener) : ListAdapter<SportCoursModel, CoursesListAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента списка курсов
class Holder(view: View, val listener_courses: Listener): RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding = ItemSportCourseBinding.bind(view)
var itemTemp: SportCoursModel? =
null // Глобальная переменная для текущего курса, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на карточку курса
init {
binding.CardViewCourses.setOnClickListener {
itemTemp?.let { it1 -> listener_courses.onClickSportCourses(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: SportCoursModel) = with(binding) {
itemTemp = item
txtCoursesSport.text = item.name
if (item.visibility == 1) {
CVCours.setCardBackgroundColor(Color.parseColor("#83da83"))
Log.i("11111111111","sasdasdasdasdasadsdasda")
} else {
CVCours.setCardBackgroundColor(Color.parseColor("#b6b6b6"))
Log.i("2222222222222","sasdasdasdasdasadsdasda")
}
Log.i("ssadsdasda","sasdasdasdasdasadsdasda")
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_sport_course, parent, false)
return Holder(view, listener_courses)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<SportCoursModel>() {
override fun areItemsTheSame(oldItem: SportCoursModel, newItem: SportCoursModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: SportCoursModel, newItem: SportCoursModel): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на карточку курса
interface Listener {
fun onClickSportCourses(item: SportCoursModel)
}
}

View File

@ -0,0 +1,76 @@
package com.example.doctor.Patients.Reports.Edit
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import com.example.doctor.Adapter.VpEditSportAdapter
import com.example.doctor.Patients.Reports.Edit.TabLayout.EditSportNoFragment
import com.example.doctor.Patients.Reports.Edit.TabLayout.EditSportYesFragment
import com.example.doctor.R
import com.example.doctor.databinding.FragmentEditSportBinding
import com.google.android.material.tabs.TabLayoutMediator
class EditSportFragment : Fragment() {
private lateinit var binding: FragmentEditSportBinding
private val tListSport = listOf(
"Активные",
"Отключенные",
)
//Список с фрагментами для переключения
private val flistSport = listOf(
EditSportYesFragment.newInstance(),
EditSportNoFragment.newInstance(),
)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentEditSportBinding.inflate(layoutInflater,container,false)
return binding.root
}
companion object {
fun newInstance() = EditSportFragment()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
init()
}
//Функция подключения переключения
private fun init() = with(binding) {
val adapter = VpEditSportAdapter(activity as FragmentActivity, flistSport)
vpEditSport.adapter = adapter
//Переключения (связываем таблаяут(переключатель) с viewpager, чтобы переключать фрагменты)
TabLayoutMediator(tabLayoutSport, vpEditSport) { tab, pos ->
tab.text =
tListSport[pos]//tab - нажатая кнопка, pos - позиция кнопки, tList[pos] - передаем название по полученной позиции
}.attach()// attach() - чтобы все переключалось, а не вывадило постоянно один экран
//Изменения цвета в зависомости на каком из tabLayout вы находитесь
binding.tabLayoutSport.setTabTextColors(getResources().getColor(R.color.black),
getResources().getColor(R.color.white));
}
// //Инициализация списка
// private fun initRcViewDay() = with(binding) {
// rcView.layoutManager =
// GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
// adapterPatient = PatientListAdapter(this@PatientsListFragment)
// rcView.adapter = adapterPatient
// }
}

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Reports.Edit
data class EditSportListNoModel(
val set_of_sports_exercises_no: List<EditSportModel>
)

View File

@ -0,0 +1,10 @@
package com.example.doctor.Patients.Reports.Edit
import com.example.doctor.Patients.Reports.QBAModel
data class EditSportListYesModel(
val set_of_sports_exercises_yes: List<EditSportModel>
)

View File

@ -0,0 +1,11 @@
package com.example.doctor.Patients.Reports.Edit
data class EditSportModel(
val number: Int,
val id: Int,
val name:String,
val description:String,
val url_image:String,
var expand : Boolean = false,
)

View File

@ -0,0 +1,98 @@
package com.example.doctor.Patients.Reports.Edit
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemEditSportNoBinding
import com.example.doctor.databinding.ItemEditSportYesBinding
// Адаптер для отображения неактивных упражнений пациента в RecyclerView
class EditSportNoAdapter(val listener_sport: Listener) :
ListAdapter<EditSportModel, EditSportNoAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента неактивного упражнения
class Holder(view: View, val listener_sport: Listener) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding = ItemEditSportNoBinding.bind(view)
var itemTemp: EditSportModel? =
null // Глобальная переменная для текущего упражнения, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на кнопку "Включить упражнение"
init {
binding.btnYeyNo.setOnClickListener {
itemTemp?.let { it1 -> listener_sport.onClickAppeals(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: EditSportModel) = with(binding) {
itemTemp = item
txtNumber.text = item.number.toString()+"."
txtNameSport.text = item.name
txtDescriptionSport.text = item.description
if (item.expand) {
binding.txtDescriptionSport.maxLines = 100
} else {
binding.txtDescriptionSport.maxLines = 1
}
binding.CardViewOld.setOnClickListener {
if (item.expand == false) {
binding.txtDescriptionSport.maxLines = 100
item.expand = true
} else {
binding.txtDescriptionSport.maxLines = 1
item.expand = false
}
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_edit_sport_no, parent, false)
return Holder(view, listener_sport)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<EditSportModel>() {
override fun areItemsTheSame(
oldItem: EditSportModel,
newItem: EditSportModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: EditSportModel,
newItem: EditSportModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на кнопку "Включить упражнение"
interface Listener {
fun onClickAppeals(item: EditSportModel)
}
}

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Reports.Edit
data class EditSportSearchModel(
val id_patient: Int,
val id_sports_courses_patient: Int,
)

View File

@ -0,0 +1,97 @@
package com.example.doctor.Patients.Reports.Edit
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemEditSportYesBinding
// Адаптер для отображения активных упражнений пациента в RecyclerView
class EditSportYesAdapter(val listener_sport: Listener) :
ListAdapter<EditSportModel, EditSportYesAdapter.Holder>(
Comparator()
) {
// ViewHolder для элемента активного упражнения
class Holder(view: View, val listener_sport: Listener) :
RecyclerView.ViewHolder(view) {
// Класс, который хранит ссылки на элементы и обрабатывает нажатия
val binding = ItemEditSportYesBinding.bind(view)
var itemTemp: EditSportModel? =
null // Глобальная переменная для текущего упражнения, чтобы можно было передать данные при нажатии
// Инициализация обработчика нажатия на кнопку "Отключить упражнение"
init {
binding.btnYeyYes.setOnClickListener {
itemTemp?.let { it1 -> listener_sport.onClickAppeals(it1) }
}
}
// Привязка данных к элементу списка
@SuppressLint("SuspiciousIndentation")
fun bind(item: EditSportModel) = with(binding) {
itemTemp = item
txtNumber.text = item.number.toString()+"."
txtNameSport.text = item.name
txtDescriptionSport.text = item.description
if (item.expand) {
binding.txtDescriptionSport.maxLines = 100
} else {
binding.txtDescriptionSport.maxLines = 1
}
binding.CardViewOld.setOnClickListener {
if (item.expand == false) {
binding.txtDescriptionSport.maxLines = 100
item.expand = true
} else {
binding.txtDescriptionSport.maxLines = 1
item.expand = false
}
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_edit_sport_yes, parent, false)
return Holder(view, listener_sport)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<EditSportModel>() {
override fun areItemsTheSame(
oldItem: EditSportModel,
newItem: EditSportModel
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: EditSportModel,
newItem: EditSportModel
): Boolean {
return oldItem == newItem
}
}
// Интерфейс для обработки нажатия на кнопку "Отключить упражнение"
interface Listener {
fun onClickAppeals(item: EditSportModel)
}
}

View File

@ -0,0 +1,317 @@
package com.example.doctor.Patients.Reports.Edit.TabLayout
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Reports.Edit.EditSportYesAdapter
import com.example.doctor.Patients.Reports.Edit.EditSportModel
import com.example.doctor.Patients.Reports.Edit.EditSportNoAdapter
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentEditSportNoBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class EditSportNoFragment : Fragment(),EditSportNoAdapter.Listener {
private lateinit var binding:FragmentEditSportNoBinding
lateinit var adapterNo: EditSportNoAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
private val model: DoctorViewModel by activityViewModels()
var id_patient = 0;
var editNo:List<EditSportModel>?=null
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentEditSportNoBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewDay()
model.EditSportListNo.observe(viewLifecycleOwner){
if(it!=null){
if(editNo!=it){
editNo = it
adapterNo.submitList(it)
binding.txtNo.visibility = View.GONE
}
}
else{
binding.txtNo.visibility = View.VISIBLE
}
}
model.id_patient.observe(viewLifecycleOwner) {id->
id_patient = id.toInt()
GetCoursesSportNo(id_patient)
}
btnClick()
}
private fun btnClick()=with(binding) {
CLLoad.setOnClickListener { }
}
//Инициализация списка
private fun initRcViewDay() = with(binding) {
rcViewEditSportNo.layoutManager =
GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapterNo = EditSportNoAdapter(this@EditSportNoFragment)
rcViewEditSportNo.adapter = adapterNo
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
//Получения списка пациентов
fun GetCoursesSportYes(id_patient:Int)= with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportYes("Bearer $Tokens", id_patient)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
model.EditSportListYes.value = List.set_of_sports_exercises_yes
}
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Получения списка пациентов
fun GetCoursesSportNo(id_patient:Int)= with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportNo("Bearer $Tokens", id_patient)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
model.EditSportListNo.value = List.set_of_sports_exercises_no
binding.txtNo.visibility = View.GONE
binding.CLLoad.visibility = View.GONE
}
else{
binding.txtNo.visibility = View.VISIBLE
binding.CLLoad.visibility = View.GONE
}
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Удаление упражнения из блока
fun UpdateBlockSportTasksNo(id:Int)= with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val NoEdit = doctorApi.UpdateBlockSportTasksNo("Bearer $Tokens", id)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = NoEdit.body()
val Nice = NoEdit.isSuccessful
val Code = NoEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
GetCoursesSportYes(id_patient)
GetCoursesSportNo(id_patient)
}
else{
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
CLLoad.visibility = View.GONE
}
CLLoad.visibility = View.GONE
}
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
companion object {
fun newInstance() = EditSportNoFragment()
}
override fun onClickAppeals(item: EditSportModel) {
binding.CLLoad.visibility = View.VISIBLE
UpdateBlockSportTasksNo(item.id)
}
}

View File

@ -0,0 +1,325 @@
package com.example.doctor.Patients.Reports.Edit.TabLayout
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Reports.Edit.EditSportYesAdapter
import com.example.doctor.Patients.Reports.Edit.EditSportModel
import com.example.doctor.Patients.Reports.Edit.EditSportNoAdapter
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentEditSportYesBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class EditSportYesFragment : Fragment(), EditSportYesAdapter.Listener {
private lateinit var binding:FragmentEditSportYesBinding
lateinit var adapterYes: EditSportYesAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
private val model: DoctorViewModel by activityViewModels()
var id_patient = 0;
var editYes:List<EditSportModel>?=null
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentEditSportYesBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewDay()
model.id_patient.observe(viewLifecycleOwner) {id->
id_patient = id.toInt()
Log.i("id_patient",id_patient.toString())
Log.i("id",id.toString())
GetCoursesSportYes(id_patient)
}
model.EditSportListYes.observe(viewLifecycleOwner){
if(it!=null){
if(editYes!=it){
editYes=it
adapterYes.submitList(it)
binding.txtYes.visibility = View.GONE
}
}
else{
binding.txtYes.visibility = View.GONE
}
}
btnClick()
}
private fun btnClick()=with(binding) {
CLLoad.setOnClickListener { }
}
//Инициализация списка
private fun initRcViewDay() = with(binding) {
rcViewEditSportYes.layoutManager =
GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapterYes = EditSportYesAdapter(this@EditSportYesFragment)
rcViewEditSportYes.adapter = adapterYes
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
//Получения списка пациентов
fun GetCoursesSportYes(id_patient:Int)=with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportYes("Bearer $Tokens", id_patient)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
model.EditSportListYes.value = List.set_of_sports_exercises_yes
binding.txtYes.visibility = View.GONE
binding.CLLoad.visibility = View.GONE
}
else{
model.EditSportListYes.value = null
binding.txtYes.visibility = View.VISIBLE
binding.rcViewEditSportYes.visibility = View.GONE
binding.CLLoad.visibility = View.GONE
}
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
//Фиксируем полученные данные
val sportEditList = sportEdit.body()
//Если нету ошибок
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Получения списка пациентов
fun GetCoursesSportNo(id_patient:Int)=with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.GetCoursesSportNo("Bearer $Tokens",id_patient)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
model.EditSportListNo.value = List.set_of_sports_exercises_no
}
CLLoad.visibility = View.GONE
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Отключение упражнения
fun UpdateBlockSportTasksYes(id_pateint:Int,id_sports_tasks:Int)=with(binding) {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val sportEdit = doctorApi.UpdateBlockSportTasksYes("Bearer $Tokens", id_pateint,id_sports_tasks)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = sportEdit.body()
val Nice = sportEdit.isSuccessful
val Code = sportEdit.code()
if(Code==429){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200){
//Если нету ошибок
if(Nice){
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
GetCoursesSportYes(id_patient)
GetCoursesSportNo(id_patient)
}
else{
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
CLLoad.visibility = View.GONE
}
CLLoad.visibility = View.GONE
}
}
else{
CLLoad.visibility = View.GONE
}
}
else if(Code==500){
CLLoad.visibility = View.GONE
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
else{
CLLoad.visibility = View.GONE
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
companion object {
fun newInstance() = EditSportYesFragment()
}
override fun onClickAppeals(item: EditSportModel) {
binding.CLLoad.visibility = View.VISIBLE
UpdateBlockSportTasksYes(id_patient, item.id)
}
}

View File

@ -0,0 +1,6 @@
package com.example.doctor.Patients.Reports.Edit
data class UpdateSportTaskNoModel(
val id: Int,
)

View File

@ -0,0 +1,7 @@
package com.example.doctor.Patients.Reports.Edit
data class UpdateSportTaskYesModel(
val id_sport_patient: Int,
val id_sports_tasks: Int,
)

View File

@ -0,0 +1,998 @@
package com.example.doctor.Patients.Reports
import android.graphics.Color
import android.os.Bundle
import android.transition.TransitionInflater
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.DoctorViewModel
import com.example.doctor.Patients.PatientsListFragment
import com.example.doctor.Patients.Reports.Edit.EditSportFragment
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.R as R_D
import android.R
import android.content.Intent
import androidx.fragment.app.FragmentActivity
import com.example.doctor.Adapter.VpAdapter
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Reports.Courses.TabLayout.CoursesAllFragment
import com.example.doctor.Patients.Reports.Courses.TabLayout.CoursesYouFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.AllSportCoursesDoctorFragment
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.YourSportCoursesDoctorFragment
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.Toast.showCustomNiceToast
import com.example.doctor.databinding.FragmentPatientsBinding
import com.example.doctor.databinding.ItemQuestionnaireAfterBinding
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.time.LocalDate
// Фрагмент для отображения детальной информации о пациенте, отчетов и курсов
class PatientFragment : Fragment() {
private lateinit var binding: FragmentPatientsBinding // Объект привязки для доступа к элементам UI макета фрагмента
private val modelDoctor: DoctorViewModel by activityViewModels() // ViewModel для хранения и управления данными приложения
lateinit var adapter: QBBAdapter // Адаптер для списка анкет ДО
lateinit var adapterCours: CoursesListAdapter // Адаптер для списка спортивных курсов
private lateinit var doctorApi: DoctorApi // Экземпляр Retrofit API для сетевых запросов
val prefDoctorConclusion = ConclusionPref() // Вспомогательный класс для получения данных из SharedPreferences
val prefDoctorClear = ClearPref() // Вспомогательный класс для очистки SharedPreferences
val prefDoctorSave = SavePref() // Вспомогательный класс для сохранения данных в SharedPreferences
var id: Int? = null // Идентификатор пациента
var block = "" // Статус блокировки пациента
var pause = "" // Статус паузы для пациента
var id_sport = "" // Идентификатор спортивного курса пациента
var btnSC = 0; // Переменная для управления состоянием кнопки (не используется в видимом коде)
var idPatient = 0; // Идентификатор текущего пациента
//Класс проверки интеренета
val enternetCheck = EnternetCheck() // Класс для проверки наличия интернет-соединения
// Для 10 сек обновления (переменные для хранения данных, вероятно, для периодического обновления)
var qba:List<QBAModel>?=null // Список анкет ДО и ПОСЛЕ
var patientAll:PatientAllModel?=null // Информация о пациенте
// Список заголовков для вкладок курсов
private val tList = listOf(
"Все", // Заголовок вкладки "Все курсы"
"Ваши", // Заголовок вкладки "Ваши курсы"
)
// Список фрагментов для переключения во ViewPager2
private val flist = listOf(
CoursesAllFragment.newInstance(), // Фрагмент для отображения всех курсов
CoursesYouFragment.newInstance(), // Фрагмент для отображения курсов, созданных доктором
)
// Функция жизненного цикла, создаёт и возвращает view фрагмента (надувание макета)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentPatientsBinding.inflate(layoutInflater, container, false)
return binding.root // Возвращаем корневой View фрагмента
}
// Функция жизненного цикла, вызывается после создания view. Инициализирует интерфейс, обработчики и подписки на данные
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewDay() // Инициализация списка анкет (RecyclerView с адаптером QBBAdapter)
init() // Инициализация вкладок курсов (ViewPager2 и TabLayout)
modelDoctor.qbaList.observe(viewLifecycleOwner) {//viewLifecycleOwner - следит за циклом жизни fragment
if(qba != it){
qba = it
adapter.submitList(it)//Напрямую переадем созданный список в adapter(ProductAdapter)
// binding.txtNullQBA.visibility = View.GONE // Скрытие текста о отсутствии анкет, если список не пустой
}
}
idPatient = prefDoctorConclusion.conclusionIdPatient(requireContext())
modelDoctor.BtnSportCoursDoctorCurrent.observe(viewLifecycleOwner){
if(it == 1){ // Если значение 1, кнопка красная (очистить)
binding.btnClearSportPatient.setCardBackgroundColor(Color.parseColor("#D86767"))
}
else if(it == 2){ // Если значение 2, кнопка зеленая (нечего очищать)
binding.btnClearSportPatient.setCardBackgroundColor(Color.parseColor("#A9D867"))
}
else{ // По умолчанию кнопка красная
binding.btnClearSportPatient.setCardBackgroundColor(Color.parseColor("#D86767"))
}
}
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(R_D.transition.slide_right)
binding.btnExit.setOnClickListener {
exitTransition = inflater.inflateTransition(R_D.transition.slide_right)
activity?.finish() // Закрытие родительской активити (PatientActivity)
}
popMenu() // Инициализация popup-меню для выбора типа анкеты
viewPatient() // Проверка и загрузка данных пациента при необходимости
// Получаем id пациента из ViewModel (вероятно, дублирование с получением из preferences)
modelDoctor.patientId.observe(viewLifecycleOwner){
Log.i("adsa","as111111111111dsadasd") // Логирование id пациента
}
// Подписка на изменение данных пациента в ViewModel
modelDoctor.patientCurrent.observe(viewLifecycleOwner) {
if(patientAll !=it){ // Если данные пациента изменились
patientAll = it // Обновляем переменную с данными пациента
binding.txtLogin.text = it.login // Обновляем логин пациента в UI
id = it.id // Обновляем id пациента
modelDoctor.id_patient.value = id // Обновляем id пациента в ViewModel
block = it.block.toString() // Получаем статус блокировки
pause = it.pause.toString() // Получаем статус паузы
id_sport = it.id_sport_patient.toString() // Получаем id спортивного курса
// Проверка даты блокировки: если дата прошла или статус null, отображаем как не заблокированный
if(block == "null"){
block(block)
}
else{
if(LocalDate.parse(block)<LocalDate.now()){
block("null")
}
else{
block(block)
}
}
// Проверка даты паузы: если дата прошла или статус null, отображаем как не на паузе
if(pause == "null"){
pause(pause)
}
else{
if(LocalDate.parse(pause)<LocalDate.now()){
pause("null")
}
else{
pause(pause)
}
}
Log.i("id_sport","$id_sport") // Логирование id спортивного курса
Log.i("id_sport123","$it") // Логирование всех данных пациента
// Проверка, есть ли у пациента активный спортивный курс
btnClearSportPatient(id_sport)
report() // Загрузка и отображение отчета по анкетам и курсам
}
}
btnCreate() // Инициализация обработчиков нажатий для основных карточек
}
// Инициализация обработчиков для основных карточек пациента (пустые обработчики)
private fun btnCreate() = with(binding) {
CVEditCard.setOnClickListener { } // Карточка редактирования данных пациента
CVSportCourses.setOnClickListener { } // Карточка спортивных курсов
CVReportCard.setOnClickListener { } // Карточка отчетов (анкет)
CVEditSportCard.setOnClickListener { } // Карточка редактирования спортивных занятий
}
// Инициализация вкладок (ViewPager + TabLayout) для переключения между всеми курсами и курсами доктора
private fun init() = with(binding) {
val adapter = VpAdapter(activity as FragmentActivity, flist) // Создание адаптера для ViewPager2
vpCourses.adapter = adapter // Установка адаптера для ViewPager2
//Переключения (связываем таблаяут(переключатель) с viewpager, чтобы переключать фрагменты)
TabLayoutMediator(tabLayoutCourses, vpCourses) { tab, pos ->
tab.text =
tList[pos]//tab - нажатая кнопка, pos - позиция кнопки, tList[pos] - передаем название по полученной позиции
}.attach()// attach() - чтобы все переключалось, а не вывадило постоянно один экран
//Изменения цвета в зависомости на каком из tabLayout вы находитесь
binding.tabLayoutCourses.setTabTextColors(
getResources().getColor(com.example.doctor.R.color.black), // Цвет текста невыбранной вкладки
getResources().getColor(com.example.doctor.R.color.white) // Цвет текста выбранной вкладки
);
}
// Проверяет необходимость загрузки данных пациента по id из SharedPreferences при переходе и очищает их
private fun viewPatient() {
val viewPatient = prefDoctorConclusion.conclusionViewPatient(requireContext()) // Получаем флаг необходимости загрузки
val idPatient = 23412 // Хардкодный id пациента (возможно, заглушка)
Log.i("viewPatient1",viewPatient.toString()) // Логирование флага
Log.i("idPatient1",viewPatient.toString()) // Логирование id (ошибка, должно быть idPatient)
if(viewPatient ==1 && idPatient !=0 && idPatient !=null){
GetPatientID(idPatient) // Загружаем данные пациента по id
prefDoctorClear.clearIdPatient(requireContext()) // Очищаем сохраненный id пациента
prefDoctorClear.clearViewPatient(requireContext()) // Очищаем флаг необходимости загрузки
Log.i("viewPatient2",viewPatient.toString()) // Логирование флага после очистки
Log.i("idPatient2",viewPatient.toString()) // Логирование id после очистки (ошибка)
}
}
// Инициализация клиента Retrofit для выполнения сетевых запросов
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY // Уровень логирования HTTP-запросов
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/") // Базовый URL API
.client(client) // Установка OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Добавление конвертера JSON
.build()
doctorApi = retrofit.create(DoctorApi::class.java) // Создание экземпляра API
}
// Получение данных пациента по его id с сервера
private fun GetPatientID(idPatient: Int) {
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listPatient = doctorApi.GetPatientID("Bearer $Tokens", idPatient) // Выполнение GET-запроса для получения данных пациента
// Переключение на главный поток для обновления UI
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listPatient.body()
val Nice = listPatient.isSuccessful
val Code = listPatient.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.patientCurrent.value = List
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Инициализация popup-меню для выбора типа анкеты (ДО или ПОСЛЕ)
private fun popMenu() {
// Создание меню
val popMenu = PopupMenu(
requireContext(), // Контекст
binding.btnQBA // View, к которому привязано меню
)
// Добавление пунктов меню
popMenu.menu.add(Menu.NONE, 0, 0, "Анкета ДО")
popMenu.menu.add(Menu.NONE, 1, 1, "Анкета ПОСЛЕ")
// Обработчик нажатия на пункты меню
popMenu.setOnMenuItemClickListener {
val id = it.itemId // Получаем id выбранного пункта
// Ситуации при нажатие на один из пунктов
if (id == 0) { // Если выбран пункт "Анкета ДО"
binding.CVQB.visibility = View.VISIBLE // Отображаем карточку с анкетой ДО
} else if (id == 1) { // Если выбран пункт "Анкета ПОСЛЕ"
binding.CVQA.visibility = View.VISIBLE // Отображаем карточку с анкетой ПОСЛЕ
} else { // В случае ошибки
Toast.makeText(requireContext(), "Ошибка", Toast.LENGTH_SHORT).show() // Показываем сообщение об ошибке
}
false // Возвращаем false, чтобы меню не закрывалось после выбора (при необходимости)
}
// Обработчик нажатия на кнопку открытия меню
binding.btnQBA.setOnClickListener {
// Активируем меню
popMenu.show() // Отображаем popup-меню
}
}
// Функция для очистки спортивного курса пациента через API
fun ClearSportPaient(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listcsp = doctorApi.ClearPatientSport("Bearer $Tokens",id!!) // Выполнение POST-запроса на очистку курса
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listcsp.body()
val Nice = listcsp.isSuccessful
val Code = listcsp.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
GetAllCoursesSport() // Обновляем список всех курсов
GetCoursesDoctor() // Обновляем список курсов доктора
modelDoctor.BtnSportCoursDoctorCurrent.value = 1 // Устанавливаем состояние кнопки "Очистить"
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity()) // Показываем сообщение об успешной очистке
}
else{
Toast(requireContext()).showCustomInfoToast("${List?.message}", requireActivity()) // Показываем сообщение об ошибке
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Получение списка курсов, созданных доктором, для данного пациента с сервера
fun GetCoursesDoctor() {
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetCoursesDoctorPatient("Bearer $Tokens",id!!) // Выполнение GET-запроса для получения курсов доктора пациента
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listCoursesDoctor.body()
val Nice = listCoursesDoctor.isSuccessful
val Code = listCoursesDoctor.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.SportCoursDoctorList.value = List.courses_doctor // Обновление списка курсов доктора в ViewModel
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Получение списка всех спортивных курсов для данного пациента с сервера
fun GetAllCoursesSport(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetCoursAllPatient("Bearer $Tokens",id!!) // Выполнение GET-запроса для получения всех курсов пациента
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.SportCoursList.value = List.courses // Обновление списка всех курсов в ViewModel
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Обновляет состояние кнопки "Очистить спорт пациента" в зависимости от наличия активного спортивного курса
private fun btnClearSportPatient(id_sport:String) {
if (id_sport == "null") { // Если id спортивного курса null, кнопка красная
modelDoctor.BtnSportCoursDoctorCurrent.value = 1
} else { // Иначе, кнопка зеленая
modelDoctor.BtnSportCoursDoctorCurrent.value = 2
}
// Обработчик нажатия на кнопку "Очистить спорт пациента"
binding.btnClearSportPatient.setOnClickListener {
ClearSportPaient() // Вызываем функцию очистки спортивного курса
}
}
// Получение списка анкет ДО и ПОСЛЕ для пациента с сервера
fun QBAPatientList()=with(binding){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientBAQiestionar("Bearer $Tokens",id!!) // Выполнение GET-запроса для получения анкет
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if(List.questionnaire !=null){
txtNullQBA.visibility = View.GONE
modelDoctor.qbaList.value = List.questionnaire
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
// Обработчик нажатия на кнопку "Пауза"
private fun pause(pause:String) {
if (pause == "null") { // Если статус паузы null, карточка зеленая (не на паузе)
binding.CVPause.setCardBackgroundColor(Color.parseColor("#A9D867"))
} else { // Иначе, карточка красная (на паузе)
binding.CVPause.setCardBackgroundColor(Color.parseColor("#D86767"))
}
// Установка обработчика нажатия на кнопку паузы
binding.btnPause.setOnClickListener {
UpdatePausePatient() // Вызываем функцию обновления статуса паузы
}
}
// Обработчик нажатия на кнопку "Блок"
private fun block(block:String) {
if (block == "null") { // Если статус блокировки null, карточка зеленая (не заблокирован)
binding.CVBlock.setCardBackgroundColor(Color.parseColor("#A9D867"))
} else { // Иначе, карточка красная (заблокирован)
binding.CVBlock.setCardBackgroundColor(Color.parseColor("#D86767"))
}
// Установка обработчика нажатия на кнопку блокировки
binding.btnBlock.setOnClickListener {
UpdateBlockPatient() // Вызываем функцию обновления статуса блокировки
}
}
// Функция для блокировки/разблокировки аккаунта пациента через API
fun UpdateBlockPatient(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.UpdateBlockAccountPatient("Bearer $Tokens", id!!) // Выполнение POST-запроса на обновление статуса блокировки
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if (block == "null") { // Если был не заблокирован, делаем заблокированным
block = "true"
binding.CVBlock.setCardBackgroundColor(Color.parseColor("#D86767")) // Меняем цвет карточки на красный
Toast(requireContext()).showCustomInfoToast("Блок установлен", requireActivity()) // Показываем сообщение
} else { // Если был заблокирован, снимаем блокировку
block = "null"
binding.CVBlock.setCardBackgroundColor(Color.parseColor("#A9D867")) // Меняем цвет карточки на зеленый
Toast(requireContext()).showCustomInfoToast("Блок убран", requireActivity()) // Показываем сообщение
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Функция для установки/снятия паузы для пациента через API
fun UpdatePausePatient(){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.UpdatePauseAccountPatient("Bearer $Tokens", id!!) // Выполнение POST-запроса на обновление статуса паузы
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
if (pause == "null") { // Если не на паузе, ставим на паузу
pause = "true"
binding.CVPause.setCardBackgroundColor(Color.parseColor("#D86767")) // Меняем цвет карточки на красный
Toast(requireContext()).showCustomInfoToast("Пауза установлен", requireActivity()) // Показываем сообщение
} else { // Если на паузе, снимаем паузу
pause = "null"
binding.CVPause.setCardBackgroundColor(Color.parseColor("#A9D867")) // Меняем цвет карточки на зеленый
Toast(requireContext()).showCustomInfoToast("Пауза убран", requireActivity()) // Показываем сообщение
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Функция для обновления логина пациента через API
fun UpdatePatientLogin(id:Int,login:String){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val updateLogin = doctorApi.UpdatePatientLogin("Bearer $Tokens",id,login) // Выполнение POST-запроса на обновление логина
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = updateLogin.body()
val Nice = updateLogin.isSuccessful
val Code = updateLogin.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity()) // Показываем сообщение об успешном обновлении
}
else{
if (List != null) { // Показываем сообщение об ошибке, если есть
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
// Функция для обновления пароля пациента через API
fun UpdatePatientPassword(id:Int,password:String){
// Проверка интернет-соединения
if (enternetCheck.isOnline(requireContext())) {
initRetrofit() // Инициализация Retrofit
val Tokens = prefDoctorConclusion.conclusionToken(requireContext()) // Получение токена
// Запуск корутины для выполнения сетевого запроса в фоновом потоке
CoroutineScope(Dispatchers.IO).launch {
val updatePassword= doctorApi.UpdatePatientPassword("Bearer $Tokens",id,password) // Выполнение POST-запроса на обновление пароля
// Переключение на главный поток для обновления UI и обработки ответа
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = updatePassword.body()
val Nice = updatePassword.isSuccessful
val Code = updatePassword.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity()) // Показываем сообщение об успешном обновлении
}
else{
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
}
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish() // Закрываем текущую активити
startActivity(intetn)
}
}
private fun sport() {
}
// Инициализация обработчиков нажатий для карточек отчета, спорта и редактирования данных/спорта
private fun report() = with(binding) {
// Обработчик нажатия на кнопку выхода: возвращает на экран списка пациентов
btnExitPatientFragment.setOnClickListener {
activity?.supportFragmentManager?.beginTransaction()
?.replace(com.example.doctor.R.id.CLMainListPatient, PatientsListFragment.newInstance()) // Заменяем текущий фрагмент на PatientsListFragment
?.commit() // Применяем изменения
//this@PatientFragment.onDestroy() // Закомментированный вызов onDestroy
}
// Обработчик нажатия на кнопку "Отчет": отображает карточку отчетов и загружает анкеты
btnReport.setOnClickListener {
CVReport.visibility = View.VISIBLE // Отображаем карточку отчетов
QBAPatientList() // Загружаем анкеты ДО и ПОСЛЕ
}
// Обработчик нажатия на кнопку "Спорт": отображает карточку спортивных курсов
btnSport.setOnClickListener {
binding.CVSport.visibility = View.VISIBLE // Отображаем карточку спортивных курсов
}
// Обработчик нажатия на кнопку закрытия карточки отчетов
btnCloseReport.setOnClickListener {
CVReport.visibility = View.GONE // Скрываем карточку отчетов
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на кнопку закрытия карточки редактирования спорта
btnClouseEditSport.setOnClickListener {
CVEditSport.visibility = View.GONE // Скрываем карточку редактирования спорта
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на саму карточку редактирования спорта для закрытия (вероятно, фон)
CVEditSport.setOnClickListener {
CVEditSport.visibility = View.GONE // Скрываем карточку редактирования спорта
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на саму карточку редактирования данных пациента для закрытия (вероятно, фон)
CVEditPatient.setOnClickListener{
CVEditPatient.visibility = View.GONE // Скрываем карточку редактирования данных пациента
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на кнопку закрытия карточки редактирования данных пациента
btnClouseEditPatient.setOnClickListener{
CVEditPatient.visibility = View.GONE // Скрываем карточку редактирования данных пациента
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на кнопку закрытия карточки спортивных курсов
btnCloseReport2.setOnClickListener {
CVSport.visibility = View.GONE // Скрываем карточку спортивных курсов
}
// Обработчик нажатия на кнопку закрытия карточки "Анкета ДО"
btnCloseBefore.setOnClickListener {
CVQB.visibility = View.GONE // Скрываем карточку "Анкета ДО"
}
// Обработчик нажатия на кнопку закрытия карточки "Анкета ПОСЛЕ"
btnCloseAfter.setOnClickListener {
CVQA.visibility = View.GONE // Скрываем карточку "Анкета ПОСЛЕ"
}
// Обработчик нажатия на саму карточку отчетов для закрытия (вероятно, фон)
CVReport.setOnClickListener {
CVReport.visibility = View.GONE // Скрываем карточку отчетов
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Обработчик нажатия на саму карточку спортивных курсов для закрытия (вероятно, фон)
CVSport.setOnClickListener {
CVSport.visibility = View.GONE // Скрываем карточку спортивных курсов
}
// Обработчик нажатия на карточку списка отчетов (пустой)
CVReportList.setOnClickListener {
}
// Обработчик нажатия на кнопку "Редактировать данные пациента": отображает карточку редактирования
btnEditPatient.setOnClickListener {
CVEditPatient.visibility = View.VISIBLE // Отображаем карточку редактирования данных пациента
}
// Переход на страницу редактирования спортивных занятий (фрагмент EditSportFragment)
binding.btnEditSport.setOnClickListener{
binding.CVEditSport.visibility = View.VISIBLE // Отображаем карточку редактирования спортивных занятий
// Вывод фрагмента редактирования спорта в контейнер CLEditSport
activity?.supportFragmentManager?.beginTransaction()
?.replace(com.example.doctor.R.id.CLEditSport, EditSportFragment.newInstance()) // Заменяем текущий фрагмент на EditSportFragment
?.commit() // Применяем изменения
}
// Обработчик нажатия на кнопку для обновления логина пациента
btnUpdateLogin.setOnClickListener{
val login = edLogin.text.toString() // Получаем введенный логин
if(login.count() != 0){ // Проверяем, что поле логина не пустое
if(login.count() > 3){ // Проверяем минимальную длину логина
UpdatePatientLogin(id!!,login) // Вызываем функцию обновления логина
}
else{
Toast(requireContext()).showCustomInfoToast("Логин слишком короткий", requireActivity()) // Показываем сообщение об ошибке (короткий логин)
}
}
else{
Toast(requireContext()).showCustomInfoToast("Поле пустое", requireActivity()) // Показываем сообщение об ошибке (поле пустое)
}
}
// Обработчик нажатия на кнопку для обновления пароля пациента
btnUpdatePassword.setOnClickListener{
val password = edPassword.text.toString() // Получаем введенный пароль
if(password.count() != 0){ // Проверяем, что поле пароля не пустое
if(password.count() > 10){ // Проверяем минимальную длину пароля
UpdatePatientPassword(id!!,password) // Вызываем функцию обновления пароля
}
else{
Toast(requireContext()).showCustomInfoToast("Пароль слишком короткий", requireActivity()) // Показываем сообщение об ошибке (короткий пароль)
}
}
else{
Toast(requireContext()).showCustomInfoToast("Поле пустое", requireActivity()) // Показываем сообщение об ошибке (поле пустое)
}
}
}
// Инициализация списка анкет ДО (RecyclerView с адаптером QBBAdapter)
private fun initRcViewDay() = with(binding) {
RCView.layoutManager = GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию // Устанавливаем GridLayoutManager с 1 столбцом (вертикальный список)
adapter = QBBAdapter() // Создаем экземпляр адаптера QBBAdapter
RCView.adapter = adapter // Устанавливаем адаптер для RecyclerView
}
// Функция для скрытия карточки отчета и очистки логина (вызывается при закрытии или уничтожении фрагмента)
fun closeViewCard() {
binding.txtLogin.text = "" // Очищаем текст логина
binding.CVReport.visibility = View.GONE // Скрываем карточку отчетов
initRcViewDay() // Повторная инициализация списка анкет (возможно, для сброса)
}
// Функция жизненного цикла фрагмента: вызывается перед уничтожением фрагмента
override fun onDestroy() {
super.onDestroy() // Вызываем метод родительского класса
closeViewCard() // Вызываем функцию скрытия карточки и очистки данных
}
companion object {
// Фабричный метод для создания экземпляра PatientFragment
fun newInstance() = PatientFragment() // Создаем и возвращаем новый экземпляр фрагмента
}
}

View File

@ -0,0 +1,66 @@
package com.example.doctor.Patients.Reports
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemQuestionnaireAfterBinding
// Адаптер для отображения анкет "После" (QA) в RecyclerView
class QAAdapter() : ListAdapter<QAModel, QAAdapter.Holder>(Comparator()) {
// ViewHolder для элемента анкеты "После"
class Holder(view: View) :
RecyclerView.ViewHolder(view) {
val binding = ItemQuestionnaireAfterBinding.bind(view) // Объект привязки для доступа к элементам UI элемента списка
// Привязка данных к элементу анкеты (здесь можно реализовать отображение ответов)
@SuppressLint("SuspiciousIndentation") // Подавление предупреждения о подозрительном отступе
fun bind(item: QAModel) = with(binding) {
// Здесь можно реализовать логику отображения ответов на вопросы анкеты
// Пример: textViewQuestion.text = item.question
// Пример: textViewAnswer.text = item.answer
}
}
// Создание ViewHolder для элемента списка. Вызывается RecyclerView при необходимости создания нового ViewHolder.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context) // Получаем LayoutInflater из контекста родительского ViewGroup
.inflate(R.layout.item_questionnaire_after, parent, false) // "Надуваем" макет элемента списка
return Holder(view) // Возвращаем новый экземпляр ViewHolder
}
// Привязка данных к ViewHolder. Вызывается RecyclerView для отображения данных в определенной позиции.
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position)) // Получаем объект данных для текущей позиции и привязываем его к ViewHolder
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы. Используется DiffUtil для эффективного обновления списка.
class Comparator : DiffUtil.ItemCallback<QAModel>() {
// Проверяет, представляют ли два объекта один и тот же элемент (сравнивает уникальные идентификаторы)
override fun areItemsTheSame(
oldItem: QAModel,
newItem: QAModel
): Boolean {
return oldItem.id == newItem.id // Сравниваем по id анкеты
}
// Проверяет, совпадает ли содержимое двух элементов (после того, как areItemsTheSame вернул true)
override fun areContentsTheSame(
oldItem: QAModel,
newItem: QAModel
): Boolean {
return oldItem == newItem // Сравниваем объекты целиком (если data class, сравнивает все свойства)
}
}
}

View File

@ -0,0 +1,21 @@
package com.example.doctor.Patients.Reports
// Модель данных для анкеты "После" (Questionnaire After - QA)
// Этот класс представляет структуру данных для хранения ответов пациента на вопросы анкеты после прохождения курса/лечения.
data class QAModel(
val id: Int, // Уникальный идентификатор анкеты
val status: String, // Статус анкеты (например, "заполнена", "не заполнена")
val one: Int, // Ответ на первый вопрос анкеты (например, оценка по шкале)
val two: Int, // Ответ на второй вопрос анкеты
val three: Int, // Ответ на третий вопрос анкеты
val four: Int, // Ответ на четвертый вопрос анкеты
val five: Int, // Ответ на пятый вопрос анкеты
val six: Int, // Ответ на шестой вопрос анкеты
val seven: Int, // Ответ на седьмой вопрос анкеты
val eight: Int, // Ответ на восьмой вопрос анкеты
val nine: Int, // Ответ на девятый вопрос анкеты
val ten: Int, // Ответ на десятый вопрос анкеты
val eleven: Int, // Ответ на одиннадцатый вопрос анкеты
val twelve: Int, // Ответ на двенадцатый вопрос анкеты
)

View File

@ -0,0 +1,8 @@
package com.example.doctor.Patients.Reports
// Модель данных для списка анкет ДО и ПОСЛЕ (QBA - Questionnaire Before and After)
// Этот класс используется для представления списка объектов QBAModel, вероятно, получаемых из API.
data class QBAListModel(
val questionnaire: List<QBAModel> // Список объектов QBAModel, содержащих данные анкет
)

View File

@ -0,0 +1,37 @@
package com.example.doctor.Patients.Reports
// Модель данных для одной комбинированной анкеты ДО и ПОСЛЕ (QBA - Questionnaire Before and After Model)
// Этот класс объединяет данные из анкет ДО и ПОСЛЕ для конкретной записи/даты.
data class QBAModel(
val id: Int, // Уникальный идентификатор комбинированной записи анкет
val date: String, // Дата заполнения анкет
val idb: Int, // Идентификатор анкеты ДО
//val statusb: Int, // Закомментированное поле: статус анкеты ДО (возможно, не используется или статус определяется по наличию idb)
val oneb: Int, // Ответ на первый вопрос анкеты ДО
val twob: Int, // Ответ на второй вопрос анкеты ДО
val threeb: Int, // Ответ на третий вопрос анкеты ДО
val fourb: Int, // Ответ на четвертый вопрос анкеты ДО
val fiveb: Int, // Ответ на пятый вопрос анкеты ДО
val sixb: Int, // Ответ на шестой вопрос анкеты ДО
val sevenb: Int, // Ответ на седьмой вопрос анкеты ДО
val eightb: Int, // Ответ на восьмой вопрос анкеты ДО
val nineb: Int, // Ответ на девятый вопрос анкеты ДО
val statusa: Int, // Статус анкеты ПОСЛЕ (например, заполнена/не заполнена)
val ida: Int, // Идентификатор анкеты ПОСЛЕ
val onea: Int, // Ответ на первый вопрос анкеты ПОСЛЕ
val twoa: Int, // Ответ на второй вопрос анкеты ПОСЛЕ
val threea: Int, // Ответ на третий вопрос анкеты ПОСЛЕ
val foura: Int, // Ответ на четвертый вопрос анкеты ПОСЛЕ
val fivea: Int, // Ответ на пятый вопрос анкеты ПОСЛЕ
val sixa: Int, // Ответ на шестой вопрос анкеты ПОСЛЕ
val sevena: Int, // Ответ на седьмой вопрос анкеты ПОСЛЕ
val eighta: Int, // Ответ на восьмой вопрос анкеты ПОСЛЕ
val ninea: Int, // Ответ на девятый вопрос анкеты ПОСЛЕ
val tena: Int, // Ответ на десятый вопрос анкеты ПОСЛЕ
val elevena: Int, // Ответ на одиннадцатый вопрос анкеты ПОСЛЕ
val twelvea: Int, // Ответ на двенадцатый вопрос анкеты ПОСЛЕ
)

View File

@ -0,0 +1,62 @@
package com.example.doctor.Patients.Reports
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemQuestionnaireBeforeBinding
// Адаптер для отображения анкет "До" (QB - Questionnaire Before) в RecyclerView
// Этот адаптер используется для привязки данных из списка QBModel к элементам списка в пользовательском интерфейсе.
class QBAdapter() : ListAdapter<QBModel, QBAdapter.Holder>(Comparator()) {
// ViewHolder для элемента анкеты "До". Предоставляет доступ к View элемента списка.
class Holder(view: View) :
RecyclerView.ViewHolder(view) {
// Объект привязки для доступа к элементам UI макета item_questionnaire_before.xml
val binding = ItemQuestionnaireBeforeBinding.bind(view)
// Привязка данных из объекта QBModel к элементам UI ViewHolder
@SuppressLint("SuspiciousIndentation") // Подавление предупреждения о подозрительном отступе
fun bind(item: QBModel) = with(binding) {
// Здесь можно реализовать логику отображения ответов на вопросы анкеты "До".
// Например, присваивание текста TextView из свойств item.
// Пример: textViewQuestion1.text = item.questionOne
// Пример: textViewAnswer1.text = item.answerOne
}
}
// Создание ViewHolder для элемента списка. Вызывается RecyclerView, когда нужно создать новый ViewHolder.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
// Создание View из макета item_questionnaire_before.xml
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_questionnaire_before, parent, false)
return Holder(view) // Возвращаем созданный ViewHolder
}
// Привязка данных к ViewHolder. Вызывается RecyclerView для отображения данных в указанной позиции.
override fun onBindViewHolder(holder: Holder, position: Int) {
// Получение объекта QBModel по позиции и привязка его к ViewHolder
holder.bind(getItem(position))
}
// Comparator для сравнения элементов списка. Используется DiffUtil для определения различий между списками и эффективного обновления.
class Comparator : DiffUtil.ItemCallback<QBModel>() {
// Проверяет, представляют ли два элемента один и тот же объект (сравнивает уникальные идентификаторы).
override fun areItemsTheSame(oldItem: QBModel, newItem: QBModel): Boolean {
return oldItem.id == newItem.id // Сравниваем по id анкеты
}
// Проверяет, совпадает ли содержимое двух элементов (вызывается, если areItemsTheSame вернул true).
override fun areContentsTheSame(oldItem: QBModel, newItem: QBModel): Boolean {
return oldItem == newItem // Сравниваем объекты целиком (для data class сравнивает все свойства)
}
}
}

View File

@ -0,0 +1,293 @@
package com.example.doctor.Patients.Reports
import android.annotation.SuppressLint
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.databinding.ItemQbaBinding
// Адаптер для отображения результатов анкетирования (QBA) в RecyclerView
class QBBAdapter() : ListAdapter<QBAModel, QBBAdapter.Holder>(Comparator()) {
// ViewHolder для элемента результата анкетирования
class Holder(view: View) :
RecyclerView.ViewHolder(view) {
val binding = ItemQbaBinding.bind(view)//view - здесь храянтся элементы и мы их bind заполним в ListItemBinding//ListItemBinding - это клласс даннйо разметки(карточки) которую мы будем заполнять, а нужна дання переменная(binding), чтобы мжно было при заполнение обращатся к элементам карточки
// Привязка данных к элементу результата анкетирования, отображение статусов и цветов
@SuppressLint("SuspiciousIndentation")
fun bind(item: QBAModel) = with(binding) {
// Здесь реализована логика отображения статусов, баллов и цветов для каждой анкеты
// (см. подробную реализацию в теле функции)
// if (item.one == 1) {
// txtB1.text = "Да"
// } else {
// txtB1.text = "Нет"
// }
txtDate.text = item.date
if(item.oneb >= 6){
txtStatusB.text = "Плохо"
CVB.setCardBackgroundColor(Color.parseColor("#DA8383"))
}
else if(item.fourb == 1 || item.fiveb == 1 ||item.sixb == 1 ||item.sevenb == 1 ||item.nineb == 1){
txtStatusB.text = "Средне"
CVB.setCardBackgroundColor(Color.parseColor("#DABA83"))
}
else{
txtStatusB.text = "Хорошо"
CVB.setCardBackgroundColor(Color.parseColor("#ABDA83"))
}
txtB1.text = item.oneb.toString()
if(item.oneb==0){
CLQB1.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
else if(item.oneb in 1..5){
CLQB1.setBackgroundColor(Color.parseColor("#C6DFD386"))
}
else{
CLQB1.setBackgroundColor(Color.parseColor("#C6DF8686"))
}
//Красный - "#C6DF8686"
//Зеленый - "#C686DF8F"
//Желтый - "#C6DFD386"
if (item.twob == 1) {
txtB2.text = "Да"
CLQB2.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB2.text = "Нет"
CLQB2.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.threeb == 1) {
txtB3.text = "Да"
CLQB3.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB3.text = "Нет"
CLQB3.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.fourb == 1) {
txtB4.text = "Да"
CLQB4.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB4.text = "Нет"
CLQB4.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.fiveb == 1) {
txtB5.text = "Да"
CLQB5.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB5.text = "Нет"
CLQB5.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.sixb == 1) {
txtB6.text = "Да"
CLQB6.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB6.text = "Нет"
CLQB6.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.sevenb == 1) {
txtB7.text = "Да"
CLQB7.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB7.text = "Нет"
CLQB7.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.eightb == 1) {
txtB8.text = "Да"
CLQB8.setBackgroundColor(Color.parseColor("#C686DF8F"))
} else {
txtB8.text = "Нет"
CLQB8.setBackgroundColor(Color.parseColor("#C6DF8686"))
}
if (item.nineb == 1) {
txtB9.text = "Да"
CLQB9.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtB9.text = "Нет"
CLQB9.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
//Если анкета после была заполнена
if(item.statusa == 1){
if(item.ninea == 1){
txtStatusA.text = "Плохо"
CVA.setCardBackgroundColor(Color.parseColor("#DA8383"))
}
else if(item.onea >= 6 || item.threea == 1 ||item.sixa == 1 ||item.eighta == 1 ||item.elevena == 1){
txtStatusA.text = "Средне"
CVA.setCardBackgroundColor(Color.parseColor("#DABA83"))
}
else{
txtStatusA.text= "Хорошо"
CVA.setCardBackgroundColor(Color.parseColor("#ABDA83"))
}
txtA1.text = item.onea.toString()
if(item.onea==0){
CLQA1.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
else if(item.onea in 1..5){
CLQA1.setBackgroundColor(Color.parseColor("#C6DFD386"))
}
else{
CLQA1.setBackgroundColor(Color.parseColor("#C6DF8686"))
}
if (item.twoa == 1) {
txtA2.text = "Да"
CLQA2.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA2.text = "Нет"
CLQA2.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.threea == 1) {
txtA3.text = "Да"
CLQA3.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA3.text = "Нет"
CLQA3.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.foura == 1) {
txtA4.text = "Да"
CLQA4.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA4.text = "Нет"
CLQA4.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.fivea == 1) {
txtA5.text = "Да"
CLQA5.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA5.text = "Нет"
CLQA5.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.sixa == 1) {
txtA6.text = "Да"
CLQA6.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA6.text = "Нет"
CLQA6.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.sevena == 1) {
txtA7.text = "Да"
CLQA7.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA7.text = "Нет"
CLQA7.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.eighta == 1) {
txtA8.text = "Да"
CLQA8.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA8.text = "Нет"
CLQA8.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.ninea == 1) {
txtA9.text = "Да"
CLQA9.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA9.text = "Нет"
CLQA9.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.tena == 1) {
txtA10.text = "Да"
CLQA10.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA10.text = "Нет"
CLQA10.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.elevena == 1) {
txtA11.text = "Да"
CLQA11.setBackgroundColor(Color.parseColor("#C6DF8686"))
} else {
txtA11.text = "Нет"
CLQA11.setBackgroundColor(Color.parseColor("#C686DF8F"))
}
if (item.twelvea == 1) {
txtA12.text = "Да"
CLQA12.setBackgroundColor(Color.parseColor("#C686DF8F"))
} else {
txtA12.text = "Нет"
CLQA12.setBackgroundColor(Color.parseColor("#C6DF8686"))
}
}
else{
//Если анкета ПОСЛЕ небыла заполнена
txtStatusA.text = "ПУСТО"
txtStatusA.setTextColor(Color.parseColor("#FFFFFF"))
CVA.setCardBackgroundColor(Color.parseColor("#000000"))
CVColorAfter.setCardBackgroundColor(Color.parseColor("#FF8E8E8E"))
txtA1.text = ""
txtA2.text = ""
txtA3.text = ""
txtA4.text = ""
txtA5.text = ""
txtA6.text = ""
txtA7.text = ""
txtA8.text = ""
txtA9.text = ""
txtA10.text = ""
txtA11.text = ""
txtA12.text = ""
}
}
}
// Создание ViewHolder для элемента списка
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_qba, parent, false)
return Holder(view)
}
// Привязка данных к ViewHolder
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))
}
// Comparator - сравнивает старый и новый списки, чтобы обновлять только изменённые элементы
class Comparator : DiffUtil.ItemCallback<QBAModel>() {
override fun areItemsTheSame(oldItem: QBAModel, newItem: QBAModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: QBAModel, newItem: QBAModel): Boolean {
return oldItem == newItem
}
}
}

View File

@ -0,0 +1,16 @@
package com.example.doctor.Patients.Reports
data class QBModel(
val id: Int,
val status: String,
val one: Int,
val two: Int,
val three: Int,
val four: Int,
val five: Int,
val six: Int,
val seven: Int,
val eight: Int,
val nine: Int,
)

View File

@ -0,0 +1,6 @@
package com.example.doctor.Patients.Reports.Requests
data class ClearSportPatientModel(
val message: String,
)

View File

@ -0,0 +1,173 @@
package com.example.doctor.Patients.TabLayoutPatient
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Adapter.PatientListAdapter
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Model.PatientIdModel
import com.example.doctor.Patients.PatientActivity
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.FragmentActiveCoursesPatientBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class ActiveCoursesPatientFragment : Fragment(),PatientListAdapter.Listener {
private lateinit var binding:FragmentActiveCoursesPatientBinding
private val modelDoctor: DoctorViewModel by activityViewModels()
private val dataModel: DataModel by activityViewModels()//Для передачи данных
lateinit var adapterPatient: PatientListAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
var patientYesList:List<PatientAllModel>?=null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentActiveCoursesPatientBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewDay()
GetPatientList()
modelDoctor.PatientActiveList.observe(viewLifecycleOwner){
if(patientYesList!=it){
patientYesList=it
adapterPatient.submitList(it)
}
}
}
//Инициализация списка
private fun initRcViewDay() = with(binding) {
rcView.layoutManager =
GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapterPatient = PatientListAdapter(this@ActiveCoursesPatientFragment)
rcView.adapter = adapterPatient
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
//Получения списка пациентов
fun GetPatientList() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientAllActive("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
modelDoctor.PatientActiveList.value = List.patient
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
companion object {
fun newInstance() = ActiveCoursesPatientFragment()
}
override fun onClickPatient(item: PatientAllModel) {
//Вывод фрагмента на активити при первоначальной загрузке
// activity?.supportFragmentManager?.beginTransaction()
// ?.replace(com.example.doctor.R.id.CLMainPatient, PatientFragment.newInstance())
// ?.commit()
// prefDoctorSave.saveIdPatient(requireContext(),item.id!!)
// prefDoctorSave.saveViewPatient(requireContext(),1)
//modelDoctor.patientId.value = PatientIdModel(item.id!!)
prefDoctorSave.saveIdPatient(requireContext(),item.id!!)
prefDoctorSave.saveViewPatient(requireContext(),1)
val intetn = Intent(requireContext(), PatientActivity::class.java)
startActivity(intetn)
// dataModel.patientList.value = 1
}
}

View File

@ -0,0 +1,173 @@
package com.example.doctor.Patients.TabLayoutPatient
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DataModel
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetCheck
import com.example.doctor.Patients.Adapter.PatientListAdapter
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Model.PatientIdModel
import com.example.doctor.Patients.PatientActivity
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.databinding.FragmentNotActiveCoursesPatientBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class NotActiveCoursesPatientFragment : Fragment(),PatientListAdapter.Listener {
private lateinit var binding:FragmentNotActiveCoursesPatientBinding
private val model: DoctorViewModel by activityViewModels()
private val dataModel: DataModel by activityViewModels()//Для передачи данных
lateinit var adapterPatient: PatientListAdapter
private lateinit var doctorApi: DoctorApi
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
//Класс проверки интеренета
val enternetCheck = EnternetCheck()
//Список не активных пациентов
var patientNoList: List<PatientAllModel>? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentNotActiveCoursesPatientBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initRcViewDay()
GetPatientList()
model.PatientNotList.observe(viewLifecycleOwner){
if(patientNoList != it){
patientNoList = it
adapterPatient.submitList(it)
}
}
}
//Инициализация списка
private fun initRcViewDay() = with(binding) {
rcView.layoutManager =
GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapterPatient = PatientListAdapter(this@NotActiveCoursesPatientFragment)
rcView.adapter = adapterPatient
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
//Получения списка пациентов
fun GetPatientList() {
if (enternetCheck.isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listProduct = doctorApi.GetPatientAllNotActive("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listProduct.body()
val Nice = listProduct.isSuccessful
val Code = listProduct.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
model.PatientNotList.value = List.patient
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
override fun onClickPatient(item: PatientAllModel) {
//Вывод фрагмента на активити при первоначальной загрузке
// activity?.supportFragmentManager?.beginTransaction()
// ?.replace(com.example.doctor.R.id.CLMainPatient, PatientFragment.newInstance())
// ?.commit()
prefDoctorSave.saveIdPatient(requireContext(),item.id!!)
prefDoctorSave.saveViewPatient(requireContext(),1)
//model.patientId.value = PatientIdModel(item.id!!)
val intetn = Intent(requireContext(), PatientActivity::class.java)
startActivity(intetn)
// dataModel.patientList.value = 1
}
companion object {
fun newInstance() = NotActiveCoursesPatientFragment()
}
}

View File

@ -0,0 +1,42 @@
package com.example.doctor.Pref
import android.content.Context
import android.content.SharedPreferences
class ClearPref() {
fun clearToken(context: Context) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORtoken", Context.MODE_PRIVATE)
val edit = prefDoctor.edit()
edit?.clear()
edit?.apply()
}
fun clearViewPatient(context: Context) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORviewPatient", Context.MODE_PRIVATE)
val edit = prefDoctor.edit()
edit?.clear()
edit?.apply()
}
fun clearIdPatient(context: Context) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORIdPatient", Context.MODE_PRIVATE)
val edit = prefDoctor.edit()
edit?.clear()
edit?.apply()
}
fun clearIdCourses(context: Context) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORIdCourses", Context.MODE_PRIVATE)
val edit = prefDoctor.edit()
edit?.clear()
edit?.apply()
}
fun clearIdActivitis(context: Context) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORIdActivitis", Context.MODE_PRIVATE)
val edit = prefDoctor.edit()
edit?.clear()
edit?.apply()
}
}

View File

@ -0,0 +1,37 @@
package com.example.doctor.Pref
import android.content.Context
import android.content.SharedPreferences
class ConclusionPref() {
fun conclusionToken(context: Context):String {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORtoken", Context.MODE_PRIVATE)
val token = prefDoctor.getString("token", "")
return token.toString()
}
fun conclusionViewPatient(context: Context):Int {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORviewPatient", Context.MODE_PRIVATE)
val viewPatient = prefDoctor.getInt("viewPatient", 0)
return viewPatient.toInt()
}
fun conclusionIdPatient(context: Context):Int {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORidPatient", Context.MODE_PRIVATE)
val idPatient = prefDoctor.getInt("idPatient", 0)
return idPatient.toInt()
}
fun conclusionIdCourses(context: Context):Int {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORidCourses", Context.MODE_PRIVATE)
val idPatient = prefDoctor.getInt("idCourses", 0)
return idPatient.toInt()
}
fun conclusionIdActivitis(context: Context):Int {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORIdActivitis", Context.MODE_PRIVATE)
val idPatient = prefDoctor.getInt("idActivitis", 0)
return idPatient.toInt()
}
}

View File

@ -0,0 +1,39 @@
package com.example.doctor.Pref
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
class SavePref (){
@SuppressLint("CommitPrefEdits")
fun saveToken(context: Context, token: String) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORtoken", Context.MODE_PRIVATE)
prefDoctor.edit().putString("token", token).apply()
}
@SuppressLint("CommitPrefEdits")
fun saveViewPatient(context: Context, view_patient: Int) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORviewPatient", Context.MODE_PRIVATE)
prefDoctor.edit().putInt("viewPatient", view_patient).apply()
}
@SuppressLint("CommitPrefEdits")
fun saveIdPatient(context: Context, view_patient: Int) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORidPatient", Context.MODE_PRIVATE)
prefDoctor.edit().putInt("idPatient", view_patient).apply()
}
@SuppressLint("CommitPrefEdits")
fun saveIdCourses(context: Context, view_patient: Int) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORidCourses", Context.MODE_PRIVATE)
prefDoctor.edit().putInt("idCourses", view_patient).apply()
}
@SuppressLint("CommitPrefEdits")
fun saveIdActivitis(context: Context, view_patient: Int) {
val prefDoctor: SharedPreferences = context.getSharedPreferences("DOCTORIdActivitis", Context.MODE_PRIVATE)
prefDoctor.edit().putInt("idActivitis", view_patient).apply()
}
}

View File

@ -0,0 +1,234 @@
package com.example.doctor.Retrofit
import com.example.doctor.Appeals.TabLayout.Model.AppealsNewListModel
import com.example.doctor.Appeals.TabLayout.Model.AppealsOldListModel
import com.example.doctor.Auth.Model.AuthModel
import com.example.doctor.Auth.Model.CheckTokenModel
import com.example.doctor.Auth.Model.UserModel
import com.example.doctor.Home.HomeInfoModel
import com.example.doctor.Patients.Model.MessageModel
import com.example.doctor.Patients.Model.CreatePatientModel
import com.example.doctor.Patients.Model.PatientAllListModel
import com.example.doctor.Patients.Model.PatientAllModel
import com.example.doctor.Patients.Model.PatientModel
import com.example.doctor.Patients.Model.PauseModel
import com.example.doctor.Patients.Reports.Courses.SportCoursDoctorListModel
import com.example.doctor.Patients.Reports.Courses.SportCoursListModel
import com.example.doctor.Patients.Reports.Edit.EditSportListNoModel
import com.example.doctor.Patients.Reports.Edit.EditSportListYesModel
import com.example.doctor.Patients.Reports.QBAListModel
import com.example.doctor.Patients.Reports.Requests.ClearSportPatientModel
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Model.EditCoursesDoctorListAllModel
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Model.EditCoursesDoctorListYourModel
import com.example.doctor.Setting.Courses.Model.CoursesDoctorListModel
import com.example.doctor.Sport.AddSportPatientModel
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Query
interface DoctorApi {
//Проверка токена
@Headers("Content-Type: application/json")
@GET("CheckTokenDoctor")
suspend fun CheckToken(@Header("Authorization") token:String): Response<CheckTokenModel>
//Выход из аккаунта
@Headers("Content-Type: application/json")
@POST("LoginDoctor")
suspend fun LoginDoctor(@Body authModel: AuthModel): Response<UserModel>
//Выход из аккаунта
@Headers("Content-Type: application/json")
@POST("LogoutDoctor")
suspend fun LogoutDoctor(@Header("Authorization") token:String):Response<MessageModel>
//Вывод всех пациентов
@Headers("Content-Type: application/json")
@GET("GetPatientAll")
suspend fun GetPatientAll(@Header("Authorization") token:String):Response<PatientAllListModel>
//Вывод пациентов конкретного врача с активным курсом
@Headers("Content-Type: application/json")
@GET("GetPatientAllActive")
suspend fun GetPatientAllActive(@Header("Authorization") token:String):Response<PatientAllListModel>
//Вывод пациентов конкретного врача с не активным курсом
@Headers("Content-Type: application/json")
@GET("GetPatientAllNotActive")
suspend fun GetPatientAllNotActive(@Header("Authorization") token:String):Response<PatientAllListModel>
//Вывод всех пациентов
@Headers("Content-Type: application/json")
@GET("GetPatientID")
suspend fun GetPatientID(@Header("Authorization") token:String,@Query("id") id:Int):Response<PatientAllModel>
//Поиск пациентов
@Headers("Content-Type: application/json")
@GET("GetPatientSearch")
suspend fun GetPatientSearch(@Header("Authorization") token:String,@Query("login") login:String):PatientModel
//Вывод всех курсов
@Headers("Content-Type: application/json")
@GET("GetCoursAll")
suspend fun GetCoursAll(@Header("Authorization") token:String):Response<SportCoursListModel>
//Вывод всех курсов
@Headers("Content-Type: application/json")
@GET("GetCoursAllPatient")
suspend fun GetCoursAllPatient(@Header("Authorization") token:String,@Query("id") id:Int):Response<SportCoursListModel>
//Вывод курсов созданных врачем
@Headers("Content-Type: application/json")
@GET("GetCoursesDoctorPatient")
suspend fun GetCoursesDoctorPatient(@Header("Authorization") token:String,@Query("id") id:Int):Response<SportCoursDoctorListModel>
//Вывод анкеты пациентов которые сейчас действуют
@Headers("Content-Type: application/json")
@GET("GetPatientBAQiestionar")
suspend fun GetPatientBAQiestionar(@Header("Authorization") token:String,@Query("id") id:Int):Response<QBAListModel>
//Создание аккаунта
@Headers("Content-Type: application/json")
@POST("CreateAccountPatient")
suspend fun CreateAccountPatient(@Header("Authorization") token:String,@Body createPatientModel: CreatePatientModel):Response<MessageModel>
//Обновление данных пользователя
@Headers("Content-Type: application/json")
@PUT("UpdateAccountPatient")
suspend fun UpdateAccountPatient(@Header("Authorization") token:String,@Query("id") id:String, @Query("login") login:String,@Query("password") password:String)
//Добавление блокировки
@Headers("Content-Type: application/json")
@PUT("UpdateBlockAccountPatient")
suspend fun UpdateBlockAccountPatient(@Header("Authorization") token:String,@Query("id") id:Int):Response<MessageModel>
//Добавление паузы
@Headers("Content-Type: application/json")
@PUT("UpdatePauseAccountPatient")
suspend fun UpdatePauseAccountPatient(@Header("Authorization") token:String,@Query("id") id:Int):Response<PauseModel>
//Получения курса пациента в зависимости от того сколько дней пройдено
@Headers("Content-Type: application/json")
@GET("GetCours")
suspend fun GetCours(@Header("Authorization") token:String,@Query("name") name:String,@Query("day") day:String)
//Добавление курса пациенту
@Headers("Content-Type: application/json")
@POST("AddSportPatient")
suspend fun AddSportPatient(@Header("Authorization") token:String,@Body addSportPatientModel: AddSportPatientModel)
//Очистка курса у пациента
@Headers("Content-Type: application/json")
@PUT("ClearPatientSport")
suspend fun ClearPatientSport(@Header("Authorization") token:String,@Query("id_patient") id_patient:Int):Response<ClearSportPatientModel>
//Вывод всех курсов
@Headers("Content-Type: application/json")
@GET("GetCoursesSport")
suspend fun GetCoursesSport(@Header("Authorization") token:String,@Query("id_patient") id_patient:Int,@Query("id_sports_courses_patient") id_sports_courses_patient:Int):Response<EditSportListNoModel>
//Вывод всех включенных упражненйи
@Headers("Content-Type: application/json")
@GET("GetCoursesSportYes")
suspend fun GetCoursesSportYes(@Header("Authorization") token:String,@Query("id_patient") id_patient:Int):Response<EditSportListYesModel>
//Вывод всех отключенных упражнений
@Headers("Content-Type: application/json")
@GET("GetCoursesSportNo")
suspend fun GetCoursesSportNo(@Header("Authorization") token:String,@Query("id_patient") id_patient:Int):Response<EditSportListNoModel>
//Отключенных упражнений
@Headers("Content-Type: application/json")
@PUT("UpdateBlockSportTasksYes")
suspend fun UpdateBlockSportTasksYes(@Header("Authorization") token:String,@Query("id_patient") id_patient:Int,@Query("id_sports_tasks") id_sports_tasks:Int):Response<MessageModel>
//Отключенных упражнений
@Headers("Content-Type: application/json")
@PUT("UpdateBlockSportTasksNo")
suspend fun UpdateBlockSportTasksNo(@Header("Authorization") token:String,@Query("id") id:Int):Response<MessageModel>
//Отключенных упражнений
@Headers("Content-Type: application/json")
@PUT("UpdatePatientLogin")
suspend fun UpdatePatientLogin(@Header("Authorization") token:String,@Query("id") id:Int,@Query("login") login:String):Response<MessageModel>
//Отключенных упражнений
@Headers("Content-Type: application/json")
@PUT("UpdatePatientPassword")
suspend fun UpdatePatientPassword(@Header("Authorization") token:String,@Query("id") id:Int,@Query("password") password:String):Response<MessageModel>
//Добавление курса пациенту
@Headers("Content-Type: application/json")
@POST("AddSportPatient")
suspend fun AddSportPatient(@Header("Authorization") token:String,@Query("id_patient") id:Int,@Query("id_course") id_course:Int,@Query("all_day") all_day:Int):Response<MessageModel>
//Вывод необработанных сообщений
@Headers("Content-Type: application/json")
@GET("GetAppealsDoctorNew")
suspend fun GetAppealsDoctorNew(@Header("Authorization") token:String) :Response<AppealsNewListModel>
//Вывод необработанных сообщений
@Headers("Content-Type: application/json")
@GET("GetAppealsDoctorOld")
suspend fun GetAppealsDoctorOld(@Header("Authorization") token:String) :Response<AppealsOldListModel>
//Подтверждение необработанных сообщений
@Headers("Content-Type: application/json")
@PUT("UpdateMessageDoctor")
suspend fun UpdateMessageDoctor(@Header("Authorization") token:String,@Query("id") id:Int,@Query("id_patient") id_patient:Int) :Response<MessageModel>
//Отправка сообщения пациенту
@Headers("Content-Type: application/json")
@POST("AddMessageDoctor")
suspend fun AddMessageDoctor(@Header("Authorization") token:String,@Query("login") login:String,@Query("text") text:String) :Response<MessageModel>
//Создание курса врачем
@Headers("Content-Type: application/json")
@POST("AddCoursesName")
suspend fun AddCoursesName(@Header("Authorization") token:String,@Query("name") name:String,@Query("description") description:String) :Response<MessageModel>
//Вывод курсов созданных врачем
@Headers("Content-Type: application/json")
@GET("GetCoursesDoctor")
suspend fun GetCoursesDoctor(@Header("Authorization") token:String) :Response<CoursesDoctorListModel>
//Вывод упражнений которые не входят в курс
@Headers("Content-Type: application/json")
@GET("GetEditCourseDoctorAll")
suspend fun GetEditCourseDoctorAll(@Header("Authorization") token:String,@Query("id_doctor_courses") id_doctor_courses:Int) :Response<EditCoursesDoctorListAllModel>
//Вывод упражнений которые входят в курс
@Headers("Content-Type: application/json")
@GET("GetEditCourseDoctorYour")
suspend fun GetEditCourseDoctorYour(@Header("Authorization") token:String,@Query("id_doctor_courses") id_doctor_courses:Int) :Response<EditCoursesDoctorListYourModel>
//Добавление упражнений в курс
@Headers("Content-Type: application/json")
@POST("AddCoursesCreatingDoctor")
suspend fun AddCoursesCreatingDoctor(@Header("Authorization") token:String,@Query("id_sports_tasks") id_sports_tasks:Int,@Query("id_sets_of_sports_activities") id_sets_of_sports_activities:Int) :Response<MessageModel>
//Удаление упражнений из курса
@Headers("Content-Type: application/json")
@DELETE("ClearCoursesCreatingDoctor")
suspend fun ClearCoursesCreatingDoctor(@Header("Authorization") token:String,@Query("id_sets_of_sports_exercises") id_sets_of_sports_exercises:Int) :Response<MessageModel>
//Вывод данных для первой страницы врача
@Headers("Content-Type: application/json")
@GET("CountPatientAndAppeals")
suspend fun CountPatientAndAppeals(@Header("Authorization") token:String) :Response<HomeInfoModel>
}

View File

@ -0,0 +1,90 @@
package com.example.doctor.Setting.Courses.Adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.Setting.Courses.Model.CoursesDoctorModel
import com.example.doctor.databinding.ItemCardCoursesDoctorBinding
class CoursesDoctorAdapter(val listener: Listener) :
ListAdapter<CoursesDoctorModel, CoursesDoctorAdapter.Holder>(
Comparator()
) {//Productitem - по этой форме будем заполнять.//ProductAdapter.holder - это создаваемый holder который хранит логику как нужно заполнять карточку
//В holder создаетс код с помошью которого мы будем заполнять и сохронять разметку
class Holder(view: View, val listener: Listener) :
RecyclerView.ViewHolder(view) {//Класс который будет хранить сссылки на элементы, и отвечает за один элемент за 1 раз, то есть сначсало нулевой элемент заполнит, потом первый, потом второй и т.д.
//Для передачи данных
val binding = ItemCardCoursesDoctorBinding.bind(view)//view - здесь храянтся элементы и мы их bind заполним в ListItemBinding//ListItemBinding - это клласс даннйо разметки(карточки) которую мы будем заполнять, а нужна дання переменная(binding), чтобы мжно было при заполнение обращатся к элементам карточки
var itemTemp: CoursesDoctorModel? =
null//Глобальная переменная для нашего item, чтобы можно было передать данные для нажатия
//init - дает возможность внутри адаптера обращаться к элементам экрана
init {
itemView.setOnClickListener {//Нажатие на ячейку//itemView - это весь элемент карточки из списка
//itemView.setEnabled(false)
itemTemp?.let { it1 -> listener.onClickCourses(it1) }
}
}
@SuppressLint("SuspiciousIndentation", "SetTextI18n")
fun bind(item: CoursesDoctorModel) = with(binding) {//Productitem - перпедаем данные
itemTemp = item
txtNumberCurds.text = item.number.toString() + "."
txtNameCoursesDoctor.text = item.name
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_card_courses_doctor, parent, false)//Создаем(надуваем) list_item
return Holder(view, listener)//Через Holder возврощаем view
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))//Заполняем по позиции карточку
}
//Comparator - сравнивает старый список и новый и если что-то изменилось, то работает с конкретным изменением списке, а не весь список переписывает
class Comparator : DiffUtil.ItemCallback<CoursesDoctorModel>() {
override fun areItemsTheSame(
oldItem: CoursesDoctorModel,
newItem: CoursesDoctorModel
): Boolean {//Тут лучше всего сравнивать по id//oldItem - элементы старого списка, newItem - элементы нового списка//Возврощает Boolean, тоесть есть изменения или нет
return oldItem.id == newItem.id//Сравниваем полностью весь список новы и старый, по очередно по одной карточке и по элементно, то есть нулевой элемент, первый, второй и т.д.. Но лучше сравнивать по id списки, а не просто весь список, так как это эфективнее, так как id уникальный(oldItem.id == newItem.id)
}
override fun areContentsTheSame(
oldItem: CoursesDoctorModel,
newItem: CoursesDoctorModel
): Boolean {//Утут нужно сравнивать весь спсок старых элементов и новых
return oldItem == newItem//Сравниваем полностью весь список новы и старый
}
}
//Интерфейс нажатия на кнопку удалить товар из корзины
interface Listener {
fun onClickCourses(item: CoursesDoctorModel)
}
}

View File

@ -0,0 +1,22 @@
package com.example.doctor.Setting.Courses
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.doctor.Patients.Reports.PatientFragment
import com.example.doctor.R
import com.example.doctor.Setting.Courses.EditCourses.CreateCoursesFragment
import com.example.doctor.databinding.ActivityCoursesBinding
class CoursesActivity : AppCompatActivity() {
private lateinit var binding: ActivityCoursesBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCoursesBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.apply {
supportFragmentManager.beginTransaction().replace(R.id.CLCoursesActivity, CreateCoursesFragment.newInstance()).commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}
}

View File

@ -0,0 +1,407 @@
package com.example.doctor.Setting.Courses.EditCourses
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import com.example.doctor.Adapter.VpAdapter
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Enternet.EnternetFragment
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Setting.Courses.Adapter.CoursesDoctorAdapter
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.AllSportCoursesDoctorFragment
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.YourSportCoursesDoctorFragment
import com.example.doctor.Setting.Courses.Model.CoursesDoctorModel
import com.example.doctor.Toast.showCustomInfoToast
import com.example.doctor.databinding.FragmentCreateCoursesBinding
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class CreateCoursesFragment : Fragment(),CoursesDoctorAdapter.Listener {
private lateinit var binding: FragmentCreateCoursesBinding
private val model: DoctorViewModel by activityViewModels()
private lateinit var doctorApi: DoctorApi
lateinit var adapter: CoursesDoctorAdapter
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCreateCoursesBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply {
initRcView()
GetCoursesDoctor()
button()
CLCreate.visibility = View.GONE
btnCreateCourses.setOnClickListener{
CLCreate.visibility = View.VISIBLE
}
//Закрытие экоана создания названия
CLCreate.setOnClickListener{
CLCreate.visibility = View.GONE
}
btnExitCreat.setOnClickListener{
CLCreate.visibility = View.GONE
}
// CLEditCourses.setOnClickListener {
// CLEditCourses.visibility = View.GONE
// }
btnExit.setOnClickListener{
activity?.finish()
}
model.CoursesDoctorList.observe(viewLifecycleOwner) {
adapter.submitList(it)
}
btnCreateCoursrsDoctor.setOnClickListener{
CreateCoursesDoctor()
}
}
}
private fun CreateCoursesDoctor() {
val name = binding.edCoursesDoctorName.text.toString()
val description = binding.edCoursesDoctorDescription.text.toString()
if(name!="" && description !=""){
AddCoursesName(name,description)
}
else{
Toast(requireContext()).showCustomInfoToast("Не все поля заполнены", requireActivity())
}
}
private fun button() = with(binding){
CVCardCreateCourses.setOnClickListener {
}
// CVEditCourses.setOnClickListener {
//
// }
}
//Получения списка пациентов
fun AddCoursesName(name:String,description:String) {
if (isOnline(requireContext())) {
visibleLoadYes()
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listCreateCoursesDoctor = doctorApi.AddCoursesName("Bearer $Tokens",name,description)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listCreateCoursesDoctor.body()
val Nice = listCreateCoursesDoctor.isSuccessful
val Code = listCreateCoursesDoctor.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
Toast(requireContext()).showCustomInfoToast(List.message, requireActivity())
GetCoursesDoctor()
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
visibleLoadNo()
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Получения списка курсов созданных доктором
fun GetCoursesDoctor() {
if (isOnline(requireContext())) {
visibleLoadYes()
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetCoursesDoctor("Bearer $Tokens")
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listCoursesDoctor.body()
val Nice = listCoursesDoctor.isSuccessful
val Code = listCoursesDoctor.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
model.CoursesDoctorList.value = List.sport_courses_doctor
binding.txtNull.visibility = View.GONE
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
visibleLoadNo()
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Инициализация списка
private fun initRcView() = with(binding) {
rcView.layoutManager = GridLayoutManager(requireContext(), 1)//По вертикали будет выводить по умолчанию
adapter = CoursesDoctorAdapter(this@CreateCoursesFragment)
rcView.adapter = adapter
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
fun visible1()=with(binding){
constraintLayout2.visibility = View.VISIBLE
CLCreate.visibility = View.GONE
// CLEditCourses.visibility = View.GONE
CLLoad.visibility = View.GONE
}
fun visible2()=with(binding){
constraintLayout2.visibility = View.GONE
CLCreate.visibility = View.VISIBLE
//CLEditCourses.visibility = View.GONE
CLLoad.visibility = View.GONE
}
fun visible3()=with(binding){
constraintLayout2.visibility = View.GONE
CLCreate.visibility = View.GONE
// CLEditCourses.visibility = View.VISIBLE
CLLoad.visibility = View.GONE
}
fun visibleLoadYes()=with(binding){
CLLoad.visibility = View.VISIBLE
}
fun visibleLoadNo()=with(binding){
CLLoad.visibility = View.GONE
}
companion object {
fun newInstance() = CreateCoursesFragment()
}
// //Получения списка курсов созданных доктором
// fun GetEditCourseDoctorAll(id:Int) {
// if (isOnline(requireContext())) {
// initRetrofit()
// val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
// CoroutineScope(Dispatchers.IO).launch {
// val listCoursesDoctor = doctorApi.GetEditCourseDoctorAll("Bearer $Tokens",id)
//
// requireActivity().runOnUiThread {
//
// //Фиксируем полученные данные
// val CoursesDoctorList = listCoursesDoctor.body()
//
// //Если нету ошибок
// if (CoursesDoctorList != null) {
// model.EditCoursesDoctorAllList.value = CoursesDoctorList.set_of_sports_exercises_all
// binding.txtNull.visibility = View.GONE
// }
// else{
// binding.txtNull.visibility = View.VISIBLE
// }
//
// }
//
// }
// } else {
// val intetn = Intent(requireContext(), EnternetActivity::class.java)
// activity?.finish()
// startActivity(intetn)
// }
//
// }
// //Получения списка курсов созданных доктором
// fun GetEditCourseDoctorYour(id:Int) {
// if (isOnline(requireContext())) {
// initRetrofit()
// val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
// CoroutineScope(Dispatchers.IO).launch {
// val listCoursesDoctor = doctorApi.GetEditCourseDoctorYour("Bearer $Tokens",id)
//
// requireActivity().runOnUiThread {
//
// //Фиксируем полученные данные
// val CoursesDoctorList = listCoursesDoctor.body()
//
// //Если нету ошибок
// if (CoursesDoctorList != null) {
// model.EditCoursesDoctorYourList.value = CoursesDoctorList.set_of_sports_exercises_your
// }
// }
// }
// } else {
// val intetn = Intent(requireContext(), EnternetActivity::class.java)
// activity?.finish()
// startActivity(intetn)
// }
//
// }
//Проверка интернета
fun isOnline(context: Context): Boolean {
if (context == null) return false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
return true
}
}
}
} else {
val activeNetworkInfo = connectivityManager.activeNetworkInfo
if (activeNetworkInfo != null && activeNetworkInfo.isConnected) {
return true
}
}
return false
}
override fun onClickCourses(item: CoursesDoctorModel){
// // CLEditCourses.visibility = View.VISIBLE
// prefDoctorSave.saveIdCourses(requireContext(),item.id)
// prefDoctorSave.saveIdActivitis(requireContext(),item.id_activity)
// // model.CoursesDoctorCA.value= CoursesDoctorCA(item.id,item.id_activity)
// GetEditCourseDoctorAll(item.id)
// GetEditCourseDoctorYour(item.id)
model.CoursesCustomDoctor.value = item
activity?.supportFragmentManager?.beginTransaction()?.replace(R.id.CLCoursesActivity, EditCoursesFragment.newInstance())?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
}

View File

@ -0,0 +1,242 @@
package com.example.doctor.Setting.Courses.EditCourses
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import com.example.doctor.Adapter.VpAdapter
import com.example.doctor.Auth.AuthActivity
import com.example.doctor.CodeError.Code429Activity
import com.example.doctor.CodeError.Code500Activity
import com.example.doctor.DoctorViewModel
import com.example.doctor.Enternet.EnternetActivity
import com.example.doctor.Pref.ClearPref
import com.example.doctor.Pref.ConclusionPref
import com.example.doctor.Pref.SavePref
import com.example.doctor.R
import com.example.doctor.Retrofit.DoctorApi
import com.example.doctor.Setting.Courses.Adapter.CoursesDoctorAdapter
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.AllSportCoursesDoctorFragment
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.YourSportCoursesDoctorFragment
import com.example.doctor.databinding.FragmentEditCoursesBinding
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class EditCoursesFragment : Fragment() {
private lateinit var binding:FragmentEditCoursesBinding
private val model: DoctorViewModel by activityViewModels()
private lateinit var doctorApi: DoctorApi
lateinit var adapter: CoursesDoctorAdapter
val prefDoctorConclusion = ConclusionPref()
val prefDoctorClear = ClearPref()
val prefDoctorSave = SavePref()
private val tList = listOf(
"добавленные",
"Все",
)
//Список с фрагментами для переключения
private val flist = listOf(
YourSportCoursesDoctorFragment.newInstance(),
AllSportCoursesDoctorFragment.newInstance(),
)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentEditCoursesBinding.inflate(layoutInflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply {
init()
binding.btnBack.setOnClickListener{
activity?.supportFragmentManager?.beginTransaction()?.replace(R.id.CLCoursesActivity, CreateCoursesFragment.newInstance())?.commit()//Заменяем наш экран на фрагмент (используем наш экран как основу)//R.id.placeHolder - куда всталяем //MainFragment.newInstance() - это то что мы вставляем
}
model.CoursesCustomDoctor.observe(viewLifecycleOwner){
txtNameCourses.text = it.name
GetEditCourseDoctorYour(it.id)
GetEditCourseDoctorAll(it.id)
}
}
}
//Получения списка упражнений созданных врачем
fun GetEditCourseDoctorYour(id:Int) {
if (isOnline(requireContext())) {
initRetrofit()
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetEditCourseDoctorYour("Bearer $Tokens",id)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val List = listCoursesDoctor.body()
val Nice = listCoursesDoctor.isSuccessful
val Code = listCoursesDoctor.code()
if(Code==429){
val intetn = Intent(requireContext(), Code429Activity::class.java)
startActivity(intetn)
}
else if(Code==200) {
//Если нету ошибок
if (Nice) {
if (List != null) {
model.EditCoursesDoctorYourList.value = List.set_of_sports_exercises_your
}
}
}
else if (Code == 500) {
val intetn = Intent(requireContext(), Code500Activity::class.java)
startActivity(intetn)
}
else if (Code == 401) {
val intetn = Intent(requireContext(), AuthActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Получения списка курсов созданных доктором
fun GetEditCourseDoctorAll(id:Int) {
if (isOnline(requireContext())) {
val Tokens = prefDoctorConclusion.conclusionToken(requireContext())
CoroutineScope(Dispatchers.IO).launch {
val listCoursesDoctor = doctorApi.GetEditCourseDoctorAll("Bearer $Tokens",id)
requireActivity().runOnUiThread {
//Фиксируем полученные данные
val CoursesDoctorList = listCoursesDoctor.body()
//Если нету ошибок
if (CoursesDoctorList != null) {
model.EditCoursesDoctorAllList.value = CoursesDoctorList.set_of_sports_exercises_all
}
}
}
} else {
val intetn = Intent(requireContext(), EnternetActivity::class.java)
activity?.finish()
startActivity(intetn)
}
}
//Функция подключения переключения
private fun init() = with(binding) {
val adapter = VpAdapter(activity as FragmentActivity, flist)
vpCourses.adapter = adapter
//Переключения (связываем таблаяут(переключатель) с viewpager, чтобы переключать фрагменты)
TabLayoutMediator(tabLayoutCourses, vpCourses) { tab, pos ->
tab.text =
tList[pos]//tab - нажатая кнопка, pos - позиция кнопки, tList[pos] - передаем название по полученной позиции
}.attach()// attach() - чтобы все переключалось, а не вывадило постоянно один экран
//Изменения цвета в зависомости на каком из tabLayout вы находитесь
binding.tabLayoutCourses.setTabTextColors(
getResources().getColor(R.color.black),
getResources().getColor(R.color.white)
);
}
//Инициализируем Retrofit
private fun initRetrofit() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://rehabilitation.vmeda.org/api/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
doctorApi = retrofit.create(DoctorApi::class.java)
}
//Проверка интернета
fun isOnline(context: Context): Boolean {
if (context == null) return false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
return true
}
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> {
return true
}
}
}
} else {
val activeNetworkInfo = connectivityManager.activeNetworkInfo
if (activeNetworkInfo != null && activeNetworkInfo.isConnected) {
return true
}
}
return false
}
companion object {
fun newInstance() = EditCoursesFragment()
}
}

View File

@ -0,0 +1,107 @@
package com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.doctor.R
import com.example.doctor.Setting.Courses.EditCourses.TabLayoutEditCourses.Model.EditCoursesDoctorModel
import com.example.doctor.databinding.ItemEditSportYesBinding
class EditCoursesDoctorAllAdapter(val listener_sport: Listener) :
ListAdapter<EditCoursesDoctorModel, EditCoursesDoctorAllAdapter.Holder>(
Comparator()
) {//Productitem - по этой форме будем заполнять.//ProductAdapter.holder - это создаваемый holder который хранит логику как нужно заполнять карточку
//В holder создаетс код с помошью которого мы будем заполнять и сохронять разметку
class Holder(view: View, val listener_sport: Listener) :
RecyclerView.ViewHolder(view) {//Класс который будет хранить сссылки на элементы, и отвечает за один элемент за 1 раз, то есть сначсало нулевой элемент заполнит, потом первый, потом второй и т.д.
//Для передачи данных
val binding = ItemEditSportYesBinding.bind(view)//view - здесь храянтся элементы и мы их bind заполним в ListItemBinding//ListItemBinding - это клласс даннйо разметки(карточки) которую мы будем заполнять, а нужна дання переменная(binding), чтобы мжно было при заполнение обращатся к элементам карточки
var itemTemp: EditCoursesDoctorModel? =
null//Глобальная переменная для нашего item, чтобы можно было передать данные для нажатия
//init - дает возможность внутри адаптера обращаться к элементам экрана
init {
binding.btnYeyYes.setOnClickListener {//Нажатие на ячейку//itemView - это весь элемент карточки из списка
itemTemp?.let { it1 -> listener_sport.onClickCoursesAll(it1) }
}
}
@SuppressLint("SuspiciousIndentation")
fun bind(item: EditCoursesDoctorModel) = with(binding) {//Productitem - перпедаем данные
itemTemp = item
txtNumber.text = item.number.toString()+"."
txtNameSport.text = item.name
txtDescriptionSport.text = item.description
if (item.expand) {
binding.txtDescriptionSport.maxLines = 100
} else {
binding.txtDescriptionSport.maxLines = 1
}
binding.CardViewOld.setOnClickListener {
if (item.expand == false) {
binding.txtDescriptionSport.maxLines = 100
item.expand = true
} else {
binding.txtDescriptionSport.maxLines = 1
item.expand = false
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_edit_sport_yes, parent, false)//Создаем(надуваем) list_item
return Holder(view, listener_sport)//Через Holder возврощаем view
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val view = holder.bind(getItem(position))//Заполняем по позиции карточку
}
//Comparator - сравнивает старый список и новый и если что-то изменилось, то работает с конкретным изменением списке, а не весь список переписывает
class Comparator : DiffUtil.ItemCallback<EditCoursesDoctorModel>() {
override fun areItemsTheSame(
oldItem: EditCoursesDoctorModel,
newItem: EditCoursesDoctorModel
): Boolean {//Тут лучше всего сравнивать по id//oldItem - элементы старого списка, newItem - элементы нового списка//Возврощает Boolean, тоесть есть изменения или нет
return oldItem.id == newItem.id//Сравниваем полностью весь список новы и старый, по очередно по одной карточке и по элементно, то есть нулевой элемент, первый, второй и т.д.. Но лучше сравнивать по id списки, а не просто весь список, так как это эфективнее, так как id уникальный(oldItem.id == newItem.id)
}
override fun areContentsTheSame(
oldItem: EditCoursesDoctorModel,
newItem: EditCoursesDoctorModel
): Boolean {//Утут нужно сравнивать весь спсок старых элементов и новых
return oldItem == newItem//Сравниваем полностью весь список новы и старый
}
}
//Интерфейс нажатия на кнопку удалить товар из корзины
interface Listener {
fun onClickCoursesAll(item: EditCoursesDoctorModel)
}
}

Some files were not shown because too many files have changed in this diff Show More