made solon 2.0
@@ -1,3 +1,15 @@
|
|||||||
*.swp
|
*.iml
|
||||||
TODO.md
|
.gradle
|
||||||
./.idea/
|
/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
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/help" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/mobile/help" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
*.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
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
@@ -1 +1 @@
|
|||||||
Solon
|
solon
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="WizardSettings">
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="imageWizard">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="imageAssetPanel">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="actionbar">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/tmp/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="launcher">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="foregroundClipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="imagePath" value="/tmp/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundImage">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="$PROJECT_DIR$/app/src/main/res/drawable/solon_500_yellow.png" />
|
||||||
|
<entry key="scalingPercent" value="70" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundTextAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="outputName" value="launcher" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="launcherLegacy">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/tmp/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="notification">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/tmp/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="tvBanner">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="tvChannel">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="foregroundClipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="imagePath" value="/tmp/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundImage">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundTextAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<JetCodeStyleSettings>
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</JetCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="kotlin">
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="deploymentTargetDropDown">
|
|
||||||
<value>
|
|
||||||
<entry key="app">
|
|
||||||
<State />
|
|
||||||
</entry>
|
|
||||||
</value>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -4,15 +4,18 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2024-09-22T16:40:27.288755501Z">
|
<DropdownSelection timestamp="2024-10-20T07:27:51.115175643Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="LocalEmulator" identifier="path=/home/thinker/.android/avd/5_inch_API_31.avd" />
|
<DeviceId pluginId="LocalEmulator" identifier="path=/home/thinker/.android/avd/Motorola_Moto_e22_API_31.avd" />
|
||||||
</handle>
|
</handle>
|
||||||
</Target>
|
</Target>
|
||||||
</DropdownSelection>
|
</DropdownSelection>
|
||||||
<DialogSelection />
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
|
<SelectionState runConfigName="DefaultPreview">
|
||||||
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewDeviceShouldUseNewSpec" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="Kotlin2JsCompilerArguments">
|
||||||
|
<option name="moduleKind" value="plain" />
|
||||||
|
</component>
|
||||||
|
<component name="Kotlin2JvmCompilerArguments">
|
||||||
|
<option name="jvmTarget" value="1.8" />
|
||||||
|
</component>
|
||||||
|
<component name="KotlinCommonCompilerArguments">
|
||||||
|
<option name="apiVersion" value="2.0" />
|
||||||
|
<option name="languageVersion" value="2.0" />
|
||||||
|
</component>
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.22" />
|
<option name="version" value="2.0.0" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MaterialThemeProjectNewConfig">
|
||||||
|
<option name="metadata">
|
||||||
|
<MTProjectMetadataState>
|
||||||
|
<option name="migrated" value="true" />
|
||||||
|
<option name="pristineConfig" value="false" />
|
||||||
|
<option name="userId" value="-239e49af:192a4be9597:-7ffe" />
|
||||||
|
</MTProjectMetadataState>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="ProjectType">
|
||||||
|
<option name="id" value="Android" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/help" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
alias(libs.plugins.android.application)
|
||||||
id("org.jetbrains.kotlin.android")
|
alias(libs.plugins.kotlin.android)
|
||||||
|
alias(libs.plugins.kotlin.compose)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -12,39 +13,42 @@ android {
|
|||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0.9"
|
versionName = "2.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
compose = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.core:core-ktx:1.12.0")
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
implementation("com.google.android.material:material:1.11.0")
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
implementation(libs.androidx.ui)
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
|
implementation(libs.androidx.ui.graphics)
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
|
implementation(libs.androidx.material3)
|
||||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
implementation(libs.okhttp)
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
implementation(libs.glide)
|
||||||
implementation("androidx.viewpager2:viewpager2:1.0.0")
|
implementation(libs.androidx.material.icons.extended)
|
||||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
|
||||||
implementation("com.google.android.material:material:1.11.0")
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"artifactType": {
|
||||||
|
"type": "APK",
|
||||||
|
"kind": "Directory"
|
||||||
|
},
|
||||||
|
"applicationId": "com.odweta.solon",
|
||||||
|
"variantName": "release",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "SINGLE",
|
||||||
|
"filters": [],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 1,
|
||||||
|
"versionName": "2.0",
|
||||||
|
"outputFile": "app-release.apk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elementType": "File",
|
||||||
|
"baselineProfiles": [
|
||||||
|
{
|
||||||
|
"minApi": 28,
|
||||||
|
"maxApi": 30,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/1/app-release.dm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minApi": 31,
|
||||||
|
"maxApi": 2147483647,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/0/app-release.dm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minSdkVersionForDexing": 28
|
||||||
|
}
|
||||||
@@ -10,29 +10,23 @@
|
|||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/launcher"
|
||||||
android:label="@string/app_name"
|
android:label="Solon"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Solon"
|
android:theme="@style/Theme.Solon"
|
||||||
tools:targetApi="tiramisu"
|
tools:targetApi="31">
|
||||||
android:usesCleartextTraffic="true"
|
|
||||||
android:enableOnBackInvokedCallback="true">
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.Solon"
|
android:label="@string/app_name"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:theme="@style/Theme.Solon">
|
||||||
android:screenOrientation="portrait">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<meta-data
|
|
||||||
android:name="preloaded_fonts"
|
|
||||||
android:resource="@array/preloaded_fonts" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,129 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import java.time.format.TextStyle
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AboutScreen(modifier: Modifier = Modifier) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
horizontalAlignment = Alignment.Start
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isShowing.value = IsShowing.Menu
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(100.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBackIosNew, // Replace with your desired icon
|
||||||
|
contentDescription = "Back icon",
|
||||||
|
modifier = Modifier.size(35.dp) // Adjust size if needed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.solon_just_yellow),
|
||||||
|
contentDescription = "Solon logo",
|
||||||
|
modifier = Modifier.size(200.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Přehlednost je podstata",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
fontStyle = FontStyle.Italic,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Odlehčená verze mobilní aplikace Škola OnLine",
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 25.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
) {
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Vývoj: ",
|
||||||
|
textAlign = TextAlign.Start,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "@Odweta",
|
||||||
|
color = PastelYellow,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
textAlign = TextAlign.End,
|
||||||
|
textDecoration = TextDecoration.Underline,
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
uriHandler.openUri("https://www.gitlab.com/Odweta/solon")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.Spannable
|
|
||||||
import android.text.SpannableString
|
|
||||||
import android.text.method.LinkMovementMethod
|
|
||||||
import android.text.style.ClickableSpan
|
|
||||||
import android.text.style.UnderlineSpan
|
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.TextView
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
|
|
||||||
class AboutFragment : DialogFragment() {
|
|
||||||
private lateinit var gestureDetector: GestureDetector
|
|
||||||
private var initialTouchY: Float = 0f
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
private val swipeVelocityThreshold = 100
|
|
||||||
private lateinit var dialog: Dialog
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_about, container, false)
|
|
||||||
|
|
||||||
// Set up GestureDetector
|
|
||||||
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
|
|
||||||
|
|
||||||
// Attach the gesture detector to the root layout
|
|
||||||
view.setOnTouchListener { _, event ->
|
|
||||||
view.performClick()
|
|
||||||
handleTouchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
val link = view.findViewById<TextView>(R.id.link)
|
|
||||||
val underlinedText = SpannableString(link.text)
|
|
||||||
underlinedText.setSpan(UnderlineSpan(), 8, link.text.length, 0)
|
|
||||||
|
|
||||||
link.text = underlinedText
|
|
||||||
makeTextViewClickable(link, "https://gitlab.com/Odweta", 8)
|
|
||||||
|
|
||||||
|
|
||||||
val srcLink = view.findViewById<TextView>(R.id.sourceCode)
|
|
||||||
val underlinedText2 = SpannableString(srcLink.text)
|
|
||||||
underlinedText2.setSpan(UnderlineSpan(), 1, srcLink.text.length, 0)
|
|
||||||
|
|
||||||
srcLink.text = underlinedText2
|
|
||||||
makeTextViewClickable(srcLink, "https://gitlab.com/Odweta/solon")
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
dialog = super.onCreateDialog(savedInstanceState)
|
|
||||||
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
|
|
||||||
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
|
||||||
dialog.setCancelable(true)
|
|
||||||
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeTextViewClickable(link: TextView, url: String, offset: Int = 0) {
|
|
||||||
val clickableSpan = object : ClickableSpan() {
|
|
||||||
override fun onClick(widget: View) {
|
|
||||||
if (Vars.internetAvail) {
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
|
||||||
startActivity(intent)
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
requireContext(),
|
|
||||||
"Bez připojení k internetu.",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val spannable = Spannable.Factory.getInstance().newSpannable(link.text)
|
|
||||||
spannable.setSpan(clickableSpan, offset, link.text.length, Spannable.SPAN_COMPOSING)
|
|
||||||
|
|
||||||
link.text = spannable
|
|
||||||
link.movementMethod = LinkMovementMethod.getInstance()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
|
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFling(
|
|
||||||
e1: MotionEvent?,
|
|
||||||
e2: MotionEvent,
|
|
||||||
velocityX: Float,
|
|
||||||
velocityY: Float
|
|
||||||
): Boolean {
|
|
||||||
val diffY = e1?.let { e2.y.minus(it.y) } ?: 0f
|
|
||||||
if (diffY > swipeThreshold && abs(velocityY) > swipeVelocityThreshold) {
|
|
||||||
// Swiped down
|
|
||||||
dismiss()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SameReturnValue", "SameReturnValue", "SameReturnValue")
|
|
||||||
private fun handleTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
initialTouchY = event.rawY
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
val deltaY = event.rawY - initialTouchY
|
|
||||||
dialog?.window?.attributes?.y = deltaY.toInt()
|
|
||||||
dialog?.window?.attributes?.windowAnimations = 0
|
|
||||||
dialog?.show()
|
|
||||||
|
|
||||||
// Check if the dialog has been dragged beyond a threshold and dismiss if necessary
|
|
||||||
if (deltaY > 200) {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
initialTouchY = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,7 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// check if file exists
|
// check if file exists
|
||||||
val file = File(Vars.fileDir, Vars.accountDataFilePath)
|
val file = File(fileDir, accountDataFilePath)
|
||||||
|
|
||||||
return if (!file.exists()) {
|
return if (!file.exists()) {
|
||||||
// it does not exist
|
// it does not exist
|
||||||
@@ -36,15 +36,15 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
} else {
|
} else {
|
||||||
// it exists, so it shall be parsed
|
// it exists, so it shall be parsed
|
||||||
val acc: Account = parseAccountDataFile(file)
|
val acc: Account = parseAccountDataFile(file)
|
||||||
Vars.username = acc.username
|
username = acc.username
|
||||||
Vars.password = acc.password
|
password = acc.password
|
||||||
acc.error == 0
|
acc.error == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(acc: Account): Boolean {
|
fun save(acc: Account): Boolean {
|
||||||
return try {
|
return try {
|
||||||
val file = File(Vars.fileDir, Vars.accountDataFilePath)
|
val file = File(fileDir, accountDataFilePath)
|
||||||
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -55,8 +55,8 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
|
|
||||||
suspend fun isValid(acc: Account): Boolean {
|
suspend fun isValid(acc: Account): Boolean {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
Vars.username = acc.username
|
username = acc.username
|
||||||
Vars.password = acc.password
|
password = acc.password
|
||||||
|
|
||||||
val token = Network.getToken()
|
val token = Network.getToken()
|
||||||
!JSONObject(token).has("error")
|
!JSONObject(token).has("error")
|
||||||
|
|||||||
@@ -1,751 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewTreeObserver
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ScrollView
|
|
||||||
import android.widget.Space
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.core.view.marginLeft
|
|
||||||
import androidx.core.view.setMargins
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalTime
|
|
||||||
class CalWeekFragment : Fragment() {
|
|
||||||
private lateinit var viewPager: ViewPager2
|
|
||||||
private lateinit var adapter: DayPagerAdapter
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_cal_week, container, false)
|
|
||||||
|
|
||||||
viewPager = view.findViewById(R.id.dayPager)
|
|
||||||
|
|
||||||
adapter = DayPagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)
|
|
||||||
|
|
||||||
Vars.dayCounter = 0
|
|
||||||
for (i in 0 until Vars.days.size) {
|
|
||||||
adapter.addFragment(DayFragment())
|
|
||||||
}
|
|
||||||
|
|
||||||
viewPager.viewTreeObserver.addOnPreDrawListener {
|
|
||||||
viewPager.currentItem = Vars.selectedDay
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
|
||||||
override fun onPageSelected(position: Int) {
|
|
||||||
super.onPageSelected(position)
|
|
||||||
if (viewPager.isLaidOut) {
|
|
||||||
Vars.selectedDay = position
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewPager.adapter = adapter
|
|
||||||
viewPager.offscreenPageLimit = adapter.itemCount
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DayPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
|
||||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
|
||||||
|
|
||||||
private val fragmentList = mutableListOf<Fragment>()
|
|
||||||
|
|
||||||
fun addFragment(fragment: Fragment) {
|
|
||||||
fragmentList.add(fragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return fragmentList.size
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment {
|
|
||||||
return fragmentList[position]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DayFragment : Fragment() {
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.fragment_day, container, false)
|
|
||||||
|
|
||||||
val dayLayout: LinearLayout = view.findViewById(R.id.layoutDayMain)
|
|
||||||
createDayView(Vars.dayList[Vars.dayCounter], dayLayout, resources)
|
|
||||||
Vars.dayCounter += 1
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun highlightCurrent(
|
|
||||||
subj: Subject,
|
|
||||||
day: Day,
|
|
||||||
subjectDrawable: GradientDrawable,
|
|
||||||
subjectStroke: Int,
|
|
||||||
i: Int
|
|
||||||
) {
|
|
||||||
handler.postDelayed(object : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
subjectDrawable.setStroke(0, 0)
|
|
||||||
|
|
||||||
val now = LocalTime.now()
|
|
||||||
val nowD = LocalDate.now().dayOfMonth
|
|
||||||
val nowH = now.hour
|
|
||||||
val nowM = now.minute
|
|
||||||
val nowT = LocalTime.of(nowH, nowM)
|
|
||||||
|
|
||||||
lateinit var subjST: LocalTime
|
|
||||||
lateinit var subjET: LocalTime
|
|
||||||
val subjD = day.date.split(".")[0].toInt()
|
|
||||||
|
|
||||||
if ("T" !in subj.start && "T" !in subj.end) {
|
|
||||||
val subjSH = subj.start.split(":")[0].toInt()
|
|
||||||
val subjSM = subj.start.split(":")[1].toInt()
|
|
||||||
|
|
||||||
val subjEH = subj.end.split(":")[0].toInt()
|
|
||||||
val subjEM = subj.end.split(":")[1].toInt()
|
|
||||||
|
|
||||||
subjST = LocalTime.of(subjSH, subjSM)
|
|
||||||
subjET = LocalTime.of(subjEH, subjEM)
|
|
||||||
} else {
|
|
||||||
val subjSH = subj.start
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[0]
|
|
||||||
.toInt()
|
|
||||||
val subjSM = subj.start
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[1]
|
|
||||||
.toInt()
|
|
||||||
|
|
||||||
val subjEH = subj.end
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[0]
|
|
||||||
.toInt()
|
|
||||||
val subjEM = subj.end
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[1]
|
|
||||||
.toInt()
|
|
||||||
|
|
||||||
subjST = LocalTime.of(subjSH, subjSM)
|
|
||||||
subjET = LocalTime.of(subjEH, subjEM)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
nowT in subjST..subjET &&
|
|
||||||
nowD == subjD
|
|
||||||
) {
|
|
||||||
if (i < day.subjects.size - 1 && !day.subjects[i + 1].free && !subj.free) {
|
|
||||||
subjectDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectStroke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else if (i < day.subjects.size - 1 && day.subjects[i + 1].free && nowT != subjET) {
|
|
||||||
subjectDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectStroke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else if (i < day.subjects.size - 1 && subj.free && !day.subjects[i + 1].free && nowT != subjET) {
|
|
||||||
subjectDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectStroke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else if (i == day.subjects.size - 1) {
|
|
||||||
subjectDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectStroke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
nowD == subjD &&
|
|
||||||
i > 0
|
|
||||||
) {
|
|
||||||
lateinit var prevET: LocalTime
|
|
||||||
|
|
||||||
val prev = day.subjects[i - 1]
|
|
||||||
if ("T" !in prev.start && "T" !in prev.end) {
|
|
||||||
val prevEH = prev.end
|
|
||||||
.split(":")[0]
|
|
||||||
.toInt()
|
|
||||||
val prevEM = prev.end
|
|
||||||
.split(":")[1]
|
|
||||||
.toInt()
|
|
||||||
|
|
||||||
prevET = LocalTime.of(prevEH, prevEM)
|
|
||||||
} else {
|
|
||||||
val prevEH = prev.end
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[0]
|
|
||||||
.toInt()
|
|
||||||
val prevEM = prev.end
|
|
||||||
.split("T")[1]
|
|
||||||
.split(":")[1]
|
|
||||||
.toInt()
|
|
||||||
|
|
||||||
prevET = LocalTime.of(prevEH, prevEM)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
nowT < subjST &&
|
|
||||||
nowT > prevET
|
|
||||||
) {
|
|
||||||
subjectDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectStroke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requireView().postInvalidate()
|
|
||||||
// repeat every second
|
|
||||||
handler.postDelayed(this, 1000L)
|
|
||||||
}
|
|
||||||
}, 0L)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
// Stop updating UI when the view is destroyed
|
|
||||||
handler.removeCallbacksAndMessages(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("UseCompatLoadingForDrawables")
|
|
||||||
private fun createDayView(day: Day, rootLayout: LinearLayout, resources: Resources) {
|
|
||||||
val customFont = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
|
|
||||||
val scrollView = ScrollView(requireContext())
|
|
||||||
scrollView.scrollBarStyle = R.style.Theme_Solon_Scrollbar
|
|
||||||
|
|
||||||
val dayLayout = LinearLayout(requireContext())
|
|
||||||
dayLayout.orientation = LinearLayout.VERTICAL
|
|
||||||
|
|
||||||
val nameDateTextView = TextView(requireContext())
|
|
||||||
nameDateTextView.text = String.format("%s %s", day.name, day.date)
|
|
||||||
nameDateTextView.setTypeface(customFont, Typeface.BOLD_ITALIC)
|
|
||||||
//nameDateTextView.textSize = 28f
|
|
||||||
nameDateTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
nameDateTextView.setPadding(10, 0, 10, 40)
|
|
||||||
nameDateTextView.gravity = Gravity.CENTER_HORIZONTAL
|
|
||||||
|
|
||||||
rootLayout.addView(nameDateTextView)
|
|
||||||
|
|
||||||
var prevSubj = Subject()
|
|
||||||
prevSubj.name = ""
|
|
||||||
prevSubj.place = ""
|
|
||||||
prevSubj.substitute = ""
|
|
||||||
prevSubj.teacher = ""
|
|
||||||
prevSubj.number = ""
|
|
||||||
prevSubj.start = ""
|
|
||||||
prevSubj.end = ""
|
|
||||||
prevSubj.free = false
|
|
||||||
|
|
||||||
for ((i, subj) in day.subjects.withIndex()) {
|
|
||||||
val subjectBackground = when (subj.substitute) {
|
|
||||||
"0" -> if (subj.place != "Volno") {
|
|
||||||
R.color.primary_transparent_bg
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free_transparent_bg
|
|
||||||
}
|
|
||||||
"1" -> if (subj.place != "Volno") {
|
|
||||||
R.color.cal_week_substitute_transparent_bg
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free_transparent_bg
|
|
||||||
}
|
|
||||||
"2" -> if (subj.place != "Volno") {
|
|
||||||
R.color.cal_week_event_transparent_bg
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free_transparent_bg
|
|
||||||
}
|
|
||||||
else -> R.color.primary_transparent_bg
|
|
||||||
}
|
|
||||||
|
|
||||||
val subjectStroke = when (subj.substitute) {
|
|
||||||
"0" -> if (subj.place != "Volno") {
|
|
||||||
R.color.primary
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free
|
|
||||||
}
|
|
||||||
"1" -> if (subj.place != "Volno") {
|
|
||||||
R.color.cal_week_substitute
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free
|
|
||||||
}
|
|
||||||
"2" -> if (subj.place != "Volno") {
|
|
||||||
R.color.cal_week_event
|
|
||||||
} else {
|
|
||||||
R.color.cal_week_free
|
|
||||||
}
|
|
||||||
else -> R.color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
val subjectDrawable = GradientDrawable()
|
|
||||||
subjectDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
subjectDrawable.cornerRadius =
|
|
||||||
resources.getDimension(R.dimen.corner_radius) // Specify corner radius in resources
|
|
||||||
subjectDrawable.setColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectBackground
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// launch a periodic check for highlighting the current lecture
|
|
||||||
highlightCurrent(subj, day, subjectDrawable, subjectStroke, i)
|
|
||||||
|
|
||||||
|
|
||||||
val subjectLayout = LinearLayout(requireContext())
|
|
||||||
subjectLayout.orientation = LinearLayout.HORIZONTAL
|
|
||||||
subjectLayout.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
subjectLayout.background = subjectDrawable
|
|
||||||
|
|
||||||
// height specifier
|
|
||||||
val heightSpecifier = View(requireContext())
|
|
||||||
heightSpecifier.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
0,
|
|
||||||
160
|
|
||||||
)
|
|
||||||
|
|
||||||
subjectLayout.addView(heightSpecifier)
|
|
||||||
|
|
||||||
val subjectNumberDrawable = GradientDrawable()
|
|
||||||
subjectNumberDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
subjectNumberDrawable.cornerRadius = resources.getDimension(R.dimen.corner_radius)
|
|
||||||
subjectNumberDrawable.setColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
subjectBackground
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val subjectNumberTextView = TextView(requireContext())
|
|
||||||
subjectNumberTextView.typeface = customFont
|
|
||||||
subjectNumberTextView.text = subj.number
|
|
||||||
//subjectNumberTextView.textSize = 33f
|
|
||||||
subjectNumberTextView.setPadding(20, 20, 20, 20)
|
|
||||||
subjectNumberTextView.gravity = Gravity.CENTER // Center text vertically
|
|
||||||
subjectNumberTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
subjectNumberTextView.background = subjectNumberDrawable
|
|
||||||
|
|
||||||
val frameLayout = FrameLayout(requireContext())
|
|
||||||
val layoutParams = LinearLayout.LayoutParams(
|
|
||||||
120,
|
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
)
|
|
||||||
frameLayout.foregroundGravity = Gravity.CENTER
|
|
||||||
frameLayout.layoutParams = layoutParams
|
|
||||||
|
|
||||||
frameLayout.addView(subjectNumberTextView)
|
|
||||||
|
|
||||||
if (subj.substitute != "2") {
|
|
||||||
subjectLayout.addView(frameLayout)
|
|
||||||
}
|
|
||||||
|
|
||||||
val namePlaceLL = LinearLayout(requireContext())
|
|
||||||
namePlaceLL.orientation = LinearLayout.VERTICAL
|
|
||||||
|
|
||||||
val subjectNameTextView = TextView(requireContext())
|
|
||||||
if (subj.name != "Volno") {
|
|
||||||
subjectNameTextView.text = subj.name.uppercase()
|
|
||||||
}
|
|
||||||
subjectNameTextView.setTypeface(customFont, Typeface.BOLD)
|
|
||||||
//subjectNameTextView.textSize = 29f
|
|
||||||
subjectNameTextView.setPadding(0, 0, 0, 0)
|
|
||||||
subjectNameTextView.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
subjectNameTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!subj.free) {
|
|
||||||
namePlaceLL.addView(subjectNameTextView)
|
|
||||||
}
|
|
||||||
|
|
||||||
val subjectPlaceTextView = TextView(requireContext())
|
|
||||||
subjectPlaceTextView.typeface = customFont
|
|
||||||
subjectPlaceTextView.text = subj.place
|
|
||||||
subjectPlaceTextView.setPadding(0, 0, 0, 0)
|
|
||||||
if (subj.free) {
|
|
||||||
// italic
|
|
||||||
subjectPlaceTextView.setTypeface(customFont, Typeface.ITALIC)
|
|
||||||
subjectPlaceTextView.text = "Volno "
|
|
||||||
}
|
|
||||||
//subjectPlaceTextView.textSize = 22f
|
|
||||||
subjectPlaceTextView.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
subjectPlaceTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (subj.substitute != "2") {
|
|
||||||
namePlaceLL.addView(subjectPlaceTextView)
|
|
||||||
}
|
|
||||||
|
|
||||||
namePlaceLL.setPadding(30, 15, 20, 15)
|
|
||||||
|
|
||||||
subjectLayout.addView(namePlaceLL)
|
|
||||||
|
|
||||||
if (subj.teacher == "Jindřich Svoboda") {
|
|
||||||
val img = ImageView(requireContext())
|
|
||||||
img.setImageDrawable(resources.getDrawable(R.drawable.spock))
|
|
||||||
val frameLayout2 = FrameLayout(requireContext())
|
|
||||||
val layoutParams2 = LinearLayout.LayoutParams(
|
|
||||||
100,
|
|
||||||
120,
|
|
||||||
)
|
|
||||||
frameLayout2.foregroundGravity = Gravity.CENTER
|
|
||||||
frameLayout2.layoutParams = layoutParams2
|
|
||||||
|
|
||||||
frameLayout2.addView(img)
|
|
||||||
subjectLayout.addView(frameLayout2)
|
|
||||||
}
|
|
||||||
|
|
||||||
val params = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
params.gravity = Gravity.END
|
|
||||||
|
|
||||||
val timeTeacherLayout = LinearLayout(requireContext())
|
|
||||||
timeTeacherLayout.orientation = LinearLayout.VERTICAL
|
|
||||||
timeTeacherLayout.layoutParams = params
|
|
||||||
timeTeacherLayout.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
|
|
||||||
val subjectTimeTextView = TextView(requireContext())
|
|
||||||
val subjectTimeString = subj.start + "–" + subj.end
|
|
||||||
subjectTimeTextView.typeface = customFont
|
|
||||||
subjectTimeTextView.text = subjectTimeString
|
|
||||||
//subjectTimeTextView.textSize = 20f
|
|
||||||
subjectTimeTextView.setPadding(10, 0, 20, 0)
|
|
||||||
subjectTimeTextView.gravity = Gravity.END
|
|
||||||
subjectTimeTextView.isSingleLine = true
|
|
||||||
subjectTimeTextView.textAlignment = View.TEXT_ALIGNMENT_TEXT_END
|
|
||||||
subjectTimeTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val subjectTeacherTextView = TextView(requireContext())
|
|
||||||
subjectTeacherTextView.text = subj.teacher
|
|
||||||
subjectTeacherTextView.typeface = customFont
|
|
||||||
//subjectTeacherTextView.textSize = 15f
|
|
||||||
subjectTeacherTextView.setPadding(0, 10, 20, 10)
|
|
||||||
subjectTeacherTextView.textAlignment = View.TEXT_ALIGNMENT_TEXT_END
|
|
||||||
subjectTeacherTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
timeTeacherLayout.addView(subjectTimeTextView)
|
|
||||||
if (subj.name != "Volno") {
|
|
||||||
subjectTimeTextView.setPadding(0, 10, 20, 0)
|
|
||||||
timeTeacherLayout.addView(subjectTeacherTextView)
|
|
||||||
}
|
|
||||||
timeTeacherLayout.setPadding(0, 0, 10, 0)
|
|
||||||
|
|
||||||
if (subj.substitute != "2") {
|
|
||||||
subjectLayout.addView(timeTeacherLayout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// drawables
|
|
||||||
val substituteDrawable = GradientDrawable()
|
|
||||||
substituteDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
substituteDrawable.cornerRadius = resources.getDimension(R.dimen.corner_radius)
|
|
||||||
substituteDrawable.setColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.cal_week_substitute
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val eventDrawable = GradientDrawable()
|
|
||||||
eventDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
eventDrawable.cornerRadius = resources.getDimension(R.dimen.corner_radius)
|
|
||||||
eventDrawable.setColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.cal_week_event
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Attach an OnPreDrawListener to the rootLayout's ViewTreeObserver
|
|
||||||
rootLayout.viewTreeObserver.addOnPreDrawListener(object :
|
|
||||||
ViewTreeObserver.OnPreDrawListener {
|
|
||||||
override fun onPreDraw(): Boolean {
|
|
||||||
// Remove the listener to avoid multiple callbacks
|
|
||||||
rootLayout.viewTreeObserver.removeOnPreDrawListener(this)
|
|
||||||
|
|
||||||
// Call your function or perform an action here
|
|
||||||
if (subj.free) {
|
|
||||||
subjectPlaceTextView.text = "Volno "
|
|
||||||
}
|
|
||||||
|
|
||||||
nameDateTextView.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
|
|
||||||
if (subj.substitute == "2") {
|
|
||||||
namePlaceLL.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
|
||||||
namePlaceLL.setPadding(0, 0, 0, 0)
|
|
||||||
subjectNameTextView.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
subjectLayout.width,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
subjectNameTextView.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
|
||||||
subjectNameTextView.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true to continue with the drawing, or false to cancel
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val subjectLayoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
subjectLayoutParams.setMargins(
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
|
|
||||||
0,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
subjectLayout.layoutParams = subjectLayoutParams
|
|
||||||
|
|
||||||
if (prevSubj.name != subj.name && i != 0) {
|
|
||||||
val subjectSeparator = Space(requireContext())
|
|
||||||
subjectSeparator.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height) // Specify separator height in resources
|
|
||||||
)
|
|
||||||
|
|
||||||
dayLayout.addView(subjectSeparator)
|
|
||||||
} else if (i != 0) {
|
|
||||||
val subjectSeparator = ImageView(requireContext())
|
|
||||||
subjectSeparator.setImageResource(R.drawable.squiggly_line_100_yellow_transparent_one_color_edge)
|
|
||||||
subjectSeparator.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)
|
|
||||||
)
|
|
||||||
|
|
||||||
dayLayout.addView(subjectSeparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
subjectNumberTextView.textSize = resources.getDimension(R.dimen.text_size_subject_number) / resources.displayMetrics.scaledDensity
|
|
||||||
subjectNameTextView.textSize = resources.getDimension(R.dimen.text_size_subject_name) / resources.displayMetrics.scaledDensity
|
|
||||||
if (subj.free) {
|
|
||||||
subjectPlaceTextView.textSize =
|
|
||||||
resources.getDimension(R.dimen.text_size_subject_place_free) / resources.displayMetrics.scaledDensity
|
|
||||||
} else {
|
|
||||||
subjectPlaceTextView.textSize =
|
|
||||||
resources.getDimension(R.dimen.text_size_subject_place) / resources.displayMetrics.scaledDensity
|
|
||||||
}
|
|
||||||
subjectTimeTextView.textSize = resources.getDimension(R.dimen.text_size_subject_time) / resources.displayMetrics.scaledDensity
|
|
||||||
subjectTeacherTextView.textSize = resources.getDimension(R.dimen.text_size_subject_teacher) / resources.displayMetrics.scaledDensity
|
|
||||||
|
|
||||||
dayLayout.addView(subjectLayout)
|
|
||||||
|
|
||||||
prevSubj = subj
|
|
||||||
}
|
|
||||||
|
|
||||||
val subjectSeparator = Space(requireContext())
|
|
||||||
subjectSeparator.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height) // Specify separator height in resources
|
|
||||||
)
|
|
||||||
|
|
||||||
dayLayout.addView(subjectSeparator)
|
|
||||||
|
|
||||||
val dayEndTextView = TextView(requireContext())
|
|
||||||
val endTime = day.subjects[day.subjects.size - 1].end
|
|
||||||
Vars.dayEndString = "Den končí v $endTime"
|
|
||||||
dayEndTextView.text = Vars.dayEndString
|
|
||||||
dayEndTextView.typeface = customFont
|
|
||||||
//dayEndTextView.setAutoSizeTextTypeUniformWithConfiguration(55, 85, 1, 0)
|
|
||||||
dayEndTextView.setPadding(0, 25, 0, 25)
|
|
||||||
dayEndTextView.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
|
||||||
dayEndTextView.gravity = Gravity.CENTER
|
|
||||||
dayEndTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val dayEndDrawable = GradientDrawable()
|
|
||||||
dayEndDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
dayEndDrawable.cornerRadius = resources.getDimension((R.dimen.corner_radius))
|
|
||||||
dayEndDrawable.setColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.primary_transparent_bg
|
|
||||||
)
|
|
||||||
)
|
|
||||||
dayEndDrawable.setStroke(
|
|
||||||
10,
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.primary
|
|
||||||
)
|
|
||||||
)
|
|
||||||
dayEndTextView.background = dayEndDrawable
|
|
||||||
|
|
||||||
val dayEndSeparator = Space(requireContext())
|
|
||||||
dayEndSeparator.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height) // Specify separator height in resources
|
|
||||||
)
|
|
||||||
val dayEndSeparator2 = Space(requireContext())
|
|
||||||
dayEndSeparator2.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height) // Specify separator height in resources
|
|
||||||
)
|
|
||||||
|
|
||||||
val endParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
130
|
|
||||||
)
|
|
||||||
endParams.setMargins(
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
|
|
||||||
0,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
dayEndTextView.layoutParams = endParams
|
|
||||||
|
|
||||||
dayLayout.addView(dayEndSeparator)
|
|
||||||
dayLayout.addView(dayEndTextView)
|
|
||||||
dayLayout.addView(dayEndSeparator2)
|
|
||||||
|
|
||||||
scrollView.addView(dayLayout)
|
|
||||||
|
|
||||||
rootLayout.addView(scrollView)
|
|
||||||
|
|
||||||
// fill in the rest with empty space
|
|
||||||
val sepr = Space(requireContext())
|
|
||||||
sepr.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
Vars.height - rootLayout.height
|
|
||||||
)
|
|
||||||
|
|
||||||
rootLayout.addView(sepr)
|
|
||||||
|
|
||||||
nameDateTextView.textSize = resources.getDimension(R.dimen.text_size_name_date) / resources.displayMetrics.scaledDensity
|
|
||||||
dayEndTextView.textSize = resources.getDimension(R.dimen.text_size_day_end) / resources.displayMetrics.scaledDensity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Subject {
|
|
||||||
lateinit var name: String
|
|
||||||
lateinit var place: String
|
|
||||||
lateinit var teacher: String
|
|
||||||
lateinit var substitute: String
|
|
||||||
lateinit var number: String
|
|
||||||
lateinit var start: String
|
|
||||||
lateinit var end: String
|
|
||||||
var free: Boolean = false
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun freeSubject(number: String, start: String, end: String): Subject {
|
|
||||||
val s = Subject()
|
|
||||||
|
|
||||||
s.name = "Volno"
|
|
||||||
s.place = "Volno"
|
|
||||||
s.teacher = "Volno"
|
|
||||||
s.substitute = "0"
|
|
||||||
s.number = number
|
|
||||||
s.start = start
|
|
||||||
s.end = end
|
|
||||||
s.free = true
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
fun empty(): Subject {
|
|
||||||
val s = Subject()
|
|
||||||
|
|
||||||
s.name = "err"
|
|
||||||
s.place = "error"
|
|
||||||
s.teacher = "error"
|
|
||||||
s.substitute = "0"
|
|
||||||
s.number = "0"
|
|
||||||
s.start = "00:00"
|
|
||||||
s.end = "00:00"
|
|
||||||
s.free = false
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "subject ${this.name} at ${this.place} from ${this.start} to ${this.end}; free? ${this.free}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Day {
|
|
||||||
var name: String = ""
|
|
||||||
var date: String = ""
|
|
||||||
var subjects: List<Subject> = mutableListOf()
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
|
|
||||||
class Dialogs {
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
class LanguageChange(context: Context) : AlertDialog(context) {
|
|
||||||
init {
|
|
||||||
// Initialize your dialog properties
|
|
||||||
setTitle("Změnit jazyk")
|
|
||||||
setCancelable(true)
|
|
||||||
// Inflate the layout for the dialog
|
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.radio_group_language, null)
|
|
||||||
window?.setBackgroundDrawableResource(R.drawable.alert_dialog_background)
|
|
||||||
setView(view)
|
|
||||||
|
|
||||||
// Set positive button (e.g., "OK" button)
|
|
||||||
setButton(
|
|
||||||
BUTTON_POSITIVE,
|
|
||||||
"OK"
|
|
||||||
) { _, _ ->
|
|
||||||
// functionality here
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set negative button (e.g., "Cancel" button)
|
|
||||||
setButton(
|
|
||||||
BUTTON_NEGATIVE,
|
|
||||||
"Zrušit"
|
|
||||||
) { _, _ ->
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
|
|
||||||
val okButton = getButton(BUTTON_POSITIVE)
|
|
||||||
okButton?.setTextColor(ContextCompat.getColor(context, R.color.white))
|
|
||||||
val cancelButton = getButton(BUTTON_NEGATIVE)
|
|
||||||
cancelButton?.setTextColor(ContextCompat.getColor(context, R.color.white))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.widget.Toast
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import org.json.JSONObject
|
||||||
|
import kotlin.math.cos
|
||||||
|
|
||||||
|
private var week: List<Day> = mutableListOf()
|
||||||
|
private var toastShowing: Boolean = false
|
||||||
|
private var toastShown: Boolean = false
|
||||||
|
private var toast2Shown: Boolean = false
|
||||||
|
|
||||||
|
private lateinit var coscope_: CoroutineScope
|
||||||
|
|
||||||
|
private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) {
|
||||||
|
coscope.launch {
|
||||||
|
while (true) {
|
||||||
|
if (Util.internetAvail(ctx) && !internetAvail) {
|
||||||
|
internetAvail = Util.internetAvail(ctx)
|
||||||
|
coscope.launch {
|
||||||
|
fetchNewData(ctx, coscope)
|
||||||
|
}
|
||||||
|
} else if (!internetAvail) {
|
||||||
|
internetAvail = Util.internetAvail(ctx)
|
||||||
|
toolbarText.value = "Bez připojení k internetu."
|
||||||
|
} else {
|
||||||
|
internetAvail = Util.internetAvail(ctx)
|
||||||
|
}
|
||||||
|
delay(1000) // Check for internet availability every second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchNewData(ctx: Context, coscope: CoroutineScope) {
|
||||||
|
coscope.launch {
|
||||||
|
done = false
|
||||||
|
|
||||||
|
// variables for the loading animation
|
||||||
|
val loadingArray: Array<String> = arrayOf(
|
||||||
|
"Načítání nových dat",
|
||||||
|
"Načítání nových dat.",
|
||||||
|
"Načítání nových dat..",
|
||||||
|
"Načítání nových dat..."
|
||||||
|
)
|
||||||
|
val delayTime: Long = 300 // delay in ms
|
||||||
|
|
||||||
|
// show a loading animation
|
||||||
|
while (!done && Util.internetAvail(ctx)) {
|
||||||
|
for (text in loadingArray) {
|
||||||
|
toolbarText.value = text
|
||||||
|
delay(delayTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (text in loadingArray.reversedArray().slice(1..<loadingArray.size)) {
|
||||||
|
toolbarText.value = text
|
||||||
|
delay(delayTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(delayTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the role of the student
|
||||||
|
val role = if (Parsing.userIsParent()) {
|
||||||
|
" – Rodič"
|
||||||
|
} else {
|
||||||
|
" – Student"
|
||||||
|
}
|
||||||
|
|
||||||
|
// display the full name of the user in the toolbar
|
||||||
|
toolbarText.value =
|
||||||
|
"${
|
||||||
|
JSONObject(
|
||||||
|
Util.fileToString(
|
||||||
|
userDataFilePath
|
||||||
|
)
|
||||||
|
).getString("fullName")}$role"
|
||||||
|
}
|
||||||
|
|
||||||
|
coscope.launch {
|
||||||
|
launchPhase1(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun launchPhase0(ctx: Context, coscope: CoroutineScope) {
|
||||||
|
// start a sign in activity
|
||||||
|
// gather input and put it into global state (if login is needed)
|
||||||
|
// otherwise show the splash screen and load the app
|
||||||
|
|
||||||
|
/* check if there is a saved user account
|
||||||
|
*
|
||||||
|
* if yes, use that
|
||||||
|
* otherwise show the login activity
|
||||||
|
*/
|
||||||
|
|
||||||
|
coscope_ = coscope
|
||||||
|
fileDir = ctx.filesDir
|
||||||
|
width = Util.getDisplayWidth(ctx)
|
||||||
|
height = Util.getDisplayHeight(ctx)
|
||||||
|
|
||||||
|
val accSaved: Boolean = Account.haveSaved()
|
||||||
|
|
||||||
|
if (!accSaved) {
|
||||||
|
// show the sign in screen
|
||||||
|
screenToShow.value = Screen.SignIn
|
||||||
|
} else {
|
||||||
|
// show the splash/loading screen
|
||||||
|
screenToShow.value = Screen.Splash
|
||||||
|
coscope.launch {
|
||||||
|
// launch!
|
||||||
|
launchPhase1(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun launchPhase1(ctx: Context) {
|
||||||
|
val toast: Toast = Toast.makeText(
|
||||||
|
ctx,
|
||||||
|
"Nelze načíst data, zkuste se připojit k internetu.",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
)
|
||||||
|
|
||||||
|
val toast2: Toast = Toast.makeText(
|
||||||
|
ctx,
|
||||||
|
"Připojeno k internetu.",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
|
||||||
|
// check if the file is available offline,
|
||||||
|
// if yes, load the data and don't connect to the internet
|
||||||
|
internetAvail = Util.internetAvail(ctx)
|
||||||
|
timeTableAvailOffline =
|
||||||
|
Util.fileExists(timeTableFilePath) && !Util.fileIsEmpty(timeTableFilePath)
|
||||||
|
marksAvailOffline =
|
||||||
|
Util.fileExists(marksFilePath) && !Util.fileIsEmpty(marksFilePath)
|
||||||
|
|
||||||
|
if (toastShown && internetAvail && !toast2Shown) {
|
||||||
|
toast2Shown = true
|
||||||
|
toast2.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timeTableAvailOffline || internetAvail) {
|
||||||
|
// set up the API (required for later uses of it)
|
||||||
|
Network.setupAPI()
|
||||||
|
|
||||||
|
if (internetAvail) {
|
||||||
|
// cancel a toast, if any
|
||||||
|
if (toastShowing && !toastShown) {
|
||||||
|
toast.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the JSON data
|
||||||
|
val timeTableJSON = Network.getTimeTableJSON()
|
||||||
|
|
||||||
|
// try to save them into a file for later use
|
||||||
|
timeTableAvailOffline =
|
||||||
|
Util.saveStringToFile(timeTableFilePath, timeTableJSON)
|
||||||
|
|
||||||
|
// parse the data
|
||||||
|
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
||||||
|
|
||||||
|
// fetch and parse marks
|
||||||
|
marksJSON = Network.getMarksJSON()
|
||||||
|
|
||||||
|
marksAvailOffline =
|
||||||
|
Util.saveStringToFile(marksFilePath, marksJSON)
|
||||||
|
|
||||||
|
marks = Parsing.parseMarksJSON(marksJSON)
|
||||||
|
|
||||||
|
// continue to launch phase 2
|
||||||
|
done = true
|
||||||
|
launchPhase2(ctx)
|
||||||
|
} else {
|
||||||
|
if (timeTableAvailOffline) {
|
||||||
|
// cancel a toast, if any
|
||||||
|
if (toastShowing && !toastShown) {
|
||||||
|
toast.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the offline data
|
||||||
|
val timeTableJSON = Util.fileToString(timeTableFilePath)
|
||||||
|
|
||||||
|
// parse the data
|
||||||
|
if (timeTableJSON != "") {
|
||||||
|
// cancel a toast, if any
|
||||||
|
if (toastShowing && !toastShown) {
|
||||||
|
toast.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the data
|
||||||
|
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
||||||
|
|
||||||
|
// continue launching
|
||||||
|
done = true
|
||||||
|
launchPhase2(ctx)
|
||||||
|
} else {
|
||||||
|
// make a toast or something
|
||||||
|
toast.show()
|
||||||
|
|
||||||
|
// try to reconnect to the internet
|
||||||
|
launchPhase1(ctx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// make a toast or something
|
||||||
|
if (!toastShown) {
|
||||||
|
toast.show()
|
||||||
|
toastShowing = true
|
||||||
|
toastShown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to reconnect to the internet
|
||||||
|
launchPhase1(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// load offline
|
||||||
|
|
||||||
|
// cancel a toast, if any
|
||||||
|
if (toastShowing && !toastShown) {
|
||||||
|
toast.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the offline data
|
||||||
|
val timeTableJSON = Util.fileToString(timeTableFilePath)
|
||||||
|
|
||||||
|
marksJSON = Util.fileToString(marksFilePath)
|
||||||
|
if (marksJSON == "") {
|
||||||
|
marksJSON =
|
||||||
|
"""{"message": "Zatím žádné známky, zkuste aktualizovat data."}"""
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the data
|
||||||
|
if (timeTableJSON != "") {
|
||||||
|
// cancel a toast, if any
|
||||||
|
if (toastShowing && !toastShown) {
|
||||||
|
toast.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the data
|
||||||
|
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
||||||
|
|
||||||
|
marks = Parsing.parseMarksJSON(marksJSON)
|
||||||
|
|
||||||
|
// continue launching
|
||||||
|
done = true
|
||||||
|
launchPhase2(ctx)
|
||||||
|
} else {
|
||||||
|
// make a toast or something
|
||||||
|
if (!toastShown) {
|
||||||
|
toast.show()
|
||||||
|
toastShowing = true
|
||||||
|
toastShown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to reconnect to the internet
|
||||||
|
launchPhase1(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchPhase2(ctx: Context) {
|
||||||
|
days = week
|
||||||
|
for ((i, day) in week.withIndex()) {
|
||||||
|
dayMap[i] = day
|
||||||
|
dayList.add(day)
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded = true
|
||||||
|
|
||||||
|
coscope_.launch {
|
||||||
|
setOnInternetAvailListener(ctx, coscope_)
|
||||||
|
}
|
||||||
|
|
||||||
|
val role = if (Parsing.userIsParent()) {
|
||||||
|
" – Rodič"
|
||||||
|
} else {
|
||||||
|
" – Student"
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarText.value = "${
|
||||||
|
JSONObject(
|
||||||
|
Util.fileToString(
|
||||||
|
userDataFilePath
|
||||||
|
)
|
||||||
|
).getString("fullName")}$role"
|
||||||
|
|
||||||
|
// set the main content view
|
||||||
|
screenToShow.value = Screen.Main
|
||||||
|
}
|
||||||
@@ -1,338 +1,82 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.util.Log
|
||||||
import android.widget.Button
|
import androidx.activity.ComponentActivity
|
||||||
import android.widget.EditText
|
import androidx.activity.compose.setContent
|
||||||
import android.widget.Toast
|
import androidx.compose.foundation.background
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import kotlinx.coroutines.delay
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import kotlinx.coroutines.launch
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import com.odweta.solon.ui.theme.SolonTheme
|
||||||
|
import kotlin.math.sign
|
||||||
|
|
||||||
interface MainActivityListener {
|
class MainActivity : ComponentActivity() {
|
||||||
fun onSignIn(view: View, wantDelete: Boolean, dialog: Dialog?)
|
|
||||||
|
|
||||||
fun launchPhase1()
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), MainActivityListener {
|
|
||||||
private var week: List<Day> = mutableListOf()
|
|
||||||
private var toastShowing: Boolean = false
|
|
||||||
private var toastShown: Boolean = false
|
|
||||||
private var toast2Shown: Boolean = false
|
|
||||||
|
|
||||||
// @section COMPANION
|
|
||||||
companion object {
|
|
||||||
private var intfc: MainActivityListener? = null
|
|
||||||
|
|
||||||
fun setListener(context: Context) {
|
|
||||||
if (context is MainActivityListener) {
|
|
||||||
intfc = context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun callOnSignIn(view: View, wantDelete: Boolean, dialog: Dialog?) {
|
|
||||||
intfc?.onSignIn(view, wantDelete, dialog)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun callLaunchPhase1() {
|
|
||||||
intfc?.launchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// @section LISTENERS
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
// set variables
|
makeStatusBarBlack(window)
|
||||||
Vars.fileDir = applicationContext.filesDir
|
|
||||||
Vars.width = Util.getDisplayWidth(this)
|
|
||||||
Vars.height = Util.getDisplayHeight(this)
|
|
||||||
|
|
||||||
// start the app (coroutine because splashscreen)
|
setContent {
|
||||||
lifecycleScope.launch {
|
if (!loaded) {
|
||||||
launch()
|
launchPhase0(LocalContext.current, rememberCoroutineScope())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @section SIGN_IN
|
|
||||||
override fun onSignIn(view: View, wantDelete: Boolean, dialog: Dialog?) {
|
|
||||||
val acc = Account(
|
|
||||||
view.findViewById<EditText>(R.id.usernameField).text.toString(),
|
|
||||||
view.findViewById<EditText>(R.id.passwordField).text.toString(),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
|
|
||||||
var checked = false
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val btn = view.findViewById<Button>(R.id.signInButton)
|
|
||||||
|
|
||||||
while (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování")
|
|
||||||
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování.")
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování..")
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování...")
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování..")
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování.")
|
|
||||||
}
|
|
||||||
if (!checked) {
|
|
||||||
delay(300)
|
|
||||||
btn.text = String.format("%s", "Přihlašování")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
btn.text = String.format("%s", "Přihlásit se")
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val valid = Account.isValid(acc)
|
|
||||||
|
|
||||||
checked = true
|
|
||||||
|
|
||||||
if (valid) {
|
|
||||||
Account.save(acc)
|
|
||||||
if (!wantDelete) {
|
|
||||||
dialog?.dismiss()
|
|
||||||
}
|
|
||||||
launch()
|
|
||||||
} else {
|
|
||||||
if (wantDelete) {
|
|
||||||
Util.deleteFile(Vars.accountDataFilePath)
|
|
||||||
}
|
|
||||||
Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
"Neplatné přihlašovací údaje nebo nejste připojeni k internetu, zkuste to znovu.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// @section LAUNCH
|
|
||||||
private fun launch() {
|
|
||||||
setContentView(R.layout.activity_container)
|
|
||||||
|
|
||||||
/* check if there is a saved user account
|
|
||||||
* if yes, use that
|
|
||||||
* otherwise show the login activity
|
|
||||||
*/
|
|
||||||
|
|
||||||
val accSaved: Boolean = Account.haveSaved()
|
|
||||||
|
|
||||||
if (!accSaved) {
|
|
||||||
// show the sign in screen
|
|
||||||
showSignInScreen()
|
|
||||||
} else {
|
|
||||||
// show the splash/loading screen
|
|
||||||
showSplashScreen()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
// launch!
|
|
||||||
launchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun launchPhase1() {
|
|
||||||
val toast: Toast = Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
"Nelze načíst data, zkuste se připojit k internetu.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
)
|
|
||||||
|
|
||||||
val toast2: Toast = Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
"Připojeno k internetu.",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
// check if the file is available offline,
|
|
||||||
// if yes, load the data and don't connect to the internet
|
|
||||||
Vars.internetAvail = Util.internetAvail(applicationContext)
|
|
||||||
Vars.timeTableAvailOffline =
|
|
||||||
Util.fileExists(Vars.timeTableFilePath) && !Util.fileIsEmpty(Vars.timeTableFilePath)
|
|
||||||
Vars.marksAvailOffline =
|
|
||||||
Util.fileExists(Vars.marksFilePath) && !Util.fileIsEmpty(Vars.marksFilePath)
|
|
||||||
|
|
||||||
if (toastShown && Vars.internetAvail && !toast2Shown) {
|
|
||||||
toast2Shown = true
|
|
||||||
toast2.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Vars.timeTableAvailOffline || Vars.internetAvail) {
|
when (signedInAndReadyToLaunch.value) {
|
||||||
// set up the API (required for later uses of it)
|
true -> launchPhase0(LocalContext.current, rememberCoroutineScope())
|
||||||
Network.setupAPI()
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
if (Vars.internetAvail) {
|
SolonTheme {
|
||||||
// cancel a toast, if any
|
when (screenToShow.value) {
|
||||||
if (toastShowing && !toastShown) {
|
Screen.Main -> MainScreen()
|
||||||
toast.cancel()
|
Screen.Splash -> SplashScreen()
|
||||||
}
|
Screen.SignIn -> SignInScreen()
|
||||||
|
|
||||||
// get the JSON data
|
|
||||||
val timeTableJSON = Network.getTimeTableJSON()
|
|
||||||
|
|
||||||
// try to save them into a file for later use
|
|
||||||
Vars.timeTableAvailOffline =
|
|
||||||
Util.saveStringToFile(Vars.timeTableFilePath, timeTableJSON)
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
|
|
||||||
// fetch and parse marks
|
|
||||||
Vars.marksJSON = Network.getMarksJSON()
|
|
||||||
|
|
||||||
Vars.marksAvailOffline =
|
|
||||||
Util.saveStringToFile(Vars.marksFilePath, Vars.marksJSON)
|
|
||||||
|
|
||||||
Vars.marks = Parsing.parseMarksJSON(Vars.marksJSON)
|
|
||||||
|
|
||||||
// continue to launch phase 2
|
|
||||||
launchPhase2()
|
|
||||||
} else {
|
|
||||||
if (Vars.timeTableAvailOffline) {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the offline data
|
|
||||||
val timeTableJSON = Util.fileToString(Vars.timeTableFilePath)
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
if (timeTableJSON != "") {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
|
|
||||||
// continue launching
|
|
||||||
launchPhase2()
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
toast.show()
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
if (!toastShown) {
|
|
||||||
toast.show()
|
|
||||||
toastShowing = true
|
|
||||||
toastShown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// load offline
|
|
||||||
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the offline data
|
|
||||||
val timeTableJSON = Util.fileToString(Vars.timeTableFilePath)
|
|
||||||
|
|
||||||
Vars.marksJSON = Util.fileToString(Vars.marksFilePath)
|
|
||||||
if (Vars.marksJSON == "") {
|
|
||||||
Vars.marksJSON =
|
|
||||||
"""{"message": "Zatím žádné známky, zkuste aktualizovat data."}"""
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
if (timeTableJSON != "") {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
|
|
||||||
Vars.marks = Parsing.parseMarksJSON(Vars.marksJSON)
|
|
||||||
|
|
||||||
// continue launching
|
|
||||||
launchPhase2()
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
if (!toastShown) {
|
|
||||||
toast.show()
|
|
||||||
toastShowing = true
|
|
||||||
toastShown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun launchPhase2() {
|
@Composable
|
||||||
Vars.days = week
|
fun MainScreen(modifier: Modifier = Modifier) {
|
||||||
for ((i, day) in week.withIndex()) {
|
Column(
|
||||||
Vars.dayMap[i] = day
|
modifier = Modifier
|
||||||
Vars.dayList.add(day)
|
.fillMaxSize()
|
||||||
}
|
.background(Color.Black)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = barModifier,
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
ToolbarScreen()
|
||||||
|
}
|
||||||
|
|
||||||
// set the main content view
|
Box(
|
||||||
ft(R.id.app_root, MainFragment(), R.anim.slide_up, R.anim.slide_down)
|
modifier = Modifier
|
||||||
}
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
when (isShowing.value) {
|
||||||
|
IsShowing.Timetable -> TimetableScreen()
|
||||||
|
IsShowing.Marks -> MarksScreen()
|
||||||
|
IsShowing.Menu -> MenuScreen()
|
||||||
|
IsShowing.About -> AboutScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @section SPLASH_SCREENS
|
Box(
|
||||||
private fun showSignInScreen() {
|
modifier = barModifier,
|
||||||
ft(R.id.app_root, SignInMainFragment(), R.anim.slide_up, R.anim.slide_down)
|
contentAlignment = Alignment.Center
|
||||||
}
|
) {
|
||||||
|
NavbarScreen()
|
||||||
private fun showSplashScreen() {
|
}
|
||||||
ft(R.id.app_root, SplashFragment(), R.anim.slide_up, R.anim.slide_down)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fragment Transition
|
|
||||||
private fun ft(container: Int, frag: Fragment, animIn: Int, animOut: Int) {
|
|
||||||
if (Util.isAppInForeground(applicationContext, packageName)) {
|
|
||||||
val ft = supportFragmentManager.beginTransaction()
|
|
||||||
|
|
||||||
ft.setCustomAnimations(
|
|
||||||
animIn,
|
|
||||||
animOut
|
|
||||||
)
|
|
||||||
|
|
||||||
ft.replace(container, frag)
|
|
||||||
|
|
||||||
ft.commit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
class MainFragment : Fragment() {
|
|
||||||
private var done: Boolean = false
|
|
||||||
private var role: String = " - Student"
|
|
||||||
private lateinit var navbar: BottomNavigationView
|
|
||||||
private lateinit var toolbar: TextView
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
return inflater.inflate(R.layout.activity_main, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
MainActivity.setListener(requireContext())
|
|
||||||
setup(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setup(view: View) {
|
|
||||||
toolbar = view.findViewById(R.id.toolbar)
|
|
||||||
//toolbar.setAutoSizeTextTypeUniformWithConfiguration(60, 65, 1, 0)
|
|
||||||
toolbar.textSize = resources.getDimension(R.dimen.text_size_toolbar) / resources.displayMetrics.scaledDensity
|
|
||||||
toolbar.ellipsize = null
|
|
||||||
toolbar.setHorizontallyScrolling(false)
|
|
||||||
|
|
||||||
role = if (Parsing.userIsParent()) {
|
|
||||||
" – Rodič"
|
|
||||||
} else {
|
|
||||||
" – Student"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
Util.fileToString(Vars.userDataFilePath) != "" &&
|
|
||||||
JSONObject(Util.fileToString(Vars.userDataFilePath)).has("fullName")
|
|
||||||
) {
|
|
||||||
toolbar.text =
|
|
||||||
String.format(
|
|
||||||
"%s",
|
|
||||||
"${JSONObject(
|
|
||||||
Util.fileToString(
|
|
||||||
Vars.userDataFilePath
|
|
||||||
)
|
|
||||||
).getString("fullName")}$role"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
toolbar.text = String.format("%s", "Přihlašte se, prosím.")
|
|
||||||
}
|
|
||||||
|
|
||||||
navbar = view.findViewById(R.id.bottomNav)
|
|
||||||
|
|
||||||
var frag = requireFragmentManager().findFragmentById(R.id.fragmentContainer)
|
|
||||||
|
|
||||||
if (!Vars.resetNav) {
|
|
||||||
if (frag == null || frag is CalWeekFragment) {
|
|
||||||
frag = CalWeekFragment()
|
|
||||||
navbar.selectedItemId = R.id.nav_timetable
|
|
||||||
}
|
|
||||||
if (frag is MarksFragment) {
|
|
||||||
frag = MarksFragment()
|
|
||||||
navbar.selectedItemId = R.id.nav_marks
|
|
||||||
}
|
|
||||||
if (frag is MenuFragment) {
|
|
||||||
frag = MenuFragment()
|
|
||||||
navbar.selectedItemId = R.id.nav_menu
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
frag = CalWeekFragment()
|
|
||||||
navbar.selectedItemId = R.id.nav_timetable
|
|
||||||
Vars.resetNav = false
|
|
||||||
}
|
|
||||||
|
|
||||||
requireFragmentManager().beginTransaction()
|
|
||||||
.replace(R.id.fragmentContainer, frag)
|
|
||||||
.commit()
|
|
||||||
|
|
||||||
navbar.setOnItemSelectedListener {
|
|
||||||
val ft = requireFragmentManager().beginTransaction()
|
|
||||||
|
|
||||||
when (it.itemId) {
|
|
||||||
R.id.nav_timetable -> {
|
|
||||||
ft.setCustomAnimations(
|
|
||||||
R.anim.slide_up,
|
|
||||||
R.anim.slide_down,
|
|
||||||
)
|
|
||||||
ft.replace(R.id.fragmentContainer, CalWeekFragment())
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_marks -> {
|
|
||||||
ft.setCustomAnimations(
|
|
||||||
R.anim.slide_up,
|
|
||||||
R.anim.slide_down,
|
|
||||||
)
|
|
||||||
ft.replace(R.id.fragmentContainer, MarksFragment())
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_menu -> {
|
|
||||||
ft.setCustomAnimations(
|
|
||||||
R.anim.slide_up,
|
|
||||||
R.anim.slide_down,
|
|
||||||
)
|
|
||||||
ft.replace(R.id.fragmentContainer, MenuFragment())
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> return@setOnItemSelectedListener false
|
|
||||||
}
|
|
||||||
|
|
||||||
ft.commit()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnInternetAvailListener()
|
|
||||||
done = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setOnInternetAvailListener() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
while (true) {
|
|
||||||
if (Util.internetAvail(requireContext()) && !Vars.internetAvail) {
|
|
||||||
Vars.internetAvail = Util.internetAvail(requireContext())
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
fetchNewData()
|
|
||||||
}
|
|
||||||
} else if (!Vars.internetAvail) {
|
|
||||||
Vars.internetAvail = Util.internetAvail(requireContext())
|
|
||||||
toolbar.text = String.format("%s", "Bez připojení k internetu.")
|
|
||||||
} else {
|
|
||||||
Vars.internetAvail = Util.internetAvail(requireContext())
|
|
||||||
}
|
|
||||||
delay(1000) // Check for internet availability every second
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchNewData() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
done = false
|
|
||||||
|
|
||||||
// variables for the loading animation
|
|
||||||
val loadingArray: Array<String> = arrayOf(
|
|
||||||
"Načítání nových dat",
|
|
||||||
"Načítání nových dat.",
|
|
||||||
"Načítání nových dat..",
|
|
||||||
"Načítání nových dat..."
|
|
||||||
)
|
|
||||||
val delayTime: Long = 300 // delay in ms
|
|
||||||
|
|
||||||
// show a loading animation
|
|
||||||
while (!done && Util.internetAvail(requireContext())) {
|
|
||||||
for (text in loadingArray) {
|
|
||||||
toolbar.text = text
|
|
||||||
delay(delayTime)
|
|
||||||
}
|
|
||||||
for (text in loadingArray.reversedArray().slice(1..<loadingArray.size)) {
|
|
||||||
toolbar.text = text
|
|
||||||
delay(delayTime)
|
|
||||||
}
|
|
||||||
delay(delayTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the role of the student
|
|
||||||
role = if (Parsing.userIsParent()) {
|
|
||||||
" – Rodič"
|
|
||||||
} else {
|
|
||||||
" – Student"
|
|
||||||
}
|
|
||||||
|
|
||||||
// display the full name of the user in the toolbar
|
|
||||||
toolbar.text =
|
|
||||||
String.format(
|
|
||||||
"%s",
|
|
||||||
"${JSONObject(
|
|
||||||
Util.fileToString(
|
|
||||||
Vars.userDataFilePath
|
|
||||||
)
|
|
||||||
).getString("fullName")}$role"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
MainActivity.callLaunchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ScrollView
|
|
||||||
import android.widget.Space
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
|
|
||||||
// details for the marks of one subject
|
|
||||||
class MarkDetailsFragment : DialogFragment() {
|
|
||||||
private lateinit var gestureDetector: GestureDetector
|
|
||||||
private var initialTouchY: Float = 0f
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
private lateinit var rootLayout: LinearLayout
|
|
||||||
private lateinit var scrollView: ScrollView
|
|
||||||
private var isScrollingToDismissEnabled = false
|
|
||||||
private var isScrollingToTop = true
|
|
||||||
private lateinit var dialog: Dialog
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
// set the style so the dialog is fullscreen
|
|
||||||
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
// inflate the layout
|
|
||||||
val view = inflater.inflate(R.layout.activity_mark_details, container, false)
|
|
||||||
|
|
||||||
// get the root layout
|
|
||||||
rootLayout = view.findViewById(R.id.one_mark_root)
|
|
||||||
|
|
||||||
// set up gestures
|
|
||||||
gestures(view)
|
|
||||||
|
|
||||||
// construct the view
|
|
||||||
construct()
|
|
||||||
|
|
||||||
// return the view
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private fun gestures(view: View) {
|
|
||||||
// Set up GestureDetector
|
|
||||||
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
|
|
||||||
|
|
||||||
scrollView = view.findViewById(R.id.mark_detail_scroll)
|
|
||||||
scrollView.scrollY = 0
|
|
||||||
|
|
||||||
scrollView.setOnTouchListener { _, event ->
|
|
||||||
scrollView.performClick()
|
|
||||||
gestureDetector.onTouchEvent(event)
|
|
||||||
// Return false to allow normal scrolling
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollView.viewTreeObserver.addOnScrollChangedListener {
|
|
||||||
isScrollingToTop = !scrollView.canScrollVertically(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach the gesture detector to the root layout
|
|
||||||
view.setOnTouchListener { _, event ->
|
|
||||||
view.performClick()
|
|
||||||
handleTouchEvent(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
|
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
|
||||||
// Reset the flag when the user touches the screen
|
|
||||||
isScrollingToDismissEnabled = false
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFling(
|
|
||||||
e1: MotionEvent?,
|
|
||||||
e2: MotionEvent,
|
|
||||||
velocityX: Float,
|
|
||||||
velocityY: Float
|
|
||||||
): Boolean {
|
|
||||||
val diffY = e1?.let { e2.y - it.y } ?: 0f
|
|
||||||
if (diffY > swipeThreshold) {
|
|
||||||
// Swiped down
|
|
||||||
if (isScrollingToTop) {
|
|
||||||
// Enable dismissing only if scrolled to top
|
|
||||||
isScrollingToDismissEnabled = true
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
|
||||||
private fun construct() {
|
|
||||||
/* show all the marks in separate views with yet another onclick listener for even more
|
|
||||||
* details
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TV == TextView
|
|
||||||
// LL == LinearLayout
|
|
||||||
// DR == Drawable
|
|
||||||
// FL == FrameLayout
|
|
||||||
// SV == ScrollView
|
|
||||||
|
|
||||||
val marks = MarksFragment.currentMarks
|
|
||||||
val idx = MarksFragment.idx
|
|
||||||
|
|
||||||
if (idx !in 0 until marks.size) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val font = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
val gradeTV = TextView(requireContext())
|
|
||||||
gradeTV.text = marks[idx].grade
|
|
||||||
gradeTV.textSize = 60f
|
|
||||||
gradeTV.setTypeface(font, Typeface.BOLD)
|
|
||||||
gradeTV.background = Util.getAvgDrawable(requireContext(), marks[idx!!].grade)
|
|
||||||
gradeTV.gravity = Gravity.CENTER
|
|
||||||
val pr = LinearLayout.LayoutParams(
|
|
||||||
Util.getDisplayWidth(requireContext())/3,
|
|
||||||
Util.getDisplayWidth(requireContext())/3
|
|
||||||
)
|
|
||||||
pr.setMargins(0, 100, 0, 100)
|
|
||||||
gradeTV.layoutParams = pr
|
|
||||||
gradeTV.setPadding(20, 20, 20, 20)
|
|
||||||
gradeTV.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
|
|
||||||
|
|
||||||
|
|
||||||
val subjectDesc = makeTV("Předmět:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/2)
|
|
||||||
val subjectTV = makeTV(Vars.subjectNameMap[marks[idx!!].subject] ?: marks[idx!!].subject, Typeface.NORMAL, 22f)
|
|
||||||
|
|
||||||
val descDesc = makeTV("Popis:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
|
|
||||||
val descTV = makeTV(marks[idx!!].theme, Typeface.NORMAL, 22f)
|
|
||||||
|
|
||||||
val dateDesc = makeTV("Datum:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
|
|
||||||
val dateTV = makeTV(getDate(marks[idx!!].date), Typeface.NORMAL, 22f)
|
|
||||||
val weightDesc = makeTV("Váha:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
|
|
||||||
val weightTV = makeTV((marks[idx!!].weight).replace(".", ","), Typeface.NORMAL, 22f)
|
|
||||||
|
|
||||||
val subjectRow = makeRow(subjectDesc, subjectTV)
|
|
||||||
val descRow = makeRow(descDesc, descTV)
|
|
||||||
val dateRow = makeRow(dateDesc, dateTV)
|
|
||||||
val weightRow = makeRow(weightDesc, weightTV)
|
|
||||||
|
|
||||||
rootLayout.addView(gradeTV)
|
|
||||||
rootLayout.addView(subjectRow)
|
|
||||||
rootLayout.addView(descRow)
|
|
||||||
rootLayout.addView(dateRow)
|
|
||||||
rootLayout.addView(weightRow)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDate(dateIn: String): String {
|
|
||||||
val dateList = dateIn
|
|
||||||
.split("T")[0]
|
|
||||||
.split("-")
|
|
||||||
|
|
||||||
return "${dateList[2]}. ${dateList[1]}. ${dateList[0]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeTV(text: String, typeface: Int, width: Int): TextView {
|
|
||||||
val font = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
val tv = TextView(requireContext())
|
|
||||||
tv.text = text
|
|
||||||
tv.textSize = 25f
|
|
||||||
tv.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
|
||||||
tv.setPadding(40, 20, 20, 20)
|
|
||||||
tv.setTypeface(font, typeface)
|
|
||||||
tv.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val p = LinearLayout.LayoutParams(
|
|
||||||
width,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
tv.layoutParams = p
|
|
||||||
tv.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
tv.ellipsize = null
|
|
||||||
tv.setHorizontallyScrolling(false)
|
|
||||||
|
|
||||||
return tv
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeTV(text: String, typeface: Int, size: Float): TextView {
|
|
||||||
val font = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
val tv = TextView(requireContext())
|
|
||||||
tv.text = text
|
|
||||||
tv.textSize = size
|
|
||||||
tv.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
|
||||||
tv.setPadding(40, 20, 20, 20)
|
|
||||||
val p = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
p.gravity = Gravity.CENTER
|
|
||||||
tv.layoutParams = p
|
|
||||||
tv.setTypeface(font, typeface)
|
|
||||||
tv.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
tv.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
tv.ellipsize = null
|
|
||||||
tv.setHorizontallyScrolling(false)
|
|
||||||
|
|
||||||
return tv
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeRow(left: TextView, right: TextView): LinearLayout {
|
|
||||||
val ll = LinearLayout(requireContext())
|
|
||||||
ll.orientation = LinearLayout.VERTICAL
|
|
||||||
ll.gravity = Gravity.CENTER_HORIZONTAL
|
|
||||||
val p = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
p.setMargins(20, 0, 20, 0)
|
|
||||||
ll.layoutParams = p
|
|
||||||
ll.background = ResourcesCompat.getDrawable(resources, R.drawable.pastel_yellow_no_stroke, null)!!
|
|
||||||
ll.addView(left)
|
|
||||||
ll.addView(right)
|
|
||||||
|
|
||||||
val otherLL = LinearLayout(requireContext())
|
|
||||||
otherLL.orientation = LinearLayout.VERTICAL
|
|
||||||
otherLL.addView(createSpace())
|
|
||||||
|
|
||||||
val root = LinearLayout(requireContext())
|
|
||||||
root.orientation = LinearLayout.VERTICAL
|
|
||||||
root.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
Util.getDisplayWidth(requireContext())-40,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
|
|
||||||
root.addView(ll)
|
|
||||||
root.addView(otherLL)
|
|
||||||
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSpace(): Space {
|
|
||||||
val space = Space(requireContext())
|
|
||||||
space.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)
|
|
||||||
)
|
|
||||||
|
|
||||||
return space
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
dialog = super.onCreateDialog(savedInstanceState)
|
|
||||||
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
|
|
||||||
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
|
||||||
dialog.setCancelable(true)
|
|
||||||
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SameReturnValue")
|
|
||||||
private fun handleTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
initialTouchY = event.rawY
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
val deltaY = event.rawY - initialTouchY
|
|
||||||
dialog.window?.attributes?.y = deltaY.toInt()
|
|
||||||
dialog.window?.attributes?.windowAnimations = 0
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
// Check if the dialog has been dragged beyond a threshold and dismiss if necessary
|
|
||||||
if (deltaY > 200) {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
initialTouchY = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.odweta.solon.ui.theme.PastelGreen
|
||||||
|
import com.odweta.solon.ui.theme.PastelGreenTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelOrange
|
||||||
|
import com.odweta.solon.ui.theme.PastelOrangeTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelRed
|
||||||
|
import com.odweta.solon.ui.theme.PastelRedTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
||||||
|
|
||||||
|
enum class MarksShow {
|
||||||
|
All,
|
||||||
|
Subject,
|
||||||
|
Detail
|
||||||
|
}
|
||||||
|
|
||||||
|
var marksShow: MutableState<MarksShow> = mutableStateOf(MarksShow.All)
|
||||||
|
private var subjectToShow: String = ""
|
||||||
|
private var markToShow: Mark = Mark()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MarksScreen() {
|
||||||
|
when (marksShow.value) {
|
||||||
|
MarksShow.All -> MarksAll()
|
||||||
|
MarksShow.Subject -> MarksSubject()
|
||||||
|
MarksShow.Detail -> MarksDetail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAvgColor(avg: String, isBorder: Boolean = false): Color {
|
||||||
|
val aux = avg.replace(",", ".").toFloat().toInt()
|
||||||
|
return if (aux in 1..<2) {
|
||||||
|
if (isBorder) {
|
||||||
|
PastelGreen
|
||||||
|
} else {
|
||||||
|
PastelGreenTransparent
|
||||||
|
}
|
||||||
|
} else if (aux in 2..<3) {
|
||||||
|
if (isBorder) {
|
||||||
|
PastelYellow
|
||||||
|
} else {
|
||||||
|
PastelYellowTransparent
|
||||||
|
}
|
||||||
|
} else if (aux in 3..<4) {
|
||||||
|
if (isBorder) {
|
||||||
|
PastelOrange
|
||||||
|
} else {
|
||||||
|
PastelOrangeTransparent
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isBorder) {
|
||||||
|
PastelRed
|
||||||
|
} else {
|
||||||
|
PastelRedTransparent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MarksAll() {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
) {
|
||||||
|
for ((subject, markList) in marks) {
|
||||||
|
var marksString = ""
|
||||||
|
for (m in 0 until markList.size-1) {
|
||||||
|
if (markList[m].grade in "0123456789") {
|
||||||
|
marksString += markList[m].grade + ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
marksString += markList[markList.size-1].grade
|
||||||
|
|
||||||
|
if (marks.keys.indexOf(subject) > 0) {
|
||||||
|
Box(modifier = Modifier.height(10.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(100.dp)
|
||||||
|
.background(
|
||||||
|
color = getAvgColor(Util.avg(markList)), // decide on the color (transparent)
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.clickable {
|
||||||
|
marksShow.value = MarksShow.Subject
|
||||||
|
subjectToShow = subject
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(210.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(
|
||||||
|
color = getAvgColor(Util.avg(markList)), // decide on the color (not transparent)
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = subject.uppercase(),
|
||||||
|
fontSize = 35.sp,
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(10.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(Color.Black)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = Util.avg(markList).replace(".", ","),
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxHeight(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = marksString,
|
||||||
|
fontSize = 22.sp,
|
||||||
|
color = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MarksSubject() {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
marksShow.value = MarksShow.All
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(100.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBackIosNew, // Replace with your desired icon
|
||||||
|
contentDescription = "Back icon",
|
||||||
|
modifier = Modifier.size(35.dp) // Adjust size if needed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Box(modifier = Modifier.height(100.dp)) {
|
||||||
|
Text(
|
||||||
|
text = subjectNameMap[subjectToShow]!!,
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.background(PastelYellowTransparent)
|
||||||
|
.padding(vertical = 20.dp)
|
||||||
|
) // subject
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = Util.avg(marks[subjectToShow]!!).replace(".", ","),
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = getAvgColor(
|
||||||
|
Util.avg(marks[subjectToShow]!!),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.background(
|
||||||
|
getAvgColor(
|
||||||
|
Util.avg(marks[subjectToShow]!!)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.padding(vertical = 32.5.dp)
|
||||||
|
) // average
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Column(modifier = Modifier.verticalScroll(scrollState)) {
|
||||||
|
for ((i, mark) in marks[subjectToShow]!!.withIndex()) {
|
||||||
|
if (i > 0) {
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.background(
|
||||||
|
color = getAvgColor(mark.grade),
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.padding(vertical = 20.dp)
|
||||||
|
.clickable {
|
||||||
|
markToShow = mark
|
||||||
|
marksShow.value = MarksShow.Detail
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = mark.grade,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp
|
||||||
|
) // grade
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.weight(1f),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = mark.theme,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 23.sp
|
||||||
|
) // theme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MarksDetail() {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
marksShow.value = MarksShow.Subject
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(100.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBackIosNew, // Replace with your desired icon
|
||||||
|
contentDescription = "Back icon",
|
||||||
|
modifier = Modifier.size(35.dp) // Adjust size if needed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Row {
|
||||||
|
Box(modifier = Modifier.height(100.dp)) {
|
||||||
|
Text(
|
||||||
|
text = markToShow.theme,
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.background(PastelYellowTransparent)
|
||||||
|
.padding(vertical = 20.dp)
|
||||||
|
) // description
|
||||||
|
}
|
||||||
|
} // description
|
||||||
|
|
||||||
|
Row {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = markToShow.grade,
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 35.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(100.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = getAvgColor(
|
||||||
|
Util.avg(mutableListOf(markToShow)),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.background(
|
||||||
|
getAvgColor(
|
||||||
|
Util.avg(mutableListOf(markToShow))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.padding(vertical = 32.5.dp)
|
||||||
|
) // average
|
||||||
|
}
|
||||||
|
} // grade
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.background(
|
||||||
|
color = PastelYellowTransparent,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.padding(vertical = 20.dp, horizontal = 10.dp)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(150.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Váha:",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.weight(1f),
|
||||||
|
contentAlignment = Alignment.CenterEnd
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = markToShow.weight.replace(".", ","),
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} // weight
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.background(
|
||||||
|
color = PastelYellowTransparent,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.padding(vertical = 20.dp, horizontal = 10.dp)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(150.dp)
|
||||||
|
.align(Alignment.CenterVertically),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Datum:",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.weight(1f),
|
||||||
|
contentAlignment = Alignment.CenterEnd
|
||||||
|
) {
|
||||||
|
val rawDate: String = markToShow.date.split("T")[0]
|
||||||
|
val year = rawDate.split("-")[0]
|
||||||
|
val month = rawDate.split("-")[1]
|
||||||
|
val day = rawDate.split("-")[2]
|
||||||
|
val date = "$day. $month. $year"
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = date,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} // date
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,313 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.Space
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.core.view.contains
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
class MarksFragment : Fragment() {
|
|
||||||
private lateinit var inflater: LayoutInflater
|
|
||||||
private var container: ViewGroup? = null
|
|
||||||
private var savedInstanceState: Bundle? = null
|
|
||||||
private val marksOneSubjectDialog: DialogFragment = MarksOneSubjectFragment()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
this.inflater = inflater
|
|
||||||
this.container = container
|
|
||||||
this.savedInstanceState = savedInstanceState
|
|
||||||
|
|
||||||
if (Vars.marksAvailOffline && !Util.fileIsEmpty(Vars.marksFilePath)) {
|
|
||||||
Vars.marksJSON = Util.fileToString(Vars.marksFilePath)
|
|
||||||
Vars.marks = Parsing.parseMarksJSON(Vars.marksJSON)
|
|
||||||
} else {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
Vars.marksJSON = Network.getMarksJSON()
|
|
||||||
Vars.marksAvailOffline = Util.saveStringToFile(Vars.marksFilePath, Vars.marksJSON)
|
|
||||||
Vars.marks = Parsing.parseMarksJSON(Vars.marksJSON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
Vars.marks.keys.contains("-") &&
|
|
||||||
Vars.marks.keys.size == 1
|
|
||||||
) {
|
|
||||||
val view = inflater.inflate(R.layout.activity_no_marks, container, false)
|
|
||||||
|
|
||||||
val root = view.findViewById<LinearLayout>(R.id.no_mark_container)
|
|
||||||
|
|
||||||
for (subject in Vars.marks.keys) {
|
|
||||||
val viewToAdd = Vars.marks[subject]?.let { createMarkView(it) } as View
|
|
||||||
if (!root.contains(viewToAdd)) {
|
|
||||||
root.addView(viewToAdd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
} else {
|
|
||||||
val view = inflater.inflate(R.layout.activity_marks, container, false)
|
|
||||||
|
|
||||||
val root = view.findViewById<LinearLayout>(R.id.root)
|
|
||||||
|
|
||||||
for ((i, subject) in Vars.marks.keys.withIndex()) {
|
|
||||||
root.addView(Vars.marks[subject]?.let { createMarkView(it) })
|
|
||||||
if (i < Vars.marks.keys.size-1) {
|
|
||||||
root.addView(createSpace())
|
|
||||||
} else {
|
|
||||||
root.addView(createSpace2())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSpace(): Space {
|
|
||||||
val space = Space(requireContext())
|
|
||||||
space.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)
|
|
||||||
)
|
|
||||||
|
|
||||||
return space
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSpace2(): Space {
|
|
||||||
val space = Space(requireContext())
|
|
||||||
space.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/2
|
|
||||||
)
|
|
||||||
|
|
||||||
return space
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeDR(marks: MutableList<Mark>): GradientDrawable {
|
|
||||||
val avgDrawable = GradientDrawable()
|
|
||||||
avgDrawable.shape = GradientDrawable.RECTANGLE
|
|
||||||
avgDrawable.cornerRadius = resources.getDimension(R.dimen.corner_radius)
|
|
||||||
avgDrawable.setColor(
|
|
||||||
if (!marks.contains(Mark().none())) {
|
|
||||||
Util.getAvgBgColor(requireContext(), Util.avg(marks))
|
|
||||||
} else {
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.pastel_orange_transparent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return avgDrawable
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createMarkView(marks: MutableList<Mark>): LinearLayout {
|
|
||||||
val markRoot = LinearLayout(requireContext())
|
|
||||||
markRoot.orientation = LinearLayout.HORIZONTAL
|
|
||||||
val params = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
params.setMargins(20, 0, 20, 0)
|
|
||||||
params.height = 160
|
|
||||||
markRoot.layoutParams = params
|
|
||||||
markRoot.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
|
|
||||||
val customFont = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
|
|
||||||
val rootDR = makeDR(marks)
|
|
||||||
val flDR = makeDR(marks)
|
|
||||||
val separatorDR = makeDR(marks)
|
|
||||||
|
|
||||||
markRoot.background = rootDR
|
|
||||||
|
|
||||||
if (marks[0].subject == "Zatím žádné známky.") {
|
|
||||||
markRoot.gravity = Gravity.CENTER
|
|
||||||
val tv = TextView(requireContext())
|
|
||||||
tv.text = String.format("%s", "Zatím žádné známky.")
|
|
||||||
tv.textSize = 30f
|
|
||||||
tv.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
tv.gravity = Gravity.CENTER
|
|
||||||
tv.setTypeface(customFont, Typeface.BOLD)
|
|
||||||
|
|
||||||
markRoot.addView(tv)
|
|
||||||
|
|
||||||
return markRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val subjectTextView = TextView(requireContext())
|
|
||||||
subjectTextView.text = marks[0].subject.uppercase()
|
|
||||||
//subjectTextView.setPadding(20, 20, 20, 20)
|
|
||||||
//subjectTextView.setAutoSizeTextTypeUniformWithConfiguration(65, 85, 1, 0)
|
|
||||||
subjectTextView.textSize = resources.getDimension(R.dimen.text_size_subject_number) / resources.displayMetrics.scaledDensity
|
|
||||||
subjectTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
subjectTextView.gravity = Gravity.CENTER
|
|
||||||
subjectTextView.setTypeface(customFont, Typeface.BOLD)
|
|
||||||
|
|
||||||
val fl2 = FrameLayout(requireContext())
|
|
||||||
fl2.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
160,
|
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
)
|
|
||||||
fl2.addView(subjectTextView)
|
|
||||||
|
|
||||||
|
|
||||||
val avgTextView = TextView(requireContext())
|
|
||||||
avgTextView.typeface = customFont
|
|
||||||
|
|
||||||
val text = if (!marks.contains(Mark().none())) {
|
|
||||||
Util.avg(marks).replace(".", ",")
|
|
||||||
} else {
|
|
||||||
"-"
|
|
||||||
}
|
|
||||||
avgTextView.text = text
|
|
||||||
//avgTextView.setPadding(20, 20, 20, 20)
|
|
||||||
//avgTextView.setAutoSizeTextTypeUniformWithConfiguration(65, 85, 1, 0)
|
|
||||||
avgTextView.textSize = resources.getDimension(R.dimen.text_size_subject_number) / resources.displayMetrics.scaledDensity
|
|
||||||
avgTextView.gravity = Gravity.CENTER // Center text vertically
|
|
||||||
avgTextView.setTypeface(customFont, Typeface.NORMAL)
|
|
||||||
avgTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val frameLayout = FrameLayout(requireContext())
|
|
||||||
frameLayout.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
160,
|
|
||||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
)
|
|
||||||
frameLayout.addView(avgTextView)
|
|
||||||
|
|
||||||
val flLL = LinearLayout(requireContext())
|
|
||||||
flLL.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
flLL.orientation = LinearLayout.HORIZONTAL
|
|
||||||
flLL.background = flDR
|
|
||||||
|
|
||||||
val separator = LinearLayout(requireContext())
|
|
||||||
separator.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
separator.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
separator.background = separatorDR
|
|
||||||
|
|
||||||
val space = TextView(requireContext())
|
|
||||||
space.setPadding(0, 40, 0, 40)
|
|
||||||
space.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
space.text = " "
|
|
||||||
space.textSize = 22f
|
|
||||||
space.background = ResourcesCompat.getDrawable(resources, R.color.black, null)
|
|
||||||
space.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
separator.addView(space)
|
|
||||||
|
|
||||||
flLL.addView(fl2)
|
|
||||||
flLL.addView(separator)
|
|
||||||
flLL.addView(frameLayout)
|
|
||||||
|
|
||||||
markRoot.addView(flLL)
|
|
||||||
|
|
||||||
val marksTextView = TextView(requireContext())
|
|
||||||
var markString = ""
|
|
||||||
for ((i, mark) in marks.withIndex()) {
|
|
||||||
markString += mark.grade
|
|
||||||
if (i < marks.size - 1) {
|
|
||||||
markString += ", "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
marksTextView.text = markString
|
|
||||||
marksTextView.setPadding(20, 20, 20, 20)
|
|
||||||
//marksTextView.setAutoSizeTextTypeUniformWithConfiguration(45, 65, 1, 0)
|
|
||||||
marksTextView.textSize = resources.getDimension(R.dimen.text_size_mark) / resources.displayMetrics.scaledDensity
|
|
||||||
marksTextView.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
marksTextView.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT
|
|
||||||
)
|
|
||||||
marksTextView.gravity = Gravity.CENTER
|
|
||||||
marksTextView.ellipsize = null
|
|
||||||
marksTextView.setHorizontallyScrolling(false)
|
|
||||||
|
|
||||||
markRoot.addView(marksTextView)
|
|
||||||
|
|
||||||
// add an onclick event listener for mark details
|
|
||||||
markRoot.setOnClickListener {
|
|
||||||
/* mark details will be a DialogFragment
|
|
||||||
* and will slide up from the bottom
|
|
||||||
*/
|
|
||||||
currentMarks = marks
|
|
||||||
if (marksOneSubjectDialog.dialog?.isShowing == false || marksOneSubjectDialog.dialog == null) {
|
|
||||||
marksOneSubjectDialog.show(requireFragmentManager(), "fragment_mark_details")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return markRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var currentMarks: MutableList<Mark> = mutableListOf()
|
|
||||||
var idx: Int = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Mark {
|
|
||||||
lateinit var grade: String // markText
|
|
||||||
lateinit var weight: String // weight
|
|
||||||
lateinit var subject: String // subjectId -> parse that
|
|
||||||
lateinit var date: String // markDate
|
|
||||||
lateinit var theme: String // theme
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "mark: ${this.grade} * ${this.weight}, subject: ${this.subject}, description: ${this.theme}, date: ${this.date}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun none(): Mark {
|
|
||||||
val mark = Mark()
|
|
||||||
mark.subject = "Zatím žádné známky."
|
|
||||||
mark.grade = "0"
|
|
||||||
mark.weight = "0"
|
|
||||||
mark.date = "-"
|
|
||||||
mark.theme = "-"
|
|
||||||
|
|
||||||
return mark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ScrollView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
|
|
||||||
|
|
||||||
// details for the marks of one subject
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
class MarksOneSubjectFragment : DialogFragment() {
|
|
||||||
private var initialTouchY: Float = 0f
|
|
||||||
private lateinit var rootLayout: LinearLayout
|
|
||||||
private lateinit var scrollView: ScrollView
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
private var isScrollingToDismissEnabled = false
|
|
||||||
private var isScrollingToTop = true
|
|
||||||
private lateinit var gestureDetector: GestureDetector
|
|
||||||
private lateinit var dialog: Dialog
|
|
||||||
private val markDetailsDialog: DialogFragment = MarkDetailsFragment()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
// set the style so the dialog is fullscreen
|
|
||||||
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
// inflate the layout
|
|
||||||
val view = inflater.inflate(R.layout.activity_marks_one_subject, container, false)
|
|
||||||
|
|
||||||
// get the root layout
|
|
||||||
rootLayout = view.findViewById(R.id.mark_details_root)
|
|
||||||
|
|
||||||
// set up gestures
|
|
||||||
gestures(view)
|
|
||||||
|
|
||||||
// construct the view
|
|
||||||
construct()
|
|
||||||
|
|
||||||
// return the view
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private fun gestures(view: View) {
|
|
||||||
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
|
|
||||||
|
|
||||||
scrollView = view.findViewById(R.id.mark_details_scroll)
|
|
||||||
scrollView.scrollY = 0
|
|
||||||
|
|
||||||
scrollView.setOnTouchListener { _, event ->
|
|
||||||
scrollView.performClick()
|
|
||||||
gestureDetector.onTouchEvent(event)
|
|
||||||
// Return false to allow normal scrolling
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollView.viewTreeObserver.addOnScrollChangedListener {
|
|
||||||
isScrollingToTop = !scrollView.canScrollVertically(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach the gesture detector to the root layout
|
|
||||||
view.setOnTouchListener { _, event ->
|
|
||||||
view.performClick()
|
|
||||||
handleTouchEvent(event, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
|
||||||
private fun construct() {
|
|
||||||
/* show all the marks in separate views with yet another onclick listener for even more
|
|
||||||
* details
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TV == TextView
|
|
||||||
// LL == LinearLayout
|
|
||||||
// DR == Drawable
|
|
||||||
// FL == FrameLayout
|
|
||||||
// SV == ScrollView
|
|
||||||
|
|
||||||
val marks = MarksFragment.currentMarks
|
|
||||||
|
|
||||||
val customFont = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
val bgColor = if (!marks.contains(Mark().none())) {
|
|
||||||
Util.getAvgBgColor(requireContext(), Util.avg(marks))
|
|
||||||
} else {
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.pastel_orange
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val bgStroke = if (!marks.contains(Mark().none())) {
|
|
||||||
Util.getAvgStrokeColor(requireContext(), Util.avg(marks))
|
|
||||||
} else {
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.pastel_orange
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val bg = GradientDrawable()
|
|
||||||
bg.setColor(bgColor)
|
|
||||||
bg.setStroke(10, bgStroke)
|
|
||||||
bg.cornerRadius = resources.getDimension(R.dimen.corner_radius)
|
|
||||||
|
|
||||||
// the view for all the details of one subject (not the marks)
|
|
||||||
// e.g. average in that subject, hours per week maybe idk
|
|
||||||
val subjectDetailsLL = LinearLayout(requireContext())
|
|
||||||
subjectDetailsLL.orientation = LinearLayout.HORIZONTAL
|
|
||||||
subjectDetailsLL.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
subjectDetailsLL.setPadding(40, 40, 40, 40)
|
|
||||||
subjectDetailsLL.background = bg
|
|
||||||
val params = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
params.setMargins(0, 40, 0, 40)
|
|
||||||
subjectDetailsLL.layoutParams = params
|
|
||||||
|
|
||||||
/* items:
|
|
||||||
* - whole name of the subject
|
|
||||||
* - avg
|
|
||||||
* - maybe more idk
|
|
||||||
*/
|
|
||||||
val wholeNameTV = TextView(requireContext())
|
|
||||||
// index by the abbrev and get the name (if null just fallback to the abbrev)
|
|
||||||
wholeNameTV.text = Vars.subjectNameMap[marks[0].subject] ?: marks[0].subject
|
|
||||||
wholeNameTV.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
wholeNameTV.setTypeface(customFont, Typeface.BOLD)
|
|
||||||
wholeNameTV.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
wholeNameTV.ellipsize = null
|
|
||||||
wholeNameTV.setHorizontallyScrolling(false)
|
|
||||||
subjectDetailsLL.addView(wholeNameTV)
|
|
||||||
|
|
||||||
val avgTV = TextView(requireContext())
|
|
||||||
avgTV.text = "${Util.avg(marks).replace(".", ",")} " // plus a space for the italic stuff
|
|
||||||
avgTV.textSize = 28f
|
|
||||||
avgTV.setTypeface(customFont, Typeface.BOLD_ITALIC)
|
|
||||||
avgTV.textAlignment = View.TEXT_ALIGNMENT_TEXT_END
|
|
||||||
avgTV.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
if (wholeNameTV.text.length < 15) {
|
|
||||||
wholeNameTV.textSize = 28f
|
|
||||||
} else {
|
|
||||||
wholeNameTV.textSize = 24f
|
|
||||||
}
|
|
||||||
avgTV.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
subjectDetailsLL.addView(avgTV)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// a vertical LL for individual marks
|
|
||||||
val marksLL = LinearLayout(requireContext())
|
|
||||||
marksLL.orientation = LinearLayout.VERTICAL
|
|
||||||
|
|
||||||
for ((i, mark) in marks.withIndex()) {
|
|
||||||
val markLL = LinearLayout(requireContext())
|
|
||||||
markLL.orientation = LinearLayout.HORIZONTAL
|
|
||||||
markLL.gravity = Gravity.CENTER_VERTICAL
|
|
||||||
|
|
||||||
val markTV = TextView(requireContext())
|
|
||||||
markTV.text = mark.grade
|
|
||||||
markTV.setPadding(30, 30, 30, 30)
|
|
||||||
markTV.textSize = 30f
|
|
||||||
markTV.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val descTV = TextView(requireContext())
|
|
||||||
descTV.text = mark.theme
|
|
||||||
descTV.setPadding(20, 20, 20, 20)
|
|
||||||
descTV.textSize = 20f
|
|
||||||
descTV.setTextColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
R.color.white
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
descTV.setOnTouchListener { _, event ->
|
|
||||||
handleTouchEvent(event, i)
|
|
||||||
}
|
|
||||||
descTV.setTypeface(customFont, Typeface.NORMAL)
|
|
||||||
descTV.ellipsize = null
|
|
||||||
descTV.setHorizontallyScrolling(false)
|
|
||||||
|
|
||||||
markLL.setOnTouchListener { _, event ->
|
|
||||||
handleTouchEvent(event, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
markLL.addView(markTV)
|
|
||||||
markLL.addView(descTV)
|
|
||||||
|
|
||||||
marksLL.addView(markLL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add everything to the root layout
|
|
||||||
rootLayout.addView(subjectDetailsLL)
|
|
||||||
rootLayout.addView(marksLL)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
dialog = super.onCreateDialog(savedInstanceState)
|
|
||||||
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
|
|
||||||
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
|
||||||
dialog.setCancelable(true)
|
|
||||||
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SameReturnValue", "DEPRECATION")
|
|
||||||
private fun handleTouchEvent(event: MotionEvent, i: Int? = null): Boolean {
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
initialTouchY = event.rawY
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
val deltaY = event.rawY - initialTouchY
|
|
||||||
dialog.window?.attributes?.y = deltaY.toInt()
|
|
||||||
dialog.window?.attributes?.windowAnimations = 0
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
// Check if the dialog has been dragged beyond a threshold and dismiss if necessary
|
|
||||||
if (deltaY > 200) {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
if (dialog.isShowing) {
|
|
||||||
i?.let {
|
|
||||||
MarksFragment.idx = it
|
|
||||||
if (
|
|
||||||
it in 0 until MarksFragment.currentMarks.size &&
|
|
||||||
markDetailsDialog.dialog?.isShowing == false ||
|
|
||||||
markDetailsDialog.dialog == null
|
|
||||||
) {
|
|
||||||
markDetailsDialog.show(
|
|
||||||
requireFragmentManager(),
|
|
||||||
"fragment_mark_details"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initialTouchY = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
|
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
|
||||||
// Reset the flag when the user touches the screen
|
|
||||||
isScrollingToDismissEnabled = false
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFling(
|
|
||||||
e1: MotionEvent?,
|
|
||||||
e2: MotionEvent,
|
|
||||||
velocityX: Float,
|
|
||||||
velocityY: Float
|
|
||||||
): Boolean {
|
|
||||||
val diffY = e1?.let { e2.y - it.y } ?: 0f
|
|
||||||
if (diffY > swipeThreshold) {
|
|
||||||
// Swiped down
|
|
||||||
if (isScrollingToTop) {
|
|
||||||
// Enable dismissing only if scrolled to top
|
|
||||||
isScrollingToDismissEnabled = true
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MenuScreen(modifier: Modifier = Modifier) {
|
||||||
|
var showDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
// Button to trigger the dialog
|
||||||
|
Button(
|
||||||
|
onClick = { showDialog = true },
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(230.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Odhlásit se",
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(100.dp))
|
||||||
|
|
||||||
|
// Dialog implementation
|
||||||
|
if (showDialog) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showDialog = false }, // Close the dialog on dismiss
|
||||||
|
title = {
|
||||||
|
Text(text = "Odhlásit se", color = Color.White)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text("Opravdu se chcete odhlásit? Tato akce zavře aplikaci.", color = Color.White)
|
||||||
|
},
|
||||||
|
containerColor = Color.Black,
|
||||||
|
modifier = Modifier
|
||||||
|
.border(width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
||||||
|
roundedCornerDimen)), // Yellow border
|
||||||
|
confirmButton = {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
showDialog = false
|
||||||
|
Util.deleteFile(userDataFilePath)
|
||||||
|
Util.deleteFile(timeTableFilePath)
|
||||||
|
Util.deleteFile(marksFilePath)
|
||||||
|
Util.deleteFile(accountDataFilePath)
|
||||||
|
exitProcess(0)
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Black, // Black background for the button
|
||||||
|
contentColor = Color.White // Yellow text for the button
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
||||||
|
roundedCornerDimen)) // Yellow border
|
||||||
|
) {
|
||||||
|
Text("Ano")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
showDialog = false
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Black, // Black background for the button
|
||||||
|
contentColor = Color.White,
|
||||||
|
// Yellow text for the button
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
||||||
|
roundedCornerDimen)) // Yellow border
|
||||||
|
) {
|
||||||
|
Text("Ne")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) // TODO: THEME DIALOG
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(onClick = {
|
||||||
|
screenToShow.value = Screen.SignIn
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(230.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Změnit přihlášení",
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(100.dp))
|
||||||
|
|
||||||
|
Button(onClick = {
|
||||||
|
isShowing.value = IsShowing.About
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(230.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "O aplikaci",
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Button
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
class MenuFragment : Fragment() {
|
|
||||||
private lateinit var signOutDialog: Dialog
|
|
||||||
private lateinit var signInDialog: DialogFragment
|
|
||||||
private lateinit var aboutDialog: DialogFragment
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_menu, container, false)
|
|
||||||
|
|
||||||
addCallbacks(view)
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
private fun addCallbacks(view: View) {
|
|
||||||
//val settings = view.findViewById<Button>(R.id.menu_button_settings)
|
|
||||||
val signOut = view.findViewById<Button>(R.id.menu_button_sign_out)
|
|
||||||
val signIn = view.findViewById<Button>(R.id.menu_button_sign_in)
|
|
||||||
val about = view.findViewById<Button>(R.id.menu_button_about)
|
|
||||||
|
|
||||||
//settings.setOnClickListener {
|
|
||||||
// SettingsFragment().show(requireFragmentManager(), "fragment_settings")
|
|
||||||
//}
|
|
||||||
|
|
||||||
// init dialogs
|
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(context, R.style.Theme_Solon_AlertDialog)
|
|
||||||
builder
|
|
||||||
.setView(LayoutInflater.from(context).inflate(R.layout.alert_dialog_sign_out, null))
|
|
||||||
.setPositiveButton("Ano") { dialog, _ ->
|
|
||||||
Util.deleteFile(Vars.userDataFilePath)
|
|
||||||
Util.deleteFile(Vars.timeTableFilePath)
|
|
||||||
Util.deleteFile(Vars.marksFilePath)
|
|
||||||
Util.deleteFile(Vars.accountDataFilePath)
|
|
||||||
dialog.dismiss()
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
.setNegativeButton("Ne") { dialog, _ ->
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
signOutDialog = builder.create()
|
|
||||||
|
|
||||||
signInDialog = SignInFragment()
|
|
||||||
|
|
||||||
aboutDialog = AboutFragment()
|
|
||||||
|
|
||||||
signOut.setOnClickListener {
|
|
||||||
if (!signOutDialog.isShowing) {
|
|
||||||
signOutDialog.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signIn.setOnClickListener {
|
|
||||||
if (signInDialog.dialog?.isShowing == false || signInDialog.dialog == null) {
|
|
||||||
signInDialog.show(requireFragmentManager(), "fragment_sign_in")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
about.setOnClickListener {
|
|
||||||
if (aboutDialog.dialog?.isShowing == false || aboutDialog.dialog == null) {
|
|
||||||
aboutDialog.show(requireFragmentManager(), "fragment_about")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.Schedule
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
|
||||||
|
private var timetableColor: MutableState<Color> = mutableStateOf(PastelYellow)
|
||||||
|
private var marksColor: MutableState<Color> = mutableStateOf(Color.White)
|
||||||
|
private var menuColor: MutableState<Color> = mutableStateOf(Color.White)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NavbarScreen(modifier: Modifier = Modifier) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isShowing.value = IsShowing.Timetable
|
||||||
|
timetableColor.value = PastelYellow
|
||||||
|
marksColor.value = Color.White
|
||||||
|
menuColor.value = Color.White
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = timetableColor.value,
|
||||||
|
containerColor = Color.Black
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Schedule,
|
||||||
|
contentDescription = "Schedule Icon",
|
||||||
|
modifier = Modifier.size(25.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(30.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isShowing.value = IsShowing.Marks
|
||||||
|
timetableColor.value = Color.White
|
||||||
|
marksColor.value = PastelYellow
|
||||||
|
menuColor.value = Color.White
|
||||||
|
marksShow.value = MarksShow.All
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = marksColor.value,
|
||||||
|
containerColor = Color.Black
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.marks),
|
||||||
|
contentDescription = "Marks Icon",
|
||||||
|
modifier = Modifier.size(25.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(30.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isShowing.value = IsShowing.Menu
|
||||||
|
timetableColor.value = Color.White
|
||||||
|
marksColor.value = Color.White
|
||||||
|
menuColor.value = PastelYellow
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = menuColor.value,
|
||||||
|
containerColor = Color.Black
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Menu,
|
||||||
|
contentDescription = "Menu Icon",
|
||||||
|
modifier = Modifier.size(25.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
@@ -13,13 +14,13 @@ class Network {
|
|||||||
suspend fun getToken(): String {
|
suspend fun getToken(): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(Vars.tokenUrl)
|
.url(tokenUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.post(
|
.post(
|
||||||
FormBody.Builder()
|
FormBody.Builder()
|
||||||
.add("grant_type", "password")
|
.add("grant_type", "password")
|
||||||
.add("username", Vars.username)
|
.add("username", username)
|
||||||
.add("password", Vars.password)
|
.add("password", password)
|
||||||
.add("client_id", "test_client")
|
.add("client_id", "test_client")
|
||||||
.add("scope", "openid offline_access profile sol_api")
|
.add("scope", "openid offline_access profile sol_api")
|
||||||
.build()
|
.build()
|
||||||
@@ -27,10 +28,11 @@ class Network {
|
|||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val resp = Vars.client.newCall(request).execute()
|
val resp = client.newCall(request).execute()
|
||||||
val respString = resp.body?.string()
|
val respString = resp.body?.string()
|
||||||
val respJson = respString?.let { JSONObject(it) }
|
respString.toString()
|
||||||
respJson.toString()
|
//val respJson = respString?.let { JSONObject(it) }
|
||||||
|
//respJson.toString()
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
"""{"error": "json"}"""
|
"""{"error": "json"}"""
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -42,32 +44,37 @@ class Network {
|
|||||||
|
|
||||||
suspend fun setupAPI() {
|
suspend fun setupAPI() {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val token = getToken()
|
token = "NETWORK_UNREACHABLE"
|
||||||
Vars.token = "NETWORK_UNREACHABLE"
|
token = getToken()
|
||||||
if (!JSONObject(token).has("error")) {
|
if (""""error": """ !in token) {
|
||||||
Vars.token = JSONObject(token).get("access_token").toString()
|
token = JSONObject(token).get("access_token").toString()
|
||||||
}
|
}
|
||||||
if (Vars.token == "NETWORK_UNREACHABLE") {
|
if (token == "NETWORK_UNREACHABLE" || """"error": """ in token) {
|
||||||
Vars.userData = ""
|
userData = ""
|
||||||
Vars.studentId = ""
|
studentId = ""
|
||||||
Vars.internetAvail = false
|
internetAvail = false
|
||||||
return@withContext
|
return@withContext
|
||||||
}
|
}
|
||||||
Vars.internetAvail = true
|
internetAvail = true
|
||||||
Vars.userData = getUserDataJSON()
|
userData = getUserDataJSON()
|
||||||
Util.saveStringToFile(Vars.userDataFilePath, Vars.userData)
|
Util.saveStringToFile(userDataFilePath, userData)
|
||||||
Vars.studentId = getStudentId()
|
if (!Parsing.userIsParent()) {
|
||||||
//Vars.syid = getSYID()
|
studentClass = JSONObject(
|
||||||
Vars.syid = ""
|
Util.fileToString(userDataFilePath)
|
||||||
|
).getJSONObject("class").get("name").toString()
|
||||||
|
}
|
||||||
|
studentId = getStudentId()
|
||||||
|
//syid = getSYID()
|
||||||
|
syid = ""
|
||||||
|
|
||||||
Vars.marksUrl = "${Vars.apiBaseUrl}/v1/students/${Vars.studentId}/marks/list"//?SemesterId=${Vars.syid}"
|
marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list"//?SemesterId=${syid}"
|
||||||
|
|
||||||
Vars.isAPISetUp = true
|
isAPISetUp = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private fun getSYID(): String {
|
/*private fun getSYID(): String {
|
||||||
val f = Util.fileToString(Vars.userDataFilePath)
|
val f = Util.fileToString(userDataFilePath)
|
||||||
|
|
||||||
lateinit var syidRoot: String
|
lateinit var syidRoot: String
|
||||||
lateinit var toAdd: String
|
lateinit var toAdd: String
|
||||||
@@ -99,9 +106,9 @@ class Network {
|
|||||||
|
|
||||||
private fun getStudentId(): String {
|
private fun getStudentId(): String {
|
||||||
return if (!Parsing.userIsParent()) {
|
return if (!Parsing.userIsParent()) {
|
||||||
JSONObject(Vars.userData).getString("personID")
|
JSONObject(userData).getString("personID")
|
||||||
} else {
|
} else {
|
||||||
JSONObject(Vars.userData).getJSONArray("children")
|
JSONObject(userData).getJSONArray("children")
|
||||||
.getJSONObject(0)
|
.getJSONObject(0)
|
||||||
.getString("id")
|
.getString("id")
|
||||||
}
|
}
|
||||||
@@ -110,14 +117,14 @@ class Network {
|
|||||||
private suspend fun getUserDataJSON(): String {
|
private suspend fun getUserDataJSON(): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(Vars.userDataUrl)
|
.url(userDataUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer ${Vars.token}") // using Bearer auth token
|
.header("Authorization", "Bearer $token") // using Bearer auth token
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val resp = Vars.client.newCall(request).execute()
|
val resp = client.newCall(request).execute()
|
||||||
val respString = resp.body?.string().toString()
|
val respString = resp.body?.string().toString()
|
||||||
respString
|
respString
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
@@ -129,20 +136,20 @@ class Network {
|
|||||||
suspend fun getTimeTableJSON(): String {
|
suspend fun getTimeTableJSON(): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val userIsParent = Parsing.userIsParent()
|
val userIsParent = Parsing.userIsParent()
|
||||||
var url = Vars.timeTableUrl
|
var url = timeTableUrl
|
||||||
if (userIsParent) {
|
if (userIsParent) {
|
||||||
url += "?studentId=${Vars.studentId}"
|
url += "?studentId=$studentId"
|
||||||
}
|
}
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer ${Vars.token}")
|
.header("Authorization", "Bearer $token")
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val resp = Vars.client.newCall(request).execute()
|
val resp = client.newCall(request).execute()
|
||||||
resp.body?.string().toString()
|
resp.body?.string().toString()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
"""{"error": "network"}"""
|
"""{"error": "network"}"""
|
||||||
@@ -153,14 +160,14 @@ class Network {
|
|||||||
suspend fun getMarksJSON(): String {
|
suspend fun getMarksJSON(): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(Vars.marksUrl)
|
.url(marksUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer ${Vars.token}")
|
.header("Authorization", "Bearer $token")
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val resp = Vars.client.newCall(request).execute()
|
val resp = client.newCall(request).execute()
|
||||||
resp.body?.string().toString()
|
resp.body?.string().toString()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
"""{"error": "network"}"""
|
"""{"error": "network"}"""
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class Parsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun userIsParent(): Boolean {
|
fun userIsParent(): Boolean {
|
||||||
return if (Vars.userData != "")
|
return if (userData != "")
|
||||||
JSONObject(Vars.userData).getString("userType") == "parent"
|
JSONObject(userData).getString("userType") == "parent"
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +208,15 @@ class Parsing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val sCopy = subjects.toList()
|
||||||
|
for (s in 0 until sCopy.size) {
|
||||||
|
if ("-" in subjects[s].number) {
|
||||||
|
subjects[s].number = "1"
|
||||||
|
subjects[s].start = "08:00"
|
||||||
|
subjects[s].end = "08:45"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -320,7 +329,7 @@ class Parsing {
|
|||||||
subjectMap[subj.getString("id")] = subj.getString("abbrev")
|
subjectMap[subj.getString("id")] = subj.getString("abbrev")
|
||||||
|
|
||||||
// map names to abbrevs
|
// map names to abbrevs
|
||||||
Vars.subjectNameMap[subj.getString("abbrev")] = subj.getString("name")
|
subjectNameMap[subj.getString("abbrev")] = subj.getString("name")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0..<marksJSONArray.length()) {
|
for (i in 0..<marksJSONArray.length()) {
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.GestureDetector.SimpleOnGestureListener
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.ScrollView
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class SettingsFragment : DialogFragment() {
|
|
||||||
private lateinit var scrollView: ScrollView
|
|
||||||
private var isScrollingToDismissEnabled = false
|
|
||||||
private var isScrollingToTop = true
|
|
||||||
private val gestureDetector: GestureDetector by lazy {
|
|
||||||
GestureDetector(requireContext(), SwipeGestureListener())
|
|
||||||
}
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SwipeGestureListener : SimpleOnGestureListener() {
|
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
|
||||||
// Reset the flag when the user touches the screen
|
|
||||||
isScrollingToDismissEnabled = false
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFling(
|
|
||||||
e1: MotionEvent?,
|
|
||||||
e2: MotionEvent,
|
|
||||||
velocityX: Float,
|
|
||||||
velocityY: Float
|
|
||||||
): Boolean {
|
|
||||||
val diffY = e1?.let { e2.y - it.y } ?: 0f
|
|
||||||
if (diffY > swipeThreshold) {
|
|
||||||
// Swiped down
|
|
||||||
if (isScrollingToTop) {
|
|
||||||
// Enable dismissing only if scrolled to top
|
|
||||||
isScrollingToDismissEnabled = true
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_settings, container, false)
|
|
||||||
|
|
||||||
scrollView = view.findViewById(R.id.scrollViewSettings)
|
|
||||||
scrollView.scrollY = 0
|
|
||||||
|
|
||||||
scrollView.setOnTouchListener { _, event ->
|
|
||||||
scrollView.performClick()
|
|
||||||
gestureDetector.onTouchEvent(event)
|
|
||||||
// Return false to allow normal scrolling
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollView.viewTreeObserver.addOnScrollChangedListener {
|
|
||||||
isScrollingToTop = !scrollView.canScrollVertically(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val button: Button = view.findViewById(R.id.setting_language_button_choice) // replace with your button ID
|
|
||||||
button.setOnClickListener {
|
|
||||||
Dialogs.LanguageChange(requireContext()).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val dialog = super.onCreateDialog(savedInstanceState)
|
|
||||||
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
|
||||||
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
private var buttonText: MutableState<String> = mutableStateOf("Přihlásit se")
|
||||||
|
|
||||||
|
private fun changeButtonText(s: String) {
|
||||||
|
buttonText.value = s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: String, usernameText: String, passwordText: String) {
|
||||||
|
username = usernameText
|
||||||
|
password = passwordText
|
||||||
|
val acc = Account(username, password, 0)
|
||||||
|
var checked = false
|
||||||
|
|
||||||
|
coscope.launch {
|
||||||
|
while (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování")
|
||||||
|
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování.")
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování..")
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování...")
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování..")
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování.")
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
delay(300)
|
||||||
|
changeButtonText("Přihlašování")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changeButtonText("Přihlásit se")
|
||||||
|
}
|
||||||
|
|
||||||
|
coscope.launch {
|
||||||
|
signedInAndReadyToLaunch.value = false
|
||||||
|
val valid = Account.isValid(acc)
|
||||||
|
|
||||||
|
checked = true
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
Account.save(acc)
|
||||||
|
signedInAndReadyToLaunch.value = true
|
||||||
|
screenToShow.value = Screen.Splash
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
ctx,
|
||||||
|
"Neplatné přihlašovací údaje nebo nejste připojeni k internetu, zkuste to znovu.",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SignInScreen() {
|
||||||
|
var usernameText by remember { mutableStateOf("") }
|
||||||
|
var passwordText by remember { mutableStateOf("") }
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
val coscope = rememberCoroutineScope()
|
||||||
|
var isPasswordVisible by remember { mutableStateOf(false) } // State for visibility toggle
|
||||||
|
val visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation()
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Black)
|
||||||
|
.verticalScroll(scrollState),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.solon_just_yellow),
|
||||||
|
contentDescription = "Solon logo",
|
||||||
|
modifier = Modifier.size(230.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
value = usernameText,
|
||||||
|
onValueChange = { input -> usernameText = input },
|
||||||
|
modifier = Modifier
|
||||||
|
.border(width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
||||||
|
roundedCornerDimen))
|
||||||
|
.width(230.dp),
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedTextColor = Color.White, // White text
|
||||||
|
unfocusedTextColor = Color.White, // White text when not focused
|
||||||
|
focusedContainerColor = Color.Black, // Black background when focused
|
||||||
|
unfocusedContainerColor = Color.Black, // Black background when not focused
|
||||||
|
cursorColor = PastelYellow, // Yellow cursor
|
||||||
|
focusedIndicatorColor = Color.Black, // Yellow border when focused
|
||||||
|
unfocusedIndicatorColor = Color.Black // Yellow border when not focused
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
value = passwordText,
|
||||||
|
onValueChange = { input -> passwordText = input },
|
||||||
|
visualTransformation = visualTransformation,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(230.dp)
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(
|
||||||
|
roundedCornerDimen
|
||||||
|
)
|
||||||
|
),
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedTextColor = Color.White, // White text
|
||||||
|
unfocusedTextColor = Color.White, // White text when not focused
|
||||||
|
focusedContainerColor = Color.Black, // Black background when focused
|
||||||
|
unfocusedContainerColor = Color.Black, // Black background when not focused
|
||||||
|
cursorColor = PastelYellow, // Yellow cursor
|
||||||
|
focusedIndicatorColor = Color.Black, // Yellow border when focused
|
||||||
|
unfocusedIndicatorColor = Color.Black // Yellow border when not focused
|
||||||
|
),
|
||||||
|
trailingIcon = {
|
||||||
|
// Toggle button for showing/hiding password
|
||||||
|
IconButton(onClick = { isPasswordVisible = !isPasswordVisible }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isPasswordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff,
|
||||||
|
contentDescription = if (isPasswordVisible) "Hide password" else "Show password",
|
||||||
|
tint = Color.Gray // You can customize the icon color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
signInButtonCallback(ctx, coscope, buttonText.value, usernameText, passwordText)
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Black
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen),
|
||||||
|
color = PastelYellow
|
||||||
|
)
|
||||||
|
.width(230.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = buttonText.value,
|
||||||
|
fontSize = 23.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.InputType
|
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.Gravity
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.CompoundButton
|
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.ImageButton
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.RelativeLayout
|
|
||||||
import android.widget.ToggleButton
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
class SignInFragment : DialogFragment() {
|
|
||||||
private lateinit var gestureDetector: GestureDetector
|
|
||||||
private var initialTouchY: Float = 0f
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
private val swipeVelocityThreshold = 100
|
|
||||||
private lateinit var dialog: Dialog
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
// Set up GestureDetector
|
|
||||||
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
|
|
||||||
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_sign_in, container, false)
|
|
||||||
MainActivity.setListener(requireContext())
|
|
||||||
|
|
||||||
view.setOnTouchListener { _, event ->
|
|
||||||
view.performClick()
|
|
||||||
handleTouchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
dialog = super.onCreateDialog(savedInstanceState)
|
|
||||||
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
|
|
||||||
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
|
||||||
dialog.setCancelable(true)
|
|
||||||
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
view.findViewById<Button>(R.id.signInButton).setOnClickListener {
|
|
||||||
Vars.resetNav = true
|
|
||||||
MainActivity.callOnSignIn(view, false, dialog)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find views
|
|
||||||
val passwordEditText = view.findViewById<EditText>(R.id.passwordField)
|
|
||||||
val showPasswordToggleButton = view.findViewById<ImageButton>(R.id.showPasswordToggleButton)
|
|
||||||
showPasswordToggleButton.bringToFront()
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.hide, null)
|
|
||||||
|
|
||||||
// Set up toggle button to reveal/hide password
|
|
||||||
showPasswordToggleButton.setOnClickListener { _ ->
|
|
||||||
if (Vars.isChecked) {
|
|
||||||
// Show password
|
|
||||||
passwordEditText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.show, null)
|
|
||||||
Vars.isChecked = false
|
|
||||||
} else {
|
|
||||||
// Hide password
|
|
||||||
passwordEditText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
|
||||||
passwordEditText.typeface = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.hide, null)
|
|
||||||
Vars.isChecked = true
|
|
||||||
}
|
|
||||||
// Move cursor to the end of the text
|
|
||||||
passwordEditText.setSelection(passwordEditText.text?.length ?: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
|
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
override fun onFling(
|
|
||||||
e1: MotionEvent?,
|
|
||||||
e2: MotionEvent,
|
|
||||||
velocityX: Float,
|
|
||||||
velocityY: Float
|
|
||||||
): Boolean {
|
|
||||||
val diffY = e1?.let { e2.y.minus(it.y) } ?: 0f
|
|
||||||
if (diffY > swipeThreshold && abs(velocityY) > swipeVelocityThreshold) {
|
|
||||||
// Swiped down
|
|
||||||
dismiss()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SameReturnValue")
|
|
||||||
private fun handleTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
initialTouchY = event.rawY
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
val deltaY = event.rawY - initialTouchY
|
|
||||||
dialog.window?.attributes?.y = deltaY.toInt()
|
|
||||||
dialog.window?.attributes?.windowAnimations = 0
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
// Check if the dialog has been dragged beyond a threshold and dismiss if necessary
|
|
||||||
if (deltaY > 200) {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
initialTouchY = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.InputType
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.ImageButton
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
|
|
||||||
class SignInMainFragment : Fragment() {
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_sign_in, container, false)
|
|
||||||
MainActivity.setListener(requireContext())
|
|
||||||
|
|
||||||
view.findViewById<Button>(R.id.signInButton).setOnClickListener {
|
|
||||||
MainActivity.callOnSignIn(view, true, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find views
|
|
||||||
val passwordEditText = view.findViewById<EditText>(R.id.passwordField)
|
|
||||||
val showPasswordToggleButton = view.findViewById<ImageButton>(R.id.showPasswordToggleButton)
|
|
||||||
showPasswordToggleButton.bringToFront()
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.hide, null)
|
|
||||||
|
|
||||||
// Set up toggle button to reveal/hide password
|
|
||||||
showPasswordToggleButton.setOnClickListener { _ ->
|
|
||||||
if (Vars.isChecked) {
|
|
||||||
// Show password
|
|
||||||
passwordEditText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.show, null)
|
|
||||||
Vars.isChecked = false
|
|
||||||
} else {
|
|
||||||
// Hide password
|
|
||||||
passwordEditText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
|
||||||
passwordEditText.typeface = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
|
|
||||||
showPasswordToggleButton.background = ResourcesCompat.getDrawable(resources, R.drawable.hide, null)
|
|
||||||
Vars.isChecked = true
|
|
||||||
}
|
|
||||||
// Move cursor to the end of the text
|
|
||||||
passwordEditText.setSelection(passwordEditText.text?.length ?: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SplashScreen() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Black),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.solon_just_yellow),
|
||||||
|
contentDescription = "Solon logo",
|
||||||
|
modifier = Modifier.size(200.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.size(200.dp),
|
||||||
|
factory = { context: Context ->
|
||||||
|
ImageView(context).apply {
|
||||||
|
// Set a placeholder if needed
|
||||||
|
// setImageResource(R.drawable.placeholder)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update = { imageView ->
|
||||||
|
Glide.with(imageView.context)
|
||||||
|
.load(R.drawable.loading)
|
||||||
|
.into(imageView)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
|
|
||||||
class SplashFragment : Fragment() {
|
|
||||||
private lateinit var img: ImageView
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val view = inflater.inflate(R.layout.activity_splash_screen, container, false)
|
|
||||||
img = view.findViewById(R.id.loading_gif)
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// start the loading animation
|
|
||||||
Glide.with(requireContext())
|
|
||||||
.load(R.drawable.loading3)
|
|
||||||
.into(img)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.text.format.Time
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.odweta.solon.ui.theme.PastelGreen
|
||||||
|
import com.odweta.solon.ui.theme.PastelGreenTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelRed
|
||||||
|
import com.odweta.solon.ui.theme.PastelRedTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun TimetableScreen() {
|
||||||
|
val pagerState = rememberPagerState( pageCount = { days.size } )
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) { pageIndex ->
|
||||||
|
DayScreen(days[pageIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSubjectColor(s: Subject, transparent: Boolean): Color {
|
||||||
|
return if (s.free) {
|
||||||
|
if (transparent) {
|
||||||
|
PastelGreenTransparent
|
||||||
|
} else {
|
||||||
|
PastelGreen
|
||||||
|
}
|
||||||
|
} else if (s.substitute == "1") {
|
||||||
|
if (transparent) {
|
||||||
|
PastelRedTransparent
|
||||||
|
} else {
|
||||||
|
PastelRed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (transparent) {
|
||||||
|
PastelYellowTransparent
|
||||||
|
} else {
|
||||||
|
PastelYellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isTimeBetween(givenTime: LocalTime, startTime: LocalTime, endTime: LocalTime): Boolean {
|
||||||
|
// Check if the given time is between startTime and endTime
|
||||||
|
return givenTime.isAfter(startTime) && givenTime.isBefore(endTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ModifierFactoryExtensionFunction")
|
||||||
|
@Composable
|
||||||
|
fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
|
||||||
|
val dayFormatter = DateTimeFormatter.ofPattern("dd. MM. yyyy")
|
||||||
|
val hourFormatter = DateTimeFormatter.ofPattern("HH:mm:ss")
|
||||||
|
val dateParsed = LocalDate.parse(d.date + " " + LocalDate.now().year, dayFormatter)
|
||||||
|
val startTimeParsed = LocalTime.parse(s.start + ":00", hourFormatter)
|
||||||
|
val endTimeParsed = LocalTime.parse(s.end + ":00", hourFormatter)
|
||||||
|
|
||||||
|
val todayDate = LocalDate.now()
|
||||||
|
val now = LocalTime.now()
|
||||||
|
|
||||||
|
if (dateParsed == todayDate && isTimeBetween(now, startTimeParsed, endTimeParsed)) {
|
||||||
|
currentLectureNumber = lectureNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (lectureNumber == currentLectureNumber && dateParsed == todayDate) {
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(100.dp)
|
||||||
|
.background(
|
||||||
|
color = getSubjectColor(s, true), // decide on the color (transparent)
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
.border(
|
||||||
|
width = 5.dp,
|
||||||
|
color = getSubjectColor(s, false),
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(100.dp)
|
||||||
|
.background(
|
||||||
|
color = getSubjectColor(s, true), // decide on the color (transparent)
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DayScreen(day: Day) {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(50.dp)
|
||||||
|
.padding(bottom = 20.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${day.name} ${day.date}",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontStyle = FontStyle.Italic
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
) {
|
||||||
|
for (subject in day.subjects) {
|
||||||
|
if (day.subjects.indexOf(subject) > 0) {
|
||||||
|
Box(modifier = Modifier.height(10.dp)) {
|
||||||
|
if (subject.name == day.subjects[day.subjects.indexOf(subject) - 1].name) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.squiggly_line_yellow),
|
||||||
|
contentDescription = "Spojovač stejných předmětů",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = subjectModifier(day, subject, subject.number.toInt())
|
||||||
|
) {
|
||||||
|
if (subject.substitute != "2") {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(50.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(
|
||||||
|
color = getSubjectColor(
|
||||||
|
subject,
|
||||||
|
true
|
||||||
|
), // decide on the color (not transparent)
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = subject.number,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subject.substitute != "2") {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(start = 20.dp),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.Start
|
||||||
|
) {
|
||||||
|
if (!subject.free) {
|
||||||
|
Text(
|
||||||
|
text = subject.name.uppercase(),
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 25.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = subject.place,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 21.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(start = 20.dp),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = subject.name,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(vertical = 5.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (!Parsing.userIsParent()) {
|
||||||
|
if (
|
||||||
|
subject.teacher == "Jindřich Svoboda" &&
|
||||||
|
studentClass == "5. G"
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.spock),
|
||||||
|
contentDescription = "Spock",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subject.substitute != "2") {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(end = 20.dp),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.End
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${subject.start}–${subject.end}",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 21.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!subject.free) {
|
||||||
|
Text(
|
||||||
|
text = subject.teacher,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ToolbarScreen() {
|
||||||
|
Text(
|
||||||
|
text = toolbarText.value,
|
||||||
|
fontSize = 25.sp,
|
||||||
|
color = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -18,8 +18,13 @@ import android.util.DisplayMetrics
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import com.odweta.solon.ui.theme.PastelGreenTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelOrangeTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelRedTransparent
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
@@ -45,7 +50,7 @@ class Util {
|
|||||||
|
|
||||||
fun saveStringToFile(filePath: String, s: String): Boolean {
|
fun saveStringToFile(filePath: String, s: String): Boolean {
|
||||||
// get a file object with the specified path
|
// get a file object with the specified path
|
||||||
val f = File(Vars.fileDir, filePath)
|
val f = File(fileDir, filePath)
|
||||||
|
|
||||||
// if it does not exist, create it
|
// if it does not exist, create it
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
@@ -67,7 +72,7 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fileToString(filePath: String): String {
|
fun fileToString(filePath: String): String {
|
||||||
val f = File(Vars.fileDir, filePath)
|
val f = File(fileDir, filePath)
|
||||||
|
|
||||||
return if (f.exists()) {
|
return if (f.exists()) {
|
||||||
if (f.canRead()) {
|
if (f.canRead()) {
|
||||||
@@ -85,12 +90,12 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fileExists(filePath: String): Boolean {
|
fun fileExists(filePath: String): Boolean {
|
||||||
val f = File(Vars.fileDir, filePath)
|
val f = File(fileDir, filePath)
|
||||||
return f.exists()
|
return f.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fileIsEmpty(filePath: String): Boolean {
|
fun fileIsEmpty(filePath: String): Boolean {
|
||||||
val f = File(Vars.fileDir, filePath)
|
val f = File(fileDir, filePath)
|
||||||
val content = f.readText()
|
val content = f.readText()
|
||||||
return content == ""
|
return content == ""
|
||||||
}
|
}
|
||||||
@@ -110,7 +115,7 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deleteFile(path: String): Boolean {
|
fun deleteFile(path: String): Boolean {
|
||||||
val f = File(Vars.fileDir, path)
|
val f = File(fileDir, path)
|
||||||
|
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
try {
|
try {
|
||||||
@@ -173,23 +178,20 @@ class Util {
|
|||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAvgBgColor(ctx: Context, avg: String): Int {
|
/*fun getAvgBgColor(ctx: Context, avg: String): Color {
|
||||||
var color: Int = R.color.pastel_orange_transparent
|
var color: Color = PastelOrangeTransparent
|
||||||
|
|
||||||
if (avg.toFloat() in 1f..<2f) {
|
if (avg.toFloat() in 1f..<2f) {
|
||||||
color = R.color.pastel_green_transparent
|
color = PastelGreenTransparent
|
||||||
} else if (avg.toFloat() in 2f..<3f) {
|
} else if (avg.toFloat() in 2f..<3f) {
|
||||||
color = R.color.pastel_yellow_transparent
|
color = PastelYellowTransparent
|
||||||
} else if (avg.toFloat() in 3f..<4f) {
|
} else if (avg.toFloat() in 3f..<4f) {
|
||||||
color = R.color.pastel_orange_transparent
|
color = PastelOrangeTransparent
|
||||||
} else if (avg.toFloat() in 4f..5f) {
|
} else if (avg.toFloat() in 4f..5f) {
|
||||||
color = R.color.pastel_red_transparent
|
color = PastelRedTransparent
|
||||||
}
|
}
|
||||||
|
|
||||||
return ContextCompat.getColor(
|
return color
|
||||||
ctx,
|
|
||||||
color
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fun getAvgStrokeColor(ctx: Context, avg: String): Int {
|
fun getAvgStrokeColor(ctx: Context, avg: String): Int {
|
||||||
var color: Int = R.color.pastel_orange
|
var color: Int = R.color.pastel_orange
|
||||||
@@ -217,6 +219,6 @@ class Util {
|
|||||||
d.cornerRadius = 8f
|
d.cornerRadius = 8f
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.odweta.solon
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class Vars {
|
|
||||||
companion object {
|
|
||||||
const val accountDataFilePath: String = "account_data.txt"
|
|
||||||
const val timeTableFilePath: String = "timetable.json"
|
|
||||||
const val userDataFilePath: String = "userdata.json"
|
|
||||||
const val marksFilePath: String = "marks.json"
|
|
||||||
var fileDir: File = File("")
|
|
||||||
var width: Int = 0
|
|
||||||
var height: Int = 0
|
|
||||||
var internetAvail: Boolean = false
|
|
||||||
|
|
||||||
var dayCounter: Int = 0
|
|
||||||
|
|
||||||
var timeTableAvailOffline: Boolean = false
|
|
||||||
var marksAvailOffline: Boolean = false
|
|
||||||
|
|
||||||
val subjectNameMap = mutableMapOf<String, String>()
|
|
||||||
|
|
||||||
val dayMap = mutableMapOf<Int, Day>()
|
|
||||||
val dayList = mutableListOf<Day>()
|
|
||||||
var days = listOf<Day>()
|
|
||||||
|
|
||||||
var marksJSON: String = ""
|
|
||||||
var marks: MutableMap<String, MutableList<Mark>> = mutableMapOf()
|
|
||||||
|
|
||||||
var username: String = ""
|
|
||||||
var password: String = ""
|
|
||||||
|
|
||||||
val client = OkHttpClient()
|
|
||||||
|
|
||||||
var resetNav: Boolean = false
|
|
||||||
|
|
||||||
var isAPISetUp: Boolean = false
|
|
||||||
|
|
||||||
var selectedDay: Int = 0
|
|
||||||
var dayEndString: String = ""
|
|
||||||
|
|
||||||
var isChecked: Boolean = true
|
|
||||||
|
|
||||||
const val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
|
|
||||||
const val tokenUrl = "$apiBaseUrl/connect/token"
|
|
||||||
var token: String = ""
|
|
||||||
const val userDataUrl = "$apiBaseUrl/v1/user"
|
|
||||||
var userData: String = ""
|
|
||||||
var studentId: String = ""
|
|
||||||
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
|
||||||
var syid = "" // school year id
|
|
||||||
var marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list?SemesterId=$syid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.odweta.solon.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
/*val Purple80 = Color(0xFFD0BCFF)
|
||||||
|
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||||
|
val Pink80 = Color(0xFFEFB8C8)
|
||||||
|
|
||||||
|
val Purple40 = Color(0xFF6650a4)
|
||||||
|
val PurpleGrey40 = Color(0xFF625b71)
|
||||||
|
val Pink40 = Color(0xFF7D5260)*/
|
||||||
|
|
||||||
|
val Primary = Color(0xFFFFCC33)
|
||||||
|
val Secondary = Color(0xFF000000)
|
||||||
|
|
||||||
|
val Black = Color(0xFF000000)
|
||||||
|
val White = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
|
val Transparent = Color(0x00000000)
|
||||||
|
|
||||||
|
val PastelRed = Color(0xFFFF6666)
|
||||||
|
val PastelGreen = Color(0xFF00CC99)
|
||||||
|
val PastelOrange = Color(0xFFFF9933)
|
||||||
|
val PastelYellow = Color(0xFFFFCC33)
|
||||||
|
|
||||||
|
val PastelRedTransparent = Color(0x50FF6666)
|
||||||
|
val PastelGreenTransparent = Color(0x5000CC99)
|
||||||
|
val PastelOrangeTransparent = Color(0x50FF9933)
|
||||||
|
val PastelYellowTransparent = Color(0x50FFCC33)
|
||||||
|
|
||||||
|
val TimetableSubstitute = Color(0xFFFF6666)
|
||||||
|
val TimetableSubstituteTransparentBg = Color(0x50FF6666)
|
||||||
|
|
||||||
|
val TimetableEvent = Color(0xFF6699CC)
|
||||||
|
val TimetableEventTransparentBg = Color(0x506699CC)
|
||||||
|
|
||||||
|
val TimetableFree = Color(0xFF00CC99)
|
||||||
|
val TimetableFreeTransparentBg = Color(0x5000CC99)
|
||||||
|
|
||||||
|
val PrimaryTransparentBg = Color(0x50FFCC33)
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.view.Window
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
// Global values (dimens, modifiers, ...)
|
||||||
|
|
||||||
|
val roundedCornerDimen = 8.dp
|
||||||
|
val borderWidthDimen = 5.dp
|
||||||
|
|
||||||
|
val barModifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(100.dp)
|
||||||
|
.padding(20.dp)
|
||||||
|
//.background(PastelYellowTransparent)
|
||||||
|
.border(
|
||||||
|
width = borderWidthDimen,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(roundedCornerDimen)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun makeStatusBarBlack(window: Window) {
|
||||||
|
window.statusBarColor = Color.Black.toArgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
const val accountDataFilePath: String = "account_data.txt"
|
||||||
|
const val timeTableFilePath: String = "timetable.json"
|
||||||
|
const val userDataFilePath: String = "userdata.json"
|
||||||
|
const val marksFilePath: String = "marks.json"
|
||||||
|
lateinit var fileDir: File
|
||||||
|
var width: Int = 0
|
||||||
|
var height: Int = 0
|
||||||
|
var internetAvail: Boolean = false
|
||||||
|
|
||||||
|
var loaded: Boolean = false
|
||||||
|
|
||||||
|
var studentClass = "1. A"
|
||||||
|
|
||||||
|
var currentLectureNumber = 0
|
||||||
|
|
||||||
|
enum class IsShowing {
|
||||||
|
Timetable,
|
||||||
|
Marks,
|
||||||
|
Menu,
|
||||||
|
About
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Screen {
|
||||||
|
Main,
|
||||||
|
Splash,
|
||||||
|
SignIn
|
||||||
|
}
|
||||||
|
|
||||||
|
var screenToShow: MutableState<Screen> = mutableStateOf(Screen.Main)
|
||||||
|
|
||||||
|
var signedInAndReadyToLaunch: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
|
var isShowing: MutableState<IsShowing> = mutableStateOf(IsShowing.Timetable)
|
||||||
|
|
||||||
|
var toolbarText: MutableState<String> = mutableStateOf("")
|
||||||
|
|
||||||
|
var done: Boolean = false
|
||||||
|
|
||||||
|
var timeTableAvailOffline: Boolean = false
|
||||||
|
var marksAvailOffline: Boolean = false
|
||||||
|
|
||||||
|
val subjectNameMap = mutableMapOf<String, String>()
|
||||||
|
|
||||||
|
val dayMap = mutableMapOf<Int, Day>()
|
||||||
|
val dayList = mutableListOf<Day>()
|
||||||
|
var days = listOf<Day>()
|
||||||
|
|
||||||
|
var marksJSON: String = ""
|
||||||
|
var marks: MutableMap<String, MutableList<Mark>> = mutableMapOf()
|
||||||
|
|
||||||
|
var username: String = ""
|
||||||
|
var password: String = ""
|
||||||
|
|
||||||
|
val client = OkHttpClient()
|
||||||
|
|
||||||
|
var resetNav: Boolean = false
|
||||||
|
|
||||||
|
var isAPISetUp: Boolean = false
|
||||||
|
|
||||||
|
var selectedDay: Int = 0
|
||||||
|
var dayEndString: String = ""
|
||||||
|
|
||||||
|
var isChecked: Boolean = true
|
||||||
|
|
||||||
|
const val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
|
||||||
|
const val tokenUrl = "$apiBaseUrl/connect/token"
|
||||||
|
var token: String = ""
|
||||||
|
const val userDataUrl = "$apiBaseUrl/v1/user"
|
||||||
|
var userData: String = ""
|
||||||
|
var studentId: String = ""
|
||||||
|
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
||||||
|
var syid = "" // school year id
|
||||||
|
var marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list?SemesterId=$syid"
|
||||||
|
|
||||||
|
class Subject {
|
||||||
|
lateinit var name: String
|
||||||
|
lateinit var place: String
|
||||||
|
lateinit var teacher: String
|
||||||
|
lateinit var substitute: String
|
||||||
|
lateinit var number: String
|
||||||
|
lateinit var start: String
|
||||||
|
lateinit var end: String
|
||||||
|
var free: Boolean = false
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun freeSubject(number: String, start: String, end: String): Subject {
|
||||||
|
val s = Subject()
|
||||||
|
|
||||||
|
s.name = "Volno"
|
||||||
|
s.place = "Volno"
|
||||||
|
s.teacher = "Volno"
|
||||||
|
s.substitute = "0"
|
||||||
|
s.number = number
|
||||||
|
s.start = start
|
||||||
|
s.end = end
|
||||||
|
s.free = true
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun empty(): Subject {
|
||||||
|
val s = Subject()
|
||||||
|
|
||||||
|
s.name = "err"
|
||||||
|
s.place = "error"
|
||||||
|
s.teacher = "error"
|
||||||
|
s.substitute = "0"
|
||||||
|
s.number = "0"
|
||||||
|
s.start = "00:00"
|
||||||
|
s.end = "00:00"
|
||||||
|
s.free = false
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "subject ${this.name} at ${this.place} from ${this.start} to ${this.end}; free? ${this.free}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Day {
|
||||||
|
var name: String = ""
|
||||||
|
var date: String = ""
|
||||||
|
var subjects: List<Subject> = mutableListOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Mark {
|
||||||
|
lateinit var grade: String // markText
|
||||||
|
lateinit var weight: String // weight
|
||||||
|
lateinit var subject: String // subjectId -> parse that
|
||||||
|
lateinit var date: String // markDate
|
||||||
|
lateinit var theme: String // theme
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "mark: ${this.grade} * ${this.weight}, subject: ${this.subject}, description: ${this.theme}, date: ${this.date}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun none(): Mark {
|
||||||
|
val mark = Mark()
|
||||||
|
mark.subject = "Zatím žádné známky."
|
||||||
|
mark.grade = "0"
|
||||||
|
mark.weight = "0"
|
||||||
|
mark.date = "-"
|
||||||
|
mark.theme = "-"
|
||||||
|
|
||||||
|
return mark
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.odweta.solon.ui.theme
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
|
||||||
|
private val DarkColorScheme = darkColorScheme(
|
||||||
|
primary = Black,
|
||||||
|
secondary = White,
|
||||||
|
tertiary = Secondary
|
||||||
|
)
|
||||||
|
|
||||||
|
private val LightColorScheme = lightColorScheme(
|
||||||
|
primary = Black,
|
||||||
|
secondary = White,
|
||||||
|
tertiary = Secondary
|
||||||
|
|
||||||
|
/* Other default colors to override
|
||||||
|
background = Color(0xFFFFFBFE),
|
||||||
|
surface = Color(0xFFFFFBFE),
|
||||||
|
onPrimary = Color.White,
|
||||||
|
onSecondary = Color.White,
|
||||||
|
onTertiary = Color.White,
|
||||||
|
onBackground = Color(0xFF1C1B1F),
|
||||||
|
onSurface = Color(0xFF1C1B1F),
|
||||||
|
*/
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SolonTheme(
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
// Dynamic color is available on Android 12+
|
||||||
|
dynamicColor: Boolean = true,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val colorScheme = when {
|
||||||
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
|
val context = LocalContext.current
|
||||||
|
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
darkTheme -> DarkColorScheme
|
||||||
|
else -> LightColorScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = colorScheme,
|
||||||
|
typography = Typography,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.odweta.solon.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
|
// Set of Material typography styles to start with
|
||||||
|
val Typography = Typography(
|
||||||
|
bodyLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
/* Other default text styles to override
|
||||||
|
titleLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 22.sp,
|
||||||
|
lineHeight = 28.sp,
|
||||||
|
letterSpacing = 0.sp
|
||||||
|
),
|
||||||
|
labelSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
)
|
||||||
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<translate
|
|
||||||
android:fromYDelta="0"
|
|
||||||
android:toYDelta="100%"
|
|
||||||
android:duration="300" />
|
|
||||||
</set>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<translate
|
|
||||||
android:fromYDelta="100%"
|
|
||||||
android:toYDelta="0%"
|
|
||||||
android:duration="600"
|
|
||||||
android:interpolator="@android:anim/accelerate_interpolator" />
|
|
||||||
</set>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
|
|
||||||
<corners android:radius="@dimen/corner_radius" />
|
|
||||||
<solid android:color="@color/black" />
|
|
||||||
<stroke android:width="5dp" android:color="@color/pastel_yellow" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
|
|
||||||
<corners android:radius="@dimen/corner_radius" />
|
|
||||||
<solid android:color="@color/pastel_yellow_transparent" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="@drawable/button_clicked_background" android:state_pressed="true" />
|
|
||||||
<item android:drawable="@drawable/button_background" />
|
|
||||||
</selector>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
|
|
||||||
<corners android:radius="@dimen/corner_radius" />
|
|
||||||
<solid android:color="#90FFCC33" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
<size android:width="2dp" /> <!-- Adjust width as needed -->
|
|
||||||
<solid android:color="@color/white" /> <!-- Set desired color -->
|
|
||||||
</shape>
|
|
||||||
|
Before Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="108dp"
|
||||||
|
android:width="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108">
|
||||||
|
|
||||||
|
<!-- Background Color -->
|
||||||
|
<path android:fillColor="#000000"
|
||||||
|
android:pathData="M0,0h108v108h-108z"/>
|
||||||
|
|
||||||
|
<!-- Vertical Grid Lines -->
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<!-- Repeat the lines for remaining grid -->
|
||||||
|
|
||||||
|
<!-- Horizontal Grid Lines -->
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<!-- Repeat the lines for remaining grid -->
|
||||||
|
|
||||||
|
<!-- Additional Grid Lines within the Central Area -->
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="0.8"/>
|
||||||
|
<!-- Repeat similar paths for the remaining inner lines -->
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 983 B |
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="@color/pastel_yellow_transparent" />
|
|
||||||
<corners android:radius="@dimen/corner_radius" />
|
|
||||||
</shape>
|
|
||||||
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
|
|
||||||
<corners android:radius="@dimen/corner_radius" />
|
|
||||||
<solid android:color="@color/transparent" />
|
|
||||||
<stroke android:width="10px" android:color="@color/pastel_yellow" />
|
|
||||||
</shape>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
<font
|
|
||||||
app:fontStyle="normal"
|
|
||||||
app:fontWeight="400"
|
|
||||||
app:font="@font/roboto_src"/>
|
|
||||||
</font-family>
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,108 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/appBarLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/imageView2"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp"
|
|
||||||
android:background="@drawable/toolbar_background"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:text="@string/about_app"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_size_toolbar" />
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView2"
|
|
||||||
android:layout_width="300dp"
|
|
||||||
android:layout_height="300dp"
|
|
||||||
android:contentDescription="@string/solon_logo"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/podstata"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
|
|
||||||
app:srcCompat="@drawable/solon_500_yellow" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/podstata"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="6dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:text="@string/slogan"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textStyle="italic"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textView"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView2" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_width="299dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginBottom="250dp"
|
|
||||||
android:text="@string/desc_about"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="24sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.416"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView2"
|
|
||||||
app:layout_constraintVertical_bias="1.0"
|
|
||||||
tools:ignore="TextSizeCheck" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/link"
|
|
||||||
style="@style/LinkText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Vývoj: @Odweta"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textFontWeight="400"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView"
|
|
||||||
app:layout_constraintVertical_bias="0.3" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sourceCode"
|
|
||||||
style="@style/LinkText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/source_code"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity"
|
|
||||||
android:fontFamily="@font/roboto">
|
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
|
||||||
android:id="@+id/dayPager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:id="@+id/app_root" />
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/toolbarFrame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/fragmentContainer"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:background="@drawable/toolbar_background"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="15dp"
|
|
||||||
android:textSize="25sp"
|
|
||||||
android:textColor="@color/white" />
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/fragmentContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/bottomNav"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbarFrame"
|
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
|
||||||
|
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
|
||||||
android:id="@+id/bottomNav"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/toolbar_background"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
app:itemTextColor="@color/white"
|
|
||||||
android:padding="5dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/fragmentContainer"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:menu="@menu/menu_navbar" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/mark_detail_scroll"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/one_mark_root"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</ScrollView>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/root"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/mark_details_scroll"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/mark_details_root"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</ScrollView>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<!--<Button
|
|
||||||
android:id="@+id/menu_button_settings"
|
|
||||||
android:layout_width="190dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:layout_marginTop="200dp"
|
|
||||||
android:layout_marginBottom="50dp"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:text="@string/settings"
|
|
||||||
android:textSize="22sp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/menu_button_sign_out"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.497"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />-->
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/menu_button_sign_out"
|
|
||||||
android:layout_width="190dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:text="@string/sign_out"
|
|
||||||
android:textSize="22sp"
|
|
||||||
app:cornerRadius="@dimen/corner_radius"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/menu_button_sign_in"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/menu_button_sign_in"
|
|
||||||
android:layout_width="190dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:ellipsize="none"
|
|
||||||
android:scrollHorizontally="false"
|
|
||||||
android:text="@string/sign_in"
|
|
||||||
android:textSize="22sp"
|
|
||||||
app:cornerRadius="@dimen/corner_radius"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/menu_button_about"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.497"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/menu_button_sign_out" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/menu_button_about"
|
|
||||||
android:layout_width="190dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:text="@string/about_app"
|
|
||||||
android:textSize="22sp"
|
|
||||||
app:cornerRadius="@dimen/corner_radius"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/menu_button_sign_in" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/no_mark_container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:foregroundGravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/appBarLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/scrollViewSettings"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp"
|
|
||||||
android:background="@drawable/toolbar_background"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:text="@string/settings"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="25sp" />
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/scrollViewSettings"
|
|
||||||
android:layout_width="409dp"
|
|
||||||
android:layout_height="673dp"
|
|
||||||
android:layout_marginStart="1dp"
|
|
||||||
android:layout_marginTop="1dp"
|
|
||||||
android:layout_marginEnd="1dp"
|
|
||||||
android:layout_marginBottom="1dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:paddingRight="20dp"
|
|
||||||
android:paddingBottom="10dp"
|
|
||||||
tools:ignore="UselessParent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="180dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/lang_change"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textColorHighlight="#FFFFFF"
|
|
||||||
android:textColorHint="#FFFFFF"
|
|
||||||
android:textColorLink="#FFFFFF"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/setting_language_button_choice"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:text="@string/lang_choose" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/logo"
|
|
||||||
android:layout_width="286dp"
|
|
||||||
android:layout_height="96dp"
|
|
||||||
android:layout_marginTop="120dp"
|
|
||||||
android:contentDescription="@string/solon_logo"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.496"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_bias="0.0"
|
|
||||||
app:srcCompat="@drawable/solon_just_yellow" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/frame"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="50dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/signInButton"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/logo">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/usernameField"
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:background="@drawable/button_background"
|
|
||||||
android:ems="10"
|
|
||||||
android:hint="@string/username"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="text"
|
|
||||||
android:paddingHorizontal="20dp"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textColorHighlight="@color/white"
|
|
||||||
android:textColorHint="#C8FFFFFF"
|
|
||||||
android:textColorLink="@color/white"
|
|
||||||
android:textCursorDrawable="@drawable/cursor"
|
|
||||||
android:theme="@style/sign_in_field"
|
|
||||||
app:circularflow_radiusInDP="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:background="@drawable/button_background">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/passwordField"
|
|
||||||
android:layout_width="190dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:ems="10"
|
|
||||||
android:background="@color/transparent"
|
|
||||||
android:hint="@string/password"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:paddingHorizontal="20dp"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textColorHighlight="@color/white"
|
|
||||||
android:textColorHint="#C8FFFFFF"
|
|
||||||
android:textColorLink="@color/white"
|
|
||||||
android:textCursorDrawable="@drawable/cursor"
|
|
||||||
android:theme="@style/sign_in_field" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/showPasswordToggleButton"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="20dp"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/signInButton"
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:background="@drawable/button_background_selector"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
android:text="@string/sign_in_"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.497"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/frame"
|
|
||||||
app:layout_constraintVertical_bias="0.056" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</ScrollView>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView3"
|
|
||||||
android:layout_width="300dp"
|
|
||||||
android:layout_height="300dp"
|
|
||||||
android:layout_marginTop="115dp"
|
|
||||||
android:layout_marginBottom="116dp"
|
|
||||||
android:contentDescription="@string/kolaonline_enhanced"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.495"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_bias="0.16"
|
|
||||||
app:srcCompat="@drawable/solon_500_yellow" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/loading_gif"
|
|
||||||
android:layout_width="200dp"
|
|
||||||
android:layout_height="200dp"
|
|
||||||
android:contentDescription="@string/loading_gif"
|
|
||||||
android:src="@drawable/loading3"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.497"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView3"
|
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/sign_out_warning"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:windowBackground="@drawable/button_background"
|
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:gravity="start" />
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layoutDayMain"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/black"
|
|
||||||
android:fontFamily="@font/roboto"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<RadioGroup
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:padding="20dp">
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/lang_cz"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:layout_marginHorizontal="20dp"
|
|
||||||
android:theme="@style/Theme.Solon.RadioButton" />
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/lang_en"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:layout_marginHorizontal="20dp"
|
|
||||||
android:theme="@style/Theme.Solon.RadioButton" />
|
|
||||||
</RadioGroup>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
Before Width: | Height: | Size: 125 KiB |
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/nav_timetable"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:icon="@android:drawable/ic_dialog_dialer"
|
|
||||||
android:title="@string/timetable" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/nav_marks"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:icon="@mipmap/grade2_foreground"
|
|
||||||
android:title="@string/marks" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/nav_menu"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:icon="@drawable/menu_240"
|
|
||||||
android:title="@string/menu" />
|
|
||||||
</menu>
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:tools="http://schemas.android.com/tools"
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
tools:ignore="MonochromeLauncherIcon">
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||