mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2025-12-10 02:05:20 +00:00
Refactor flavours (#17)
- Fastlane completed - Circleci config completed - Flavours build completed
This commit is contained in:
@@ -14,18 +14,17 @@ commands:
|
|||||||
description: checkout repo and android dependencies
|
description: checkout repo and android dependencies
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- android/restore-gradle-cache
|
||||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
build_gradle:
|
||||||
- run:
|
description: Build the gradle
|
||||||
name: Chmod permissions
|
steps:
|
||||||
command: sudo chmod +x ./gradlew
|
- android/restore-gradle-cache
|
||||||
- run:
|
- run:
|
||||||
name: Download Dependencies
|
name: Download Dependencies
|
||||||
command: ./gradlew androidDependencies
|
command: |
|
||||||
- save_cache:
|
sudo chmod +x ./gradlew
|
||||||
paths:
|
./gradlew androidDependencies
|
||||||
- ~/.gradle
|
- android/save-gradle-cache
|
||||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
|
||||||
run_tests:
|
run_tests:
|
||||||
description: run tests for flavour specified
|
description: run tests for flavour specified
|
||||||
parameters:
|
parameters:
|
||||||
@@ -34,8 +33,11 @@ commands:
|
|||||||
default: "AtlasWeather"
|
default: "AtlasWeather"
|
||||||
steps:
|
steps:
|
||||||
# The next step will run the unit tests
|
# The next step will run the unit tests
|
||||||
- android/run-tests:
|
- build_gradle
|
||||||
test-command: ./gradlew test<< parameters.flavour >>DebugUnitTest --continue
|
- run:
|
||||||
|
name: Run non-instrumentation unit tests
|
||||||
|
command: |
|
||||||
|
./gradlew test<< parameters.flavour >>DebugUnitTest --continue
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: app/build/reports
|
path: app/build/reports
|
||||||
destination: reports
|
destination: reports
|
||||||
@@ -48,27 +50,47 @@ commands:
|
|||||||
type: string
|
type: string
|
||||||
default: "AtlasWeather"
|
default: "AtlasWeather"
|
||||||
steps:
|
steps:
|
||||||
|
- build_gradle
|
||||||
- android/start-emulator-and-run-tests:
|
- android/start-emulator-and-run-tests:
|
||||||
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
|
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
|
||||||
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
|
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
|
||||||
system-image: system-images;android-25;google_apis;x86
|
system-image: system-images;android-26;google_apis;x86
|
||||||
max-tries: 1
|
pull-data: true
|
||||||
kill-emulators: false
|
pull-data-path: /storage/emulated/0/Android/data/
|
||||||
- run:
|
pull-data-target: ~/app-data
|
||||||
name: Pull screenshots from device
|
restore-gradle-cache-prefix: v1a
|
||||||
command: |
|
|
||||||
mkdir ~/screenshots
|
|
||||||
adb pull /storage/emulated/0/Android/data/com.appttude.h_mal.atlas_weather/files/screengrab/en-US/images/screenshots ~/screenshots
|
|
||||||
when: on_fail
|
|
||||||
# store test reports
|
# store test reports
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: app/build/reports/androidTests/connected
|
path: app/build/reports/androidTests/connected
|
||||||
destination: reports
|
destination: reports
|
||||||
# store screenshots for failed ui tests
|
# store screenshots for failed ui tests
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ~/screenshots
|
path: ~/app-data
|
||||||
destination: screenshots
|
destination: screenshots
|
||||||
|
- store_test_results:
|
||||||
|
path: app/build/outputs/androidTest-results/connected
|
||||||
|
deploy_to_play_store:
|
||||||
|
description: deploy to playstore based on flavour
|
||||||
|
parameters:
|
||||||
|
flavour:
|
||||||
|
type: string
|
||||||
|
default: "AtlasWeather"
|
||||||
|
steps:
|
||||||
|
# The next step will run the unit tests
|
||||||
|
- android/decode-keystore:
|
||||||
|
keystore-location: "./app/keystore.jks"
|
||||||
|
- run:
|
||||||
|
name: Setup playstore key
|
||||||
|
command: |
|
||||||
|
echo "$GOOGLE_PLAY_KEY" > "google-play-key.json"
|
||||||
|
- build_gradle
|
||||||
|
- run:
|
||||||
|
name: Run fastlane command to deploy to playstore
|
||||||
|
command: |
|
||||||
|
pwd
|
||||||
|
bundle exec fastlane deploy<< parameters.flavour >>
|
||||||
|
- store_test_results:
|
||||||
|
path: fastlane/report.xml
|
||||||
# Define a job to be invoked later in a workflow.
|
# Define a job to be invoked later in a workflow.
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
||||||
jobs:
|
jobs:
|
||||||
@@ -90,39 +112,56 @@ jobs:
|
|||||||
- setup_repo
|
- setup_repo
|
||||||
- run_tests:
|
- run_tests:
|
||||||
flavour: << parameters.flavour >>
|
flavour: << parameters.flavour >>
|
||||||
ui-test-and-release:
|
- run_ui_tests:
|
||||||
# Parameters used for determining
|
flavour: << parameters.flavour >>
|
||||||
|
deploy-to-playstore:
|
||||||
parameters:
|
parameters:
|
||||||
flavour:
|
flavour:
|
||||||
type: string
|
type: string
|
||||||
default: "AtlasWeather"
|
default: "Driver"
|
||||||
executor:
|
docker:
|
||||||
name: android/android-machine
|
- image: cimg/android:2023.07-browsers
|
||||||
tag: 2023.05.1
|
auth:
|
||||||
|
username: ${DOCKER_USERNAME}
|
||||||
|
password: ${DOCKER_PASSWORD}
|
||||||
steps:
|
steps:
|
||||||
- setup_repo
|
- setup_repo
|
||||||
- run_ui_tests
|
- deploy_to_play_store:
|
||||||
- run:
|
flavour: << parameters.flavour >>
|
||||||
name: Setup variables for release
|
|
||||||
command: |
|
|
||||||
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "android/app/release_keystore.jks"
|
|
||||||
echo "$GOOGLE_PLAY_KEY" > "android/playstore.json"
|
|
||||||
# And finally run the release build
|
|
||||||
- run:
|
|
||||||
name: Assemble and Upload to PlayStore
|
|
||||||
command: |
|
|
||||||
pwd
|
|
||||||
bundle exec fastlane deploy<< parameters.flavour >>
|
|
||||||
|
|
||||||
# Invoke jobs via workflows
|
# Invoke jobs via workflows
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
|
build-release-mono:
|
||||||
|
jobs:
|
||||||
|
- build-and-test:
|
||||||
|
context: appttude
|
||||||
|
flavour: "MonoWeather"
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- main_atlas
|
||||||
|
- deploy-to-playstore:
|
||||||
|
context: appttude
|
||||||
|
flavour: "MonoWeather"
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- main_mono
|
||||||
|
requires:
|
||||||
|
- build-and-test
|
||||||
build-release-atlas:
|
build-release-atlas:
|
||||||
jobs:
|
jobs:
|
||||||
- build-and-test:
|
- build-and-test:
|
||||||
|
context: appttude
|
||||||
flavour: "AtlasWeather"
|
flavour: "AtlasWeather"
|
||||||
- ui-test-and-release:
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- main_mono
|
||||||
|
- deploy-to-playstore:
|
||||||
|
context: appttude
|
||||||
flavour: "AtlasWeather"
|
flavour: "AtlasWeather"
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
@@ -130,14 +169,3 @@ workflows:
|
|||||||
- main_atlas
|
- main_atlas
|
||||||
requires:
|
requires:
|
||||||
- build-and-test
|
- build-and-test
|
||||||
build-release-mono:
|
|
||||||
jobs:
|
|
||||||
- build-and-test:
|
|
||||||
flavour: "MonoWeather"
|
|
||||||
- ui-test-and-release:
|
|
||||||
flavour: "MonoWeather"
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only: main_admin
|
|
||||||
requires:
|
|
||||||
- build-and-test
|
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -88,3 +88,11 @@ gen-external-apklibs
|
|||||||
.idea/assetWizardSettings.xml
|
.idea/assetWizardSettings.xml
|
||||||
.idea/gradle.xml
|
.idea/gradle.xml
|
||||||
.idea/jarRepositorie
|
.idea/jarRepositorie
|
||||||
|
|
||||||
|
# Gem/fastlane
|
||||||
|
/Gemfile.lock
|
||||||
|
/fastlane/report.xml
|
||||||
|
# Google play files
|
||||||
|
/google-play-key.json
|
||||||
|
|
||||||
|
/.idea/androidTestResultsUserPreferences.xml
|
||||||
|
|||||||
113
.idea/androidTestResultsUserPreferences.xml
generated
Normal file
113
.idea/androidTestResultsUserPreferences.xml
generated
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AndroidTestResultsUserPreferences">
|
||||||
|
<option name="androidTestResultsTableState">
|
||||||
|
<map>
|
||||||
|
<entry key="-2146704034">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="-2008434490">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="-409920851">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="170536241">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="287238248">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="408375334">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="1127175145">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="1256180664">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
24
.idea/codeStyles/Project.xml
generated
24
.idea/codeStyles/Project.xml
generated
@@ -1,24 +1,13 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
<value>
|
|
||||||
<package name="java.util" alias="false" withSubpackages="false" />
|
|
||||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
|
||||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
|
||||||
<value>
|
|
||||||
<package name="" alias="false" withSubpackages="true" />
|
|
||||||
<package name="java" alias="false" withSubpackages="true" />
|
|
||||||
<package name="javax" alias="false" withSubpackages="true" />
|
|
||||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
|
||||||
<package name="" alias="true" withSubpackages="true" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<codeStyleSettings language="XML">
|
<codeStyleSettings language="XML">
|
||||||
|
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
<arrangement>
|
<arrangement>
|
||||||
<rules>
|
<rules>
|
||||||
<section>
|
<section>
|
||||||
@@ -127,5 +116,8 @@
|
|||||||
</rules>
|
</rules>
|
||||||
</arrangement>
|
</arrangement>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</codeStyleSettings>
|
||||||
</code_scheme>
|
</code_scheme>
|
||||||
</component>
|
</component>
|
||||||
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="KotlinJpsPluginSettings">
|
||||||
|
<option name="version" value="1.6.0" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
21
.idea/navEditor.xml
generated
21
.idea/navEditor.xml
generated
@@ -79,6 +79,18 @@
|
|||||||
</LayoutPositions>
|
</LayoutPositions>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="settings_fragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="12" />
|
||||||
|
<option name="y" value="12" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="worldItemFragment">
|
<entry key="worldItemFragment">
|
||||||
<value>
|
<value>
|
||||||
<LayoutPositions>
|
<LayoutPositions>
|
||||||
@@ -88,6 +100,15 @@
|
|||||||
<option name="y" value="408" />
|
<option name="y" value="408" />
|
||||||
</Point>
|
</Point>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="action_worldItemFragment_to_furtherDetailsFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
</LayoutPositions>
|
</LayoutPositions>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ android {
|
|||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
|
freeCompilerArgs += [
|
||||||
|
'-Xjvm-default=enable'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "default"
|
flavorDimensions "default"
|
||||||
@@ -71,7 +74,7 @@ android {
|
|||||||
versionName "3.0.0"
|
versionName "3.0.0"
|
||||||
}
|
}
|
||||||
monoWeather {
|
monoWeather {
|
||||||
applicationId "com.appttude.h_mal.atlas_weather.monoWeather"
|
applicationId "com.appttude.h_mal.monoWeather"
|
||||||
versionCode 5
|
versionCode 5
|
||||||
versionName "3.0.0"
|
versionName "3.0.0"
|
||||||
}
|
}
|
||||||
@@ -106,16 +109,17 @@ dependencies {
|
|||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
|
||||||
implementation 'androidx.test.espresso:espresso-idling-resource:3.4.0'
|
implementation 'androidx.test.espresso:espresso-idling-resource:3.4.0'
|
||||||
|
implementation 'androidx.preference:preference:1.2.1'
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
||||||
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
||||||
// Unit testing
|
/ * Unit testing * /
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
// android unit testing and espresso
|
/ * android unit testing and espresso * /
|
||||||
androidTestImplementation 'androidx.test:rules:1.4.1-alpha06'
|
androidTestImplementation 'androidx.test:rules:1.4.1-alpha06'
|
||||||
androidTestImplementation "androidx.test:core:1.4.0"
|
androidTestImplementation "androidx.test:core:1.4.0"
|
||||||
|
|
||||||
@@ -131,48 +135,48 @@ dependencies {
|
|||||||
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
|
||||||
androidTestImplementation "org.hamcrest:hamcrest:2.2"
|
androidTestImplementation "org.hamcrest:hamcrest:2.2"
|
||||||
//mock websever for testing retrofit responses
|
/ * mock websever for testing retrofit responses * /
|
||||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.6.0"
|
testImplementation "com.squareup.okhttp3:mockwebserver:4.6.0"
|
||||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
||||||
|
|
||||||
//mockito and livedata testing
|
/ * mockito and livedata testing * /
|
||||||
testImplementation 'org.mockito:mockito-inline:2.13.0'
|
testImplementation 'org.mockito:mockito-inline:2.13.0'
|
||||||
implementation 'androidx.arch.core:core-testing:2.2.0'
|
implementation 'androidx.arch.core:core-testing:2.2.0'
|
||||||
|
|
||||||
// Mockk
|
/ * MockK * /
|
||||||
def mockk_ver = "1.10.5"
|
def mockk_ver = "1.10.5"
|
||||||
testImplementation "io.mockk:mockk:$mockk_ver"
|
testImplementation "io.mockk:mockk:$mockk_ver"
|
||||||
androidTestImplementation "io.mockk:mockk-android:$mockk_ver"
|
androidTestImplementation "io.mockk:mockk-android:$mockk_ver"
|
||||||
|
|
||||||
// Retrofit
|
/ * Retrofit * /
|
||||||
def retrofit_ver = "2.8.1"
|
def retrofit_ver = "2.8.1"
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_ver"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit_ver"
|
||||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_ver"
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit_ver"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
|
implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
|
||||||
|
|
||||||
// Shared prefs
|
/ * Shared prefs * /
|
||||||
def prefs_ver = "1.1.1"
|
def prefs_ver = "1.1.1"
|
||||||
implementation "androidx.preference:preference-ktx:$prefs_ver"
|
implementation "androidx.preference:preference-ktx:$prefs_ver"
|
||||||
|
|
||||||
//Kodein Dependency Injection
|
/ *Kodein Dependency Injection * /
|
||||||
def kodein_version = "6.2.1"
|
def kodein_version = "6.2.1"
|
||||||
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
|
implementation "org.kodein.di:kodein-di-generic-jvm:$kodein_version"
|
||||||
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
|
implementation "org.kodein.di:kodein-di-framework-android-x:$kodein_version"
|
||||||
|
|
||||||
// Room database
|
/ * Room database * /
|
||||||
def room_version = "2.3.0-alpha03"
|
def room_version = "2.3.0-alpha03"
|
||||||
implementation "androidx.room:room-runtime:$room_version"
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
implementation "androidx.room:room-ktx:$room_version"
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
|
|
||||||
// Picasso
|
/ * Picasso * /
|
||||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||||
|
|
||||||
// coroutine
|
/ * coroutine * /
|
||||||
def coroutine_version = "1.3.9"
|
def coroutine_version = "1.3.9"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
|
||||||
|
|
||||||
// tomtom search
|
/ * tomtom search * /
|
||||||
def tomtom_version = "2.4771"
|
def tomtom_version = "2.4771"
|
||||||
implementation "com.tomtom.online:sdk-search:$tomtom_version"
|
implementation "com.tomtom.online:sdk-search:$tomtom_version"
|
||||||
implementation "com.tomtom.online:sdk-maps:2.4807"
|
implementation "com.tomtom.online:sdk-maps:2.4807"
|
||||||
@@ -181,9 +185,9 @@ dependencies {
|
|||||||
def coroutines_google_ver = "1.1.1"
|
def coroutines_google_ver = "1.1.1"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_google_ver"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_google_ver"
|
||||||
|
|
||||||
/ * Glide */
|
/ * Picasso * /
|
||||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
|
||||||
/ * screenshot library * /
|
/ * screenshot library * /
|
||||||
androidTestImplementation 'tools.fastlane:screengrab:2.1.1'
|
androidTestImplementation 'tools.fastlane:screengrab:2.1.1'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.UiController
|
||||||
|
import androidx.test.espresso.ViewAction
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.rule.GrantPermissionRule
|
||||||
|
import com.appttude.h_mal.atlas_weather.application.TestAppClass
|
||||||
|
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
|
||||||
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import tools.fastlane.screengrab.Screengrab
|
||||||
|
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
||||||
|
|
||||||
|
open class BaseTest<A : Activity>(
|
||||||
|
private val activity: Class<A>,
|
||||||
|
private val intentBundle: Bundle? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
|
lateinit var scenario: ActivityScenario<A>
|
||||||
|
private lateinit var testApp: TestAppClass
|
||||||
|
private lateinit var testActivity: Activity
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
var snapshotRule: SnapshotRule = SnapshotRule()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
||||||
|
val startIntent =
|
||||||
|
Intent(InstrumentationRegistry.getInstrumentation().targetContext, activity)
|
||||||
|
if (intentBundle != null) {
|
||||||
|
startIntent.replaceExtras(intentBundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
testApp = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass
|
||||||
|
runBlocking {
|
||||||
|
beforeLaunch()
|
||||||
|
}
|
||||||
|
|
||||||
|
scenario = ActivityScenario.launch(startIntent)
|
||||||
|
scenario.onActivity {
|
||||||
|
testActivity = it
|
||||||
|
}
|
||||||
|
afterLaunch()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stubEndpoint(url: String, stub: Stubs) {
|
||||||
|
testApp.stubUrl(url, stub.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unstubEndpoint(url: String) {
|
||||||
|
testApp.removeUrlStub(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getActivity() = testActivity
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
testFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun beforeLaunch() {}
|
||||||
|
open fun afterLaunch() {}
|
||||||
|
open fun testFinished() {}
|
||||||
|
|
||||||
|
fun waitFor(delay: Long) {
|
||||||
|
Espresso.onView(ViewMatchers.isRoot()).perform(object : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View> = ViewMatchers.isRoot()
|
||||||
|
override fun getDescription(): String = "wait for $delay milliseconds"
|
||||||
|
override fun perform(uiController: UiController, v: View?) {
|
||||||
|
uiController.loopMainThreadForAtLeast(delay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.utils
|
package com.appttude.h_mal.atlas_weather
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -16,14 +16,9 @@ import androidx.test.espresso.action.ViewActions.swipeDown
|
|||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.PickerActions
|
import androidx.test.espresso.contrib.PickerActions
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
import com.appttude.h_mal.atlas_weather.helpers.checkErrorMessage
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
import com.appttude.h_mal.atlas_weather.helpers.checkImage
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withClassName
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import com.appttude.h_mal.atlas_weather.checkErrorMessage
|
|
||||||
import com.appttude.h_mal.atlas_weather.checkImage
|
|
||||||
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
|
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
import org.hamcrest.CoreMatchers.anything
|
import org.hamcrest.CoreMatchers.anything
|
||||||
@@ -46,6 +41,8 @@ open class BaseTestRobot {
|
|||||||
|
|
||||||
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
|
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
|
||||||
|
|
||||||
|
fun matchDisplayed(resId: Int): ViewInteraction = matchView(resId).check(matches(isDisplayed()))
|
||||||
|
|
||||||
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
|
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
|
||||||
.check(matches(withText(text)))
|
.check(matches(withText(text)))
|
||||||
|
|
||||||
@@ -142,7 +139,7 @@ open class BaseTestRobot {
|
|||||||
Resources.getSystem().getString(resId)
|
Resources.getSystem().getString(resId)
|
||||||
|
|
||||||
fun pullToRefresh(resId: Int){
|
fun pullToRefresh(resId: Int){
|
||||||
onView(allOf(withId(resId), ViewMatchers.isDisplayed())).perform(swipeDown())
|
onView(allOf(withId(resId), isDisplayed())).perform(swipeDown())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectDateInPicker(year: Int, month: Int, day: Int) {
|
fun selectDateInPicker(year: Int, month: Int, day: Int) {
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
//package com.appttude.h_mal.atlas_weather
|
|
||||||
//
|
|
||||||
//import android.Manifest
|
|
||||||
//import android.R
|
|
||||||
//import android.app.Activity
|
|
||||||
//import android.content.Context
|
|
||||||
//import android.os.Build
|
|
||||||
//import android.view.View
|
|
||||||
//import android.view.WindowManager
|
|
||||||
//import androidx.annotation.StringRes
|
|
||||||
//import androidx.test.core.app.ActivityScenario
|
|
||||||
//import androidx.test.espresso.*
|
|
||||||
//import androidx.test.espresso.Espresso.onView
|
|
||||||
//import androidx.test.espresso.assertion.ViewAssertions.matches
|
|
||||||
//import androidx.test.espresso.matcher.ViewMatchers.*
|
|
||||||
//import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
|
||||||
//import androidx.test.rule.GrantPermissionRule
|
|
||||||
//import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseActivity
|
|
||||||
////import h_mal.appttude.com.driver.base.BaseActivity
|
|
||||||
//import com.appttude.h_mal.atlas_weather.helpers.BaseViewAction
|
|
||||||
//import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
|
|
||||||
//import org.hamcrest.CoreMatchers
|
|
||||||
//import org.hamcrest.Description
|
|
||||||
//import org.hamcrest.Matcher
|
|
||||||
//import org.hamcrest.TypeSafeMatcher
|
|
||||||
//import org.hamcrest.core.AllOf
|
|
||||||
//import org.junit.After
|
|
||||||
//import org.junit.Before
|
|
||||||
//import org.junit.Rule
|
|
||||||
//import tools.fastlane.screengrab.Screengrab
|
|
||||||
//import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
|
||||||
//import tools.fastlane.screengrab.locale.LocaleTestRule
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//open class BaseUiTest<T : BaseActivity>(
|
|
||||||
// private val activity: Class<T>
|
|
||||||
//) {
|
|
||||||
//
|
|
||||||
// private lateinit var mActivityScenarioRule: ActivityScenario<T>
|
|
||||||
// private var mIdlingResource: IdlingResource? = null
|
|
||||||
//
|
|
||||||
// private lateinit var currentActivity: Activity
|
|
||||||
//
|
|
||||||
// @get:Rule
|
|
||||||
// var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
//
|
|
||||||
// @get:Rule
|
|
||||||
// var snapshotRule: SnapshotRule = SnapshotRule()
|
|
||||||
//
|
|
||||||
// @Rule
|
|
||||||
// @JvmField
|
|
||||||
// var localeTestRule = LocaleTestRule()
|
|
||||||
//
|
|
||||||
// @Before
|
|
||||||
// fun setup() {
|
|
||||||
// Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
|
||||||
// beforeLaunch()
|
|
||||||
// mActivityScenarioRule = ActivityScenario.launch(activity)
|
|
||||||
// mActivityScenarioRule.onActivity {
|
|
||||||
//// mIdlingResource = it.getIdlingResource()!!
|
|
||||||
//// IdlingRegistry.getInstance().register(mIdlingResource)
|
|
||||||
// afterLaunch(it)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @After
|
|
||||||
// fun tearDown() {
|
|
||||||
// mIdlingResource?.let {
|
|
||||||
// IdlingRegistry.getInstance().unregister(it)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun getResourceString(@StringRes stringRes: Int): String {
|
|
||||||
// return getInstrumentation().targetContext.resources.getString(
|
|
||||||
// stringRes
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun waitFor(delay: Long) {
|
|
||||||
// onView(isRoot()).perform(object : ViewAction {
|
|
||||||
// override fun getConstraints(): Matcher<View> = isRoot()
|
|
||||||
// override fun getDescription(): String = "wait for $delay milliseconds"
|
|
||||||
// override fun perform(uiController: UiController, v: View?) {
|
|
||||||
// uiController.loopMainThreadForAtLeast(delay)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// open fun beforeLaunch() {}
|
|
||||||
// open fun afterLaunch(context: Context) {}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// @Suppress("DEPRECATION")
|
|
||||||
// fun checkToastMessage(message: String) {
|
|
||||||
// onView(withText(message)).inRoot(object : TypeSafeMatcher<Root>() {
|
|
||||||
// override fun describeTo(description: Description?) {
|
|
||||||
// description?.appendText("is toast")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun matchesSafely(root: Root): Boolean {
|
|
||||||
// root.run {
|
|
||||||
// if (windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST) {
|
|
||||||
// decorView.run {
|
|
||||||
// if (windowToken === applicationWindowToken) {
|
|
||||||
// // windowToken == appToken means this window isn't contained by any other windows.
|
|
||||||
// // if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ).check(matches(isDisplayed()))
|
|
||||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
|
||||||
// waitFor(3500)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun checkSnackBarDisplayedByMessage(message: String) {
|
|
||||||
// onView(
|
|
||||||
// CoreMatchers.allOf(
|
|
||||||
// withId(com.google.android.material.R.id.snackbar_text),
|
|
||||||
// withText(message)
|
|
||||||
// )
|
|
||||||
// ).check(matches(isDisplayed()))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private fun getCurrentActivity(): Activity {
|
|
||||||
// onView(AllOf.allOf(withId(R.id.content), isDisplayed()))
|
|
||||||
// .perform(object : BaseViewAction() {
|
|
||||||
// override fun setPerform(uiController: UiController?, view: View?) {
|
|
||||||
// if (view?.context is Activity) {
|
|
||||||
// currentActivity = view.context as Activity
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// return currentActivity
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.helpers
|
|
||||||
|
|
||||||
import android.os.Environment
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File paths for images on device
|
|
||||||
*/
|
|
||||||
fun getImagePath(imageConst: String): String {
|
|
||||||
return File(
|
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
|
||||||
"/Camera/images/$imageConst"
|
|
||||||
).absolutePath
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather
|
package com.appttude.h_mal.atlas_weather.helpers
|
||||||
|
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.helpers
|
|
||||||
|
|
||||||
import android.content.ClipData
|
|
||||||
import android.content.ClipData.Item
|
|
||||||
import android.net.Uri
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
object DataHelper {
|
|
||||||
|
|
||||||
fun createClipItem(filePath: String) = Item(
|
|
||||||
Uri.fromFile(
|
|
||||||
File(filePath)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun createClipData(item: Item, mimeType: String = "text/uri-list") =
|
|
||||||
ClipData(null, arrayOf(mimeType), item)
|
|
||||||
|
|
||||||
fun createClipData(filePath: String) = createClipData(createClipItem(filePath))
|
|
||||||
|
|
||||||
fun createClipData(filePaths: Array<String>): ClipData {
|
|
||||||
val clipData = createClipData(filePaths[0])
|
|
||||||
val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1)
|
|
||||||
clipData.addFilePaths(remainingFiles)
|
|
||||||
return clipData
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createClipData(uri: Uri) = createClipData(Item(uri))
|
|
||||||
|
|
||||||
fun ClipData.addFilePaths(filePaths: Array<String>) {
|
|
||||||
filePaths.forEach { addItem(createClipItem(it)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.data.location
|
package com.appttude.h_mal.atlas_weather.instrumentationTests
|
||||||
|
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
|
||||||
import com.appttude.h_mal.atlas_weather.model.types.LocationType
|
import com.appttude.h_mal.atlas_weather.model.types.LocationType
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.hamcrest.Matcher.*
|
import org.hamcrest.Matcher.*
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.testsuite
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
|
||||||
import androidx.test.espresso.action.ViewActions
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
|
||||||
import androidx.test.espresso.matcher.RootMatchers.isDialog
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.rule.ActivityTestRule
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
|
||||||
import com.appttude.h_mal.atlas_weather.application.TestAppClass
|
|
||||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
|
||||||
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Rule
|
|
||||||
import tools.fastlane.screengrab.Screengrab
|
|
||||||
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
|
||||||
|
|
||||||
open class BaseTest<A : Activity> {
|
|
||||||
|
|
||||||
lateinit var testApp: TestAppClass
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
var snapshotRule: SnapshotRule = SnapshotRule()
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
var mActivityTestRule: ActivityTestRule<A> =
|
|
||||||
object : ActivityTestRule<A>(getGenericClassAt<A>(0).java) {
|
|
||||||
override fun beforeActivityLaunched() {
|
|
||||||
super.beforeActivityLaunched()
|
|
||||||
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
|
||||||
|
|
||||||
testApp =
|
|
||||||
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass
|
|
||||||
setupFeed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterActivityLaunched() {
|
|
||||||
|
|
||||||
// Dismiss dialog
|
|
||||||
onView(withText("AGREE")).inRoot(isDialog()).check(matches(isDisplayed()))
|
|
||||||
.perform(ViewActions.click())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stubEndpoint(url: String, stub: Stubs) {
|
|
||||||
testApp.stubUrl(url, stub.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unstubEndpoint(url: String) {
|
|
||||||
testApp.removeUrlStub(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun tearDown() {
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun setupFeed() {}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.testsuite
|
|
||||||
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.test.core.app.ActivityScenario
|
|
||||||
import androidx.test.core.app.ActivityScenario.launch
|
|
||||||
import androidx.test.espresso.Espresso
|
|
||||||
import androidx.test.espresso.action.ViewActions
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
|
||||||
import androidx.test.espresso.matcher.RootMatchers
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
|
||||||
import com.appttude.h_mal.atlas_weather.application.TestAppClass
|
|
||||||
import com.appttude.h_mal.atlas_weather.robot.homeScreen
|
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
|
||||||
class HomePageUITestScenario : BaseMainScenario() {
|
|
||||||
|
|
||||||
override fun setupFeed() {
|
|
||||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun loadApp_validWeatherResponse_returnsValidPage() {
|
|
||||||
homeScreen {
|
|
||||||
verifyCurrentTemperature(2)
|
|
||||||
verifyCurrentLocation("Mock Location")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class BaseMainScenario {
|
|
||||||
|
|
||||||
lateinit var scenario: ActivityScenario<MainActivity>
|
|
||||||
private lateinit var testApp: TestAppClass
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
scenario = launch(MainActivity::class.java)
|
|
||||||
scenario.onActivity {
|
|
||||||
runBlocking {
|
|
||||||
testApp = it.application as TestAppClass
|
|
||||||
setupFeed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dismiss dialog on start up
|
|
||||||
Espresso.onView(ViewMatchers.withText("AGREE"))
|
|
||||||
.inRoot(RootMatchers.isDialog())
|
|
||||||
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
|
||||||
.perform(ViewActions.click())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stubEndpoint(url: String, stub: Stubs) {
|
|
||||||
testApp.stubUrl(url, stub.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unstubEndpoint(url: String) {
|
|
||||||
testApp.removeUrlStub(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun tearDown() {
|
|
||||||
testFinished()
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun setupFeed() {}
|
|
||||||
open fun testFinished() {}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.widget
|
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.test.espresso.Espresso
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
||||||
import androidx.test.rule.ActivityTestRule
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
|
|
||||||
class WidgetLocationPermissionActivityTest {
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
var mActivityTestRule : ActivityTestRule<WidgetLocationPermissionActivity> =
|
|
||||||
ActivityTestRule(WidgetLocationPermissionActivity::class.java, false, false)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun demo_test() {
|
|
||||||
val startIntent = Intent().apply {
|
|
||||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 112)
|
|
||||||
}
|
|
||||||
mActivityTestRule.launchActivity(startIntent)
|
|
||||||
|
|
||||||
Espresso.onView((ViewMatchers.withId(R.id.declaration_text))).check(matches(isDisplayed()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.robot
|
package com.appttude.h_mal.atlas_weather.robot
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.utils.BaseTestRobot
|
|
||||||
|
|
||||||
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
||||||
class HomeScreenRobot : BaseTestRobot() {
|
class HomeScreenRobot : BaseTestRobot() {
|
||||||
|
|||||||
@@ -1,29 +1,22 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.tests
|
package com.appttude.h_mal.atlas_weather.tests
|
||||||
|
|
||||||
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
|
|
||||||
import com.appttude.h_mal.atlas_weather.robot.homeScreen
|
import com.appttude.h_mal.atlas_weather.robot.homeScreen
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.testsuite.BaseTest
|
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class HomePageUITest : BaseTest<MainActivity>() {
|
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
@Rule
|
override fun beforeLaunch() {
|
||||||
@JvmField
|
|
||||||
var mGrantPermissionRule: GrantPermissionRule =
|
|
||||||
GrantPermissionRule.grant(
|
|
||||||
"android.permission.ACCESS_COARSE_LOCATION")
|
|
||||||
|
|
||||||
override fun setupFeed() {
|
|
||||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun loadApp_validWeatherResponse_returnsValidPage() {
|
fun loadApp_validWeatherResponse_returnsValidPage() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
|
waitFor(2000)
|
||||||
verifyCurrentTemperature(2)
|
verifyCurrentTemperature(2)
|
||||||
verifyCurrentLocation("Mock Location")
|
verifyCurrentLocation("Mock Location")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.tests
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
|
||||||
import com.appttude.h_mal.atlas_weather.robot.homeScreen
|
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.testsuite.BaseTest
|
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class HomePageUITest : BaseTest<MainActivity>() {
|
|
||||||
|
|
||||||
override fun setupFeed() {
|
|
||||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun loadApp_validWeatherResponse_returnsValidPage() {
|
|
||||||
homeScreen {
|
|
||||||
verifyCurrentTemperature(2)
|
|
||||||
verifyCurrentLocation("Mock Location")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
|
import androidx.test.espresso.matcher.RootMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||||
|
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||||
|
|
||||||
|
open class MonoBaseTest: BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
|
override fun afterLaunch() {
|
||||||
|
// Dismiss dialog on start up
|
||||||
|
Espresso.onView(ViewMatchers.withText("AGREE"))
|
||||||
|
.inRoot(RootMatchers.isDialog())
|
||||||
|
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
||||||
|
.perform(ViewActions.click())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.robot
|
package com.appttude.h_mal.monoWeather.robot
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.utils.BaseTestRobot
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
|
|
||||||
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
|
||||||
class HomeScreenRobot : BaseTestRobot() {
|
class HomeScreenRobot : BaseTestRobot() {
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.robot
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
|
|
||||||
|
fun widgetPermissionScreen(func: WidgetPermissionScreenRobot.() -> Unit) =
|
||||||
|
WidgetPermissionScreenRobot().apply { func() }
|
||||||
|
|
||||||
|
class WidgetPermissionScreenRobot : BaseTestRobot() {
|
||||||
|
fun declarationDisplayed() = matchDisplayed(R.id.declaration_text)
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.tests
|
||||||
|
|
||||||
|
|
||||||
|
import com.appttude.h_mal.monoWeather.robot.homeScreen
|
||||||
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
|
import com.appttude.h_mal.monoWeather.MonoBaseTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class HomePageUITest : MonoBaseTest() {
|
||||||
|
|
||||||
|
override fun beforeLaunch() {
|
||||||
|
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun loadApp_validWeatherResponse_returnsValidPage() {
|
||||||
|
homeScreen {
|
||||||
|
verifyCurrentTemperature(2)
|
||||||
|
verifyCurrentLocation("Mock Location")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.tests
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||||
|
import com.appttude.h_mal.monoWeather.robot.widgetPermissionScreen
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.widget.WidgetLocationPermissionActivity
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetLocationPermissionActivityTest : BaseTest<WidgetLocationPermissionActivity>(
|
||||||
|
activity = WidgetLocationPermissionActivity::class.java,
|
||||||
|
intentBundle = Bundle().apply {
|
||||||
|
putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, 112)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun demo_test() {
|
||||||
|
widgetPermissionScreen {
|
||||||
|
declarationDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
package="com.appttude.h_mal.atlas_weather"
|
|
||||||
tools:node="merge">
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
||||||
@@ -14,7 +12,7 @@
|
|||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:node="merge">
|
tools:node="merge">
|
||||||
|
|
||||||
<activity android:name=".atlasWeather.ui.MainActivity"
|
<activity android:name=".ui.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"
|
||||||
@@ -26,18 +24,12 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".atlasWeather.ui.settings.UnitSettingsActivity"
|
|
||||||
android:label="Settings"
|
|
||||||
android:exported="true"/>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".atlasWeather.notification.NotificationReceiver"
|
android:name=".notification.NotificationReceiver"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
android:exported="true"/>
|
android:exported="true"/>
|
||||||
|
|
||||||
<receiver android:name=".atlasWeather.widget.NewAppWidget"
|
<receiver android:name=".widget.NewAppWidget"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
@@ -49,11 +41,6 @@
|
|||||||
android:name="android.appwidget.provider"
|
android:name="android.appwidget.provider"
|
||||||
android:resource="@xml/new_app_widget_info" />
|
android:resource="@xml/new_app_widget_info" />
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".atlasWeather.widget.WidgetRemoteViewsService"
|
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.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.utils.Event
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.hide
|
|
||||||
import com.appttude.h_mal.atlas_weather.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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.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.atlasWeather.ui.settings.UnitSettingsActivity
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
||||||
import kotlinx.android.synthetic.atlasWeather.activity_main.*
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity(){
|
|
||||||
|
|
||||||
lateinit var navHost: NavHostFragment
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContentView(R.layout.activity_main)
|
|
||||||
|
|
||||||
val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.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.application.LOCATION_PERMISSION_REQUEST
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter.WeatherRecyclerAdapter
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
|
||||||
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 {
|
|
||||||
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.settings
|
|
||||||
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.preference.PreferenceActivity
|
|
||||||
import android.preference.PreferenceFragment
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.notification.NotificationReceiver
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.widget.NewAppWidget
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
class UnitSettingsActivity : PreferenceActivity() {
|
|
||||||
private var prefListener: OnSharedPreferenceChangeListener? = null
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
PreferenceManager.setDefaultValues(this, R.xml.prefs, false)
|
|
||||||
fragmentManager.beginTransaction().replace(android.R.id.content, MyPreferenceFragment()).commit()
|
|
||||||
|
|
||||||
//listener on changed sort order preference:
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
|
||||||
prefListener = OnSharedPreferenceChangeListener { _, key ->
|
|
||||||
if (key == "temp_units") {
|
|
||||||
val intent = Intent(baseContext, NewAppWidget::class.java)
|
|
||||||
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
|
||||||
val ids = AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(application, NewAppWidget::class.java))
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
|
||||||
sendBroadcast(intent)
|
|
||||||
}
|
|
||||||
if (key == "notif_boolean") {
|
|
||||||
setupNotificationBroadcaster(baseContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "widget_black_background"){
|
|
||||||
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|
|
||||||
val widgetManager = AppWidgetManager.getInstance(this)
|
|
||||||
val ids = widgetManager.getAppWidgetIds(ComponentName(this, NewAppWidget::class.java))
|
|
||||||
AppWidgetManager.getInstance(this).notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
|
||||||
sendBroadcast(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prefs.registerOnSharedPreferenceChangeListener(prefListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setupNotificationBroadcaster(context: Context) {
|
|
||||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
val notificationIntent = Intent(context, NotificationReceiver::class.java)
|
|
||||||
val broadcast = PendingIntent.getBroadcast(context, 100, notificationIntent,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
|
||||||
val cal: Calendar = Calendar.getInstance()
|
|
||||||
cal.set(Calendar.HOUR_OF_DAY, 6)
|
|
||||||
cal.set(Calendar.MINUTE, 8)
|
|
||||||
cal.set(Calendar.SECOND, 5)
|
|
||||||
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.timeInMillis, AlarmManager.INTERVAL_DAY, broadcast)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
|
||||||
super.onBackPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
|
|
||||||
// Log.i(TAG, "onSharedPreferenceChanged: " + s);
|
|
||||||
// if (s == "temp_units"){
|
|
||||||
// Intent intent = new Intent(getBaseContext(), NewAppWidget.class);
|
|
||||||
// intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
|
||||||
//
|
|
||||||
// int[] ids = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), NewAppWidget.class));
|
|
||||||
// intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
|
|
||||||
// sendBroadcast(intent);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
class MyPreferenceFragment : PreferenceFragment() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
addPreferencesFromResource(R.xml.prefs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.TaskStackBuilder
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.appwidget.AppWidgetProvider
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.RemoteViews
|
|
||||||
import androidx.annotation.LayoutRes
|
|
||||||
|
|
||||||
abstract class BaseWidgetClass : AppWidgetProvider(){
|
|
||||||
|
|
||||||
fun createRemoteView(context: Context, @LayoutRes id: Int): RemoteViews {
|
|
||||||
return RemoteViews(context.packageName, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AppWidgetProvider.createUpdatePendingIntent(context: Context, appWidgetId: Int): PendingIntent? {
|
|
||||||
val seconds = (System.currentTimeMillis() / 1000L).toInt()
|
|
||||||
val intentUpdate = Intent(context, this::class.java)
|
|
||||||
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
|
||||||
val idArray = intArrayOf(appWidgetId)
|
|
||||||
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
|
|
||||||
|
|
||||||
return PendingIntent.getBroadcast(
|
|
||||||
context, seconds, intentUpdate,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
|
|
||||||
val clickIntentTemplate = Intent(context, activityClass)
|
|
||||||
|
|
||||||
return TaskStackBuilder.create(context)
|
|
||||||
.addNextIntentWithParentStack(clickIntentTemplate)
|
|
||||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
|
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.RemoteViews
|
|
||||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
|
||||||
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetData
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.kodein.di.KodeinAware
|
|
||||||
import org.kodein.di.LateInitKodein
|
|
||||||
import org.kodein.di.generic.instance
|
|
||||||
|
|
||||||
|
|
||||||
class MyWidgetRemoteViewsFactory(
|
|
||||||
private val context: Context,
|
|
||||||
val intent: Intent
|
|
||||||
) : RemoteViewsFactory{
|
|
||||||
private val TAG = "MyWidgetRemoteViewsFactory"
|
|
||||||
|
|
||||||
private val kodein = LateInitKodein()
|
|
||||||
private val helper : ServicesHelper by kodein.instance()
|
|
||||||
|
|
||||||
private var appWidgetId: Int? = 0
|
|
||||||
private var list: List<InnerWidgetData>? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
|
||||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
|
||||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {}
|
|
||||||
override fun onDataSetChanged() {
|
|
||||||
runBlocking {
|
|
||||||
list = helper.getWidgetInnerWeather()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun onDestroy() {}
|
|
||||||
|
|
||||||
override fun getCount(): Int = list?.size ?: 5
|
|
||||||
|
|
||||||
override fun getViewAt(i: Int): RemoteViews {
|
|
||||||
val rv = RemoteViews(context.packageName, R.layout.widget_item)
|
|
||||||
|
|
||||||
if (list.isNullOrEmpty()) return rv
|
|
||||||
|
|
||||||
|
|
||||||
list?.get(i)?.let {
|
|
||||||
rv.setTextViewText(R.id.widget_item_day, it.date)
|
|
||||||
rv.setImageViewBitmap(R.id.widget_item_image, it.icon)
|
|
||||||
rv.setTextViewText(R.id.widget_item_temp_high, it.highTemp)
|
|
||||||
rv.setOnClickFillInIntent(R.id.widget_item_layout, intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLoadingView(): RemoteViews {
|
|
||||||
return RemoteViews(context.packageName, R.layout.widget_item_loading)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getViewTypeCount(): Int = 1
|
|
||||||
|
|
||||||
|
|
||||||
override fun getItemId(i: Int): Long = i.toLong()
|
|
||||||
|
|
||||||
|
|
||||||
override fun hasStableIds(): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.RemoteViews
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
|
|
||||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
|
||||||
import com.appttude.h_mal.atlas_weather.model.widget.WidgetData
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.kodein.di.KodeinAware
|
|
||||||
import org.kodein.di.LateInitKodein
|
|
||||||
import org.kodein.di.generic.instance
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of App Widget functionality.
|
|
||||||
*/
|
|
||||||
private val TAG = NewAppWidget::class.java.simpleName
|
|
||||||
class NewAppWidget : BaseWidgetClass() {
|
|
||||||
|
|
||||||
private val kodein = LateInitKodein()
|
|
||||||
private val helper : ServicesHelper by kodein.instance()
|
|
||||||
|
|
||||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
|
||||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
|
||||||
// There may be multiple widgets active, so update all of them
|
|
||||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val results = helper.fetchData()
|
|
||||||
if (results) return@launch
|
|
||||||
val weatherWidgetCurrent = helper.getWidgetWeather()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main){
|
|
||||||
for (appWidgetId in appWidgetIds) {
|
|
||||||
val updatePendingIntent = createUpdatePendingIntent(context, appWidgetId)
|
|
||||||
val views = createRemoteView(context, R.layout.new_app_widget)
|
|
||||||
bindView(context, appWidgetId, views, updatePendingIntent, weatherWidgetCurrent)
|
|
||||||
}
|
|
||||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEnabled(context: Context) {
|
|
||||||
try {
|
|
||||||
val appWidgetManager = AppWidgetManager.getInstance(context)
|
|
||||||
val thisAppWidget = ComponentName(context.packageName, NewAppWidget::class.java.name)
|
|
||||||
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
|
|
||||||
onUpdate(context, appWidgetManager, appWidgetIds)
|
|
||||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_listview)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "onEnabled: ", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisabled(context: Context) {
|
|
||||||
// Enter relevant functionality for when the last widget is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
if (intent.action ==
|
|
||||||
AppWidgetManager.ACTION_APPWIDGET_UPDATE) {
|
|
||||||
val appWidgetManager = AppWidgetManager.getInstance(context)
|
|
||||||
val thisAppWidget = ComponentName(context.packageName, NewAppWidget::class.java.name)
|
|
||||||
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
|
|
||||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_listview)
|
|
||||||
}
|
|
||||||
super.onReceive(context, intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createForecastListIntent(
|
|
||||||
context: Context,
|
|
||||||
appWidgetId: Int
|
|
||||||
): Intent {
|
|
||||||
return Intent(context, WidgetRemoteViewsService::class.java).apply {
|
|
||||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
|
||||||
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindView(
|
|
||||||
context: Context,
|
|
||||||
appWidgetId: Int,
|
|
||||||
views: RemoteViews,
|
|
||||||
updatePendingIntent: PendingIntent?,
|
|
||||||
weather: WidgetData?){
|
|
||||||
|
|
||||||
val appWidgetManager = AppWidgetManager.getInstance(context)
|
|
||||||
|
|
||||||
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
|
|
||||||
|
|
||||||
weather?.let {
|
|
||||||
|
|
||||||
val intent = createForecastListIntent(
|
|
||||||
context,
|
|
||||||
appWidgetId
|
|
||||||
)
|
|
||||||
|
|
||||||
views.setRemoteAdapter(R.id.widget_listview, intent)
|
|
||||||
views.setTextViewText(R.id.widget_main_temp, it.currentTemp)
|
|
||||||
views.setTextViewText(R.id.widget_feel_temp, "°C")
|
|
||||||
views.setTextViewText(R.id.widget_current_location, it.location)
|
|
||||||
views.setImageViewResource(R.id.location_icon, R.drawable.location_flag)
|
|
||||||
// views.setImageViewBitmap(R.id.widget_current_icon, it.icon)
|
|
||||||
|
|
||||||
val clickPendingIntentTemplate = createClickingPendingIntent(context, MainActivity::class.java)
|
|
||||||
views.setPendingIntentTemplate(R.id.widget_listview, clickPendingIntentTemplate)
|
|
||||||
|
|
||||||
views.setOnClickPendingIntent(R.id.widget_current_icon, updatePendingIntent)
|
|
||||||
views.setOnClickPendingIntent(R.id.widget_current_location, updatePendingIntent)
|
|
||||||
|
|
||||||
// Instruct the widget manager to update the widget
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
|
||||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "onPostExecute: weather is empty")
|
|
||||||
views.setTextViewText(R.id.widget_current_location, "Refresh")
|
|
||||||
views.setImageViewResource(R.id.widget_current_icon, R.drawable.widget_error_icon)
|
|
||||||
views.setImageViewResource(R.id.location_icon, R.drawable.refreshing)
|
|
||||||
views.setOnClickPendingIntent(R.id.widget_current_icon, updatePendingIntent)
|
|
||||||
views.setOnClickPendingIntent(R.id.widget_current_location, updatePendingIntent)
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.RemoteViewsService
|
|
||||||
|
|
||||||
class WidgetRemoteViewsService : RemoteViewsService() {
|
|
||||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
|
||||||
return MyWidgetRemoteViewsFactory(applicationContext, intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.TaskStackBuilder
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
|
|
||||||
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
|
|
||||||
val clickIntentTemplate = Intent(context, activityClass)
|
|
||||||
|
|
||||||
return TaskStackBuilder.create(context)
|
|
||||||
.addNextIntentWithParentStack(clickIntentTemplate)
|
|
||||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.notification
|
package com.appttude.h_mal.atlas_weather.notification
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.notification
|
package com.appttude.h_mal.atlas_weather.notification
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
@@ -12,13 +12,10 @@ import android.content.pm.PackageManager
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
|
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||||
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
|
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.LateInitKodein
|
import org.kodein.di.LateInitKodein
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui
|
package com.appttude.h_mal.atlas_weather.ui
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
|
||||||
|
val tabs = setOf(R.id.nav_home, R.id.nav_world)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui
|
package com.appttude.h_mal.atlas_weather.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -8,7 +8,7 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter.WeatherRecyclerAdapter
|
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.details
|
package com.appttude.h_mal.atlas_weather.ui.details
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.dialog
|
package com.appttude.h_mal.atlas_weather.ui.dialog
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
@@ -14,7 +14,6 @@ interface DeclarationBuilder{
|
|||||||
|
|
||||||
fun Context.readFromResources(@StringRes id: Int) = resources.getString(id)
|
fun Context.readFromResources(@StringRes id: Int) = resources.getString(id)
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
|
||||||
fun buildMessage(): CharSequence? {
|
fun buildMessage(): CharSequence? {
|
||||||
val link1 = "<font color='blue'><a href=\"$link\">here</a></font>"
|
val link1 = "<font color='blue'><a href=\"$link\">here</a></font>"
|
||||||
val message = "$message See my privacy policy: $link1"
|
val message = "$message See my privacy policy: $link1"
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.dialog
|
package com.appttude.h_mal.atlas_weather.ui.dialog
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
|
|
||||||
|
|
||||||
class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) {
|
class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) {
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui.home
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.navigation.Navigation.findNavController
|
||||||
|
import androidx.navigation.ui.onNavDestinationSelected
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||||
|
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||||
|
import com.appttude.h_mal.atlas_weather.ui.dialog.PermissionsDeclarationDialog
|
||||||
|
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
|
||||||
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
|
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
|
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(R.layout.fragment_home) {
|
||||||
|
private val viewModel by getFragmentViewModel<MainViewModel>()
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
|
val recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
|
||||||
|
navigateToFurtherDetails(it)
|
||||||
|
})
|
||||||
|
|
||||||
|
forecast_listview.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = recyclerAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
swipe_refresh.apply {
|
||||||
|
setOnRefreshListener {
|
||||||
|
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||||
|
viewModel.fetchData()
|
||||||
|
isRefreshing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherLiveData.observe(viewLifecycleOwner) {
|
||||||
|
recyclerAdapter.addCurrent(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar))
|
||||||
|
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
||||||
|
viewModel.operationRefresh.observe(viewLifecycleOwner) { it ->
|
||||||
|
it.getContentIfNotHandled()?.let {
|
||||||
|
swipe_refresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(viewLifecycleOwner) {
|
||||||
|
swipe_refresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||||
|
viewModel.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun permissionsGranted() {
|
||||||
|
viewModel.fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateToFurtherDetails(forecast: Forecast) {
|
||||||
|
val directions = HomeFragmentDirections
|
||||||
|
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||||
|
navigateTo(directions)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
inflater.inflate(R.menu.menu_main, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val navController = findNavController(requireActivity(), R.id.container)
|
||||||
|
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
|
package com.appttude.h_mal.atlas_weather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter
|
package com.appttude.h_mal.atlas_weather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
|
package com.appttude.h_mal.atlas_weather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
|
package com.appttude.h_mal.atlas_weather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
|
package com.appttude.h_mal.atlas_weather.ui.home.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui.settings
|
||||||
|
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.notification.NotificationReceiver
|
||||||
|
import com.appttude.h_mal.atlas_weather.widget.NewAppWidget
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.prefs, rootKey)
|
||||||
|
|
||||||
|
//listener on changed sort order preference:
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
prefs.registerOnSharedPreferenceChangeListener { _, key ->
|
||||||
|
if (key == "temp_units") {
|
||||||
|
val intent = Intent(requireContext(), NewAppWidget::class.java)
|
||||||
|
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
val ids = AppWidgetManager.getInstance(requireContext())
|
||||||
|
.getAppWidgetIds(ComponentName(requireContext(), NewAppWidget::class.java))
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
||||||
|
requireContext().sendBroadcast(intent)
|
||||||
|
}
|
||||||
|
if (key == "notif_boolean") {
|
||||||
|
setupNotificationBroadcaster(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == "widget_black_background"){
|
||||||
|
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|
||||||
|
val widgetManager = AppWidgetManager.getInstance(requireContext())
|
||||||
|
val ids =
|
||||||
|
widgetManager.getAppWidgetIds(ComponentName(requireContext(), NewAppWidget::class.java))
|
||||||
|
AppWidgetManager.getInstance(requireContext())
|
||||||
|
.notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
||||||
|
requireContext().sendBroadcast(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupNotificationBroadcaster(context: Context) {
|
||||||
|
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||||
|
val notificationIntent = Intent(context, NotificationReceiver::class.java)
|
||||||
|
val broadcast = PendingIntent.getBroadcast(context, 100, notificationIntent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 6)
|
||||||
|
cal.set(Calendar.MINUTE, 8)
|
||||||
|
cal.set(Calendar.SECOND, 5)
|
||||||
|
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.timeInMillis, AlarmManager.INTERVAL_DAY, broadcast)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
|
package com.appttude.h_mal.atlas_weather.ui.world
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -7,28 +7,20 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.observe
|
import androidx.lifecycle.observe
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||||
import com.appttude.h_mal.atlas_weather.utils.goBack
|
import com.appttude.h_mal.atlas_weather.utils.goBack
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
|
||||||
class AddLocationFragment : BaseFragment(), KodeinAware {
|
class AddLocationFragment : BaseFragment(R.layout.activity_add_forecast) {
|
||||||
override val kodein by kodein()
|
|
||||||
private val factory by instance<ApplicationViewModelFactory>()
|
|
||||||
|
|
||||||
private val viewModel by viewModels<WorldViewModel> { factory }
|
private val viewModel by getFragmentViewModel<WorldViewModel>()
|
||||||
|
|
||||||
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
|
package com.appttude.h_mal.atlas_weather.ui.world
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -9,12 +9,10 @@ import androidx.fragment.app.viewModels
|
|||||||
import androidx.lifecycle.observe
|
import androidx.lifecycle.observe
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldRecyclerAdapter
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
|
|
||||||
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldFragmentDirections
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_add_location.*
|
import kotlinx.android.synthetic.main.fragment_add_location.*
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
@@ -25,17 +23,8 @@ import org.kodein.di.generic.instance
|
|||||||
* A simple [Fragment] subclass.
|
* A simple [Fragment] subclass.
|
||||||
* create an instance of this fragment.
|
* create an instance of this fragment.
|
||||||
*/
|
*/
|
||||||
class WorldFragment : BaseFragment(), KodeinAware {
|
class WorldFragment : BaseFragment(R.layout.fragment_add_location) {
|
||||||
override val kodein by kodein()
|
val viewModel by getFragmentViewModel<WorldViewModel>()
|
||||||
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
|
package com.appttude.h_mal.atlas_weather.ui.world
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
10
app/src/atlasWeather/res/drawable/gradient.xml
Normal file
10
app/src/atlasWeather/res/drawable/gradient.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="@color/colour_two"
|
||||||
|
android:centerColor="@color/colour_three"
|
||||||
|
android:endColor="@color/colour_four"
|
||||||
|
android:type="linear"
|
||||||
|
android:angle="45"/>
|
||||||
|
</shape>
|
||||||
BIN
app/src/atlasWeather/res/font/archeologicaps.ttf
Normal file
BIN
app/src/atlasWeather/res/font/archeologicaps.ttf
Normal file
Binary file not shown.
@@ -76,7 +76,7 @@
|
|||||||
android:id="@+id/icon_main_4"
|
android:id="@+id/icon_main_4"
|
||||||
android:layout_width="64dp"
|
android:layout_width="64dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="64dp"
|
||||||
tools:src="@drawable/day_305" />
|
tools:srcCompat="@drawable/water_drop" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -48,7 +48,9 @@
|
|||||||
android:id="@+id/list_icon"
|
android:id="@+id/list_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:src="@drawable/day_305" />
|
android:adjustViewBounds="true"
|
||||||
|
tools:layout_width="32dp"
|
||||||
|
tools:srcCompat="@drawable/water_drop" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -8,21 +8,17 @@
|
|||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_home"
|
android:id="@+id/nav_home"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.HomeFragment"
|
android:name="com.appttude.h_mal.atlas_weather.ui.home.HomeFragment"
|
||||||
android:label="Home"
|
android:label="Home"
|
||||||
tools:layout="@layout/fragment_home">
|
tools:layout="@layout/fragment_home">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_homeFragment_to_furtherDetailsFragment"
|
android:id="@+id/action_homeFragment_to_furtherDetailsFragment"
|
||||||
app:destination="@id/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>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/furtherDetailsFragment"
|
android:id="@+id/furtherDetailsFragment"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.details.FurtherInfoFragment"
|
android:name="com.appttude.h_mal.atlas_weather.ui.details.FurtherInfoFragment"
|
||||||
android:label="Further Details">
|
android:label="Further Details">
|
||||||
<argument
|
<argument
|
||||||
android:name="forecast"
|
android:name="forecast"
|
||||||
@@ -31,44 +27,36 @@
|
|||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_world"
|
android:id="@+id/nav_world"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldFragment"
|
android:name="com.appttude.h_mal.atlas_weather.ui.world.WorldFragment"
|
||||||
android:label="World"
|
android:label="World"
|
||||||
tools:layout="@layout/fragment__two">
|
tools:layout="@layout/fragment__two">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_worldFragment_to_addLocationFragment"
|
android:id="@+id/action_worldFragment_to_addLocationFragment"
|
||||||
app:destination="@id/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
|
<action
|
||||||
android:id="@+id/action_worldFragment_to_worldItemFragment"
|
android:id="@+id/action_worldFragment_to_worldItemFragment"
|
||||||
app:destination="@id/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>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/addLocationFragment"
|
android:id="@+id/addLocationFragment"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.AddLocationFragment"
|
android:name="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment"
|
||||||
android:label="Add Weather Location"
|
android:label="Add Weather Location"
|
||||||
tools:layout="@layout/activity_add_forecast" />
|
tools:layout="@layout/activity_add_forecast" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/worldItemFragment"
|
android:id="@+id/worldItemFragment"
|
||||||
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.WorldItemFragment"
|
android:name="com.appttude.h_mal.atlas_weather.ui.WorldItemFragment"
|
||||||
android:label="Overview"
|
android:label="Overview"
|
||||||
tools:layout="@layout/fragment_home">
|
tools:layout="@layout/fragment_home">
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_worldItemFragment_to_furtherDetailsFragment"
|
android:id="@+id/action_worldItemFragment_to_furtherDetailsFragment"
|
||||||
app:destination="@id/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
|
<argument
|
||||||
android:name="weatherDisplay"
|
android:name="weatherDisplay"
|
||||||
app:argType="com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay" />
|
app:argType="com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/settings_fragment"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.ui.settings.SettingsFragment"
|
||||||
|
android:label="SettingsFragment" />
|
||||||
</navigation>
|
</navigation>
|
||||||
12
app/src/atlasWeather/res/values/colors.xml
Normal file
12
app/src/atlasWeather/res/values/colors.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#3F51B5</color>
|
||||||
|
<color name="colorPrimaryDark">#303F9F</color>
|
||||||
|
<color name="colorAccent">#FF4081</color>
|
||||||
|
|
||||||
|
<color name="colour_one">#E8D0DD</color>
|
||||||
|
<color name="colour_two">#5F8E7B</color>
|
||||||
|
<color name="colour_three">#B3C0CA</color>
|
||||||
|
<color name="colour_four">#8C98AD</color>
|
||||||
|
<color name="colour_five">#2E3532</color>
|
||||||
|
</resources>
|
||||||
@@ -3,24 +3,27 @@
|
|||||||
<!-- Base application theme. -->
|
<!-- Base application theme. -->
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="colorPrimary">@android:color/black</item>
|
<item name="colorPrimary">@android:color/transparent</item>
|
||||||
<item name="colorPrimaryDark">@color/colour_four</item>
|
<item name="colorPrimaryDark">@color/colour_four</item>
|
||||||
<item name="colorAccent">@color/colour_one</item>
|
<item name="colorAccent">@color/colour_one</item>
|
||||||
|
<item name="android:windowBackground">@drawable/gradient</item>
|
||||||
<item name="fontFamily">sans-serif-light</item>
|
<item name="fontFamily">sans-serif-light</item>
|
||||||
<item name="android:textColor">@color/colorAccent</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar">
|
<style name="AppTheme.NoActionBar">
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:windowBackground">@drawable/gradient</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="@android:style/TextAppearance">
|
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="@android:style/TextAppearance">
|
||||||
|
<item name="android:fontFamily">@font/archeologicaps</item>
|
||||||
<!--<item name="android:textColor">@color/colour_five</item>-->
|
<!--<item name="android:textColor">@color/colour_five</item>-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="titlebar" parent="@android:style/TextAppearance">
|
<style name="titlebar" parent="@android:style/TextAppearance">
|
||||||
|
<item name="android:fontFamily">@font/archeologicaps</item>
|
||||||
<!--<item name="android:textColor">@color/colour_five</item>-->
|
<!--<item name="android:textColor">@color/colour_five</item>-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -42,12 +45,4 @@
|
|||||||
<item name="android:textSize">32sp</item>
|
<item name="android:textSize">32sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="icon_style__further_deatils">
|
|
||||||
<item name="android:layout_width">64dp</item>
|
|
||||||
<item name="android:layout_height">64dp</item>
|
|
||||||
<item name="android:adjustViewBounds">true</item>
|
|
||||||
<item name="android:layout_gravity">center</item>
|
|
||||||
<item name="android:tint">@color/colorAccent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:configure="com.appttude.h_mal.atlas_weather.monoWeather.ui.widget.WidgetLocationPermissionActivity"
|
android:configure="com.appttude.h_mal.atlas_weather.ui.widget.WidgetLocationPermissionActivity"
|
||||||
android:initialKeyguardLayout="@layout/weather_app_widget"
|
android:initialKeyguardLayout="@layout/weather_app_widget"
|
||||||
android:initialLayout="@layout/weather_app_widget"
|
android:initialLayout="@layout/weather_app_widget"
|
||||||
android:minHeight="110.0dp"
|
android:minHeight="110.0dp"
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.appttude.h_mal.atlas_weather">
|
package="com.appttude.h_mal.atlas_weather">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.SET_ALARM" />
|
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
|
||||||
|
<application android:networkSecurityConfig="@xml/network_security_config" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.location"
|
android:name="android.hardware.location"
|
||||||
|
|||||||
@@ -1,27 +1,12 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.application
|
package com.appttude.h_mal.atlas_weather.application
|
||||||
|
|
||||||
import androidx.room.RoomDatabase
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
|
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.Api
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
|
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
|
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
|
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
|
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.loggingInterceptor
|
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.loggingInterceptor
|
||||||
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepositoryImpl
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
|
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
|
||||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import org.kodein.di.Kodein
|
|
||||||
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
|
const val LOCATION_PERMISSION_REQUEST = 505
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import kotlin.coroutines.suspendCoroutine
|
|||||||
|
|
||||||
|
|
||||||
class LocationProviderImpl(
|
class LocationProviderImpl(
|
||||||
val applicationContext: Context
|
private val applicationContext: Context
|
||||||
) : LocationProvider, LocationHelper(applicationContext) {
|
) : LocationProvider, LocationHelper(applicationContext) {
|
||||||
private var locationManager =
|
private var locationManager =
|
||||||
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
|
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.data.network.networkUtils
|
package com.appttude.h_mal.atlas_weather.data.network.networkUtils
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkInterceptor
|
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkInterceptor
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package com.appttude.h_mal.atlas_weather.model.forecast
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.appttude.h_mal.atlas_weather.model.weather.DailyWeather
|
import com.appttude.h_mal.atlas_weather.model.weather.DailyWeather
|
||||||
import com.appttude.h_mal.atlas_weather.utils.parcelableCreator
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.toDayName
|
import com.appttude.h_mal.atlas_weather.utils.toDayName
|
||||||
import com.appttude.h_mal.atlas_weather.utils.toDayString
|
import com.appttude.h_mal.atlas_weather.utils.toDayString
|
||||||
import com.appttude.h_mal.atlas_weather.utils.toTime
|
import com.appttude.h_mal.atlas_weather.utils.toTime
|
||||||
|
|
||||||
|
|
||||||
data class Forecast(
|
data class Forecast(
|
||||||
val date: String?,
|
val date: String?,
|
||||||
val day: String?,
|
val day: String?,
|
||||||
@@ -39,7 +39,9 @@ data class Forecast(
|
|||||||
parcel.readString(),
|
parcel.readString(),
|
||||||
parcel.readString(),
|
parcel.readString(),
|
||||||
parcel.readString(),
|
parcel.readString(),
|
||||||
parcel.readString())
|
parcel.readString()
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
constructor(dailyWeather: DailyWeather) : this(
|
constructor(dailyWeather: DailyWeather) : this(
|
||||||
dailyWeather.dt?.toDayString(),
|
dailyWeather.dt?.toDayString(),
|
||||||
@@ -72,13 +74,20 @@ data class Forecast(
|
|||||||
parcel.writeString(uvi)
|
parcel.writeString(uvi)
|
||||||
parcel.writeString(sunrise)
|
parcel.writeString(sunrise)
|
||||||
parcel.writeString(sunset)
|
parcel.writeString(sunset)
|
||||||
|
parcel.writeString(cloud)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object{
|
companion object CREATOR : Parcelable.Creator<Forecast> {
|
||||||
@JvmField val CREATOR = parcelableCreator(::Forecast)
|
override fun createFromParcel(parcel: Parcel): Forecast {
|
||||||
|
return Forecast(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<Forecast?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.model.forecast
|
package com.appttude.h_mal.atlas_weather.model.forecast
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
|
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
|
||||||
import com.appttude.h_mal.atlas_weather.model.weather.Hour
|
import com.appttude.h_mal.atlas_weather.model.weather.Hour
|
||||||
|
|
||||||
@@ -20,7 +22,26 @@ data class WeatherDisplay(
|
|||||||
val lat: Double = 0.00,
|
val lat: Double = 0.00,
|
||||||
val lon: Double = 0.00,
|
val lon: Double = 0.00,
|
||||||
var displayName: String?
|
var displayName: String?
|
||||||
|
): Parcelable {
|
||||||
|
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.createTypedArrayList(Hour),
|
||||||
|
parcel.createTypedArrayList(Forecast),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readString(),
|
||||||
|
parcel.readDouble(),
|
||||||
|
parcel.readDouble(),
|
||||||
|
parcel.readString()
|
||||||
) {
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
constructor(entity: EntityItem) : this(
|
constructor(entity: EntityItem) : this(
|
||||||
entity.weather.current?.temp,
|
entity.weather.current?.temp,
|
||||||
@@ -39,5 +60,38 @@ data class WeatherDisplay(
|
|||||||
entity.weather.lon,
|
entity.weather.lon,
|
||||||
entity.weather.locationString
|
entity.weather.locationString
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeValue(averageTemp)
|
||||||
|
parcel.writeString(unit)
|
||||||
|
parcel.writeString(location)
|
||||||
|
parcel.writeString(iconURL)
|
||||||
|
parcel.writeString(description)
|
||||||
|
parcel.writeTypedList(hourly)
|
||||||
|
parcel.writeTypedList(forecast)
|
||||||
|
parcel.writeString(windSpeed)
|
||||||
|
parcel.writeString(windDirection)
|
||||||
|
parcel.writeString(precipitation)
|
||||||
|
parcel.writeString(humidity)
|
||||||
|
parcel.writeString(clouds)
|
||||||
|
parcel.writeDouble(lat)
|
||||||
|
parcel.writeDouble(lon)
|
||||||
|
parcel.writeString(displayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.model.weather
|
package com.appttude.h_mal.atlas_weather.model.weather
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Current
|
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Current
|
||||||
|
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
|
||||||
|
|
||||||
data class Current(
|
data class Current(
|
||||||
val dt: Int? = null,
|
val dt: Int? = null,
|
||||||
@@ -34,7 +35,7 @@ data class Current(
|
|||||||
dailyItem.feelsLike,
|
dailyItem.feelsLike,
|
||||||
dailyItem.windDeg,
|
dailyItem.windDeg,
|
||||||
dailyItem.dewPoint,
|
dailyItem.dewPoint,
|
||||||
dailyItem.weather?.get(0)?.icon?.let { "https://openweathermap.org/img/wn/${it}@4x.png" },
|
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
|
||||||
dailyItem.weather?.get(0)?.description,
|
dailyItem.weather?.get(0)?.description,
|
||||||
dailyItem.weather?.get(0)?.main,
|
dailyItem.weather?.get(0)?.main,
|
||||||
dailyItem.weather?.get(0)?.id,
|
dailyItem.weather?.get(0)?.id,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.model.weather
|
package com.appttude.h_mal.atlas_weather.model.weather
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.DailyItem
|
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.DailyItem
|
||||||
|
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
|
||||||
|
|
||||||
|
|
||||||
data class DailyWeather(
|
data class DailyWeather(
|
||||||
@@ -39,7 +40,7 @@ data class DailyWeather(
|
|||||||
dailyItem.dewPoint,
|
dailyItem.dewPoint,
|
||||||
dailyItem.windSpeed,
|
dailyItem.windSpeed,
|
||||||
dailyItem.windDeg,
|
dailyItem.windDeg,
|
||||||
dailyItem.weather?.get(0)?.icon?.let { "https://openweathermap.org/img/wn/${it}@4x.png" },
|
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
|
||||||
dailyItem.weather?.get(0)?.description,
|
dailyItem.weather?.get(0)?.description,
|
||||||
dailyItem.weather?.get(0)?.main,
|
dailyItem.weather?.get(0)?.main,
|
||||||
dailyItem.weather?.get(0)?.id,
|
dailyItem.weather?.get(0)?.id,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.model.weather
|
package com.appttude.h_mal.atlas_weather.model.weather
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
|
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
|
||||||
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Hour as ForecastHour
|
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Hour as ForecastHour
|
||||||
|
|
||||||
@@ -8,12 +10,38 @@ data class Hour(
|
|||||||
val dt: Int? = null,
|
val dt: Int? = null,
|
||||||
val temp: Double? = null,
|
val temp: Double? = null,
|
||||||
val icon: String? = null
|
val icon: String? = null
|
||||||
|
): Parcelable {
|
||||||
|
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||||
|
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||||
|
parcel.readString()
|
||||||
) {
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
constructor(hour: ForecastHour) : this(
|
constructor(hour: ForecastHour) : this(
|
||||||
hour.dt,
|
hour.dt,
|
||||||
hour.temp,
|
hour.temp,
|
||||||
generateIconUrlString(hour.weather?.getOrNull(0)?.icon)
|
generateIconUrlString(hour.weather?.getOrNull(0)?.icon)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeValue(dt)
|
||||||
|
parcel.writeValue(temp)
|
||||||
|
parcel.writeString(icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object CREATOR : Parcelable.Creator<Hour> {
|
||||||
|
override fun createFromParcel(parcel: Parcel): Hour {
|
||||||
|
return Hour(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<Hour?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
package com.appttude.h_mal.monoWeather.ui
|
||||||
|
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
@@ -14,11 +14,11 @@ import androidx.lifecycle.Observer
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||||
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Event
|
import com.appttude.h_mal.atlas_weather.utils.Event
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||||
import com.appttude.h_mal.atlas_weather.utils.hide
|
import com.appttude.h_mal.atlas_weather.utils.hide
|
||||||
import com.appttude.h_mal.atlas_weather.utils.show
|
import com.appttude.h_mal.atlas_weather.utils.show
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -27,7 +27,8 @@ import org.kodein.di.android.x.kodein
|
|||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayoutId), KodeinAware {
|
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayoutId),
|
||||||
|
KodeinAware {
|
||||||
|
|
||||||
override val kodein by kodein()
|
override val kodein by kodein()
|
||||||
val factory by instance<ApplicationViewModelFactory>()
|
val factory by instance<ApplicationViewModelFactory>()
|
||||||
@@ -43,9 +44,11 @@ abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentL
|
|||||||
|
|
||||||
// toggle visibility of progress spinner while async operations are taking place
|
// toggle visibility of progress spinner while async operations are taking place
|
||||||
fun progressBarStateObserver(progressBar: View) = Observer<Event<Boolean>> {
|
fun progressBarStateObserver(progressBar: View) = Observer<Event<Boolean>> {
|
||||||
when (it.getContentIfNotHandled()) {
|
it.getContentIfNotHandled()?.let { i ->
|
||||||
true -> progressBar.fadeIn()
|
if (i)
|
||||||
false -> progressBar.fadeOut()
|
progressBar.fadeIn()
|
||||||
|
else
|
||||||
|
progressBar.fadeOut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +75,11 @@ abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentL
|
|||||||
permissionCode: Int,
|
permissionCode: Int,
|
||||||
permissionGranted: () -> Unit
|
permissionGranted: () -> Unit
|
||||||
) {
|
) {
|
||||||
if (ActivityCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
|
if (ActivityCompat.checkSelfPermission(
|
||||||
|
requireContext(),
|
||||||
|
permission
|
||||||
|
) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
requestPermissions(arrayOf(permission), permissionCode)
|
requestPermissions(arrayOf(permission), permissionCode)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -123,11 +130,16 @@ abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentL
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int,
|
||||||
|
permissions: Array<String?>,
|
||||||
|
grantResults: IntArray
|
||||||
|
) {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
if (requestCode == LOCATION_PERMISSION_REQUEST) {
|
if (requestCode == LOCATION_PERMISSION_REQUEST) {
|
||||||
if (grantResults.isNotEmpty() &&
|
if (grantResults.isNotEmpty() &&
|
||||||
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
permissionsGranted()
|
permissionsGranted()
|
||||||
displayToast("Permission granted")
|
displayToast("Permission granted")
|
||||||
} else {
|
} else {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
package com.appttude.h_mal.atlas_weather.ui
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -11,7 +11,6 @@ import androidx.navigation.ui.AppBarConfiguration
|
|||||||
import androidx.navigation.ui.setupActionBarWithNavController
|
import androidx.navigation.ui.setupActionBarWithNavController
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.settings.UnitSettingsActivity
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import kotlinx.android.synthetic.main.activity_main_navigation.*
|
import kotlinx.android.synthetic.main.activity_main_navigation.*
|
||||||
|
|
||||||
@@ -35,29 +34,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBottomBar(navView: BottomNavigationView, navController: NavController) {
|
private fun setupBottomBar(navView: BottomNavigationView, navController: NavController) {
|
||||||
val tabs = setOf(R.id.nav_home, R.id.nav_world)
|
|
||||||
val appBarConfiguration = AppBarConfiguration(tabs)
|
val appBarConfiguration = AppBarConfiguration(tabs)
|
||||||
|
|
||||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
navView.setupWithNavController(navController)
|
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 {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
// Handle action bar item clicks here. The action bar will
|
// Handle action bar item clicks here. The action bar will
|
||||||
// automatically handle clicks on the Home/Up button, so long
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
// as you specify a parent activity in AndroidManifest.xml.
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_settings -> {
|
|
||||||
val i = Intent(this, UnitSettingsActivity::class.java)
|
|
||||||
startActivity(i)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
android.R.id.home -> onBackPressed()
|
android.R.id.home -> onBackPressed()
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
@@ -4,9 +4,9 @@ package com.appttude.h_mal.atlas_weather.utils
|
|||||||
fun generateIconUrlString(icon: String?): String?{
|
fun generateIconUrlString(icon: String?): String?{
|
||||||
return icon?.let {
|
return icon?.let {
|
||||||
StringBuilder()
|
StringBuilder()
|
||||||
.append("https://openweathermap.org/img/wn/")
|
.append("http://openweathermap.org/img/wn/")
|
||||||
.append(it)
|
.append(it)
|
||||||
.append("@4x.png")
|
.append("@2x.png")
|
||||||
.toString()
|
.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.appttude.h_mal.atlas_weather.utils
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -10,7 +11,7 @@ import android.widget.ImageView
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.bumptech.glide.Glide
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
fun View.show() {
|
fun View.show() {
|
||||||
this.visibility = View.VISIBLE
|
this.visibility = View.VISIBLE
|
||||||
@@ -33,15 +34,9 @@ fun ViewGroup.generateView(layoutId: Int): View = LayoutInflater
|
|||||||
.inflate(layoutId, this, false)
|
.inflate(layoutId, this, false)
|
||||||
|
|
||||||
fun ImageView.loadImage(url: String?){
|
fun ImageView.loadImage(url: String?){
|
||||||
val c = Glide.with(this)
|
Picasso.get().load(url)
|
||||||
.load(url)
|
.placeholder(R.drawable.ic_baseline_cloud_queue_24)
|
||||||
viewTreeObserver.addOnPreDrawListener {
|
|
||||||
c.override(width, height)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
c.placeholder(R.drawable.ic_baseline_cloud_queue_24)
|
|
||||||
.error(R.drawable.ic_baseline_cloud_off_24)
|
.error(R.drawable.ic_baseline_cloud_off_24)
|
||||||
.fitCenter()
|
|
||||||
.into(this)
|
.into(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
||||||
import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
|
import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
|
||||||
|
|
||||||
|
|
||||||
class ApplicationViewModelFactory(
|
class ApplicationViewModelFactory(
|
||||||
private val locationProvider: LocationProvider,
|
private val locationProvider: LocationProvider,
|
||||||
private val repository: RepositoryImpl
|
private val repository: RepositoryImpl
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
package com.appttude.h_mal.atlas_weather.widget
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
package com.appttude.h_mal.atlas_weather.widget
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetProvider
|
import android.appwidget.AppWidgetProvider
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import com.appttude.h_mal.atlas_weather.widget.WidgetJobServiceIntent.Companion.enqueueWork
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetJobServiceIntent.Companion.enqueueWork
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of App Widget functionality.
|
* Implementation of App Widget functionality.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
package com.appttude.h_mal.atlas_weather.widget
|
||||||
|
|
||||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
@@ -13,12 +13,12 @@ import android.widget.RemoteViews
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.app.ActivityCompat.checkSelfPermission
|
import androidx.core.app.ActivityCompat.checkSelfPermission
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.widget.WidgetState.*
|
||||||
|
import com.appttude.h_mal.atlas_weather.widget.WidgetState.Companion.getWidgetState
|
||||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||||
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
|
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
|
||||||
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
|
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity
|
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.*
|
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.Companion.getWidgetState
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
|
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
|
||||||
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
|
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
package com.appttude.h_mal.atlas_weather.widget
|
||||||
|
|
||||||
enum class WidgetState {
|
enum class WidgetState {
|
||||||
NO_LOCATION,
|
NO_LOCATION,
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
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="com.appttude.h_mal.atlas_weather.monoWeather.ui.world.AddLocationFragment">
|
tools:context="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment">
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:menu="@menu/tabs_menu" />
|
app:menu="@menu/tabs_menu" />
|
||||||
|
|
||||||
<fragment
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -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.monoWeather.ui.world.WorldFragment">
|
tools:context="com.appttude.h_mal.atlas_weather.ui.world.WorldFragment">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -5,7 +5,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.monoWeather.ui.world.AddLocationFragment">
|
tools:context="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="gone">
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
style="?android:attr/progressBarStyle"
|
style="?android:attr/progressBarStyle"
|
||||||
@@ -34,6 +34,4 @@
|
|||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context=".legacy.ui.home.MainActivity">
|
tools:context=".legacy.ui.home.MainActivity">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/settings_fragment"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="100"
|
||||||
android:title="@string/action_settings"
|
android:title="@string/action_settings"
|
||||||
android:icon="@drawable/ic_round_settings_24"
|
android:icon="@drawable/ic_round_settings_24"
|
||||||
|
|||||||
@@ -27,4 +27,12 @@
|
|||||||
<item name="android:textColor">#ffffff</item>
|
<item name="android:textColor">#ffffff</item>
|
||||||
<item name="android:textSize">12sp</item>
|
<item name="android:textSize">12sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="icon_style__further_deatils">
|
||||||
|
<item name="android:layout_width">48dp</item>
|
||||||
|
<item name="android:layout_height">48dp</item>
|
||||||
|
<item name="android:adjustViewBounds">true</item>
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
|
<item name="android:tint">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
6
app/src/main/res/xml/network_security_config.xml
Normal file
6
app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<domain includeSubdomains="true">openweathermap.org</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
@@ -2,9 +2,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -15,7 +12,7 @@
|
|||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:node="merge">
|
tools:node="merge">
|
||||||
<activity
|
<activity
|
||||||
android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity"
|
android:name="com.appttude.h_mal.atlas_weather.ui.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"
|
||||||
@@ -27,18 +24,15 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
|
||||||
android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.settings.UnitSettingsActivity"
|
|
||||||
android:label="Settings" />
|
|
||||||
|
|
||||||
<activity android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.widget.WidgetLocationPermissionActivity"
|
<activity android:name="com.appttude.h_mal.monoWeather.ui.widget.WidgetLocationPermissionActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver android:name="com.appttude.h_mal.atlas_weather.monoWeather.widget.NewAppWidget"
|
<receiver android:name="com.appttude.h_mal.atlas_weather.widget.NewAppWidget"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
@@ -52,7 +46,7 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetJobServiceIntent"
|
android:name="com.appttude.h_mal.atlas_weather.widget.WidgetJobServiceIntent"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.settings
|
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.preference.PreferenceActivity
|
|
||||||
import android.preference.PreferenceFragment
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.NewAppWidget
|
|
||||||
|
|
||||||
|
|
||||||
class UnitSettingsActivity : PreferenceActivity() {
|
|
||||||
private var prefListener: OnSharedPreferenceChangeListener? = null
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
PreferenceManager.setDefaultValues(this, R.xml.prefs_screen, false)
|
|
||||||
fragmentManager.beginTransaction().replace(android.R.id.content, MyPreferenceFragment()).commit()
|
|
||||||
|
|
||||||
//listener on changed sort order preference:
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
|
||||||
prefListener = OnSharedPreferenceChangeListener { _, key ->
|
|
||||||
if (key == "temp_units") {
|
|
||||||
val intent = Intent(baseContext, NewAppWidget::class.java)
|
|
||||||
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
|
||||||
val ids = AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(application, NewAppWidget::class.java))
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
|
||||||
sendBroadcast(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "widget_black_background"){
|
|
||||||
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|
|
||||||
val widgetManager = AppWidgetManager.getInstance(this)
|
|
||||||
val ids = widgetManager.getAppWidgetIds(ComponentName(this, NewAppWidget::class.java))
|
|
||||||
AppWidgetManager.getInstance(this).notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
|
||||||
sendBroadcast(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prefs.registerOnSharedPreferenceChangeListener(prefListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MyPreferenceFragment : PreferenceFragment() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
addPreferencesFromResource(R.xml.prefs_screen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
|
||||||
|
val tabs = setOf(R.id.nav_home, R.id.nav_world)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.dialog
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
|
import android.text.Html
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
interface DeclarationBuilder{
|
||||||
|
val link: String
|
||||||
|
val message: String
|
||||||
|
|
||||||
|
fun Context.readFromResources(@StringRes id: Int) = resources.getString(id)
|
||||||
|
|
||||||
|
fun buildMessage(): CharSequence? {
|
||||||
|
val link1 = "<font color='blue'><a href=\"$link\">here</a></font>"
|
||||||
|
val message = "$message See my privacy policy: $link1"
|
||||||
|
return Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.dialog
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) {
|
||||||
|
|
||||||
|
override val link: String = "https://sites.google.com/view/hmaldev/home/monochrome"
|
||||||
|
override val message: String = "Hi, thank you for downloading my app. Google play isn't letting me upload my app to the Playstore until I have a privacy declaration :(. My app is basically used to demonstrate my code=ing to potential employers and others. I do NOT store or process any information. The location permission in the app is there just to provide the end user with weather data."
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseDeclarationDialog(val context: Context): DeclarationBuilder {
|
||||||
|
abstract override val link: String
|
||||||
|
abstract override val message: String
|
||||||
|
|
||||||
|
lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
|
fun showDialog(agreeCallback: () -> Unit = { }, disagreeCallback: () -> Unit = { }) {
|
||||||
|
val myMessage = buildMessage()
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(context)
|
||||||
|
.setPositiveButton("agree") { _, _ ->
|
||||||
|
agreeCallback()
|
||||||
|
}
|
||||||
|
.setNegativeButton("disagree") { _, _ ->
|
||||||
|
disagreeCallback()
|
||||||
|
}
|
||||||
|
.setMessage(myMessage)
|
||||||
|
.setCancelable(false)
|
||||||
|
|
||||||
|
dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
// Make the textview clickable. Must be called after show()
|
||||||
|
val msgTxt = dialog.findViewById<View>(android.R.id.message) as TextView?
|
||||||
|
msgTxt?.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dismiss() = dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
package com.appttude.h_mal.monoWeather.ui
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
package com.appttude.h_mal.monoWeather.ui
|
||||||
|
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.details
|
package com.appttude.h_mal.monoWeather.ui.details
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home
|
package com.appttude.h_mal.monoWeather.ui.home
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.observe
|
import androidx.navigation.Navigation.findNavController
|
||||||
|
import androidx.navigation.ui.onNavDestinationSelected
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||||
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.dialog.PermissionsDeclarationDialog
|
import com.appttude.h_mal.monoWeather.dialog.PermissionsDeclarationDialog
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.BaseFragment
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
@@ -35,6 +34,7 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) {
|
|||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
val recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
|
val recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
|
||||||
navigateToFurtherDetails(it)
|
navigateToFurtherDetails(it)
|
||||||
@@ -86,4 +86,14 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) {
|
|||||||
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||||
navigateTo(directions)
|
navigateTo(directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
inflater.inflate(R.menu.menu_main, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val navController = findNavController(requireActivity(), R.id.container)
|
||||||
|
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
|
package com.appttude.h_mal.monoWeather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@@ -17,7 +17,7 @@ class ViewHolderCurrent(listItemView: View) : RecyclerView.ViewHolder(listItemVi
|
|||||||
var tempUnit: TextView = listItemView.findViewById(R.id.temp_unit_4)
|
var tempUnit: TextView = listItemView.findViewById(R.id.temp_unit_4)
|
||||||
|
|
||||||
fun bindData(weather: WeatherDisplay?){
|
fun bindData(weather: WeatherDisplay?){
|
||||||
locationTV.text = weather?.location
|
locationTV.text = weather?.displayName
|
||||||
conditionTV.text = weather?.description
|
conditionTV.text = weather?.description
|
||||||
weatherIV.loadImage(weather?.iconURL)
|
weatherIV.loadImage(weather?.iconURL)
|
||||||
avgTempTV.text = weather?.averageTemp?.toInt().toString()
|
avgTempTV.text = weather?.averageTemp?.toInt().toString()
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter
|
package com.appttude.h_mal.monoWeather.ui.home.adapter
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.EmptyViewHolder
|
import com.appttude.h_mal.monoWeather.ui.EmptyViewHolder
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast.ViewHolderForecast
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecast.ViewHolderForecast
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
||||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
||||||
import com.appttude.h_mal.atlas_weather.utils.generateView
|
import com.appttude.h_mal.atlas_weather.utils.generateView
|
||||||
|
|
||||||
class WeatherRecyclerAdapter(
|
class WeatherRecyclerAdapter(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast
|
package com.appttude.h_mal.monoWeather.ui.home.adapter.forecast
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user