mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2026-01-31 02:51:46 +00:00
Completion of weather app with new api
- MVVM - SOLID - Atlas Weather Views ported to kotlin
This commit is contained in:
38
.idea/assetWizardSettings.xml
generated
38
.idea/assetWizardSettings.xml
generated
@@ -106,6 +106,44 @@
|
|||||||
</PersistentState>
|
</PersistentState>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="vectorWizard">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="vectorAssetStep">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="clipartAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="url" value="jar:file:/C:/Program%20Files/Android/Android%20Studio/plugins/android/lib/android.jar!/images/material/icons/materialicons/public/baseline_public_24.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="ffffff" />
|
||||||
|
<entry key="outputName" value="ic_baseline_public_24" />
|
||||||
|
<entry key="sourceFile" value="D:\Android Studio Projects\Private work\Altas_-_Weather" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
152
.idea/codeStyles/Project.xml
generated
152
.idea/codeStyles/Project.xml
generated
@@ -1,29 +1,131 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<Objective-C-extensions>
|
<JetCodeStyleSettings>
|
||||||
<file>
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
<value>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
<package name="java.util" alias="false" withSubpackages="false" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
</value>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
</option>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
<value>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
<package name="" alias="false" withSubpackages="true" />
|
||||||
</file>
|
<package name="java" alias="false" withSubpackages="true" />
|
||||||
<class>
|
<package name="javax" alias="false" withSubpackages="true" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
</value>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
</option>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
</JetCodeStyleSettings>
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
<codeStyleSettings language="XML">
|
||||||
</class>
|
<arrangement>
|
||||||
<extensions>
|
<rules>
|
||||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
<section>
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
<rule>
|
||||||
</extensions>
|
<match>
|
||||||
</Objective-C-extensions>
|
<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>
|
||||||
</code_scheme>
|
</code_scheme>
|
||||||
</component>
|
</component>
|
||||||
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
|
<option name="testRunner" value="PLATFORM" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
|
|||||||
40
.idea/jarRepositories.xml
generated
Normal file
40
.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RemoteRepositoriesConfiguration">
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Maven Central repository" />
|
||||||
|
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="jboss.community" />
|
||||||
|
<option name="name" value="JBoss Community repository" />
|
||||||
|
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="BintrayJCenter" />
|
||||||
|
<option name="name" value="BintrayJCenter" />
|
||||||
|
<option name="url" value="https://jcenter.bintray.com/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="Google" />
|
||||||
|
<option name="name" value="Google" />
|
||||||
|
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\android\m2repository" />
|
||||||
|
<option name="name" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\android\m2repository" />
|
||||||
|
<option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\google\m2repository" />
|
||||||
|
<option name="name" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\google\m2repository" />
|
||||||
|
<option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/google/m2repository/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\m2repository" />
|
||||||
|
<option name="name" value="C:\Users\h_mal\AppData\Local\Android\Sdk\extras\m2repository" />
|
||||||
|
<option name="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/extras/m2repository/" />
|
||||||
|
</remote-repository>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
18
.idea/misc.xml
generated
18
.idea/misc.xml
generated
@@ -5,22 +5,36 @@
|
|||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||||
<option name="myNullables">
|
<option name="myNullables">
|
||||||
<value>
|
<value>
|
||||||
<list size="5">
|
<list size="12">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||||
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="android.annotation.Nullable" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||||
|
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||||
|
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
||||||
</list>
|
</list>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
<option name="myNotNulls">
|
<option name="myNotNulls">
|
||||||
<value>
|
<value>
|
||||||
<list size="4">
|
<list size="11">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||||
|
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="android.annotation.NonNull" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||||
|
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
||||||
</list>
|
</list>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,6 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/Altas_-_Weather.iml" filepath="$PROJECT_DIR$/Altas_-_Weather.iml" group="Altas_-_Weather" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/app/Altas_-_Weather-app.iml" filepath="$PROJECT_DIR$/app/Altas_-_Weather-app.iml" group="Altas_-_Weather/app" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/Weather_app.iml" filepath="$PROJECT_DIR$/Weather_app.iml" />
|
<module fileurl="file://$PROJECT_DIR$/Weather_app.iml" filepath="$PROJECT_DIR$/Weather_app.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
|
|||||||
102
.idea/navEditor.xml
generated
Normal file
102
.idea/navEditor.xml
generated
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="navEditor-manualLayoutAlgorithm2">
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="main_navigation.xml">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="addLocationFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="434" />
|
||||||
|
<option name="y" value="398" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="furtherDetailsFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="-20" />
|
||||||
|
<option name="y" value="403" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="nav_home">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="12" />
|
||||||
|
<option name="y" value="12" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="action_homeFragment_to_furtherDetailsFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="nav_world">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="306" />
|
||||||
|
<option name="y" value="6" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="action_worldFragment_to_addLocationFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_worldFragment_to_worldItemFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="worldItemFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="213" />
|
||||||
|
<option name="y" value="408" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,15 +1,23 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
// kotlin kapt
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
// Android navigation
|
||||||
|
apply plugin: 'androidx.navigation.safeargs'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 26
|
compileSdkVersion 30
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.appttude.h_mal.atlas_weather"
|
applicationId "com.appttude.h_mal.atlas_weather"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 26
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|
||||||
|
buildConfigField "String", "ParamOne", "${paramOneEndPoint}"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -17,20 +25,74 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To inline the bytecode built with JVM target 1.8 into
|
||||||
|
// bytecode that is being built with JVM target 1.6. (e.g. navArgs)
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
implementation 'androidx.appcompat:appcompat:1.0.0'
|
||||||
implementation 'com.android.support:design:26.1.0'
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation 'com.android.support:support-v4:26.1.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
|
||||||
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||||
implementation 'com.android.support:support-vector-drawable:26.1.0'
|
implementation 'androidx.vectordrawable:vectordrawable:1.0.0'
|
||||||
implementation "com.google.android.gms:play-services-location:16.0.0"
|
implementation "com.google.android.gms:play-services-location:16.0.0"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
|
||||||
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
|
||||||
|
// Unit testing
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
|
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
||||||
implementation 'com.android.support:cardview-v7:26.1.0'
|
implementation "org.jetbrains.kotlin:kotlin-test:1.3.71"
|
||||||
|
|
||||||
|
// android unit testing and espresso
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
|
implementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
//mock websever for testing retrofit responses
|
||||||
|
testImplementation "com.squareup.okhttp3:mockwebserver:4.6.0"
|
||||||
|
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
||||||
|
|
||||||
|
//mockito and livedata testing
|
||||||
|
testImplementation 'org.mockito:mockito-inline:2.13.0'
|
||||||
|
implementation 'android.arch.core:core-testing'
|
||||||
|
androidTestImplementation 'androidx.test:rules:1.3.0-rc01'
|
||||||
|
|
||||||
|
// Mockk
|
||||||
|
def mockk_ver = "1.10.2"
|
||||||
|
testImplementation "io.mockk:mockk:$mockk_ver"
|
||||||
|
androidTestImplementation "io.mockk:mockk-android:$mockk_ver"
|
||||||
|
|
||||||
|
// Retrofit
|
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
|
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
|
||||||
|
|
||||||
|
// Shared prefs
|
||||||
|
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||||
|
|
||||||
|
//Kodein Dependency Injection
|
||||||
|
def kodein_version = "6.2.1"
|
||||||
|
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
|
||||||
|
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
|
||||||
|
|
||||||
|
// Room database
|
||||||
|
def room_version = "2.3.0-alpha03"
|
||||||
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
|
|
||||||
|
// Picasso
|
||||||
|
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.test.InstrumentationRegistry;
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ExampleInstrumentedTest {
|
|
||||||
@Test
|
|
||||||
public void useAppContext() throws Exception {
|
|
||||||
// Context of the app under test.
|
|
||||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
|
||||||
|
|
||||||
assertEquals("com.example.h_mal.weather_app", appContext.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.utils
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DateUtilsKtTest{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toDayString_testStandardData_outputCorrect() {
|
||||||
|
val input = 1606183160
|
||||||
|
|
||||||
|
val result = input.toDayString()
|
||||||
|
|
||||||
|
assertEquals(result, "Nov 24")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toDayName_testStandardData_outputCorrect() {
|
||||||
|
val input = 1606183160
|
||||||
|
|
||||||
|
val result = input.toDayName()
|
||||||
|
|
||||||
|
assertEquals(result, "Tuesday")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
android:required="true" />
|
android:required="true" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".mvvm.application.AppClass"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity
|
<activity android:name=".mvvm.ui.MainActivity"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.MainActivity"
|
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
@@ -34,24 +34,39 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<!-- <activity-->
|
||||||
|
<!-- android:name=".legacy.ui.home.MainActivity"-->
|
||||||
|
<!-- android:label="@string/app_name"-->
|
||||||
|
<!-- android:launchMode="singleTop"-->
|
||||||
|
<!-- android:theme="@style/AppTheme.NoActionBar">-->
|
||||||
|
<!-- <intent-filter>-->
|
||||||
|
<!-- <action android:name="android.intent.action.MAIN" />-->
|
||||||
|
<!-- <action android:name="android.intent.action.VIEW" />-->
|
||||||
|
|
||||||
<receiver android:name="com.appttude.h_mal.atlas_weather.NotificationReceiver"
|
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity"/>
|
<!-- </intent-filter>-->
|
||||||
|
<!-- </activity>-->
|
||||||
|
|
||||||
<activity android:name="com.appttude.h_mal.atlas_weather.FurtherInfoActivity"
|
<receiver
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity"/>
|
android:name=".legacy.services.notifcation.NotificationReceiver"
|
||||||
<activity
|
|
||||||
android:name="com.appttude.h_mal.atlas_weather.AddForecast"
|
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity" />
|
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity" />
|
||||||
<activity android:name="com.appttude.h_mal.atlas_weather.UnitSettings"
|
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity"/>
|
<activity
|
||||||
|
android:name=".legacy.ui.FurtherInfoActivity"
|
||||||
|
android:parentActivityName=".legacy.ui.home.MainActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".legacy.ui.AddForecastActivity"
|
||||||
|
android:parentActivityName=".legacy.ui.home.MainActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".legacy.ui.UnitSettingsActivity"
|
||||||
|
android:parentActivityName=".legacy.ui.home.MainActivity" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="com.appttude.h_mal.atlas_weather.dbfiles.ForecastProvider"
|
android:name=".legacy.data.sql.ForecastProvider"
|
||||||
android:authorities="com.appttude.h_mal.atlas_weather"
|
android:authorities="com.appttude.h_mal.atlas_weather"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<receiver android:name="com.appttude.h_mal.atlas_weather.AppWidget.NewAppWidget">
|
<receiver android:name=".legacy.AppWidget.NewAppWidget">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
|
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
|
||||||
@@ -63,19 +78,17 @@
|
|||||||
android:resource="@xml/new_app_widget_info" />
|
android:resource="@xml/new_app_widget_info" />
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<activity android:name="com.appttude.h_mal.atlas_weather.WorldItemActivity"
|
<activity
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity">
|
android:name=".legacy.ui.WorldItemActivity"
|
||||||
|
android:parentActivityName=".legacy.ui.home.MainActivity"></activity>
|
||||||
</activity>
|
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="com.appttude.h_mal.atlas_weather.AppWidget.WidgetRemoteViewsService"
|
android:name=".legacy.AppWidget.WidgetRemoteViewsService"
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS"></service>
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
|
|
||||||
<activity android:name="com.appttude.h_mal.atlas_weather.InfoActivity"
|
<activity
|
||||||
android:parentActivityName="com.appttude.h_mal.atlas_weather.MainActivity">
|
android:name=".legacy.ui.InfoActivity"
|
||||||
|
android:parentActivityName=".legacy.ui.home.MainActivity"></activity>
|
||||||
</activity>
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.AppWidget;
|
package com.appttude.h_mal.atlas_weather.legacy.AppWidget;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -12,20 +12,20 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.RemoteViewsService;
|
import android.widget.RemoteViewsService;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.Forecast;
|
|
||||||
import com.appttude.h_mal.atlas_weather.ForecastItem;
|
|
||||||
import com.appttude.h_mal.atlas_weather.R;
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastDBHelper;
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastDBHelper;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.Forecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getImageResource;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.extractFeatureFromJson;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.extractFeatureFromJson;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.COLUMN_FORECAST_NAME;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.COLUMN_FORECAST_NAME;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.COLUMN_WIDGET_FORECAST_ITEM;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.COLUMN_WIDGET_FORECAST_ITEM;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.TABLE_NAME_WIDGET;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.TABLE_NAME_WIDGET;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getImageResource;
|
||||||
|
|
||||||
public class MyWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
public class MyWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.AppWidget;
|
package com.appttude.h_mal.atlas_weather.legacy.AppWidget;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.TaskStackBuilder;
|
import android.app.TaskStackBuilder;
|
||||||
@@ -17,12 +17,12 @@ import android.preference.PreferenceManager;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.CurrentForecast;
|
|
||||||
import com.appttude.h_mal.atlas_weather.ForecastItem;
|
|
||||||
import com.appttude.h_mal.atlas_weather.FurtherInfoActivity;
|
|
||||||
import com.appttude.h_mal.atlas_weather.R;
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastDBHelper;
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastDBHelper;
|
||||||
import com.appttude.h_mal.atlas_weather.getLatLong;
|
import com.appttude.h_mal.atlas_weather.legacy.model.CurrentForecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.FurtherInfoActivity;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -30,16 +30,16 @@ import java.text.DateFormat;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.changeToInt;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.UriBuilder;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getImageResource;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.createUrl;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getLocationName;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.extractFeatureFromJson;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.UriBuilder;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.makeHttpRequest;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.createUrl;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.COLUMN_FORECAST_NAME;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.extractFeatureFromJson;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.COLUMN_WIDGET_FORECAST_ITEM;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.makeHttpRequest;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry.TABLE_NAME_WIDGET;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.COLUMN_FORECAST_NAME;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.changeToInt;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.COLUMN_WIDGET_FORECAST_ITEM;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getImageResource;
|
||||||
import static com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry.TABLE_NAME_WIDGET;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getLocationName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of App Widget functionality.
|
* Implementation of App Widget functionality.
|
||||||
@@ -67,6 +67,7 @@ public class NewAppWidget extends AppWidgetProvider{
|
|||||||
@Override
|
@Override
|
||||||
public void onEnabled(Context context) {
|
public void onEnabled(Context context) {
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||||
|
|
||||||
@@ -84,6 +85,8 @@ public class NewAppWidget extends AppWidgetProvider{
|
|||||||
// task.execute(UriBuilder(5));
|
// task.execute(UriBuilder(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisabled(Context context) {
|
public void onDisabled(Context context) {
|
||||||
// Enter relevant functionality for when the last widget is disabled
|
// Enter relevant functionality for when the last widget is disabled
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.AppWidget;
|
package com.appttude.h_mal.atlas_weather.legacy.AppWidget;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.widget.RemoteViewsService;
|
import android.widget.RemoteViewsService;
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.loader.content.AsyncTaskLoader;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.createUrl;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.createUrl;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.extractFeatureFromJson;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.extractFeatureFromJson;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.makeHttpRequest;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.makeHttpRequest;
|
||||||
|
|
||||||
public class ForecastLoader extends android.support.v4.content.AsyncTaskLoader<List<ForecastItem>> {
|
public class ForecastLoader extends AsyncTaskLoader<List<ForecastItem>> {
|
||||||
|
|
||||||
private ArrayList<String> mUrl;
|
private ArrayList<String> mUrl;
|
||||||
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.data.network;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.CurrentForecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.Forecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -19,9 +23,8 @@ import java.nio.charset.Charset;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.Fragment_home.APIkey;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.latitude;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.latitude;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.longitude;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.longitude;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by h_mal on 05/05/2018.
|
* Created by h_mal on 05/05/2018.
|
||||||
@@ -31,24 +34,24 @@ public class RetrieveJSON {
|
|||||||
|
|
||||||
public RetrieveJSON(){}
|
public RetrieveJSON(){}
|
||||||
|
|
||||||
|
protected static String APIkey = "1fe09c8cd3c42e573c5cc7c32b27a1b4";
|
||||||
|
|
||||||
public static String UriBuilder(int days){
|
public static String UriBuilder(int days){
|
||||||
|
|
||||||
String latLong = latitude + "," + longitude;
|
String latLong = latitude + "," + longitude;
|
||||||
|
|
||||||
Uri.Builder builder = new Uri.Builder();
|
Uri.Builder builder = new Uri.Builder();
|
||||||
builder.scheme("http")
|
builder.scheme("http")
|
||||||
.authority("api.apixu.com")
|
.authority("api.weatherstack.com")
|
||||||
.appendPath("v1")
|
.appendPath("current")
|
||||||
.appendPath("forecast.json")
|
.appendQueryParameter("access_key",APIkey)
|
||||||
.appendQueryParameter("key",APIkey)
|
.appendQueryParameter("query",latLong);
|
||||||
.appendQueryParameter("q",latLong)
|
|
||||||
.appendQueryParameter("days",days+"");
|
|
||||||
|
|
||||||
return builder.build().toString().replace("%2C",",");
|
return builder.build().toString().replace("%2C",",");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String UriBuilder(String q){
|
public static String UriBuilder(String q){
|
||||||
|
|
||||||
Uri.Builder builder = new Uri.Builder();
|
Uri.Builder builder = new Uri.Builder();
|
||||||
builder.scheme("http")
|
builder.scheme("http")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.dbfiles;
|
package com.appttude.h_mal.atlas_weather.legacy.data.sql;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.dbfiles;
|
package com.appttude.h_mal.atlas_weather.legacy.data.sql;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry;
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry;
|
||||||
|
|
||||||
public class ForecastDBHelper extends SQLiteOpenHelper {
|
public class ForecastDBHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.dbfiles;
|
package com.appttude.h_mal.atlas_weather.legacy.data.sql;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
@@ -7,11 +7,12 @@ import android.content.UriMatcher;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry;
|
||||||
|
|
||||||
public class ForecastProvider extends ContentProvider {
|
public class ForecastProvider extends ContentProvider {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.model;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.model;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -9,25 +9,25 @@ import android.os.Parcelable;
|
|||||||
|
|
||||||
public class Forecast implements Parcelable {
|
public class Forecast implements Parcelable {
|
||||||
|
|
||||||
private Long date_epoch;
|
private Long date_epoch; //dt
|
||||||
private Double maxtemp_c;
|
private Double maxtemp_c; //temp.max
|
||||||
private Double maxtemp_f;
|
private Double maxtemp_f;
|
||||||
private Double mintemp_c;
|
private Double mintemp_c; //temp.min
|
||||||
private Double mintemp_f;
|
private Double mintemp_f;
|
||||||
private Double avgtemp_c;
|
private Double avgtemp_c;
|
||||||
private Double avgtemp_f;
|
private Double avgtemp_f;
|
||||||
private Double maxwind_mph;
|
private Double maxwind_mph; //wind_speed
|
||||||
private Double maxwind_kph;
|
private Double maxwind_kph;
|
||||||
private Double totalprecip_mm;
|
private Double totalprecip_mm;
|
||||||
private Double totalprecip_in;
|
private Double totalprecip_in;
|
||||||
private Double avgvis_km;
|
private Double avgvis_km;
|
||||||
private Double avgvis_miles;
|
private Double avgvis_miles;
|
||||||
private Double avghumidity;
|
private Double avghumidity; //humidity
|
||||||
private String forecast_text;
|
private String forecast_text; //weather.[0].description
|
||||||
private String iconURL;
|
private String iconURL; //weather.[0].icon
|
||||||
private Double uv;
|
private Double uv; //uvi
|
||||||
private String sunrise;
|
private String sunrise; //sunrise
|
||||||
private String sunset;
|
private String sunset; //sunset
|
||||||
private String moonrise;
|
private String moonrise;
|
||||||
private String moonset;
|
private String moonset;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.model;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.model;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -12,6 +10,11 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class infopageItem {
|
public class infopageItem {
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.services.location;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
|
||||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||||
import com.google.android.gms.location.LocationServices;
|
import com.google.android.gms.location.LocationServices;
|
||||||
|
|
||||||
@@ -16,39 +17,39 @@ import com.google.android.gms.location.LocationServices;
|
|||||||
* Created by h_mal on 05/05/2018.
|
* Created by h_mal on 05/05/2018.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class getLatLong{
|
public class getLatLong {
|
||||||
static Location location;
|
static Location location;
|
||||||
public static Double longitude;
|
public static Double longitude;
|
||||||
public static Double latitude;
|
public static Double latitude;
|
||||||
|
|
||||||
private static String TAG = getLatLong.class.getSimpleName();
|
private static String TAG = getLatLong.class.getSimpleName();
|
||||||
|
|
||||||
public getLatLong(){
|
public getLatLong() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void configLatLong(Context context) {
|
public static void configLatLong(Context context) {
|
||||||
|
|
||||||
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||||
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
|
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
|
||||||
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
!=PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
Toast.makeText(context, "Location permission denied", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "Location permission denied", Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
Log.e("latlong error", "configLatLong: ", e);
|
Log.e("latlong error", "configLatLong: ", e);
|
||||||
}finally {
|
} finally {
|
||||||
if (location == null){
|
if (location == null) {
|
||||||
Log.i(TAG, "configLatLong: location initially was null");
|
Log.i(TAG, "configLatLong: location initially was null");
|
||||||
try{
|
try {
|
||||||
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||||
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "configLatLong: ", e);
|
Log.e(TAG, "configLatLong: ", e);
|
||||||
}finally {
|
} finally {
|
||||||
if (location != null){
|
if (location != null) {
|
||||||
latitude = location.getLatitude();
|
latitude = location.getLatitude();
|
||||||
longitude = location.getLongitude();
|
longitude = location.getLongitude();
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ public class getLatLong{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
latitude = location.getLatitude();
|
latitude = location.getLatitude();
|
||||||
longitude = location.getLongitude();
|
longitude = location.getLongitude();
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.services.notifcation;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
@@ -9,29 +9,30 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.squareup.picasso.Picasso;
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
import com.squareup.picasso.Target;
|
import com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON;
|
||||||
import com.squareup.picasso.Transformation;
|
import com.appttude.h_mal.atlas_weather.legacy.model.CurrentForecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.changeToInt;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.createUrl;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getImageResource;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.extractFeatureFromJson;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.createUrl;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.makeHttpRequest;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.extractFeatureFromJson;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.latitude;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.makeHttpRequest;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.longitude;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.latitude;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.changeToInt;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.longitude;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getImageResource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by h_mal on 29/04/2018.
|
* Created by h_mal on 29/04/2018.
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -14,16 +13,19 @@ import android.widget.EditText;
|
|||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.UriBuilder;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.createUrl;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.createUrl;
|
|
||||||
|
|
||||||
public class AddForecast extends AppCompatActivity {
|
public class AddForecastActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private EditText tv;
|
private EditText tv;
|
||||||
private String nameString;
|
private String nameString;
|
||||||
@@ -53,7 +55,7 @@ public class AddForecast extends AppCompatActivity {
|
|||||||
private void submitEntry(String s){
|
private void submitEntry(String s){
|
||||||
|
|
||||||
if (TextUtils.isEmpty(s)) {
|
if (TextUtils.isEmpty(s)) {
|
||||||
Toast.makeText(AddForecast.this, "please insert a location name", Toast.LENGTH_SHORT).show();
|
Toast.makeText(AddForecastActivity.this, "please insert a location name", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +91,7 @@ public class AddForecast extends AppCompatActivity {
|
|||||||
|
|
||||||
protected Boolean doInBackground(String... urls) {
|
protected Boolean doInBackground(String... urls) {
|
||||||
HttpURLConnection urlConnection = null;
|
HttpURLConnection urlConnection = null;
|
||||||
URL url = createUrl(UriBuilder(urls[0]));
|
URL url = createUrl(RetrieveJSON.UriBuilder(urls[0]));
|
||||||
|
|
||||||
Boolean b = null;
|
Boolean b = null;
|
||||||
|
|
||||||
@@ -123,7 +125,7 @@ public class AddForecast extends AppCompatActivity {
|
|||||||
progBarAdd.setVisibility(View.GONE);
|
progBarAdd.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (feed == null){
|
if (feed == null){
|
||||||
Toast.makeText(AddForecast.this, "No connection", Toast.LENGTH_SHORT).show();
|
Toast.makeText(AddForecastActivity.this, "No connection", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +137,7 @@ public class AddForecast extends AppCompatActivity {
|
|||||||
setResult(RESULT_OK, returnIntent);
|
setResult(RESULT_OK, returnIntent);
|
||||||
finish();
|
finish();
|
||||||
}else{
|
}else{
|
||||||
Toast.makeText(AddForecast.this, "Location not found", Toast.LENGTH_SHORT).show();
|
Toast.makeText(AddForecastActivity.this, "Location not found", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.changeToInt;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.Forecast;
|
||||||
|
|
||||||
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.changeToInt;
|
||||||
|
|
||||||
public class FurtherInfoActivity extends AppCompatActivity {
|
public class FurtherInfoActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui;
|
||||||
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.infopageItem;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.AppWidget.NewAppWidget;
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.AppWidget.NewAppWidget;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.setupNotificationBroadcaster;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.setupNotificationBroadcaster;
|
||||||
|
|
||||||
public class UnitSettings extends PreferenceActivity {
|
public class UnitSettingsActivity extends PreferenceActivity {
|
||||||
|
|
||||||
private String TAG = getClass().getSimpleName();
|
private String TAG = getClass().getSimpleName();
|
||||||
private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
|
private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.loader.app.LoaderManager;
|
||||||
|
import androidx.loader.content.Loader;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.adapters.RecyclerViewAdapter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.UriBuilder;
|
|
||||||
|
|
||||||
public class WorldItemActivity extends AppCompatActivity
|
public class WorldItemActivity extends AppCompatActivity
|
||||||
implements android.support.v4.app.LoaderManager.LoaderCallbacks<List<ForecastItem>> {
|
implements LoaderManager.LoaderCallbacks<List<ForecastItem>> {
|
||||||
|
|
||||||
private static final int NEWS_LOADER_ID = 1;
|
private static final int NEWS_LOADER_ID = 1;
|
||||||
|
|
||||||
@@ -58,7 +63,7 @@ public class WorldItemActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public android.support.v4.content.Loader<List<ForecastItem>> onCreateLoader(int id, Bundle args) {
|
public Loader<List<ForecastItem>> onCreateLoader(int id, Bundle args) {
|
||||||
// URL url = createUrl(UriBuilder());
|
// URL url = createUrl(UriBuilder());
|
||||||
// ArrayList<String> entries = new ArrayList<>();
|
// ArrayList<String> entries = new ArrayList<>();
|
||||||
// entries.add(url.toString());
|
// entries.add(url.toString());
|
||||||
@@ -67,12 +72,12 @@ public class WorldItemActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(android.support.v4.content.Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
public void onLoadFinished(Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(android.support.v4.content.Loader<List<ForecastItem>> loader) {
|
public void onLoaderReset(Loader<List<ForecastItem>> loader) {
|
||||||
// loader.reset();
|
// loader.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -14,10 +12,18 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.CurrentForecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.WorldItemActivity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.changeToInt;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.changeToInt;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getImageResource;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getImageResource;
|
||||||
|
|
||||||
public class CurrentForecastAdapter extends ArrayAdapter<ForecastItem> {
|
public class CurrentForecastAdapter extends ArrayAdapter<ForecastItem> {
|
||||||
Context context;
|
Context context;
|
||||||
@@ -71,7 +77,7 @@ public class CurrentForecastAdapter extends ArrayAdapter<ForecastItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void openWorldItem(ForecastItem forcast){
|
private void openWorldItem(ForecastItem forcast){
|
||||||
Intent i = new Intent(context,WorldItemActivity.class);
|
Intent i = new Intent(context, WorldItemActivity.class);
|
||||||
i.putExtra("ForecastItem",forcast);
|
i.putExtra("ForecastItem",forcast);
|
||||||
context.startActivity(i);
|
context.startActivity(i);
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.CurrentForecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.Forecast;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.FurtherInfoActivity;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.changeToInt;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.changeToInt;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getImageResource;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getImageResource;
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.getLocationName;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.getLocationName;
|
||||||
|
|
||||||
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
@@ -247,7 +253,7 @@ public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void openFurtherInfo(Forecast forcast){
|
private void openFurtherInfo(Forecast forcast){
|
||||||
Intent i = new Intent(context,FurtherInfoActivity.class);
|
Intent i = new Intent(context, FurtherInfoActivity.class);
|
||||||
i.putExtra("currentForcast",forcast);
|
i.putExtra("currentForcast",forcast);
|
||||||
context.startActivity(i);
|
context.startActivity(i);
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui.home;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -18,21 +12,36 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.loader.app.LoaderManager;
|
||||||
|
import androidx.loader.content.Loader;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ForecastLoader;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.adapters.RecyclerViewAdapter;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.UriBuilder;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.UriBuilder;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.createUrl;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.createUrl;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.latitude;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.latitude;
|
||||||
import static com.appttude.h_mal.atlas_weather.getLatLong.longitude;
|
import static com.appttude.h_mal.atlas_weather.legacy.services.location.getLatLong.longitude;
|
||||||
|
|
||||||
|
|
||||||
public class Fragment_home extends Fragment implements android.support.v4.app.LoaderManager.LoaderCallbacks<List<ForecastItem>>{
|
public class FragmentHome extends Fragment implements LoaderManager.LoaderCallbacks<List<ForecastItem>>{
|
||||||
|
|
||||||
protected static String APIkey = "2e914b44f94a4f07853100835181104";
|
protected static String APIkey = "1fe09c8cd3c42e573c5cc7c32b27a1b4";
|
||||||
android.support.v4.app.LoaderManager loaderManager;
|
LoaderManager loaderManager;
|
||||||
android.support.v4.app.LoaderManager.LoaderCallbacks callbacks;
|
LoaderManager.LoaderCallbacks callbacks;
|
||||||
public static int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
|
public static int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
|
||||||
|
|
||||||
private static final int NEWS_LOADER_ID = 1;
|
private static final int NEWS_LOADER_ID = 1;
|
||||||
@@ -50,12 +59,6 @@ public class Fragment_home extends Fragment implements android.support.v4.app.Lo
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
|
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
|
||||||
|
|
||||||
// try {
|
|
||||||
// getLatLong.configLatLong(getContext());
|
|
||||||
// }catch (Exception e){
|
|
||||||
// System.out.println("error msg: " + e);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (ActivityCompat.checkSelfPermission(getContext(),
|
if (ActivityCompat.checkSelfPermission(getContext(),
|
||||||
android.Manifest.permission.ACCESS_FINE_LOCATION)
|
android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
@@ -124,7 +127,7 @@ public class Fragment_home extends Fragment implements android.support.v4.app.Lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public android.support.v4.content.Loader<List<ForecastItem>> onCreateLoader(int id, Bundle args) {
|
public Loader<List<ForecastItem>> onCreateLoader(int id, Bundle args) {
|
||||||
mainPG.setVisibility(View.VISIBLE);
|
mainPG.setVisibility(View.VISIBLE);
|
||||||
ArrayList<String> entries = new ArrayList<>();
|
ArrayList<String> entries = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
@@ -148,7 +151,7 @@ public class Fragment_home extends Fragment implements android.support.v4.app.Lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(android.support.v4.content.Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
public void onLoadFinished(Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
||||||
|
|
||||||
if (mSwipeRefreshLayout.isRefreshing()){
|
if (mSwipeRefreshLayout.isRefreshing()){
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
@@ -190,7 +193,7 @@ public class Fragment_home extends Fragment implements android.support.v4.app.Lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(android.support.v4.content.Loader<List<ForecastItem>> loader) {
|
public void onLoaderReset(Loader<List<ForecastItem>> loader) {
|
||||||
loader.reset();
|
loader.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui.home;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.LoaderManager;
|
|
||||||
import android.support.v4.content.Loader;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -17,18 +13,28 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract;
|
import androidx.fragment.app.Fragment;
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastContract.ForecastEntry;
|
import androidx.loader.app.LoaderManager;
|
||||||
|
import androidx.loader.content.Loader;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ForecastLoader;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastContract.ForecastEntry;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.model.ForecastItem;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.AddForecastActivity;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.WorldItemActivity;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.adapters.CurrentForecastAdapter;
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.appttude.h_mal.atlas_weather.MainActivity.networkInfo;
|
import static com.appttude.h_mal.atlas_weather.legacy.data.network.RetrieveJSON.UriBuilder;
|
||||||
import static com.appttude.h_mal.atlas_weather.RetrieveJSON.UriBuilder;
|
import static com.appttude.h_mal.atlas_weather.legacy.ui.home.MainActivity.networkInfo;
|
||||||
|
|
||||||
public class Fragment_Two extends Fragment implements android.support.v4.app.LoaderManager.LoaderCallbacks<List<ForecastItem>>{
|
public class FragmentTwo extends Fragment implements LoaderManager.LoaderCallbacks<List<ForecastItem>>{
|
||||||
|
|
||||||
private static final int NEWS_LOADER_ID = 1;
|
private static final int NEWS_LOADER_ID = 1;
|
||||||
private String TAG = getClass().getSimpleName();
|
private String TAG = getClass().getSimpleName();
|
||||||
@@ -37,9 +43,9 @@ public class Fragment_Two extends Fragment implements android.support.v4.app.Loa
|
|||||||
ProgressBar pb_2;
|
ProgressBar pb_2;
|
||||||
LinearLayout emptyView;
|
LinearLayout emptyView;
|
||||||
ListView lv;
|
ListView lv;
|
||||||
android.support.v4.app.LoaderManager loaderManager;
|
LoaderManager loaderManager;
|
||||||
|
|
||||||
public Fragment_Two() {
|
public FragmentTwo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -88,7 +94,7 @@ public class Fragment_Two extends Fragment implements android.support.v4.app.Loa
|
|||||||
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||||
Intent intent = new Intent(getContext(),WorldItemActivity.class);
|
Intent intent = new Intent(getContext(), WorldItemActivity.class);
|
||||||
intent.putExtra("ForecastItem",mAdapter.getItem(i));
|
intent.putExtra("ForecastItem",mAdapter.getItem(i));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
@@ -98,7 +104,7 @@ public class Fragment_Two extends Fragment implements android.support.v4.app.Loa
|
|||||||
fab.setOnClickListener(new View.OnClickListener() {
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Intent i = new Intent(getActivity(), AddForecast.class);
|
Intent i = new Intent(getActivity(), AddForecastActivity.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -150,31 +156,6 @@ public class Fragment_Two extends Fragment implements android.support.v4.app.Loa
|
|||||||
public void onLoadFinished(Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
public void onLoadFinished(Loader<List<ForecastItem>> loader, List<ForecastItem> data) {
|
||||||
mAdapter.clear();
|
mAdapter.clear();
|
||||||
|
|
||||||
TextView t = emptyView.findViewById(R.id.emptyViewText);
|
|
||||||
|
|
||||||
if (data == null){
|
|
||||||
lv.setVisibility(View.GONE);
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
t.setText("Add Items");
|
|
||||||
Log.i(TAG, "onLoadFinished: data null");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(networkInfo == null || !networkInfo.isConnected()){
|
|
||||||
lv.setVisibility(View.GONE);
|
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
|
||||||
t.setText("Check connection...");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != null && !data.isEmpty()) {
|
|
||||||
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
|
||||||
mAdapter.add(data.get(i));
|
|
||||||
}
|
|
||||||
emptyView.setVisibility(View.GONE);
|
|
||||||
Log.i(TAG, "onLoadFinished: data not null");
|
|
||||||
lv.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
pb_2.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather;
|
package com.appttude.h_mal.atlas_weather.legacy.ui.home;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -11,18 +11,23 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.design.widget.TabLayout;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
|
||||||
import android.support.v4.view.ViewPager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.dbfiles.ForecastDBHelper;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter;
|
||||||
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.data.sql.ForecastDBHelper;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.services.notifcation.NotificationReceiver;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.InfoActivity;
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.UnitSettingsActivity;
|
||||||
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@@ -109,11 +114,11 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
switch (id){
|
switch (id){
|
||||||
case R.id.action_settings:
|
case R.id.action_settings:
|
||||||
Intent i = new Intent(this, UnitSettings.class);
|
Intent i = new Intent(this, UnitSettingsActivity.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_into:
|
case R.id.action_into:
|
||||||
Intent infoActivity = new Intent(this,InfoActivity.class);
|
Intent infoActivity = new Intent(this, InfoActivity.class);
|
||||||
startActivity(infoActivity);
|
startActivity(infoActivity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -176,7 +181,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
||||||
* one of the sections/tabs/pages.
|
* one of the sections/tabs_menu/pages.
|
||||||
*/
|
*/
|
||||||
public class SectionsPagerAdapter extends FragmentPagerAdapter {
|
public class SectionsPagerAdapter extends FragmentPagerAdapter {
|
||||||
|
|
||||||
@@ -190,10 +195,10 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public Fragment getItem(int position) {
|
public Fragment getItem(int position) {
|
||||||
switch (position){
|
switch (position){
|
||||||
case 0:
|
case 0:
|
||||||
Fragment_home tab1 = new Fragment_home();
|
FragmentHome tab1 = new FragmentHome();
|
||||||
return tab1;
|
return tab1;
|
||||||
case 1:
|
case 1:
|
||||||
Fragment_Two tab2 = new Fragment_Two();
|
FragmentTwo tab2 = new FragmentTwo();
|
||||||
return tab2;
|
return tab2;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.application
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.test.espresso.idling.CountingIdlingResource
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.WeatherApi
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors.NetworkConnectionInterceptor
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors.QueryParamsInterceptor
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.prefs.PreferenceProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.RepositoryImpl
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.AppDatabase
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.ApplicationViewModelFactory
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import org.kodein.di.Kodein
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.x.androidXModule
|
||||||
|
import org.kodein.di.generic.bind
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
import org.kodein.di.generic.provider
|
||||||
|
import org.kodein.di.generic.singleton
|
||||||
|
|
||||||
|
const val LOCATION_PERMISSION_REQUEST = 505
|
||||||
|
class AppClass : Application(), KodeinAware {
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
// idling resource to be used for espresso testing
|
||||||
|
// when we need to wait for async operations to complete
|
||||||
|
val idlingResources = CountingIdlingResource("Data_loader")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kodein creation of modules to be retrieve within the app
|
||||||
|
override val kodein = Kodein.lazy {
|
||||||
|
import(androidXModule(this@AppClass))
|
||||||
|
|
||||||
|
bind() from singleton { Gson() }
|
||||||
|
bind() from singleton { NetworkConnectionInterceptor(instance()) }
|
||||||
|
bind() from singleton { QueryParamsInterceptor() }
|
||||||
|
bind() from singleton { WeatherApi(instance(), instance())}
|
||||||
|
bind() from singleton { AppDatabase(instance()) }
|
||||||
|
bind() from singleton { PreferenceProvider(instance()) }
|
||||||
|
bind() from singleton { RepositoryImpl(instance(), instance(), instance()) }
|
||||||
|
bind() from singleton { LocationProvider(instance()) }
|
||||||
|
bind() from provider { ApplicationViewModelFactory(instance(), instance()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.location
|
||||||
|
|
||||||
|
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.LOCATION_SERVICE
|
||||||
|
import android.location.Geocoder
|
||||||
|
import android.location.LocationManager
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class LocationProvider(
|
||||||
|
val applicationContext: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
private var locationManager =
|
||||||
|
applicationContext.getSystemService(LOCATION_SERVICE) as LocationManager?
|
||||||
|
|
||||||
|
private val geoCoder: Geocoder by lazy { Geocoder(applicationContext, Locale.getDefault()) }
|
||||||
|
|
||||||
|
@RequiresPermission(value = ACCESS_FINE_LOCATION)
|
||||||
|
fun getLatLong(): Pair<Double, Double>{
|
||||||
|
val location = locationManager
|
||||||
|
?.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||||
|
?: locationManager?.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
|
||||||
|
location ?: throw IOException("Unable to get location")
|
||||||
|
|
||||||
|
val lat = location.latitude
|
||||||
|
val long = location.longitude
|
||||||
|
return Pair(lat, long)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLocationName(lat: Double, long: Double): String{
|
||||||
|
val result = geoCoder.getFromLocation(lat, long, 1)?.get(0)
|
||||||
|
|
||||||
|
return result?.let { location ->
|
||||||
|
location.locality?.let { return it }
|
||||||
|
location.thoroughfare?.let { return it }
|
||||||
|
location.subAdminArea?.let { return it }
|
||||||
|
} ?: "$lat, $long"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLatLongFromLocationString(location: String): Pair<Double, Double>{
|
||||||
|
val locations = geoCoder.getFromLocationName(location, 1)
|
||||||
|
|
||||||
|
locations?.takeIf { it.isNotEmpty() }?.get(0)?.let {
|
||||||
|
return Pair(it.latitude, it.longitude)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw IOException("No location found")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network
|
||||||
|
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
abstract class ResponseUnwrap {
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
|
suspend fun <T : Any> responseUnwrap(
|
||||||
|
call: suspend () -> Response<T>
|
||||||
|
): T {
|
||||||
|
|
||||||
|
val response = call.invoke()
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
return response.body()!!
|
||||||
|
} else {
|
||||||
|
val error = response.errorBody()?.string()
|
||||||
|
|
||||||
|
val errorMessage = error?.let {
|
||||||
|
try {
|
||||||
|
JSONObject(it).getString("message")
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} ?: "Error Code: ${response.code()}"
|
||||||
|
|
||||||
|
throw IOException(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors.NetworkConnectionInterceptor
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors.QueryParamsInterceptor
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.WeatherResponse
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
||||||
|
interface WeatherApi {
|
||||||
|
|
||||||
|
@GET("onecall?")
|
||||||
|
suspend fun getFromApi(
|
||||||
|
@Query("lat") query: String,
|
||||||
|
@Query("lon") lon: String,
|
||||||
|
@Query("exclude") exclude: String = "hourly,minutely",
|
||||||
|
@Query("units") units: String = "metric"
|
||||||
|
): Response<WeatherResponse>
|
||||||
|
|
||||||
|
// invoke method creating an invocation of the api call
|
||||||
|
companion object{
|
||||||
|
operator fun invoke(
|
||||||
|
// injected @params
|
||||||
|
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||||
|
queryParamsInterceptor: QueryParamsInterceptor
|
||||||
|
) : WeatherApi {
|
||||||
|
|
||||||
|
|
||||||
|
val baseUrl = "https://api.openweathermap.org/data/2.5/"
|
||||||
|
|
||||||
|
// okHttpClient with interceptors
|
||||||
|
val okkHttpclient = OkHttpClient.Builder()
|
||||||
|
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||||
|
.addInterceptor(queryParamsInterceptor)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// creation of retrofit class
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.client(okkHttpclient)
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create(WeatherApi::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class NetworkConnectionInterceptor(
|
||||||
|
context: Context
|
||||||
|
) : Interceptor {
|
||||||
|
|
||||||
|
private val applicationContext = context.applicationContext
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
|
||||||
|
if (!isInternetAvailable()){
|
||||||
|
throw IOException("Make sure you have an active data connection")
|
||||||
|
}
|
||||||
|
return chain.proceed(chain.request())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isInternetAvailable(): Boolean {
|
||||||
|
var result = false
|
||||||
|
val connectivityManager =
|
||||||
|
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||||
|
connectivityManager?.let {
|
||||||
|
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||||
|
result = when {
|
||||||
|
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||||
|
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.interceptors
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.BuildConfig
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor used to add default query parameters to api calls
|
||||||
|
*/
|
||||||
|
class QueryParamsInterceptor : Interceptor{
|
||||||
|
|
||||||
|
val id = BuildConfig.ParamOne
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val original = chain.request()
|
||||||
|
val originalHttpUrl = original.url()
|
||||||
|
|
||||||
|
val url = originalHttpUrl.newBuilder()
|
||||||
|
.addQueryParameter("appid", id)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// Request customization: add request headers
|
||||||
|
// Request customization: add request headers
|
||||||
|
val requestBuilder: Request.Builder = original.newBuilder()
|
||||||
|
.url(url)
|
||||||
|
|
||||||
|
val request: Request = requestBuilder.build()
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class Current(
|
||||||
|
|
||||||
|
@field:SerializedName("sunrise")
|
||||||
|
val sunrise: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("temp")
|
||||||
|
val temp: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("visibility")
|
||||||
|
val visibility: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("uvi")
|
||||||
|
val uvi: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("pressure")
|
||||||
|
val pressure: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("clouds")
|
||||||
|
val clouds: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("feels_like")
|
||||||
|
val feelsLike: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("dt")
|
||||||
|
val dt: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("wind_deg")
|
||||||
|
val windDeg: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("dew_point")
|
||||||
|
val dewPoint: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("sunset")
|
||||||
|
val sunset: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("weather")
|
||||||
|
val weather: List<WeatherItem?>? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("humidity")
|
||||||
|
val humidity: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("wind_speed")
|
||||||
|
val windSpeed: Double? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class DailyItem(
|
||||||
|
|
||||||
|
@field:SerializedName("sunrise")
|
||||||
|
val sunrise: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("temp")
|
||||||
|
val temp: Temp? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("uvi")
|
||||||
|
val uvi: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("pressure")
|
||||||
|
val pressure: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("clouds")
|
||||||
|
val clouds: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("feels_like")
|
||||||
|
val feelsLike: FeelsLike? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("dt")
|
||||||
|
val dt: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("pop")
|
||||||
|
val pop: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("wind_deg")
|
||||||
|
val windDeg: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("dew_point")
|
||||||
|
val dewPoint: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("sunset")
|
||||||
|
val sunset: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("weather")
|
||||||
|
val weather: List<WeatherItem?>? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("humidity")
|
||||||
|
val humidity: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("wind_speed")
|
||||||
|
val windSpeed: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("rain")
|
||||||
|
val rain: Double? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class FeelsLike(
|
||||||
|
|
||||||
|
@field:SerializedName("eve")
|
||||||
|
val eve: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("night")
|
||||||
|
val night: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("day")
|
||||||
|
val day: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("morn")
|
||||||
|
val morn: Double? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class Response(
|
||||||
|
|
||||||
|
@field:SerializedName("current")
|
||||||
|
val current: Current? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("timezone")
|
||||||
|
val timezone: String? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("timezone_offset")
|
||||||
|
val timezoneOffset: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("daily")
|
||||||
|
val daily: List<DailyItem?>? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("lon")
|
||||||
|
val lon: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("lat")
|
||||||
|
val lat: Double? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class Temp(
|
||||||
|
|
||||||
|
@field:SerializedName("min")
|
||||||
|
val min: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("max")
|
||||||
|
val max: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("eve")
|
||||||
|
val eve: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("night")
|
||||||
|
val night: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("day")
|
||||||
|
val day: Double? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("morn")
|
||||||
|
val morn: Double? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class WeatherItem(
|
||||||
|
|
||||||
|
@field:SerializedName("icon")
|
||||||
|
val icon: String? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("description")
|
||||||
|
val description: String? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("main")
|
||||||
|
val main: String? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("id")
|
||||||
|
val id: Int? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class WeatherResponse(
|
||||||
|
|
||||||
|
@field:SerializedName("current")
|
||||||
|
val current: Current? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("timezone")
|
||||||
|
val timezone: String? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("timezone_offset")
|
||||||
|
val timezoneOffset: Int? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("daily")
|
||||||
|
val daily: List<DailyItem>? = null,
|
||||||
|
|
||||||
|
@field:SerializedName("lon")
|
||||||
|
val lon: Double = 0.00,
|
||||||
|
|
||||||
|
@field:SerializedName("lat")
|
||||||
|
val lat: Double = 0.00
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.CURRENT_LOCATION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared preferences to save & load last timestamp
|
||||||
|
*/
|
||||||
|
const val LOCATION_CONST = "location_"
|
||||||
|
class PreferenceProvider(
|
||||||
|
context: Context
|
||||||
|
){
|
||||||
|
|
||||||
|
private val appContext = context.applicationContext
|
||||||
|
|
||||||
|
private val preference: SharedPreferences
|
||||||
|
get() = PreferenceManager.getDefaultSharedPreferences(appContext)
|
||||||
|
|
||||||
|
fun saveLastSavedAt(locationName: String) {
|
||||||
|
preference.edit().putLong(
|
||||||
|
locationName,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLastSavedAt(locationName: String): Long? {
|
||||||
|
return preference.getLong(locationName, 0L)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAllKeys() = preference.all.keys.apply {
|
||||||
|
remove(CURRENT_LOCATION)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteLocation(locationName: String){
|
||||||
|
preference.edit().remove(locationName).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.repository
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.WeatherResponse
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.EntityItem
|
||||||
|
|
||||||
|
interface Repository {
|
||||||
|
|
||||||
|
suspend fun getWeatherFromApi(lat: String, long: String): WeatherResponse
|
||||||
|
suspend fun saveCurrentWeatherToRoom(locationId: String, weatherResponse: WeatherResponse)
|
||||||
|
suspend fun saveWeatherListToRoom(list: List<EntityItem>)
|
||||||
|
fun loadAllWeatherExceptCurrentFromRoom(): LiveData<List<EntityItem>>
|
||||||
|
fun loadCurrentWeatherFromRoom(id: String): LiveData<EntityItem>
|
||||||
|
fun isSearchValid(locationName: String): Boolean
|
||||||
|
fun saveLastSavedAt(locationName: String)
|
||||||
|
suspend fun deleteSavedWeatherEntry(locationName: String)
|
||||||
|
fun getSavedLocations(): List<String>
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.repository
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.ResponseUnwrap
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.WeatherApi
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.WeatherResponse
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.prefs.LOCATION_CONST
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.prefs.PreferenceProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.AppDatabase
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.EntityItem
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.FullWeather
|
||||||
|
|
||||||
|
private const val FIVE_MINS = 300000L
|
||||||
|
class RepositoryImpl(
|
||||||
|
private val api: WeatherApi,
|
||||||
|
private val db: AppDatabase,
|
||||||
|
private val prefs: PreferenceProvider
|
||||||
|
) : Repository, ResponseUnwrap() {
|
||||||
|
|
||||||
|
override suspend fun getWeatherFromApi(
|
||||||
|
lat: String,
|
||||||
|
long: String
|
||||||
|
): WeatherResponse {
|
||||||
|
return responseUnwrap { api.getFromApi(lat, long) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun saveCurrentWeatherToRoom(
|
||||||
|
locationId: String,
|
||||||
|
weatherResponse: WeatherResponse
|
||||||
|
){
|
||||||
|
val entity = EntityItem(
|
||||||
|
locationId,
|
||||||
|
FullWeather(weatherResponse)
|
||||||
|
)
|
||||||
|
db.getSimpleDao().upsertFullWeather(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun saveWeatherListToRoom(
|
||||||
|
list: List<EntityItem>
|
||||||
|
){
|
||||||
|
db.getSimpleDao().upsertListOfFullWeather(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadAllWeatherExceptCurrentFromRoom() = db.getSimpleDao().getAllFullWeatherWithoutCurrent()
|
||||||
|
|
||||||
|
override fun loadCurrentWeatherFromRoom(id: String) = db.getSimpleDao().getCurrentFullWeather(id)
|
||||||
|
|
||||||
|
override fun isSearchValid(locationName: String): Boolean {
|
||||||
|
val lastSaved = prefs.getLastSavedAt(locationName) ?: return true
|
||||||
|
val difference = System.currentTimeMillis() - lastSaved
|
||||||
|
return difference > FIVE_MINS
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveLastSavedAt(locationName: String) {
|
||||||
|
prefs.saveLastSavedAt("$LOCATION_CONST$locationName")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteSavedWeatherEntry(locationName: String){
|
||||||
|
db.getSimpleDao().deleteEntry(locationName)
|
||||||
|
prefs.deleteLocation(locationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSavedLocations(): List<String> {
|
||||||
|
return prefs.getAllKeys().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.room
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.EntityItem
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [EntityItem::class],
|
||||||
|
version = 1
|
||||||
|
)
|
||||||
|
@TypeConverters(Converter::class)
|
||||||
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
abstract fun getSimpleDao(): WeatherDao
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var instance: AppDatabase? = null
|
||||||
|
private val LOCK = Any()
|
||||||
|
|
||||||
|
// create an instance of room database or use previously created instance
|
||||||
|
operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
|
||||||
|
instance ?: buildDatabase(context).also {
|
||||||
|
instance = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDatabase(context: Context) =
|
||||||
|
Room.databaseBuilder(
|
||||||
|
context.applicationContext,
|
||||||
|
AppDatabase::class.java,
|
||||||
|
"MyDatabase.db"
|
||||||
|
).addTypeConverter(Converter(context))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.room
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.ProvidedTypeConverter
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.FullWeather
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.kodein
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
@ProvidedTypeConverter
|
||||||
|
class Converter(context: Context): KodeinAware{
|
||||||
|
override val kodein by kodein(context)
|
||||||
|
private val gson by instance<Gson>()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fullWeatherToString(fullWeather: FullWeather): String{
|
||||||
|
return gson.toJson(fullWeather)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun stringToFullWeather(string: String): FullWeather{
|
||||||
|
return gson.fromJson(string, FullWeather::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.room
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.CURRENT_LOCATION
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.EntityItem
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface WeatherDao {
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun upsertFullWeather(item: EntityItem)
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun upsertListOfFullWeather(items: List<EntityItem>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM EntityItem WHERE id = :userId LIMIT 1")
|
||||||
|
fun getCurrentFullWeather(userId: String) : LiveData<EntityItem>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM EntityItem WHERE id != :id")
|
||||||
|
fun getAllFullWeatherWithoutCurrent(id: String = CURRENT_LOCATION) : LiveData<List<EntityItem>>
|
||||||
|
|
||||||
|
@Query("DELETE FROM EntityItem WHERE id = :userId")
|
||||||
|
suspend fun deleteEntry(userId: String)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.data.room.entity
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.FullWeather
|
||||||
|
|
||||||
|
|
||||||
|
const val CURRENT_LOCATION = "CurrentLocation"
|
||||||
|
@Entity
|
||||||
|
data class EntityItem(
|
||||||
|
@PrimaryKey(autoGenerate = false)
|
||||||
|
val id: String,
|
||||||
|
val weather: FullWeather
|
||||||
|
)
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.model.forecast
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.DailyWeather
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.toDayName
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.toDayString
|
||||||
|
|
||||||
|
data class Forecast(
|
||||||
|
val date: String?,
|
||||||
|
val day: String?,
|
||||||
|
val condition: String?,
|
||||||
|
val weatherIcon: String?,
|
||||||
|
val mainTemp: String?,
|
||||||
|
val minorTemp: String?,
|
||||||
|
val averageTemp: String?,
|
||||||
|
val windText: String?,
|
||||||
|
val precipitation: String?,
|
||||||
|
val humidity: String?,
|
||||||
|
val uvi: String?,
|
||||||
|
val sunrise: String?,
|
||||||
|
val sunset: String?
|
||||||
|
): Parcelable {
|
||||||
|
|
||||||
|
constructor(dailyWeather: DailyWeather) : this(
|
||||||
|
dailyWeather.dt?.toDayString(),
|
||||||
|
dailyWeather.dt?.toDayName(),
|
||||||
|
dailyWeather.description,
|
||||||
|
dailyWeather.icon,
|
||||||
|
dailyWeather.max?.toInt().toString(),
|
||||||
|
dailyWeather.min?.toInt().toString(),
|
||||||
|
dailyWeather.average?.toInt().toString(),
|
||||||
|
dailyWeather.windSpeed?.toInt().toString(),
|
||||||
|
(dailyWeather.pop?.times(100)).toString(),
|
||||||
|
dailyWeather.humidity?.toString(),
|
||||||
|
dailyWeather.uvi?.toInt().toString(),
|
||||||
|
dailyWeather.sunrise?.toString(),
|
||||||
|
dailyWeather.sunset?.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeString(date)
|
||||||
|
parcel.writeString(day)
|
||||||
|
parcel.writeString(condition)
|
||||||
|
parcel.writeString(weatherIcon)
|
||||||
|
parcel.writeString(mainTemp)
|
||||||
|
parcel.writeString(minorTemp)
|
||||||
|
parcel.writeString(averageTemp)
|
||||||
|
parcel.writeString(windText)
|
||||||
|
parcel.writeString(precipitation)
|
||||||
|
parcel.writeString(humidity)
|
||||||
|
parcel.writeString(uvi)
|
||||||
|
parcel.writeString(sunrise)
|
||||||
|
parcel.writeString(sunset)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object CREATOR : Parcelable.Creator<Forecast> {
|
||||||
|
override fun createFromParcel(parcel: Parcel): Forecast {
|
||||||
|
return Forecast(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<Forecast?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.model.forecast
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.FullWeather
|
||||||
|
|
||||||
|
|
||||||
|
data class WeatherDisplay(
|
||||||
|
val averageTemp: Double?,
|
||||||
|
var unit: String?,
|
||||||
|
var location: String?,
|
||||||
|
val iconURL: String?,
|
||||||
|
val description: String?,
|
||||||
|
val forecast: List<Forecast>?,
|
||||||
|
val windSpeed: String?,
|
||||||
|
val windDirection: String?,
|
||||||
|
val precipitation: String?,
|
||||||
|
val humidity: String?,
|
||||||
|
val clouds: String?,
|
||||||
|
val lat: Double = 0.00,
|
||||||
|
val lon: Double = 0.00
|
||||||
|
): Parcelable{
|
||||||
|
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.createTypedArrayList(Forecast),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(weather: FullWeather) : this(
|
||||||
|
weather.current?.temp,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
weather.current?.icon,
|
||||||
|
weather.current?.description,
|
||||||
|
weather.daily?.map { Forecast(it) },
|
||||||
|
weather.current?.windSpeed?.toString(),
|
||||||
|
weather.current?.windDeg?.toString(),
|
||||||
|
weather.daily?.get(0)?.pop?.toString(),
|
||||||
|
weather.current?.humidity?.toString(),
|
||||||
|
weather.current?.clouds?.toString(),
|
||||||
|
weather.lat,
|
||||||
|
weather.lon
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeValue(averageTemp)
|
||||||
|
parcel.writeString(unit)
|
||||||
|
parcel.writeString(location)
|
||||||
|
parcel.writeString(iconURL)
|
||||||
|
parcel.writeString(description)
|
||||||
|
parcel.writeTypedList(forecast)
|
||||||
|
parcel.writeString(windSpeed)
|
||||||
|
parcel.writeString(windDirection)
|
||||||
|
parcel.writeString(precipitation)
|
||||||
|
parcel.writeString(humidity)
|
||||||
|
parcel.writeString(clouds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object CREATOR : Parcelable.Creator<WeatherDisplay> {
|
||||||
|
override fun createFromParcel(parcel: Parcel): WeatherDisplay {
|
||||||
|
return WeatherDisplay(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<WeatherDisplay?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.model.weather
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.Current
|
||||||
|
|
||||||
|
data class Current(
|
||||||
|
val dt: Int? = null,
|
||||||
|
val sunrise: Int? = null,
|
||||||
|
val sunset: Int? = null,
|
||||||
|
val temp: Double? = null,
|
||||||
|
val visibility: Int? = null,
|
||||||
|
val uvi: Double? = null,
|
||||||
|
val pressure: Int? = null,
|
||||||
|
val clouds: Int? = null,
|
||||||
|
val feelsLike: Double? = null,
|
||||||
|
val windDeg: Int? = null,
|
||||||
|
val dewPoint: Double? = null,
|
||||||
|
val icon: String? = null,
|
||||||
|
val description: String? = null,
|
||||||
|
val main: String? = null,
|
||||||
|
val id: Int? = null,
|
||||||
|
val humidity: Int? = null,
|
||||||
|
val windSpeed: Double? = null
|
||||||
|
){
|
||||||
|
|
||||||
|
constructor(dailyItem: Current): this(
|
||||||
|
dailyItem.dt,
|
||||||
|
dailyItem.sunrise,
|
||||||
|
dailyItem.sunset,
|
||||||
|
dailyItem.temp,
|
||||||
|
dailyItem.visibility,
|
||||||
|
dailyItem.uvi,
|
||||||
|
dailyItem.pressure,
|
||||||
|
dailyItem.clouds,
|
||||||
|
dailyItem.feelsLike,
|
||||||
|
dailyItem.windDeg,
|
||||||
|
dailyItem.dewPoint,
|
||||||
|
dailyItem.weather?.get(0)?.icon?.let { "https://openweathermap.org/img/wn/${it}@4x.png" },
|
||||||
|
dailyItem.weather?.get(0)?.description,
|
||||||
|
dailyItem.weather?.get(0)?.main,
|
||||||
|
dailyItem.weather?.get(0)?.id,
|
||||||
|
dailyItem.humidity,
|
||||||
|
dailyItem.windSpeed
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.model.weather
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.DailyItem
|
||||||
|
|
||||||
|
|
||||||
|
data class DailyWeather(
|
||||||
|
val dt: Int?,
|
||||||
|
val sunrise: Int?,
|
||||||
|
val sunset: Int?,
|
||||||
|
val min: Double? = null,
|
||||||
|
val max: Double? = null,
|
||||||
|
val average: Double? = null,
|
||||||
|
var feelsLike: Double?,
|
||||||
|
val pressure: Int?,
|
||||||
|
val humidity: Int?,
|
||||||
|
val dewPoint: Double?,
|
||||||
|
val windSpeed: Double?,
|
||||||
|
val windDeg: Int?,
|
||||||
|
val icon: String? = null,
|
||||||
|
val description: String? = null,
|
||||||
|
val main: String? = null,
|
||||||
|
val id: Int? = null,
|
||||||
|
val clouds: Int?,
|
||||||
|
val pop: Double?,
|
||||||
|
val uvi: Double?,
|
||||||
|
val rain: Double?
|
||||||
|
){
|
||||||
|
|
||||||
|
constructor(dailyItem: DailyItem): this(
|
||||||
|
dailyItem.dt,
|
||||||
|
dailyItem.sunrise,
|
||||||
|
dailyItem.sunset,
|
||||||
|
dailyItem.temp?.min,
|
||||||
|
dailyItem.temp?.max,
|
||||||
|
dailyItem.temp?.day,
|
||||||
|
dailyItem.feelsLike?.day,
|
||||||
|
dailyItem.pressure,
|
||||||
|
dailyItem.humidity,
|
||||||
|
dailyItem.dewPoint,
|
||||||
|
dailyItem.windSpeed,
|
||||||
|
dailyItem.windDeg,
|
||||||
|
dailyItem.weather?.get(0)?.icon?.let { "https://openweathermap.org/img/wn/${it}@4x.png" },
|
||||||
|
dailyItem.weather?.get(0)?.description,
|
||||||
|
dailyItem.weather?.get(0)?.main,
|
||||||
|
dailyItem.weather?.get(0)?.id,
|
||||||
|
dailyItem.clouds,
|
||||||
|
dailyItem.pop,
|
||||||
|
dailyItem.uvi,
|
||||||
|
dailyItem.rain
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.model.weather
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.network.response.forecast.WeatherResponse
|
||||||
|
|
||||||
|
data class FullWeather(
|
||||||
|
val current: Current? = null,
|
||||||
|
val timezone: String? = null,
|
||||||
|
val timezoneOffset: Int? = null,
|
||||||
|
val daily: List<DailyWeather>? = null,
|
||||||
|
val lon: Double = 0.00,
|
||||||
|
val lat: Double = 0.00
|
||||||
|
){
|
||||||
|
|
||||||
|
constructor(weatherResponse: WeatherResponse): this(
|
||||||
|
weatherResponse.current?.let { Current(it) },
|
||||||
|
weatherResponse.timezone,
|
||||||
|
weatherResponse.timezoneOffset,
|
||||||
|
weatherResponse.daily?.map { DailyWeather(it) },
|
||||||
|
weatherResponse.lon,
|
||||||
|
weatherResponse.lat
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.Event
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.displayToast
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.hide
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.show
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
abstract class BaseFragment: Fragment(){
|
||||||
|
|
||||||
|
// toggle visibility of progress spinner while async operations are taking place
|
||||||
|
fun progressBarStateObserver(progressBar: View) = Observer<Event<Boolean>> {
|
||||||
|
when(it.getContentIfNotHandled()){
|
||||||
|
true -> {
|
||||||
|
progressBar.show()
|
||||||
|
}
|
||||||
|
false -> {
|
||||||
|
progressBar.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// display a toast when operation fails
|
||||||
|
fun errorObserver() = Observer<Event<String>> {
|
||||||
|
it.getContentIfNotHandled()?.let { message ->
|
||||||
|
displayToast(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
fun getPermissionResult(
|
||||||
|
permission: String,
|
||||||
|
permissionCode: Int,
|
||||||
|
permissionGranted: () -> Unit
|
||||||
|
){
|
||||||
|
if (ActivityCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestPermissions(arrayOf(permission), permissionCode)
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
CoroutineScope(Dispatchers.Main).launch{
|
||||||
|
permissionGranted.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.ui.AppBarConfiguration
|
||||||
|
import androidx.navigation.ui.setupActionBarWithNavController
|
||||||
|
import androidx.navigation.ui.setupWithNavController
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.InfoActivity
|
||||||
|
import com.appttude.h_mal.atlas_weather.legacy.ui.UnitSettingsActivity
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.ui.home.BaseActivity
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
import kotlinx.android.synthetic.main.activity_main_navigation.*
|
||||||
|
|
||||||
|
private const val PERMISSION_LOCATION = 500
|
||||||
|
class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main_navigation)
|
||||||
|
|
||||||
|
val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
|
val navHost = supportFragmentManager
|
||||||
|
.findFragmentById(R.id.container) as NavHostFragment
|
||||||
|
val navController = navHost.navController
|
||||||
|
navController.setGraph(R.navigation.main_navigation)
|
||||||
|
|
||||||
|
setupBottomBar(navView, navController)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupBottomBar(navView: BottomNavigationView, navController: NavController) {
|
||||||
|
val tabs = setOf(R.id.nav_home, R.id.nav_world)
|
||||||
|
val appBarConfiguration = AppBarConfiguration(tabs)
|
||||||
|
|
||||||
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
|
navView.setupWithNavController(navController)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
menuInflater.inflate(R.menu.menu_main, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_settings -> {
|
||||||
|
val i = Intent(this, UnitSettingsActivity::class.java)
|
||||||
|
startActivity(i)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_into -> {
|
||||||
|
val infoActivity = Intent(this, InfoActivity::class.java)
|
||||||
|
startActivity(infoActivity)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.Forecast
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.generateView
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.loadImage
|
||||||
|
|
||||||
|
class WeatherRecyclerAdapter(
|
||||||
|
val itemClick: (Forecast) -> Unit
|
||||||
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
var weather: WeatherDisplay? = null
|
||||||
|
|
||||||
|
fun addCurrent(current: WeatherDisplay){
|
||||||
|
weather = current
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
return when (getDataType(viewType)){
|
||||||
|
is ViewType.Empty -> {
|
||||||
|
val emptyViewHolder = View(parent.context)
|
||||||
|
EmptyViewHolder(emptyViewHolder)
|
||||||
|
}
|
||||||
|
is ViewType.Current -> {
|
||||||
|
val viewCurrent = parent.generateView(R.layout.list_item4)
|
||||||
|
ViewHolderCurrent(viewCurrent)
|
||||||
|
}
|
||||||
|
is ViewType.Forecast -> {
|
||||||
|
val viewForecast = parent.generateView(R.layout.list_item_layout2)
|
||||||
|
ViewHolderForecast(viewForecast)
|
||||||
|
}
|
||||||
|
is ViewType.Further -> {
|
||||||
|
val viewFurther = parent.generateView(R.layout.list_item3)
|
||||||
|
ViewHolderFurtherDetails(viewFurther)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ViewType{
|
||||||
|
object Empty : ViewType()
|
||||||
|
object Current : ViewType()
|
||||||
|
object Forecast : ViewType()
|
||||||
|
object Further : ViewType()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDataType(type: Int): ViewType{
|
||||||
|
return when (type){
|
||||||
|
0 -> ViewType.Empty
|
||||||
|
1 -> ViewType.Current
|
||||||
|
2 -> ViewType.Forecast
|
||||||
|
3 -> ViewType.Further
|
||||||
|
else -> ViewType.Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
if (weather == null) return 0
|
||||||
|
|
||||||
|
return when(position){
|
||||||
|
0 -> 1
|
||||||
|
in 1 until itemCount -2 -> 2
|
||||||
|
itemCount - 1 -> 3
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
when (getDataType(getItemViewType(position))){
|
||||||
|
is ViewType.Empty -> {
|
||||||
|
holder as EmptyViewHolder
|
||||||
|
|
||||||
|
}
|
||||||
|
is ViewType.Current -> {
|
||||||
|
val viewHolderCurrent = holder as ViewHolderCurrent
|
||||||
|
viewHolderCurrent.bindData(weather)
|
||||||
|
}
|
||||||
|
is ViewType.Forecast -> {
|
||||||
|
val viewHolderForecast = holder as ViewHolderForecast
|
||||||
|
|
||||||
|
weather?.forecast?.get(position)?.let { i ->
|
||||||
|
viewHolderForecast.bindView(i)
|
||||||
|
viewHolderForecast.itemView.setOnClickListener {
|
||||||
|
itemClick(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ViewType.Further -> {
|
||||||
|
val viewHolderCurrent = holder as ViewHolderFurtherDetails
|
||||||
|
viewHolderCurrent.bindData(weather)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
if (weather == null) return 0
|
||||||
|
return 2 + (weather?.forecast?.size?: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ViewHolderCurrent(listItemView: View) : RecyclerView.ViewHolder(listItemView) {
|
||||||
|
|
||||||
|
var locationTV: TextView = listItemView.findViewById(R.id.location_main_4)
|
||||||
|
var conditionTV: TextView = listItemView.findViewById(R.id.condition_main_4)
|
||||||
|
var weatherIV: ImageView = listItemView.findViewById(R.id.icon_main_4)
|
||||||
|
var avgTempTV: TextView = listItemView.findViewById(R.id.temp_main_4)
|
||||||
|
var tempUnit: TextView = listItemView.findViewById(R.id.temp_unit_4)
|
||||||
|
|
||||||
|
fun bindData(weather: WeatherDisplay?){
|
||||||
|
locationTV.text = weather?.location
|
||||||
|
conditionTV.text = weather?.description
|
||||||
|
weatherIV.loadImage(weather?.iconURL)
|
||||||
|
avgTempTV.text = weather?.averageTemp?.toInt().toString()
|
||||||
|
tempUnit.text = weather?.unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ViewHolderForecast(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
|
var dateTV: TextView = itemView.findViewById(R.id.list_date)
|
||||||
|
var dayTV: TextView = itemView.findViewById(R.id.list_day)
|
||||||
|
var conditionTV: TextView = itemView.findViewById(R.id.list_condition)
|
||||||
|
var weatherIV: ImageView = itemView.findViewById(R.id.list_icon)
|
||||||
|
var mainTempTV: TextView = itemView.findViewById(R.id.list_main_temp)
|
||||||
|
var minorTempTV: TextView = itemView.findViewById(R.id.list_minor_temp)
|
||||||
|
|
||||||
|
fun bindView(forecast: Forecast?) {
|
||||||
|
dateTV.text = forecast?.date
|
||||||
|
dayTV.text = forecast?.day
|
||||||
|
conditionTV.text = forecast?.condition
|
||||||
|
weatherIV.loadImage(forecast?.weatherIcon)
|
||||||
|
mainTempTV.text = forecast?.mainTemp
|
||||||
|
minorTempTV.text = forecast?.minorTemp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ViewHolderFurtherDetails(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
|
var windSpeed: TextView = itemView.findViewById(R.id.windspeed)
|
||||||
|
var windDirection: TextView = itemView.findViewById(R.id.winddirection)
|
||||||
|
var precipitation: TextView = itemView.findViewById(R.id.precip_)
|
||||||
|
var humidity: TextView = itemView.findViewById(R.id.humidity_)
|
||||||
|
var clouds: TextView = itemView.findViewById(R.id.clouds_)
|
||||||
|
|
||||||
|
fun bindData(weather: WeatherDisplay?){
|
||||||
|
windSpeed.text = weather?.windSpeed
|
||||||
|
windDirection.text = weather?.windDirection
|
||||||
|
precipitation.text = weather?.precipitation
|
||||||
|
humidity.text = weather?.humidity
|
||||||
|
clouds.text = weather?.clouds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EmptyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.navigateTo
|
||||||
|
import kotlinx.android.synthetic.main.fragment_main.*
|
||||||
|
|
||||||
|
|
||||||
|
class WorldItemFragment : Fragment() {
|
||||||
|
private var param1: WeatherDisplay? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
param1 = WorldItemFragmentArgs.fromBundle(requireArguments()).weatherDisplay
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_home, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val recyclerAdapter = WeatherRecyclerAdapter {
|
||||||
|
val directions =
|
||||||
|
WorldItemFragmentDirections.actionWorldItemFragmentToFurtherDetailsFragment(it)
|
||||||
|
navigateTo(directions)
|
||||||
|
}
|
||||||
|
|
||||||
|
param1?.let { recyclerAdapter.addCurrent(it) }
|
||||||
|
|
||||||
|
forecast_listview.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = recyclerAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.details
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.Forecast
|
||||||
|
import kotlinx.android.synthetic.main.activity_further_info.*
|
||||||
|
|
||||||
|
|
||||||
|
private const val WEATHER = "param1"
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* Use the [FurtherInfoFragment.newInstance] factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class FurtherInfoFragment : Fragment() {
|
||||||
|
private var param1: Forecast? = null
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
param1 = FurtherInfoFragmentArgs.fromBundle(requireArguments()).forecast
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.activity_further_info, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
maxtemp.text = param1?.mainTemp
|
||||||
|
averagetemp.text = param1?.averageTemp
|
||||||
|
minimumtemp.text = param1?.minorTemp
|
||||||
|
windtext.text = param1?.windText
|
||||||
|
preciptext.text = param1?.precipitation
|
||||||
|
humiditytext.text = param1?.humidity
|
||||||
|
uvtext.text = param1?.uvi
|
||||||
|
sunrisetext.text = param1?.sunrise
|
||||||
|
sunsettext.text = param1?.sunset
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter 1.
|
||||||
|
* @return A new instance of fragment FurtherInfoFragment.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(param1: Parcelable) =
|
||||||
|
FurtherInfoFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putParcelable(WEATHER, param1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.home
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
abstract class BaseActivity : AppCompatActivity(){
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
fun getPermissionResult(
|
||||||
|
permission: String,
|
||||||
|
permissionCode: Int,
|
||||||
|
permissionGranted: () -> Unit
|
||||||
|
){
|
||||||
|
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestPermissions(arrayOf(permission), permissionCode)
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
CoroutineScope(Dispatchers.Main).launch{
|
||||||
|
permissionGranted.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.home
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.lifecycle.observe
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.application.LOCATION_PERMISSION_REQUEST
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.ui.BaseFragment
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.ui.WeatherRecyclerAdapter
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.displayToast
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.navigateTo
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.ApplicationViewModelFactory
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.MainViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_main.*
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.x.kodein
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class HomeFragment : BaseFragment(), KodeinAware {
|
||||||
|
override val kodein by kodein()
|
||||||
|
private val factory by instance<ApplicationViewModelFactory>()
|
||||||
|
|
||||||
|
private val viewModel by activityViewModels<MainViewModel> { factory }
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_home, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val recyclerAdapter = WeatherRecyclerAdapter {
|
||||||
|
val directions =
|
||||||
|
HomeFragmentDirections.actionHomeFragmentToFurtherDetailsFragment(it)
|
||||||
|
navigateTo(directions)
|
||||||
|
}
|
||||||
|
|
||||||
|
forecast_listview.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = recyclerAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
|
||||||
|
viewModel.fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
swipe_refresh.apply {
|
||||||
|
setOnRefreshListener {
|
||||||
|
viewModel.fetchData()
|
||||||
|
isRefreshing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherLiveData.observe(viewLifecycleOwner) {
|
||||||
|
recyclerAdapter.addCurrent(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar))
|
||||||
|
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner){
|
||||||
|
swipe_refresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
if (requestCode == LOCATION_PERMISSION_REQUEST) {
|
||||||
|
if (grantResults.isNotEmpty()
|
||||||
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
viewModel.fetchData()
|
||||||
|
displayToast("Permission granted")
|
||||||
|
} else {
|
||||||
|
displayToast("Permission denied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.world
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.observe
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.ui.BaseFragment
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.displayToast
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.goBack
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.ApplicationViewModelFactory
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.WorldViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.x.kodein
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
|
||||||
|
class AddLocationFragment : BaseFragment(), KodeinAware {
|
||||||
|
override val kodein by kodein()
|
||||||
|
private val factory by instance<ApplicationViewModelFactory>()
|
||||||
|
|
||||||
|
private val viewModel by viewModels<WorldViewModel> { factory }
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.activity_add_forecast, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
submit.setOnClickListener {
|
||||||
|
val locationName = location_name_tv.text?.trim()?.toString()
|
||||||
|
if (locationName.isNullOrBlank()){
|
||||||
|
submit.error = "Location cannot be blank"
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
viewModel.fetchDataForSingleLocation(locationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar))
|
||||||
|
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
||||||
|
|
||||||
|
viewModel.operationComplete.observe(viewLifecycleOwner) {
|
||||||
|
it?.getContentIfNotHandled()?.let {message ->
|
||||||
|
displayToast(message)
|
||||||
|
}
|
||||||
|
goBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.world
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.observe
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.ui.BaseFragment
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.navigateTo
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.ApplicationViewModelFactory
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.viewmodel.WorldViewModel
|
||||||
|
import kotlinx.android.synthetic.main.fragment_add_location.*
|
||||||
|
import org.kodein.di.KodeinAware
|
||||||
|
import org.kodein.di.android.x.kodein
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class WorldFragment : BaseFragment(), KodeinAware {
|
||||||
|
override val kodein by kodein()
|
||||||
|
private val factory by instance<ApplicationViewModelFactory>()
|
||||||
|
|
||||||
|
val viewModel by viewModels<WorldViewModel> { factory }
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_add_location, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val recyclerAdapter = WorldRecyclerAdapter{
|
||||||
|
val direction =
|
||||||
|
WorldFragmentDirections.actionWorldFragmentToWorldItemFragment(it)
|
||||||
|
navigateTo(direction)
|
||||||
|
}
|
||||||
|
|
||||||
|
world_recycler.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = recyclerAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherLiveData.observe(viewLifecycleOwner) {
|
||||||
|
recyclerAdapter.addCurrent(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
floatingActionButton.setOnClickListener{
|
||||||
|
navigateTo(R.id.action_worldFragment_to_addLocationFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar2))
|
||||||
|
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
viewModel.fetchAllLocations()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.ui.world
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.generateView
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.loadImage
|
||||||
|
|
||||||
|
class WorldRecyclerAdapter(
|
||||||
|
val itemClick: (WeatherDisplay) -> Unit
|
||||||
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
var weather: MutableList<WeatherDisplay> = mutableListOf()
|
||||||
|
|
||||||
|
fun addCurrent(current: List<WeatherDisplay>){
|
||||||
|
weather.clear()
|
||||||
|
weather.addAll(current)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
return when (getDataType(viewType)){
|
||||||
|
is ViewType.Empty -> {
|
||||||
|
val emptyViewHolder = View(parent.context)
|
||||||
|
EmptyViewHolder(emptyViewHolder)
|
||||||
|
}
|
||||||
|
is ViewType.Current -> {
|
||||||
|
val viewCurrent = parent.generateView(R.layout.db_list_item)
|
||||||
|
WorldHolderCurrent(viewCurrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ViewType{
|
||||||
|
object Empty : ViewType()
|
||||||
|
object Current : ViewType()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDataType(type: Int): ViewType{
|
||||||
|
return when (type){
|
||||||
|
0 -> ViewType.Empty
|
||||||
|
1 -> ViewType.Current
|
||||||
|
else -> ViewType.Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return if (weather.isEmpty()) 0 else 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
when (getDataType(getItemViewType(position))){
|
||||||
|
is ViewType.Empty -> {
|
||||||
|
holder as EmptyViewHolder
|
||||||
|
|
||||||
|
}
|
||||||
|
is ViewType.Current -> {
|
||||||
|
val viewHolderCurrent = holder as WorldHolderCurrent
|
||||||
|
viewHolderCurrent.bindData(weather[position])
|
||||||
|
viewHolderCurrent.itemView.setOnClickListener {
|
||||||
|
itemClick.invoke(weather[position])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return if (weather.size == 0) 1 else weather.size
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class WorldHolderCurrent(listItemView: View) : RecyclerView.ViewHolder(listItemView) {
|
||||||
|
|
||||||
|
var locationTV: TextView = listItemView.findViewById(R.id.db_location)
|
||||||
|
var conditionTV: TextView = listItemView.findViewById(R.id.db_condition)
|
||||||
|
var weatherIV: ImageView = listItemView.findViewById(R.id.db_icon)
|
||||||
|
var avgTempTV: TextView = listItemView.findViewById(R.id.db_main_temp)
|
||||||
|
var tempUnit: TextView = listItemView.findViewById(R.id.db_minor_temp)
|
||||||
|
|
||||||
|
fun bindData(weather: WeatherDisplay?){
|
||||||
|
locationTV.text = weather?.location
|
||||||
|
conditionTV.text = weather?.description
|
||||||
|
weatherIV.loadImage(weather?.iconURL)
|
||||||
|
avgTempTV.text = weather?.forecast?.get(0)?.mainTemp
|
||||||
|
tempUnit.text = weather?.unit
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal class EmptyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.utils
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used with livedata<T> to make observation lifecycle aware
|
||||||
|
* Display livedata response only once
|
||||||
|
*/
|
||||||
|
open class Event<out T>(private val content: T) {
|
||||||
|
|
||||||
|
var hasBeenHandled = false
|
||||||
|
private set // Allow external read but not write
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content and prevents its use again.
|
||||||
|
*/
|
||||||
|
fun getContentIfNotHandled(): T? {
|
||||||
|
return if (hasBeenHandled) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
hasBeenHandled = true
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.utils
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.NavDirections
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
|
||||||
|
fun Fragment.navigateToFragment(newFragment: Fragment){
|
||||||
|
childFragmentManager.beginTransaction()
|
||||||
|
.add(R.id.container, newFragment)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun View.navigateTo(navigationId: Int) {
|
||||||
|
Navigation.findNavController(this).navigate(navigationId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.navigateTo(navDirections: NavDirections) {
|
||||||
|
Navigation.findNavController(this).navigate(navDirections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.navigateTo(navigationId: Int) {
|
||||||
|
Navigation.findNavController(requireView()).navigate(navigationId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.navigateTo(navDirections: NavDirections) {
|
||||||
|
Navigation.findNavController(requireView()).navigate(navDirections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.goBack() = Navigation.findNavController(requireView()).popBackStack()
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.utils
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.time.temporal.ChronoUnit
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun Int.toDayString(): String {
|
||||||
|
return try {
|
||||||
|
val date = Date(this.makeMilliseconds())
|
||||||
|
val format = SimpleDateFormat("MMM d", Locale.getDefault())
|
||||||
|
format.format(date)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
"Unable to parse date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.makeMilliseconds(): Long = this * 1000L
|
||||||
|
|
||||||
|
fun Int.toDayName(): String {
|
||||||
|
return try {
|
||||||
|
val date = Date(this.makeMilliseconds())
|
||||||
|
val format = SimpleDateFormat("EEEE", Locale.getDefault())
|
||||||
|
format.format(date)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
"Unable to parse date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.changeDateFormat(): String {
|
||||||
|
return try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("dd MMMM, yyyy")
|
||||||
|
val date = LocalDate.parse(this)
|
||||||
|
date.format(formatter)
|
||||||
|
} else {
|
||||||
|
var format = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||||
|
val date = format.parse(this)
|
||||||
|
format = SimpleDateFormat("dd MMMM, yyyy", Locale.ENGLISH)
|
||||||
|
format.format(date)
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
"Unable to parse date"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.transformDateTimeString(): String {
|
||||||
|
return try {
|
||||||
|
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm", Locale.ENGLISH)
|
||||||
|
val outputFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm", Locale.ENGLISH)
|
||||||
|
val dateIn = inputFormat.parse(substringBeforeLast(":"))
|
||||||
|
outputFormat.format(dateIn)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.transformDateString(): String {
|
||||||
|
return try {
|
||||||
|
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm", Locale.ENGLISH)
|
||||||
|
val outputFormat = SimpleDateFormat("EEE, dd MMM yyyy", Locale.ENGLISH)
|
||||||
|
val dateIn = inputFormat.parse(substringBeforeLast(":"))
|
||||||
|
outputFormat.format(dateIn)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.transformPassportData(): String {
|
||||||
|
return try {
|
||||||
|
val formatIn = SimpleDateFormat("yyMMdd", Locale.ENGLISH)
|
||||||
|
val formatOut = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||||
|
val dateIn = formatIn.parse(this)
|
||||||
|
formatOut.format(dateIn)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.getYearsSinceNow(): String? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("dd MMMM, yyyy")
|
||||||
|
val now = LocalDate.now()
|
||||||
|
val date = LocalDate.parse(this, formatter)
|
||||||
|
ChronoUnit.YEARS.between(date, now).toString()
|
||||||
|
} else {
|
||||||
|
val now = Calendar.getInstance()
|
||||||
|
|
||||||
|
val date = Calendar.getInstance()
|
||||||
|
val simpleDateFormat = SimpleDateFormat("dd MMMM, yyyy", Locale.ENGLISH)
|
||||||
|
date.time = simpleDateFormat.parse(this)
|
||||||
|
val years = now.get(Calendar.YEAR) - date.get(Calendar.YEAR)
|
||||||
|
years.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String?.changeDateToSeconds(): Long {
|
||||||
|
// if (isNullOrBlank()){
|
||||||
|
// val time = System.currentTimeMillis() / 1000
|
||||||
|
// return time + 2592000
|
||||||
|
// }
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||||
|
val convertedCurrentDate = sdf.parse(this)
|
||||||
|
convertedCurrentDate.time / 1000
|
||||||
|
} catch (e: Exception) {
|
||||||
|
val time = System.currentTimeMillis() / 1000
|
||||||
|
time + 2592000
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
|
fun View.show() {
|
||||||
|
this.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.hide() {
|
||||||
|
this.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.displayToast(message: String) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.displayToast(message: String) {
|
||||||
|
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ImageView.loadImage(url: String?){
|
||||||
|
Picasso.get()
|
||||||
|
.load(url)
|
||||||
|
.placeholder(R.mipmap.ic_launcher)
|
||||||
|
.into(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ViewGroup.generateView(layoutId: Int): View = LayoutInflater
|
||||||
|
.from(context)
|
||||||
|
.inflate(layoutId, this, false)
|
||||||
|
|
||||||
|
fun ImageView.loadImage(url: String?, height: Int, width: Int){
|
||||||
|
Picasso.get()
|
||||||
|
.load(url)
|
||||||
|
.resize(width, height)
|
||||||
|
.centerCrop()
|
||||||
|
.placeholder(R.mipmap.ic_launcher)
|
||||||
|
.into(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SearchView.onSubmitListener(searchSubmit: (String) -> Unit) {
|
||||||
|
this.setOnQueryTextListener(object :
|
||||||
|
SearchView.OnQueryTextListener {
|
||||||
|
override fun onQueryTextSubmit(s: String): Boolean {
|
||||||
|
searchSubmit.invoke(s)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueryTextChange(s: String): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.RepositoryImpl
|
||||||
|
|
||||||
|
class ApplicationViewModelFactory(
|
||||||
|
private val locationProvider: LocationProvider,
|
||||||
|
private val repository: RepositoryImpl
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
with(modelClass){
|
||||||
|
return when{
|
||||||
|
isAssignableFrom(WorldViewModel::class.java) -> WorldViewModel(locationProvider, repository)
|
||||||
|
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(locationProvider, repository)
|
||||||
|
else -> throw IllegalArgumentException("Unknown ViewModel class")
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.viewmodel
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.Repository
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.CURRENT_LOCATION
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.Current
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.Event
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class MainViewModel(
|
||||||
|
private val locationProvider: LocationProvider,
|
||||||
|
private val repository: Repository
|
||||||
|
): ViewModel(){
|
||||||
|
|
||||||
|
val currentWeatherLiveData = MutableLiveData<Current>()
|
||||||
|
val weatherLiveData = MutableLiveData<WeatherDisplay>()
|
||||||
|
|
||||||
|
val operationState = MutableLiveData<Event<Boolean>>()
|
||||||
|
val operationError = MutableLiveData<Event<String>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
repository.loadCurrentWeatherFromRoom(CURRENT_LOCATION).observeForever {
|
||||||
|
it?.weather?.let { data ->
|
||||||
|
val list= WeatherDisplay(data).apply {
|
||||||
|
unit = "°C"
|
||||||
|
location = locationProvider.getLocationName(data.lat, data.lon)
|
||||||
|
}
|
||||||
|
|
||||||
|
weatherLiveData.postValue(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(value = Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
fun fetchData(){
|
||||||
|
if (!repository.isSearchValid(CURRENT_LOCATION)) return
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
operationState.postValue(Event(true))
|
||||||
|
try {
|
||||||
|
// Get location
|
||||||
|
val latLong = locationProvider.getLatLong()
|
||||||
|
// Get weather from api
|
||||||
|
val weather = repository
|
||||||
|
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
|
||||||
|
|
||||||
|
// Save data if not null
|
||||||
|
weather.let {
|
||||||
|
repository.saveLastSavedAt(CURRENT_LOCATION)
|
||||||
|
repository.saveCurrentWeatherToRoom(CURRENT_LOCATION, it)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}catch (e: IOException){
|
||||||
|
operationError.postValue(Event(e.message!!))
|
||||||
|
}finally {
|
||||||
|
operationState.postValue(Event(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.RepositoryImpl
|
||||||
|
|
||||||
|
class MainViewModelFactory(
|
||||||
|
private val locationProvider: LocationProvider,
|
||||||
|
private val repository: RepositoryImpl
|
||||||
|
) : ViewModelProvider.Factory{
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
|
||||||
|
return (MainViewModel(locationProvider, repository)) as T
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Unknown ViewModel class")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.Repository
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.room.entity.EntityItem
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.model.weather.FullWeather
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.utils.Event
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
|
||||||
|
class WorldViewModel(
|
||||||
|
private val locationProvider: LocationProvider,
|
||||||
|
private val repository: Repository
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
val weatherLiveData = MutableLiveData<List<WeatherDisplay>>()
|
||||||
|
|
||||||
|
val operationState = MutableLiveData<Event<Boolean>>()
|
||||||
|
val operationError = MutableLiveData<Event<String>>()
|
||||||
|
|
||||||
|
val operationComplete = MutableLiveData<Event<String>>()
|
||||||
|
|
||||||
|
private val weatherListLiveData = repository.loadAllWeatherExceptCurrentFromRoom()
|
||||||
|
|
||||||
|
init {
|
||||||
|
weatherListLiveData.observeForever {
|
||||||
|
val list = it.map { data ->
|
||||||
|
WeatherDisplay(data.weather).apply {
|
||||||
|
unit = "°C"
|
||||||
|
location = locationProvider.getLocationName(data.weather.lat, data.weather.lon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weatherLiveData.postValue(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchDataForSingleLocation(locationName: String) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
operationState.postValue(Event(true))
|
||||||
|
|
||||||
|
if (repository.getSavedLocations().contains(locationName)){
|
||||||
|
operationError.postValue(Event("$locationName already exists"))
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get location
|
||||||
|
val latLong =
|
||||||
|
locationProvider.getLatLongFromLocationString(locationName)
|
||||||
|
// Get weather from api
|
||||||
|
val weather = repository
|
||||||
|
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
|
||||||
|
|
||||||
|
// Save data if not null
|
||||||
|
weather.let {
|
||||||
|
repository.saveCurrentWeatherToRoom(locationName, it)
|
||||||
|
operationComplete.postValue(Event("$locationName saved"))
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
operationError.postValue(Event(e.message!!))
|
||||||
|
} finally {
|
||||||
|
operationState.postValue(Event(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchAllLocations() {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
operationState.postValue(Event(true))
|
||||||
|
try {
|
||||||
|
val list = mutableListOf<EntityItem>()
|
||||||
|
weatherLiveData.value?.forEach { weatherItem ->
|
||||||
|
// If search not valid move onto next in loop
|
||||||
|
weatherItem.location?.let {
|
||||||
|
if (!repository.isSearchValid(it)) return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val weather = repository
|
||||||
|
.getWeatherFromApi(weatherItem.lat.toString(), weatherItem.lon.toString())
|
||||||
|
|
||||||
|
weatherItem.location?.let { loc ->
|
||||||
|
repository.saveLastSavedAt(loc)
|
||||||
|
list.add(EntityItem(loc, FullWeather(weather)))
|
||||||
|
}
|
||||||
|
} catch (e: IOException) { }
|
||||||
|
}
|
||||||
|
repository.saveWeatherListToRoom(list)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
operationError.postValue(Event(e.message!!))
|
||||||
|
} finally {
|
||||||
|
operationState.postValue(Event(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.mvvm.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.location.LocationProvider
|
||||||
|
import com.appttude.h_mal.atlas_weather.mvvm.data.repository.RepositoryImpl
|
||||||
|
|
||||||
|
class WorldViewModelFactory(
|
||||||
|
private val locationProvider: LocationProvider,
|
||||||
|
private val repository: RepositoryImpl
|
||||||
|
) : ViewModelProvider.Factory{
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
if (modelClass.isAssignableFrom(WorldViewModel::class.java)) {
|
||||||
|
return (WorldViewModel(locationProvider, repository)) as T
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Unknown ViewModel class")
|
||||||
|
}
|
||||||
|
}
|
||||||
8
app/src/main/res/drawable/card_outlined.xml
Normal file
8
app/src/main/res/drawable/card_outlined.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<solid android:color="#F00" />
|
||||||
|
<size android:width="10dp"/>
|
||||||
|
<padding android:bottom="0dp" android:left="0dp" android:right="0dp" android:top="0dp"/>
|
||||||
|
<corners android:topLeftRadius="5dp" android:bottomLeftRadius="5dp"
|
||||||
|
android:topRightRadius="0.1dp" android:bottomRightRadius="0.1dp"/>
|
||||||
|
</shape>
|
||||||
5
app/src/main/res/drawable/ic_baseline_home_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_home_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_baseline_public_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_public_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
|
||||||
|
</vector>
|
||||||
@@ -3,17 +3,17 @@
|
|||||||
android:height="275dp"
|
android:height="275dp"
|
||||||
android:viewportWidth="94.0"
|
android:viewportWidth="94.0"
|
||||||
android:viewportHeight="275.0">
|
android:viewportHeight="275.0">
|
||||||
<!--<path-->
|
<path
|
||||||
<!--android:fillColor="#FF000000"-->
|
android:fillColor="#FF000000"
|
||||||
<!--android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121-->
|
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121
|
||||||
<!--45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968-->
|
45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968
|
||||||
<!--V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>-->
|
V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>
|
||||||
<!--<path-->
|
<path
|
||||||
<!--android:name="inner"-->
|
android:name="inner"
|
||||||
<!--android:fillColor="#ff0000"-->
|
android:fillColor="#ff0000"
|
||||||
<!--android:pathData="M305.949,424.6c0-1.9,0-1.9,0-3.799v-95.602c0-11.5-7.6-19.1-19.099-19.1c-11.5,0-19.1,7.6-19.1,19.1v95.602-->
|
android:pathData="M305.949,424.6c0-1.9,0-1.9,0-3.799v-95.602c0-11.5-7.6-19.1-19.099-19.1c-11.5,0-19.1,7.6-19.1,19.1v95.602
|
||||||
<!--c0,1.898,0,1.898,0,3.799c-23,7.701-38.2,28.701-38.2,53.5c0,32.5,24.9,57.4,57.4,57.4c32.499,0,57.399-24.9,57.399-57.4-->
|
c0,1.898,0,1.898,0,3.799c-23,7.701-38.2,28.701-38.2,53.5c0,32.5,24.9,57.4,57.4,57.4c32.499,0,57.399-24.9,57.399-57.4
|
||||||
<!--C344.25,453.301,328.949,432.301,305.949,424.6z"/>-->
|
C344.25,453.301,328.949,432.301,305.949,424.6z"/>
|
||||||
<path android:fillColor="#000000"
|
<path android:fillColor="#000000"
|
||||||
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121 45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968 V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>
|
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121 45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968 V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context=".AddForecast">
|
tools:context=".legacy.ui.AddForecastActivity">
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/pb_add"
|
android:id="@+id/pb_add"
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginLeft="12dp"
|
android:layout_marginLeft="24dp"
|
||||||
android:layout_marginRight="12dp"
|
android:layout_marginRight="12dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingBottom="@dimen/activity_horizontal_margin">
|
android:paddingBottom="@dimen/activity_horizontal_margin">
|
||||||
@@ -55,13 +54,22 @@
|
|||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_margin="12dp"
|
android:layout_marginRight="24dp"
|
||||||
|
android:layout_marginBottom="36dp"
|
||||||
android:background="@drawable/button_layout"
|
android:background="@drawable/button_layout"
|
||||||
android:text="@string/submit"
|
android:text="@string/submit"
|
||||||
android:textColor="#ffffff"
|
android:textColor="#ffffff"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
style="?android:attr/borderlessButtonStyle"/>
|
style="?android:attr/borderlessButtonStyle"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".FurtherInfoActivity">
|
tools:context=".legacy.ui.FurtherInfoActivity">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main_content"
|
android:id="@+id/main_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
tools:context="com.appttude.h_mal.atlas_weather.MainActivity">
|
tools:context=".legacy.ui.home.MainActivity">
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbar"
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:theme="@style/AppTheme.AppBarOverlay">
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
@@ -24,23 +25,29 @@
|
|||||||
tools:fontfamily="@font/archeologicaps"
|
tools:fontfamily="@font/archeologicaps"
|
||||||
tools:title="Atlas Weather">
|
tools:title="Atlas Weather">
|
||||||
|
|
||||||
</android.support.v7.widget.Toolbar>
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
<android.support.design.widget.TabLayout
|
<com.google.android.material.tabs.TabLayout
|
||||||
android:id="@+id/tabs"
|
android:id="@+id/tabs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:tab="hello"/>
|
tools:tab="hello"/>
|
||||||
|
|
||||||
</android.support.design.widget.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<android.support.v4.view.ViewPager
|
<androidx.viewpager.widget.ViewPager
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
|
||||||
|
|
||||||
</android.support.v4.view.ViewPager>
|
</androidx.viewpager.widget.ViewPager>
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_circular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|||||||
58
app/src/main/res/layout/activity_main_navigation.xml
Normal file
58
app/src/main/res/layout/activity_main_navigation.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?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:id="@+id/main_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||||
|
tools:title="Atlas Weather"/>
|
||||||
|
|
||||||
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
android:id="@+id/nav_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:background="?android:attr/windowBackground"
|
||||||
|
app:itemIconTint="@android:color/background_light"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:menu="@menu/tabs_menu" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/container"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:defaultNavHost="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/nav_view"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/toolbar"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_circular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:elevation="0.2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
@@ -7,13 +7,14 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="1dp">
|
android:padding="1dp">
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:cardBackgroundColor="@android:color/transparent"
|
|
||||||
app:cardCornerRadius="22dp"
|
app:cardCornerRadius="22dp"
|
||||||
card_view:cardElevation="1dp"
|
|
||||||
card_view:cardMaxElevation="1dp"
|
|
||||||
card_view:cardPreventCornerOverlap="false"
|
card_view:cardPreventCornerOverlap="false"
|
||||||
card_view:cardUseCompatPadding="true">
|
card_view:cardUseCompatPadding="true">
|
||||||
|
|
||||||
@@ -91,5 +92,5 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</android.support.v7.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.appttude.h_mal.atlas_weather.Fragment_Two">
|
tools:context=".legacy.ui.home.FragmentTwo">
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -12,43 +12,7 @@
|
|||||||
android:divider="@null">
|
android:divider="@null">
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:id="@+id/emptyView">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="64dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:alpha="0.8"
|
|
||||||
android:src="@drawable/triple"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="List Empty"
|
|
||||||
android:textSize="30sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/emptyViewText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="Add locations" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="64dp"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/floatingActionButton"
|
android:id="@+id/floatingActionButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
46
app/src/main/res/layout/fragment_add_location.xml
Normal file
46
app/src/main/res/layout/fragment_add_location.xml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?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=".legacy.ui.home.FragmentTwo">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:id="@+id/world_recycler"
|
||||||
|
android:divider="@null">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/floatingActionButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:layout_marginBottom="36dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:clickable="true"
|
||||||
|
app:srcCompat="@android:drawable/ic_input_add"
|
||||||
|
android:tint="@android:color/white"
|
||||||
|
app:elevation="0dp"
|
||||||
|
android:focusable="true" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar2"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
31
app/src/main/res/layout/fragment_home.xml
Normal file
31
app/src/main/res/layout/fragment_home.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/constraintLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".legacy.ui.home.MainActivity">
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/swipe_refresh">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/forecast_listview">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/constraintLayout"
|
android:id="@+id/constraintLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.appttude.h_mal.atlas_weather.MainActivity">
|
tools:context=".legacy.ui.home.MainActivity">
|
||||||
|
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/swipe_refresh">
|
android:id="@+id/swipe_refresh">
|
||||||
<android.support.v7.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/forecast_listview">
|
android:id="@+id/forecast_listview">
|
||||||
</android.support.v7.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
@@ -51,7 +50,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:id="@id/emptyViewText"
|
android:id="@+id/emptyViewText"
|
||||||
android:text="check connection or location settings" />
|
android:text="check connection or location settings" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|||||||
@@ -4,16 +4,16 @@
|
|||||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:padding="1dp">
|
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:cardBackgroundColor="@android:color/transparent"
|
|
||||||
app:cardCornerRadius="22dp"
|
app:cardCornerRadius="22dp"
|
||||||
card_view:cardElevation="1dp"
|
|
||||||
card_view:cardMaxElevation="1dp"
|
|
||||||
card_view:cardPreventCornerOverlap="false"
|
card_view:cardPreventCornerOverlap="false"
|
||||||
card_view:cardUseCompatPadding="true">
|
card_view:cardUseCompatPadding="true">
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/list_icon"
|
android:id="@+id/list_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
tools:src="@drawable/day_305" />
|
tools:src="@drawable/day_305" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -100,5 +100,5 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</android.support.v7.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context="com.appttude.h_mal.atlas_weather.MainActivity">
|
tools:context=".legacy.ui.home.MainActivity">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_settings"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="100"
|
||||||
|
|||||||
16
app/src/main/res/menu/tabs_menu.xml
Normal file
16
app/src/main/res/menu/tabs_menu.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_home"
|
||||||
|
android:icon="@drawable/ic_baseline_home_24"
|
||||||
|
android:title="@string/title_home"
|
||||||
|
app:showAsAction="ifRoom|withText"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_world"
|
||||||
|
android:icon="@drawable/ic_baseline_public_24"
|
||||||
|
android:title="@string/title_world"
|
||||||
|
app:showAsAction="always|withText"/>
|
||||||
|
|
||||||
|
</menu>
|
||||||
74
app/src/main/res/navigation/main_navigation.xml
Normal file
74
app/src/main/res/navigation/main_navigation.xml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation 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:id="@+id/main_navigation"
|
||||||
|
app:startDestination="@id/nav_home"
|
||||||
|
tools:ignore="UnusedNavigation">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_home"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.mvvm.ui.home.HomeFragment"
|
||||||
|
android:label="Home"
|
||||||
|
tools:layout="@layout/fragment_home">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_homeFragment_to_furtherDetailsFragment"
|
||||||
|
app:destination="@id/furtherDetailsFragment"
|
||||||
|
app:enterAnim="@anim/fragment_open_enter"
|
||||||
|
app:exitAnim="@anim/fragment_open_exit"
|
||||||
|
app:popEnterAnim="@anim/fragment_open_enter"
|
||||||
|
app:popExitAnim="@anim/fragment_open_exit" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/furtherDetailsFragment"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.mvvm.ui.details.FurtherInfoFragment"
|
||||||
|
android:label="Further Details">
|
||||||
|
<argument
|
||||||
|
android:name="forecast"
|
||||||
|
app:argType="com.appttude.h_mal.atlas_weather.mvvm.model.forecast.Forecast" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_world"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.mvvm.ui.world.WorldFragment"
|
||||||
|
android:label="World"
|
||||||
|
tools:layout="@layout/fragment__two">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_worldFragment_to_addLocationFragment"
|
||||||
|
app:destination="@id/addLocationFragment"
|
||||||
|
app:enterAnim="@anim/fragment_open_enter"
|
||||||
|
app:exitAnim="@anim/fragment_open_exit"
|
||||||
|
app:popEnterAnim="@anim/fragment_open_enter"
|
||||||
|
app:popExitAnim="@anim/fragment_open_exit" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_worldFragment_to_worldItemFragment"
|
||||||
|
app:destination="@id/worldItemFragment"
|
||||||
|
app:enterAnim="@anim/fragment_open_enter"
|
||||||
|
app:exitAnim="@anim/fragment_open_exit"
|
||||||
|
app:popEnterAnim="@anim/fragment_open_enter"
|
||||||
|
app:popExitAnim="@anim/fragment_open_exit" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/addLocationFragment"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.mvvm.ui.world.AddLocationFragment"
|
||||||
|
android:label="Add Weather Location"
|
||||||
|
tools:layout="@layout/activity_add_forecast" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/worldItemFragment"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.mvvm.ui.WorldItemFragment"
|
||||||
|
android:label="Overview"
|
||||||
|
tools:layout="@layout/fragment_home">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_worldItemFragment_to_furtherDetailsFragment"
|
||||||
|
app:destination="@id/furtherDetailsFragment"
|
||||||
|
app:enterAnim="@anim/fragment_open_enter"
|
||||||
|
app:exitAnim="@anim/fragment_open_exit"
|
||||||
|
app:popEnterAnim="@anim/fragment_open_enter"
|
||||||
|
app:popExitAnim="@anim/fragment_open_exit" />
|
||||||
|
<argument
|
||||||
|
android:name="weatherDisplay"
|
||||||
|
app:argType="com.appttude.h_mal.atlas_weather.mvvm.model.forecast.WeatherDisplay" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
</navigation>
|
||||||
@@ -139,4 +139,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string name="appwidget_text">EXAMPLE</string>
|
<string name="appwidget_text">EXAMPLE</string>
|
||||||
<string name="add_widget">Add widget</string>
|
<string name="add_widget">Add widget</string>
|
||||||
|
<string name="title_home">Home</string>
|
||||||
|
<string name="title_world">World</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user