├── .github ├── ci-gradle.properties └── workflows │ └── Check.yaml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── androiddevchallenge │ │ ├── application │ │ └── WeatherApplication.kt │ │ ├── city │ │ ├── CityManager.kt │ │ ├── CityManagerImpl.kt │ │ └── CityModule.kt │ │ ├── city_edit_view │ │ ├── CityEditView.kt │ │ ├── CityEditViewContract.kt │ │ └── CityEditViewPresenter.kt │ │ ├── date │ │ ├── DateManager.kt │ │ ├── DateManagerImpl.kt │ │ └── DateModule.kt │ │ ├── error_view │ │ └── ErrorView.kt │ │ ├── forecast_cell_view │ │ ├── ForecastCellView.kt │ │ ├── ForecastCellViewContract.kt │ │ └── ForecastCellViewPresenter.kt │ │ ├── graph │ │ ├── WeatherGraph.kt │ │ ├── WeatherGraphInitializationManager.kt │ │ ├── WeatherGraphInitializationManagerImpl.kt │ │ └── WeatherGraphInitializationModule.kt │ │ ├── main_activity │ │ ├── MainActivity.kt │ │ ├── MainActivityContract.kt │ │ └── MainActivityPresenter.kt │ │ ├── main_view │ │ ├── MainView.kt │ │ ├── MainViewContract.kt │ │ └── MainViewPresenter.kt │ │ ├── main_view_background_view │ │ └── MainViewBackgroundView.kt │ │ ├── main_view_top_bar_view │ │ ├── MainViewTopBarView.kt │ │ ├── MainViewTopBarViewContract.kt │ │ └── MainViewTopBarViewPresenter.kt │ │ ├── main_weather_animated_view │ │ └── MainWeatherAnimatedView.kt │ │ ├── network │ │ ├── NetworkManager.kt │ │ ├── NetworkManagerImpl.kt │ │ └── NetworkModule.kt │ │ ├── neumorphism_card_square_view │ │ └── NeumorphismCardSquareView.kt │ │ ├── theme │ │ ├── Shape.kt │ │ ├── ThemeCompose.kt │ │ ├── ThemeManager.kt │ │ ├── ThemeManagerImpl.kt │ │ ├── ThemeModule.kt │ │ └── Type.kt │ │ ├── weather │ │ ├── Weather.kt │ │ ├── WeatherManager.kt │ │ ├── WeatherManagerImpl.kt │ │ └── WeatherModule.kt │ │ ├── weather_api │ │ ├── WeatherApiException.kt │ │ ├── WeatherApiManager.kt │ │ ├── WeatherApiManagerImpl.kt │ │ └── WeatherApiModule.kt │ │ ├── weather_icon_view │ │ └── WeatherIconView.kt │ │ ├── weather_repository │ │ ├── WeatherRepository.kt │ │ ├── WeatherRepositoryImpl.kt │ │ └── WeatherRepositoryModule.kt │ │ └── weather_unit │ │ ├── WeatherUnit.kt │ │ ├── WeatherUnitManager.kt │ │ ├── WeatherUnitManagerImpl.kt │ │ └── WeatherUnitModule.kt │ └── res │ ├── city_edit_view │ ├── drawable-night │ │ ├── city_edit_view_ic_outline_info_24.xml │ │ └── city_edit_view_loop.xml │ ├── drawable │ │ ├── city_edit_view_ic_outline_info_24.xml │ │ └── city_edit_view_loop.xml │ ├── values-fr │ │ └── strings.xml │ └── values │ │ └── strings.xml │ ├── error_view │ ├── values-fr │ │ └── strings.xml │ └── values │ │ └── strings.xml │ ├── icon │ ├── color │ │ ├── ic_launcher_background_gradient.xml │ │ └── ic_launcher_background_gradient_dark.xml │ ├── drawable-night │ │ └── ic_launcher_background.xml │ ├── drawable-v24 │ │ └── ic_foreground_weather.png │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── ic_launcher_background_night.xml │ ├── mipmap-anydpi-v26 │ │ └── ic_launcher.xml │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ └── mipmap-xxxhdpi │ │ └── ic_launcher.png │ ├── main │ ├── values-night │ │ └── themes.xml │ └── values │ │ ├── strings.xml │ │ └── themes.xml │ ├── main_activity │ ├── drawable-hdpi │ │ └── main_activity_splash_image.png │ ├── drawable-mdpi │ │ └── main_activity_splash_image.png │ ├── drawable-night │ │ └── main_activity_splash_background.xml │ ├── drawable-xhdpi │ │ └── main_activity_splash_image.png │ ├── drawable-xxhdpi │ │ └── main_activity_splash_image.png │ ├── drawable-xxxhdpi │ │ └── main_activity_splash_image.png │ ├── drawable │ │ └── main_activity_splash_background.xml │ ├── values-night │ │ └── colors.xml │ └── values │ │ ├── colors.xml │ │ └── styles.xml │ ├── main_activity_splash_dark │ ├── drawable-hdpi │ │ └── main_activity_splash_image_dark.png │ ├── drawable-mdpi │ │ └── main_activity_splash_image_dark.png │ ├── drawable-xhdpi │ │ └── main_activity_splash_image_dark.png │ ├── drawable-xxhdpi │ │ └── main_activity_splash_image_dark.png │ └── drawable-xxxhdpi │ │ └── main_activity_splash_image_dark.png │ ├── main_weather_animated_view │ ├── drawable-hdpi │ │ └── main_weather_animated_view_circle_with_shadow.webp │ ├── drawable-mdpi │ │ └── main_weather_animated_view_circle_with_shadow.webp │ ├── drawable-xhdpi │ │ └── main_weather_animated_view_circle_with_shadow.webp │ ├── drawable-xxhdpi │ │ └── main_weather_animated_view_circle_with_shadow.webp │ ├── drawable-xxxhdpi │ │ └── main_weather_animated_view_circle_with_shadow.webp │ └── drawable │ │ └── main_weather_animated_view_circle_gradient_yellow.xml │ ├── main_weather_animated_view_figure │ ├── drawable-hdpi │ │ ├── main_weather_animated_view_figure_1.webp │ │ ├── main_weather_animated_view_figure_2.webp │ │ ├── main_weather_animated_view_figure_3.webp │ │ ├── main_weather_animated_view_figure_4.webp │ │ ├── main_weather_animated_view_figure_5.webp │ │ ├── main_weather_animated_view_figure_6.webp │ │ ├── main_weather_animated_view_figure_7.webp │ │ └── main_weather_animated_view_figure_8.webp │ ├── drawable-mdpi │ │ ├── main_weather_animated_view_figure_1.webp │ │ ├── main_weather_animated_view_figure_2.webp │ │ ├── main_weather_animated_view_figure_3.webp │ │ ├── main_weather_animated_view_figure_4.webp │ │ ├── main_weather_animated_view_figure_5.webp │ │ ├── main_weather_animated_view_figure_6.webp │ │ ├── main_weather_animated_view_figure_7.webp │ │ └── main_weather_animated_view_figure_8.webp │ ├── drawable-xhdpi │ │ ├── main_weather_animated_view_figure_1.webp │ │ ├── main_weather_animated_view_figure_2.webp │ │ ├── main_weather_animated_view_figure_3.webp │ │ ├── main_weather_animated_view_figure_4.webp │ │ ├── main_weather_animated_view_figure_5.webp │ │ ├── main_weather_animated_view_figure_6.webp │ │ ├── main_weather_animated_view_figure_7.webp │ │ └── main_weather_animated_view_figure_8.webp │ ├── drawable-xxhdpi │ │ ├── main_weather_animated_view_figure_1.webp │ │ ├── main_weather_animated_view_figure_2.webp │ │ ├── main_weather_animated_view_figure_3.webp │ │ ├── main_weather_animated_view_figure_4.webp │ │ ├── main_weather_animated_view_figure_5.webp │ │ ├── main_weather_animated_view_figure_6.webp │ │ ├── main_weather_animated_view_figure_7.webp │ │ └── main_weather_animated_view_figure_8.webp │ └── drawable-xxxhdpi │ │ ├── main_weather_animated_view_figure_1.webp │ │ ├── main_weather_animated_view_figure_2.webp │ │ ├── main_weather_animated_view_figure_3.webp │ │ ├── main_weather_animated_view_figure_4.webp │ │ ├── main_weather_animated_view_figure_5.webp │ │ ├── main_weather_animated_view_figure_6.webp │ │ ├── main_weather_animated_view_figure_7.webp │ │ └── main_weather_animated_view_figure_8.webp │ ├── theme │ ├── values-night │ │ └── booleans.xml │ └── values │ │ ├── booleans.xml │ │ └── colors.xml │ ├── weather_icon_2_view │ └── drawable-nodpi │ │ ├── weather_2_blizzard.webp │ │ ├── weather_2_clear.webp │ │ ├── weather_2_cloud_rain_thunder.webp │ │ ├── weather_2_cloud_sleet_snow_thunder.webp │ │ ├── weather_2_cloudy.webp │ │ ├── weather_2_fog.webp │ │ ├── weather_2_freezing_drizzle.webp │ │ ├── weather_2_freezing_fog.webp │ │ ├── weather_2_freezing_rain.webp │ │ ├── weather_2_heavy_rain.webp │ │ ├── weather_2_heavy_rain_swrs_day.webp │ │ ├── weather_2_heavy_rain_swrs_night.webp │ │ ├── weather_2_heavy_sleet.webp │ │ ├── weather_2_heavy_sleet_swrs_day.webp │ │ ├── weather_2_heavy_sleet_swrs_night.webp │ │ ├── weather_2_heavy_snow.webp │ │ ├── weather_2_heavy_snow_swrs_day.webp │ │ ├── weather_2_heavy_snow_swrs_night.webp │ │ ├── weather_2_iso_rain_swrs_day.webp │ │ ├── weather_2_iso_rain_swrs_night.webp │ │ ├── weather_2_iso_sleet_swrs_day.webp │ │ ├── weather_2_iso_sleet_swrs_night.webp │ │ ├── weather_2_iso_snow_swrs_day.webp │ │ ├── weather_2_iso_snow_swrs_night.webp │ │ ├── weather_2_mist.webp │ │ ├── weather_2_mod_rain.webp │ │ ├── weather_2_mod_rain_swrs_day.webp │ │ ├── weather_2_mod_rain_swrs_night.webp │ │ ├── weather_2_mod_sleet.webp │ │ ├── weather_2_mod_sleet_swrs_day.webp │ │ ├── weather_2_mod_sleet_swrs_night.webp │ │ ├── weather_2_mod_snow.webp │ │ ├── weather_2_mod_snow_swrs_day.webp │ │ ├── weather_2_mod_snow_swrs_night.webp │ │ ├── weather_2_occ_light_rain.webp │ │ ├── weather_2_occ_light_sleet.webp │ │ ├── weather_2_occ_light_snow.webp │ │ ├── weather_2_overcast.webp │ │ ├── weather_2_part_cloud_rain_thunder_day.webp │ │ ├── weather_2_part_cloud_rain_thunder_night.webp │ │ ├── weather_2_part_cloud_sleet_snow_thunder_day.webp │ │ ├── weather_2_part_cloud_sleet_snow_thunder_night.webp │ │ ├── weather_2_partly_cloudy_day.webp │ │ ├── weather_2_partly_cloudy_night.webp │ │ ├── weather_2_sunny.webp │ │ └── weather_2_wind.webp │ └── weather_icon_view │ ├── drawable-hdpi │ ├── weather_cloud_storm.webp │ ├── weather_mid_snow_fast_winds.webp │ ├── weather_moon_cloud_fast_wind.webp │ ├── weather_moon_cloud_mid_rain.webp │ ├── weather_moon_fast_wind.webp │ ├── weather_rain.webp │ ├── weather_snow.webp │ ├── weather_storm.webp │ ├── weather_sun.webp │ ├── weather_sun_cloud_angled_rain.webp │ ├── weather_sun_cloud_little_rain.webp │ └── weather_tornado.webp │ ├── drawable-mdpi │ ├── weather_cloud_storm.webp │ ├── weather_mid_snow_fast_winds.webp │ ├── weather_moon_cloud_fast_wind.webp │ ├── weather_moon_cloud_mid_rain.webp │ ├── weather_moon_fast_wind.webp │ ├── weather_rain.webp │ ├── weather_snow.webp │ ├── weather_storm.webp │ ├── weather_sun.webp │ ├── weather_sun_cloud_angled_rain.webp │ ├── weather_sun_cloud_little_rain.webp │ └── weather_tornado.webp │ ├── drawable-xhdpi │ ├── weather_cloud_storm.webp │ ├── weather_mid_snow_fast_winds.webp │ ├── weather_moon_cloud_fast_wind.webp │ ├── weather_moon_cloud_mid_rain.webp │ ├── weather_moon_fast_wind.webp │ ├── weather_rain.webp │ ├── weather_snow.webp │ ├── weather_storm.webp │ ├── weather_sun.webp │ ├── weather_sun_cloud_angled_rain.webp │ ├── weather_sun_cloud_little_rain.webp │ └── weather_tornado.webp │ ├── drawable-xxhdpi │ ├── weather_cloud_storm.webp │ ├── weather_mid_snow_fast_winds.webp │ ├── weather_moon_cloud_fast_wind.webp │ ├── weather_moon_cloud_mid_rain.webp │ ├── weather_moon_fast_wind.webp │ ├── weather_rain.webp │ ├── weather_snow.webp │ ├── weather_storm.webp │ ├── weather_sun.webp │ ├── weather_sun_cloud_angled_rain.webp │ ├── weather_sun_cloud_little_rain.webp │ └── weather_tornado.webp │ └── drawable-xxxhdpi │ ├── weather_cloud_storm.webp │ ├── weather_mid_snow_fast_winds.webp │ ├── weather_moon_cloud_fast_wind.webp │ ├── weather_moon_cloud_mid_rain.webp │ ├── weather_moon_fast_wind.webp │ ├── weather_rain.webp │ ├── weather_snow.webp │ ├── weather_storm.webp │ ├── weather_sun.webp │ ├── weather_sun_cloud_angled_rain.webp │ ├── weather_sun_cloud_little_rain.webp │ └── weather_tornado.webp ├── build.gradle ├── debug.keystore ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── results ├── banner.jpg ├── screenshot_1.png ├── screenshot_2.png ├── screenshot_3.png ├── screenshot_4.png ├── screenshot_5.png ├── video.mp4 └── video_as_gif.gif ├── settings.gradle └── spotless └── copyright.kt /.github/ci-gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Copyright 2020 The Android Open Source Project 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | org.gradle.daemon=false 19 | org.gradle.parallel=true 20 | org.gradle.jvmargs=-Xmx5120m 21 | org.gradle.workers.max=2 22 | 23 | kotlin.incremental=false 24 | kotlin.compiler.execution.strategy=in-process 25 | -------------------------------------------------------------------------------- /.github/workflows/Check.yaml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 30 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | 17 | - name: Copy CI gradle.properties 18 | run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties 19 | 20 | - name: Set up JDK 11 21 | uses: actions/setup-java@v1 22 | with: 23 | java-version: 11 24 | 25 | - name: Build project 26 | run: ./gradlew spotlessCheck assembleDebug lintDebug --stacktrace 27 | 28 | - name: Upload build outputs (APKs) 29 | uses: actions/upload-artifact@v2 30 | with: 31 | name: build-outputs 32 | path: app/build/outputs 33 | 34 | - name: Upload build reports 35 | if: always() 36 | uses: actions/upload-artifact@v2 37 | with: 38 | name: build-reports 39 | path: app/build/reports 40 | 41 | test: 42 | needs: build 43 | runs-on: macOS-latest # enables hardware acceleration in the virtual machine 44 | timeout-minutes: 30 45 | strategy: 46 | matrix: 47 | api-level: [23, 26, 29] 48 | 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v2 52 | 53 | - name: Copy CI gradle.properties 54 | run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties 55 | 56 | - name: Set up JDK 11 57 | uses: actions/setup-java@v1 58 | with: 59 | java-version: 11 60 | 61 | - name: Run instrumentation tests 62 | uses: reactivecircus/android-emulator-runner@v2 63 | with: 64 | api-level: ${{ matrix.api-level }} 65 | arch: x86 66 | disable-animations: true 67 | script: ./gradlew connectedCheck --stacktrace 68 | 69 | - name: Upload test reports 70 | if: always() 71 | uses: actions/upload-artifact@v2 72 | with: 73 | name: test-reports 74 | path: app/build/reports 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Mac files 6 | .DS_Store 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated files 15 | bin/ 16 | gen/ 17 | 18 | # Ignore gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | proguard-project.txt 28 | 29 | # Eclipse files 30 | .project 31 | .classpath 32 | .settings/ 33 | 34 | # Android Studio/IDEA 35 | *.iml 36 | .idea -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub Cards Preview](https://github.com/Mercandj/android-dev-challenge-compose-4/blob/main/results/banner.jpg?raw=true) 2 | 3 | # C-Weather: Compose with weather 4 | 5 | 6 | 7 | ![Workflow result](https://github.com/Mercandj/android-dev-challenge-compose-4/workflows/Check/badge.svg) 8 | 9 | Requirement: Replace `WeatherApiManagerImpl#YOUR_KEY_HERE_WITH_FORECAST_AVAILABLE` by your openweathermap key 10 | 11 | ## :scroll: Description 12 | 13 | 14 | * Neumorphism simple weather app that support different temperature units and cities. 15 | * Based on [Jetpack Compose](https://developer.android.com/jetpack/compose) and [openweathermap.org](https://openweathermap.org/), built for the [Jetpack Compose challenge](https://developer.android.com/dev-challenge) week 4. 16 | 17 | ## :bulb: Motivation and Context 18 | 19 | 20 | 21 | 27 | 28 | **What am I proud of?** 29 | - Split UI and logic 30 | - "Useful" app 31 | - -> Real data forecast 32 | - -> Persistence of the forecast 33 | - -> Change your City / temperature Unit 34 | - Neumorphism UI 35 | 36 | ## :camera_flash: Screenshots 37 | 38 | 39 |   40 |   41 |   42 |   43 | 44 | ## Side notes 45 | 46 | This is the first time I'm trying Jetpack Compose. 47 | Even if the spirit seems to be reactive paradigm, I will try to use it on a more "classic" way. 48 | 49 | **Why?** 50 | - Because, if one day I will use this techno in production, I will need a "transition" phase to not move all my code to the "reactive" way. 51 | - Because stay "non reactive" is easier for the reactive-beginner that I am. I hope that my project demonstrates that Jetpack Compose work well without intensive use of ViewModel, LiveData... 52 | - Because stay "non reactive" allow you to produce almost the same code on any platform easily (Unity, iOS, server...) 53 | 54 | **My goals will be:** 55 | - Discover Jetpack Compose 56 | - Split as much as possible logic from the UI with the good old "MVP" 57 | - Great UI / Great app quality (app we can publish on Google Play) 58 | 59 | **Architecture** 60 | - Code and resources split by `feature` instead of `layer` to be able to scale 61 | - DepInjection done manually and user Dagger notions: graph, module, manager... 62 | - Basic MVP explicit in Contract interfaces 63 | 64 | **Bonus** 65 | - Translated in french 🇫🇷 66 | 67 | **Requirement if you a coming from "stable Android Studio" on MacOs** 68 | - Download Java 11 (for example [here](https://jdk.java.net/archive/)) 69 | - Add it like that: `/Users/jonathan/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk` 70 | - If cannot open the jdk due to mac os permission, [here](https://superuser.com/a/1537706) a tip) 71 | 72 | **Thank you to:** 73 | - [Edwin.P that introduce me to Figma](https://www.figma.com/file/K940hjRsZGY6LrOdvJeV28/Untitled?node-id=201%3A2) 74 | - Designers on figma that provide images [here](https://www.figma.com/file/kCYEnx8j7LCxOiBcr2sjFM/Weatherly-3D-Icons-Demo-version-Community?node-id=0%3A10), [here](https://www.figma.com/community/file/890095002328610853) and [here](https://www.figma.com/file/LfxPlArXOlJ74YNfQwpz8s/SALY---3D-Illustration-Pack-(Community)?node-id=0%3A1) 75 | - The neumorphism library [here](https://github.com/fornewid/neumorphism) 76 | - Google and Jetpack compose team ❤️ 77 | 78 | ## License 79 | ``` 80 | Copyright 2020 The Android Open Source Project 81 | 82 | Licensed under the Apache License, Version 2.0 (the "License"); 83 | you may not use this file except in compliance with the License. 84 | You may obtain a copy of the License at 85 | 86 | https://www.apache.org/licenses/LICENSE-2.0 87 | 88 | Unless required by applicable law or agreed to in writing, software 89 | distributed under the License is distributed on an "AS IS" BASIS, 90 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 91 | See the License for the specific language governing permissions and 92 | limitations under the License. 93 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | build/ 4 | 5 | captures 6 | 7 | /local.properties 8 | 9 | # IntelliJ .idea folder 10 | /.idea 11 | *.iml 12 | 13 | # General 14 | .DS_Store 15 | .externalNativeBuild -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdkVersion 30 8 | 9 | defaultConfig { 10 | applicationId "com.example.androiddevchallenge" 11 | minSdkVersion 23 12 | targetSdkVersion 30 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | signingConfigs { 20 | // We use a bundled debug keystore, to allow debug builds from CI to be upgradable 21 | debug { 22 | storeFile rootProject.file('debug.keystore') 23 | storePassword 'android' 24 | keyAlias 'androiddebugkey' 25 | keyPassword 'android' 26 | } 27 | } 28 | 29 | buildTypes { 30 | debug { 31 | signingConfig signingConfigs.debug 32 | } 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | 39 | kotlinOptions { 40 | jvmTarget = "1.8" 41 | } 42 | 43 | buildFeatures { 44 | compose true 45 | 46 | // Disable unused AGP features 47 | buildConfig false 48 | aidl false 49 | renderScript false 50 | resValues false 51 | shaders false 52 | } 53 | 54 | composeOptions { 55 | kotlinCompilerExtensionVersion compose_version 56 | } 57 | 58 | packagingOptions { 59 | // Multiple dependency bring these files in. Exclude them to enable 60 | // our test APK to build (has no effect on our AARs) 61 | excludes += "/META-INF/AL2.0" 62 | excludes += "/META-INF/LGPL2.1" 63 | } 64 | 65 | 66 | sourceSets { 67 | main { 68 | // Split resources. 69 | // https://medium.com/google-developer-experts/android-project-structure-alternative-way-29ce766682f0#.sjnhetuhb 70 | res.srcDirs = [ 71 | 'src/main/res/city_edit_view', 72 | 'src/main/res/error_view', 73 | 'src/main/res/icon', 74 | 'src/main/res/main', 75 | 'src/main/res/main_activity', 76 | 'src/main/res/main_activity_splash_dark', 77 | 'src/main/res/main_weather_animated_view', 78 | 'src/main/res/main_weather_animated_view_figure', 79 | 'src/main/res/theme', 80 | 'src/main/res/weather_icon_2_view', 81 | 'src/main/res/weather_icon_view' 82 | ] 83 | } 84 | } 85 | } 86 | 87 | dependencies { 88 | implementation 'androidx.core:core-ktx:1.3.2' 89 | implementation 'androidx.appcompat:appcompat:1.3.0-beta01' 90 | implementation 'com.google.android.material:material:1.3.0' 91 | implementation "androidx.activity:activity-compose:1.3.0-alpha04" 92 | implementation "androidx.compose.ui:ui:$compose_version" 93 | implementation "androidx.compose.material:material:$compose_version" 94 | implementation "androidx.compose.material:material-icons-extended:$compose_version" 95 | implementation "androidx.compose.ui:ui-tooling:$compose_version" 96 | implementation "androidx.annotation:annotation:1.1.0" 97 | 98 | // https://github.com/fornewid/neumorphism 99 | implementation 'com.github.fornewid:neumorphism:0.3.0' 100 | 101 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0' 102 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0' 103 | implementation "androidx.compose.runtime:runtime-livedata:$compose_version" 104 | 105 | implementation "androidx.compose.animation:animation:$compose_version" 106 | 107 | implementation("com.squareup.okhttp3:okhttp:3.12.13") 108 | 109 | testImplementation 'junit:junit:4.13.2' 110 | 111 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 112 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" 113 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 14 | 15 | 16 | 17 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/application/WeatherApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.application 17 | 18 | import android.app.Application 19 | import com.example.androiddevchallenge.graph.WeatherGraph 20 | 21 | class WeatherApplication : Application() { 22 | 23 | override fun onCreate() { 24 | super.onCreate() 25 | WeatherGraph.initialize(this) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/city/CityManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.city 17 | 18 | interface CityManager { 19 | 20 | fun getCity(): String 21 | 22 | fun setCity(city: String) 23 | 24 | fun addListener(listener: Listener) 25 | 26 | fun removeListener(listener: Listener) 27 | 28 | interface Listener { 29 | 30 | fun onChanged() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/city/CityManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.city 17 | 18 | import android.content.SharedPreferences 19 | 20 | class CityManagerImpl( 21 | private val sharedPreferences: SharedPreferences 22 | ) : CityManager { 23 | 24 | private val listeners = ArrayList() 25 | private var city = "Paris, France" 26 | private var loaded = false 27 | 28 | override fun getCity(): String { 29 | loadIfNeeded() 30 | return city 31 | } 32 | 33 | override fun setCity(city: String) { 34 | loadIfNeeded() 35 | if (this.city == city) { 36 | return 37 | } 38 | this.city = city 39 | save() 40 | for (listener in listeners) { 41 | listener.onChanged() 42 | } 43 | } 44 | 45 | override fun addListener(listener: CityManager.Listener) { 46 | if (listeners.contains(listener)) { 47 | return 48 | } 49 | listeners.add(listener) 50 | } 51 | 52 | override fun removeListener(listener: CityManager.Listener) { 53 | listeners.remove(listener) 54 | } 55 | 56 | private fun loadIfNeeded() { 57 | if (loaded) { 58 | return 59 | } 60 | city = sharedPreferences.getString("city", city) ?: "city" 61 | loaded = true 62 | } 63 | 64 | private fun save() { 65 | sharedPreferences.edit().putString("city", city).apply() 66 | } 67 | 68 | companion object { 69 | 70 | const val PREFERENCE_NAME = "weather_current_city" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/city/CityModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.city 17 | 18 | import android.content.Context 19 | import android.content.SharedPreferences 20 | import com.example.androiddevchallenge.graph.WeatherGraph 21 | 22 | class CityModule { 23 | 24 | fun createCityManager(): CityManager { 25 | return CityManagerImpl( 26 | createSharedPreferences() 27 | ) 28 | } 29 | 30 | private fun createSharedPreferences(): SharedPreferences { 31 | val context = WeatherGraph.getContext() 32 | return context.getSharedPreferences( 33 | CityManagerImpl.PREFERENCE_NAME, 34 | Context.MODE_PRIVATE 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/city_edit_view/CityEditViewContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.city_edit_view 17 | 18 | interface CityEditViewContract { 19 | 20 | interface UserAction { 21 | 22 | fun onCityValidated(text: String) 23 | 24 | fun onInfoClicked() 25 | } 26 | 27 | interface Screen 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/city_edit_view/CityEditViewPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.city_edit_view 17 | 18 | import com.example.androiddevchallenge.city.CityManager 19 | import java.util.Locale 20 | 21 | class CityEditViewPresenter( 22 | private val screen: CityEditViewContract.Screen, 23 | private val cityManager: CityManager 24 | ) : CityEditViewContract.UserAction { 25 | 26 | override fun onCityValidated(text: String) { 27 | cityManager.setCity(text.capitalize(Locale.getDefault())) 28 | } 29 | 30 | override fun onInfoClicked() { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/date/DateManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.date 17 | 18 | interface DateManager { 19 | 20 | // Mon 18 21 | fun convertTimestampToSpecificFormat1(timestamp: Long): String 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/date/DateManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.date 17 | 18 | import java.text.SimpleDateFormat 19 | import java.util.Date 20 | import java.util.Locale 21 | 22 | class DateManagerImpl : DateManager { 23 | 24 | override fun convertTimestampToSpecificFormat1(timestampSecond: Long): String { 25 | val locale = Locale.getDefault() 26 | val simpleDateFormat = SimpleDateFormat("E dd", locale) 27 | return simpleDateFormat.format(Date(timestampSecond * 1_000)).capitalize(locale) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/date/DateModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.date 17 | 18 | class DateModule { 19 | 20 | fun createDateManager(): DateManager { 21 | return DateManagerImpl() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/error_view/ErrorView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.error_view 17 | 18 | import androidx.compose.foundation.Image 19 | import androidx.compose.foundation.layout.Column 20 | import androidx.compose.foundation.layout.Spacer 21 | import androidx.compose.foundation.layout.height 22 | import androidx.compose.foundation.layout.width 23 | import androidx.compose.material.MaterialTheme 24 | import androidx.compose.material.Text 25 | import androidx.compose.runtime.Composable 26 | import androidx.compose.ui.Alignment 27 | import androidx.compose.ui.Modifier 28 | import androidx.compose.ui.res.painterResource 29 | import androidx.compose.ui.res.stringResource 30 | import androidx.compose.ui.text.font.FontWeight 31 | import androidx.compose.ui.unit.dp 32 | import androidx.compose.ui.unit.sp 33 | import com.example.androiddevchallenge.R 34 | import com.example.androiddevchallenge.theme.getTextPrimaryColor 35 | import com.example.androiddevchallenge.theme.getTextSecondaryColor 36 | import com.example.androiddevchallenge.theme.getTextThirdColor 37 | 38 | @Composable 39 | fun ErrorView( 40 | modifier: Modifier = Modifier, 41 | preview: Boolean = false 42 | ) { 43 | Column { 44 | Spacer(modifier = Modifier.height(12.dp)) 45 | Text( 46 | text = stringResource(R.string.error_view_title), 47 | fontSize = 28.sp, 48 | color = MaterialTheme.colors.getTextPrimaryColor(), 49 | fontWeight = FontWeight(900), 50 | ) 51 | Spacer(modifier = Modifier.height(14.dp)) 52 | Image( 53 | painter = painterResource(R.drawable.main_weather_animated_view_figure_7), 54 | contentDescription = stringResource(R.string.error_view_image_content_description), 55 | modifier = Modifier 56 | .width(180.dp) 57 | .height(180.dp) 58 | .align(Alignment.CenterHorizontally) 59 | ) 60 | Spacer(modifier = Modifier.height(14.dp)) 61 | Text( 62 | text = stringResource(R.string.error_view_subtitle), 63 | modifier = Modifier.align(Alignment.CenterHorizontally), 64 | fontSize = 22.sp, 65 | color = MaterialTheme.colors.getTextSecondaryColor(), 66 | fontWeight = FontWeight(700), 67 | ) 68 | Spacer(modifier = Modifier.height(12.dp)) 69 | Text( 70 | text = stringResource(R.string.error_view_point_1), 71 | fontSize = 16.sp, 72 | color = MaterialTheme.colors.getTextThirdColor(), 73 | fontWeight = FontWeight(600), 74 | ) 75 | Spacer(modifier = Modifier.height(4.dp)) 76 | Text( 77 | text = stringResource(R.string.error_view_point_2), 78 | fontSize = 16.sp, 79 | color = MaterialTheme.colors.getTextThirdColor(), 80 | fontWeight = FontWeight(600), 81 | ) 82 | Spacer(modifier = Modifier.height(4.dp)) 83 | Text( 84 | text = stringResource(R.string.error_view_point_3), 85 | fontSize = 16.sp, 86 | color = MaterialTheme.colors.getTextThirdColor(), 87 | fontWeight = FontWeight(600), 88 | ) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/forecast_cell_view/ForecastCellViewContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.forecast_cell_view 17 | 18 | class ForecastCellViewContract { 19 | 20 | interface UserAction { 21 | 22 | fun onDisplayTextTemperature(): String 23 | } 24 | 25 | interface Screen 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/forecast_cell_view/ForecastCellViewPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.forecast_cell_view 17 | 18 | import com.example.androiddevchallenge.date.DateManager 19 | import com.example.androiddevchallenge.weather.Weather 20 | 21 | class ForecastCellViewPresenter( 22 | private val screen: ForecastCellViewContract.Screen, 23 | private val weather: Weather?, 24 | private val dateManager: DateManager 25 | ) : ForecastCellViewContract.UserAction { 26 | 27 | override fun onDisplayTextTemperature(): String { 28 | return createTemperatureToDisplay() 29 | } 30 | 31 | private fun createTemperatureToDisplay(): String { 32 | val weather = weather ?: return "" 33 | return dateManager.convertTimestampToSpecificFormat1(weather.timestampSecond) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/graph/WeatherGraph.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.graph 17 | 18 | import android.annotation.SuppressLint 19 | import android.content.Context 20 | import com.example.androiddevchallenge.city.CityModule 21 | import com.example.androiddevchallenge.date.DateModule 22 | import com.example.androiddevchallenge.network.NetworkModule 23 | import com.example.androiddevchallenge.theme.ThemeModule 24 | import com.example.androiddevchallenge.weather.WeatherModule 25 | import com.example.androiddevchallenge.weather_unit.WeatherUnitModule 26 | 27 | class WeatherGraph private constructor( 28 | private val context: Context 29 | ) { 30 | 31 | private val cityManager by lazy { CityModule().createCityManager() } 32 | private val dateManager by lazy { DateModule().createDateManager() } 33 | private val networkManager by lazy { NetworkModule().createNetworkManager() } 34 | private val themeManager by lazy { ThemeModule().createThemeManager() } 35 | private val weatherGraphInitializationManager by lazy { WeatherGraphInitializationModule().createWeatherGraphInitializationManager() } 36 | private val weatherManager by lazy { WeatherModule().createWeatherManager() } 37 | private val weatherUnitManager by lazy { WeatherUnitModule().createWeatherUnitManager() } 38 | 39 | companion object { 40 | 41 | @SuppressLint("StaticFieldLeak") 42 | private var graph: WeatherGraph? = null 43 | 44 | fun initialize(context: Context) { 45 | if (graph != null) { 46 | return 47 | } 48 | graph = WeatherGraph(context.applicationContext) 49 | graph!!.weatherGraphInitializationManager.initialize() 50 | } 51 | 52 | fun getCityManager() = graph!!.cityManager 53 | fun getDateManager() = graph!!.dateManager 54 | fun getContext() = graph!!.context 55 | fun getNetworkManager() = graph!!.networkManager 56 | fun getThemeManager() = graph!!.themeManager 57 | fun getWeatherManager() = graph!!.weatherManager 58 | fun getWeatherUnitManager() = graph!!.weatherUnitManager 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/graph/WeatherGraphInitializationManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.graph 17 | 18 | interface WeatherGraphInitializationManager { 19 | 20 | fun initialize() 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/graph/WeatherGraphInitializationManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.graph 17 | 18 | import com.example.androiddevchallenge.city.CityManager 19 | import com.example.androiddevchallenge.weather.WeatherManager 20 | import com.example.androiddevchallenge.weather_unit.WeatherUnitManager 21 | 22 | class WeatherGraphInitializationManagerImpl( 23 | private val cityManager: CityManager, 24 | private val weatherManager: WeatherManager, 25 | private val weatherUnitManager: WeatherUnitManager 26 | ) : WeatherGraphInitializationManager { 27 | 28 | override fun initialize() { 29 | cityManager.addListener(createCityListener()) 30 | weatherUnitManager.addListener(createWeatherUnitListener()) 31 | } 32 | 33 | private fun createCityListener() = object : CityManager.Listener { 34 | override fun onChanged() { 35 | weatherManager.clearCache() 36 | weatherManager.load() 37 | } 38 | } 39 | 40 | private fun createWeatherUnitListener() = object : WeatherUnitManager.Listener { 41 | override fun onChanged() { 42 | weatherManager.clearCache() 43 | weatherManager.load() 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/graph/WeatherGraphInitializationModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.graph 17 | 18 | class WeatherGraphInitializationModule { 19 | 20 | fun createWeatherGraphInitializationManager(): WeatherGraphInitializationManager { 21 | return WeatherGraphInitializationManagerImpl( 22 | WeatherGraph.getCityManager(), 23 | WeatherGraph.getWeatherManager(), 24 | WeatherGraph.getWeatherUnitManager() 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_activity 17 | 18 | import android.graphics.Color 19 | import android.os.Build 20 | import android.os.Bundle 21 | import android.view.View 22 | import android.view.Window 23 | import android.view.WindowInsetsController 24 | import androidx.activity.compose.setContent 25 | import androidx.annotation.ColorRes 26 | import androidx.annotation.RequiresApi 27 | import androidx.appcompat.app.AppCompatActivity 28 | import androidx.core.content.ContextCompat 29 | import com.example.androiddevchallenge.graph.WeatherGraph 30 | import com.example.androiddevchallenge.main_view.MainView 31 | import com.example.androiddevchallenge.theme.MainTheme 32 | 33 | class MainActivity : AppCompatActivity() { 34 | 35 | private val userAction by lazy { createUserAction() } 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | setContent { 40 | MainTheme { 41 | MainView() 42 | } 43 | } 44 | userAction.onCreate(savedInstanceState == null) 45 | } 46 | 47 | override fun onResume() { 48 | super.onResume() 49 | userAction.onResume() 50 | } 51 | 52 | private fun createScreen() = object : MainActivityContract.Screen { 53 | 54 | @Suppress("DEPRECATION") 55 | override fun setStatusBarTheme(@ColorRes colorRes: Int, themeDark: Boolean) { 56 | val color = ContextCompat.getColor(this@MainActivity, colorRes) 57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 58 | window.insetsController!!.setSystemBarsAppearance( 59 | if (themeDark) 0 else WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, 60 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS 61 | ) 62 | window.statusBarColor = color 63 | } else { 64 | window.statusBarColor = color 65 | val flags = window.decorView.systemUiVisibility 66 | window.decorView.systemUiVisibility = if (themeDark) { 67 | flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() 68 | } else { 69 | flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 70 | } 71 | } 72 | } 73 | 74 | override fun setNavigationBarTheme(@ColorRes colorRes: Int, themeDark: Boolean) { 75 | val color = ContextCompat.getColor(this@MainActivity, colorRes) 76 | window.navigationBarColor = if (color == Color.WHITE) { 77 | // Not supported nicely as buttons will stay white, so use black color instead. 78 | Color.BLACK 79 | } else { 80 | color 81 | } 82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 83 | window.insetsController!!.setSystemBarsAppearance( 84 | if (themeDark) 0 else WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS, 85 | WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS 86 | ) 87 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 88 | setNavigationBarButtonColor(window, !themeDark) 89 | } 90 | } 91 | 92 | @RequiresApi(api = Build.VERSION_CODES.O) 93 | private fun setNavigationBarButtonColor(window: Window, darkButton: Boolean) { 94 | val flags = window.decorView.systemUiVisibility 95 | window.decorView.systemUiVisibility = if (darkButton) { 96 | flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR 97 | } else { 98 | flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() 99 | } 100 | } 101 | } 102 | 103 | private fun createUserAction(): MainActivityContract.UserAction { 104 | return MainActivityPresenter( 105 | createScreen(), 106 | WeatherGraph.getThemeManager(), 107 | WeatherGraph.getWeatherManager() 108 | ) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_activity/MainActivityContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_activity 17 | 18 | import androidx.annotation.ColorRes 19 | 20 | interface MainActivityContract { 21 | 22 | interface UserAction { 23 | 24 | fun onCreate(savedInstanceStateNull: Boolean) 25 | 26 | fun onResume() 27 | } 28 | 29 | interface Screen { 30 | 31 | fun setStatusBarTheme(@ColorRes colorRes: Int, themeDark: Boolean) 32 | 33 | fun setNavigationBarTheme(@ColorRes colorRes: Int, themeDark: Boolean) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_activity/MainActivityPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_activity 17 | 18 | import com.example.androiddevchallenge.R 19 | import com.example.androiddevchallenge.theme.ThemeManager 20 | import com.example.androiddevchallenge.weather.WeatherManager 21 | 22 | class MainActivityPresenter( 23 | private val screen: MainActivityContract.Screen, 24 | private val themeManager: ThemeManager, 25 | private val weatherManager: WeatherManager 26 | ) : MainActivityContract.UserAction { 27 | 28 | override fun onCreate(savedInstanceStateNull: Boolean) { 29 | updateScreen() 30 | weatherManager.load() 31 | } 32 | 33 | override fun onResume() { 34 | weatherManager.load() 35 | } 36 | 37 | private fun updateScreen() { 38 | updateTheme() 39 | } 40 | 41 | private fun updateTheme() { 42 | val light = themeManager.isLight() 43 | screen.setStatusBarTheme( 44 | if (light) { 45 | R.color.main_activity_status_bar_light_theme_color 46 | } else { 47 | R.color.main_activity_status_bar_dark_theme_color 48 | }, 49 | themeDark = !light 50 | ) 51 | screen.setNavigationBarTheme( 52 | if (light) { 53 | R.color.main_activity_navigation_bar_light_theme_color 54 | } else { 55 | R.color.main_activity_navigation_bar_dark_theme_color 56 | }, 57 | themeDark = !light 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_view/MainViewContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_view 17 | 18 | import androidx.lifecycle.MutableLiveData 19 | import com.example.androiddevchallenge.weather.Weather 20 | 21 | interface MainViewContract { 22 | 23 | interface UserAction { 24 | 25 | fun getWeathers(): MutableLiveData> 26 | 27 | fun getError(): MutableLiveData 28 | } 29 | 30 | interface Screen 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_view/MainViewPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_view 17 | 18 | import androidx.lifecycle.MutableLiveData 19 | import com.example.androiddevchallenge.weather.Weather 20 | import com.example.androiddevchallenge.weather.WeatherManager 21 | 22 | class MainViewPresenter( 23 | private val screen: MainViewContract.Screen, 24 | private val weatherManager: WeatherManager 25 | ) : MainViewContract.UserAction { 26 | 27 | private var weathers = MutableLiveData(createWeathers()) 28 | private var error = MutableLiveData(createError()) 29 | 30 | init { 31 | // Leak? 32 | weatherManager.addListener(createWeatherListener()) 33 | } 34 | 35 | override fun getWeathers(): MutableLiveData> { 36 | return weathers 37 | } 38 | 39 | override fun getError(): MutableLiveData { 40 | return error 41 | } 42 | 43 | private fun updateWeathers() { 44 | weathers.value = createWeathers() 45 | } 46 | 47 | private fun updateError() { 48 | error.value = createError() 49 | } 50 | 51 | private fun createWeathers(): List { 52 | return weatherManager.getWeathers() 53 | } 54 | 55 | private fun createError(): Boolean { 56 | return weatherManager.getWeathers().size < 4 57 | } 58 | 59 | private fun createWeatherListener() = object : WeatherManager.Listener { 60 | override fun onChanged() { 61 | updateWeathers() 62 | updateError() 63 | } 64 | 65 | override fun onFailed() { 66 | updateError() 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_view_background_view/MainViewBackgroundView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_view_background_view 17 | 18 | import androidx.compose.foundation.background 19 | import androidx.compose.foundation.layout.Box 20 | import androidx.compose.foundation.layout.BoxScope 21 | import androidx.compose.material.MaterialTheme 22 | import androidx.compose.runtime.Composable 23 | import androidx.compose.ui.Modifier 24 | import androidx.compose.ui.graphics.Brush 25 | import com.example.androiddevchallenge.theme.getMainViewBottomBackgroundColor 26 | import com.example.androiddevchallenge.theme.getMainViewTopBackgroundColor 27 | 28 | @Composable 29 | fun MainViewBackgroundView( 30 | modifier: Modifier = Modifier, 31 | content: @Composable BoxScope.() -> Unit 32 | ) { 33 | Box( 34 | modifier = modifier.background( 35 | brush = Brush.verticalGradient( 36 | colors = listOf( 37 | MaterialTheme.colors.getMainViewTopBackgroundColor(), 38 | MaterialTheme.colors.getMainViewBottomBackgroundColor() 39 | ) 40 | ) 41 | ) 42 | ) { 43 | content() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_view_top_bar_view/MainViewTopBarViewContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_view_top_bar_view 17 | 18 | import androidx.lifecycle.MutableLiveData 19 | import com.example.androiddevchallenge.weather.Weather 20 | import com.example.androiddevchallenge.weather_unit.WeatherUnit 21 | 22 | interface MainViewTopBarViewContract { 23 | 24 | interface UserAction { 25 | 26 | fun getCity(): MutableLiveData 27 | 28 | fun getDate(): MutableLiveData 29 | 30 | fun getTemperature(): MutableLiveData 31 | 32 | fun getWeatherType(): MutableLiveData 33 | 34 | fun onTemperatureClick() 35 | 36 | fun onCityClicked() 37 | 38 | fun onTemperatureUnitClicked(weatherUnit: WeatherUnit) 39 | 40 | /** 41 | * @return True if current 42 | */ 43 | fun onTemperatureUnitDisplay(metric: WeatherUnit): Boolean 44 | } 45 | 46 | interface Screen 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/main_view_top_bar_view/MainViewTopBarViewPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.main_view_top_bar_view 17 | 18 | import androidx.lifecycle.MutableLiveData 19 | import com.example.androiddevchallenge.city.CityManager 20 | import com.example.androiddevchallenge.date.DateManager 21 | import com.example.androiddevchallenge.weather.Weather 22 | import com.example.androiddevchallenge.weather.WeatherManager 23 | import com.example.androiddevchallenge.weather_unit.WeatherUnit 24 | import com.example.androiddevchallenge.weather_unit.WeatherUnitManager 25 | 26 | class MainViewTopBarViewPresenter( 27 | private val screen: MainViewTopBarViewContract.Screen, 28 | private val cityManager: CityManager, 29 | private val dateManager: DateManager, 30 | private val weatherManager: WeatherManager, 31 | private val weatherUnitManager: WeatherUnitManager 32 | ) : MainViewTopBarViewContract.UserAction { 33 | 34 | private var city = MutableLiveData(createCity()) 35 | private var date = MutableLiveData(createDate()) 36 | private var temperature = MutableLiveData(createTemperature()) 37 | private var weatherType = MutableLiveData(Weather.Type.SNOW) 38 | 39 | init { 40 | // Require remove call? 41 | cityManager.addListener(createCityListener()) 42 | weatherManager.addListener(createWeatherListener()) 43 | } 44 | 45 | override fun getCity(): MutableLiveData { 46 | return city 47 | } 48 | 49 | override fun getDate(): MutableLiveData { 50 | return date 51 | } 52 | 53 | override fun getTemperature(): MutableLiveData { 54 | return temperature 55 | } 56 | 57 | override fun getWeatherType(): MutableLiveData { 58 | return weatherType 59 | } 60 | 61 | override fun onTemperatureClick() { 62 | } 63 | 64 | override fun onCityClicked() { 65 | } 66 | 67 | override fun onTemperatureUnitClicked(weatherUnit: WeatherUnit) { 68 | weatherUnitManager.setWeatherUnit(weatherUnit) 69 | } 70 | 71 | override fun onTemperatureUnitDisplay(metric: WeatherUnit): Boolean { 72 | return weatherUnitManager.getWeatherUnit() == metric 73 | } 74 | 75 | private fun updateCity() { 76 | city.value = createCity() 77 | } 78 | 79 | private fun updateDate() { 80 | date.value = createDate() 81 | } 82 | 83 | private fun updateTemperature() { 84 | temperature.value = createTemperature() 85 | } 86 | 87 | private fun updateWeatherType() { 88 | weatherType.value = createWeatherType() 89 | } 90 | 91 | private fun createCity(): String { 92 | return cityManager.getCity() 93 | } 94 | 95 | private fun createDate(): String { 96 | val weather = weatherManager.getWeathers().firstOrNull() ?: return "" 97 | return dateManager.convertTimestampToSpecificFormat1(weather.timestampSecond) 98 | } 99 | 100 | private fun createTemperature(): String { 101 | val weather = weatherManager.getWeathers().firstOrNull() ?: return "" 102 | val temperature = weather.temperature.toInt() 103 | return "$temperature°" 104 | } 105 | 106 | private fun createWeatherType(): Weather.Type { 107 | val weather = weatherManager.getWeathers().firstOrNull() ?: return Weather.Type.SNOW 108 | return weather.type 109 | } 110 | 111 | private fun createCityListener() = object : CityManager.Listener { 112 | override fun onChanged() { 113 | updateCity() 114 | } 115 | } 116 | 117 | private fun createWeatherListener() = object : WeatherManager.Listener { 118 | override fun onChanged() { 119 | updateDate() 120 | updateTemperature() 121 | updateWeatherType() 122 | } 123 | 124 | override fun onFailed() { 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/network/NetworkManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.network 17 | 18 | import androidx.annotation.WorkerThread 19 | 20 | interface NetworkManager { 21 | 22 | @WorkerThread 23 | fun get(url: String): String? 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/network/NetworkManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.network 17 | 18 | import androidx.annotation.WorkerThread 19 | import okhttp3.OkHttpClient 20 | import okhttp3.Response 21 | import okhttp3.ResponseBody 22 | import java.io.Closeable 23 | import java.io.IOException 24 | import java.util.concurrent.TimeUnit 25 | 26 | class NetworkManagerImpl : NetworkManager { 27 | 28 | @WorkerThread 29 | override fun get(url: String): String? { 30 | val okHttpRequestBuilder = okhttp3.Request.Builder() 31 | .url(url) 32 | .get() 33 | var okHttpResponse: Response? = null 34 | var body: ResponseBody? = null 35 | return try { 36 | okHttpResponse = okHttpClient.value.newCall(okHttpRequestBuilder.build()).execute() 37 | body = okHttpResponse.body() 38 | body?.string() 39 | } catch (e: IOException) { 40 | throw IllegalStateException(e) 41 | } finally { 42 | closeSilently(body, okHttpResponse) 43 | } 44 | } 45 | 46 | companion object { 47 | 48 | private val okHttpClient = lazy { 49 | val builder = OkHttpClient.Builder() 50 | builder.connectTimeout(15, TimeUnit.SECONDS) 51 | builder.build() 52 | } 53 | 54 | private fun closeSilently(vararg xs: Closeable?) { 55 | for (x in xs) { 56 | try { 57 | x?.close() 58 | } catch (ignored: Throwable) { 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/network/NetworkModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.network 17 | 18 | class NetworkModule { 19 | 20 | fun createNetworkManager(): NetworkManager { 21 | return NetworkManagerImpl() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/neumorphism_card_square_view/NeumorphismCardSquareView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.neumorphism_card_square_view 17 | 18 | import android.animation.AnimatorInflater 19 | import androidx.compose.foundation.layout.Box 20 | import androidx.compose.foundation.layout.BoxScope 21 | import androidx.compose.foundation.layout.fillMaxHeight 22 | import androidx.compose.foundation.layout.fillMaxWidth 23 | import androidx.compose.foundation.layout.height 24 | import androidx.compose.foundation.layout.width 25 | import androidx.compose.material.MaterialTheme 26 | import androidx.compose.runtime.Composable 27 | import androidx.compose.ui.Alignment 28 | import androidx.compose.ui.Modifier 29 | import androidx.compose.ui.graphics.Color 30 | import androidx.compose.ui.tooling.preview.Preview 31 | import androidx.compose.ui.unit.dp 32 | import androidx.compose.ui.viewinterop.AndroidView 33 | import com.example.androiddevchallenge.R 34 | import com.example.androiddevchallenge.main_view_background_view.MainViewBackgroundView 35 | import com.example.androiddevchallenge.theme.MainTheme 36 | import soup.neumorphism.NeumorphImageButton 37 | import soup.neumorphism.ShapeType 38 | 39 | @Composable 40 | fun NeumorphismCardSquareView( 41 | modifier: Modifier = Modifier, 42 | onClick: (() -> Unit)? = null, 43 | @ShapeType shapeType: Int = ShapeType.DEFAULT, 44 | backgroundColor: Color = Color.Transparent, 45 | content: @Composable BoxScope.() -> Unit 46 | ) { 47 | Box( 48 | modifier = modifier 49 | ) { 50 | val light = MaterialTheme.colors.isLight 51 | val topStartShadowColor = if (light) "#C6CEDA" else "#101010" 52 | val bottomEndShadowColor = if (light) "#FEFEFF" else "#262C37" 53 | AndroidView( 54 | modifier = modifier 55 | .fillMaxWidth() 56 | .fillMaxHeight(), 57 | factory = { context -> 58 | NeumorphImageButton(context).apply { 59 | setShadowColorLight(android.graphics.Color.parseColor(bottomEndShadowColor)) 60 | setShadowColorDark(android.graphics.Color.parseColor(topStartShadowColor)) 61 | setShapeType(shapeType) 62 | setBackgroundColor( 63 | argb( 64 | backgroundColor.alpha, 65 | backgroundColor.red, 66 | backgroundColor.green, 67 | backgroundColor.blue 68 | ) 69 | ) 70 | stateListAnimator = AnimatorInflater.loadStateListAnimator( 71 | context, 72 | R.animator.button_state_list_anim_neumorph 73 | ) 74 | if (onClick != null) { 75 | setOnClickListener { 76 | onClick() 77 | } 78 | } 79 | } 80 | } 81 | ) 82 | content() 83 | } 84 | } 85 | 86 | @Preview("Light Theme", widthDp = 360, heightDp = 640) 87 | @Composable 88 | fun NeumorphismCardSquareViewLightPreview() { 89 | MainTheme { 90 | MainViewBackgroundView { 91 | NeumorphismCardSquareView( 92 | modifier = Modifier 93 | .align(Alignment.Center) 94 | .width(160.dp) 95 | .height(160.dp) 96 | ) { 97 | } 98 | } 99 | } 100 | } 101 | 102 | @Preview("Dark Theme", widthDp = 360, heightDp = 640) 103 | @Composable 104 | fun NeumorphismCardSquareViewDarkPreview() { 105 | MainTheme(darkTheme = true) { 106 | MainViewBackgroundView { 107 | NeumorphismCardSquareView( 108 | modifier = Modifier 109 | .align(Alignment.Center) 110 | .width(160.dp) 111 | .height(160.dp) 112 | ) { 113 | } 114 | } 115 | } 116 | } 117 | 118 | private fun argb(alpha: Float, red: Float, green: Float, blue: Float): Int { 119 | return (alpha * 255.0f + 0.5f).toInt() shl 24 or 120 | ((red * 255.0f + 0.5f).toInt() shl 16) or 121 | ((green * 255.0f + 0.5f).toInt() shl 8) or 122 | (blue * 255.0f + 0.5f).toInt() 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | import androidx.compose.foundation.shape.RoundedCornerShape 19 | import androidx.compose.material.Shapes 20 | import androidx.compose.ui.unit.dp 21 | 22 | val shapes = Shapes( 23 | small = RoundedCornerShape(4.dp), 24 | medium = RoundedCornerShape(4.dp), 25 | large = RoundedCornerShape(0.dp) 26 | ) 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/ThemeCompose.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | import androidx.compose.foundation.isSystemInDarkTheme 19 | import androidx.compose.material.Colors 20 | import androidx.compose.material.MaterialTheme 21 | import androidx.compose.material.darkColors 22 | import androidx.compose.material.lightColors 23 | import androidx.compose.runtime.Composable 24 | import androidx.compose.ui.graphics.Color 25 | import com.example.androiddevchallenge.weather.Weather 26 | 27 | private val DarkColorPalette = darkColors( 28 | primary = Color(0xFFFDE807), 29 | primaryVariant = Color(0xFFFDE807), 30 | secondary = Color(0xFF30B0D3), 31 | background = Color(0xFF0B222F) 32 | ) 33 | 34 | private val LightColorPalette = lightColors( 35 | primary = Color(0xFF0B222F), 36 | primaryVariant = Color(0xFF0B222F), 37 | secondary = Color(0xFF30B0D3), 38 | background = Color(0xFFEEF0F5), 39 | surface = Color.White, 40 | onPrimary = Color.White, 41 | onSecondary = Color.Black, 42 | onBackground = Color.Black, 43 | onSurface = Color.Black, 44 | ) 45 | 46 | @Composable 47 | fun Colors.getMainViewTopBackgroundColor(): Color { 48 | return if (isLight) { 49 | Color(0XFFEEF0F5) 50 | } else { 51 | Color(0XFF394253) 52 | } 53 | } 54 | 55 | @Composable 56 | fun Colors.getMainViewBottomBackgroundColor(): Color { 57 | return if (isLight) { 58 | Color(0XFFEEF0F5) 59 | } else { 60 | Color(0XFF181C27) 61 | } 62 | } 63 | 64 | @Composable 65 | fun Colors.getMainViewTopBarViewTextColor(): Color { 66 | return if (isLight) { 67 | Color.Black 68 | } else { 69 | Color.White 70 | } 71 | } 72 | 73 | @Composable 74 | fun Colors.getMainViewTopBarViewDateTextColor(weatherType: Weather.Type): Color { 75 | when (weatherType) { 76 | Weather.Type.CLEAR -> if (isLight) { 77 | Color(0xFFEB8202) 78 | } else { 79 | Color(0xFFD89037) 80 | } 81 | Weather.Type.THUNDERSTORM -> { 82 | } 83 | Weather.Type.DRIZZLE -> { 84 | } 85 | Weather.Type.CLOUDS, 86 | Weather.Type.CLOUDS_SCATTERED_CLOUDS, 87 | Weather.Type.CLOUDS_BROKEN_CLOUDS, 88 | Weather.Type.CLOUDS_FEW_CLOUDS -> return if (isLight) { 89 | Color(0xFF575757) 90 | } else { 91 | Color(0xFFBBBBBB) 92 | } 93 | Weather.Type.RAIN, 94 | Weather.Type.RAIN_FREEZING_RAIN, 95 | Weather.Type.RAIN_VERY_HEAVY_RAIN, 96 | Weather.Type.RAIN_HEAVY_INTENSITY -> return if (isLight) { 97 | Color(0xFF00A1CE) 98 | } else { 99 | Color(0xFF30B0D3) 100 | } 101 | Weather.Type.RAIN_MODERATE_RAIN -> { 102 | } 103 | Weather.Type.RAIN_LIGHT_RAIN -> { 104 | } 105 | Weather.Type.SNOW -> { 106 | } 107 | Weather.Type.SNOW_LIGHT_SNOW -> { 108 | } 109 | Weather.Type.MIST -> { 110 | } 111 | } 112 | return if (isLight) { 113 | Color(0xFFEBCC02) 114 | } else { 115 | Color(0xFFFDE807) 116 | } 117 | } 118 | 119 | @Composable 120 | fun Colors.getMainViewTopViewCardColor(): Color { 121 | return if (isLight) { 122 | Color(0XFFEEF0F5) 123 | } else { 124 | Color(0XFF394253) 125 | } 126 | } 127 | 128 | @Composable 129 | fun Colors.getTextPrimaryColor(): Color { 130 | return if (isLight) { 131 | Color(0XFF000000) 132 | } else { 133 | Color(0XFFFFFFFF) 134 | } 135 | } 136 | 137 | @Composable 138 | fun Colors.getTextSecondaryColor(): Color { 139 | return if (isLight) { 140 | Color(0XFF404040) 141 | } else { 142 | Color(0XFFC0C0C0) 143 | } 144 | } 145 | 146 | @Composable 147 | fun Colors.getTextThirdColor(): Color { 148 | return if (isLight) { 149 | Color(0XFF808080) 150 | } else { 151 | Color(0XFFA0A0A0) 152 | } 153 | } 154 | 155 | @Composable 156 | fun Colors.getTextHintColor(): Color { 157 | return if (isLight) { 158 | Color(0XFFB0B0B0) 159 | } else { 160 | Color(0XFF909090) 161 | } 162 | } 163 | 164 | @Composable 165 | fun Colors.getForecastViewCardColor(): Color { 166 | return if (isLight) { 167 | Color(0XFFEEF0F5) 168 | } else { 169 | Color(0XFF181C27) 170 | } 171 | } 172 | 173 | @Composable 174 | fun MainTheme( 175 | darkTheme: Boolean = isSystemInDarkTheme(), 176 | content: @Composable() () -> Unit 177 | ) { 178 | val colors = if (darkTheme) { 179 | DarkColorPalette 180 | } else { 181 | LightColorPalette 182 | } 183 | 184 | MaterialTheme( 185 | colors = colors, 186 | typography = typography, 187 | shapes = shapes, 188 | content = content 189 | ) 190 | } 191 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/ThemeManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | interface ThemeManager { 19 | 20 | fun isLight(): Boolean 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/ThemeManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | import android.content.Context 19 | import com.example.androiddevchallenge.R 20 | 21 | class ThemeManagerImpl( 22 | private val context: Context 23 | ) : ThemeManager { 24 | 25 | override fun isLight(): Boolean { 26 | return context.resources.getBoolean(R.bool.theme_bool_light_mode) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/ThemeModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | import com.example.androiddevchallenge.graph.WeatherGraph 19 | 20 | class ThemeModule { 21 | 22 | fun createThemeManager(): ThemeManager { 23 | return ThemeManagerImpl(WeatherGraph.getContext()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/theme/Type.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.theme 17 | 18 | import androidx.compose.material.Typography 19 | import androidx.compose.ui.text.TextStyle 20 | import androidx.compose.ui.text.font.FontFamily 21 | import androidx.compose.ui.text.font.FontWeight 22 | import androidx.compose.ui.unit.sp 23 | 24 | val typography = Typography( 25 | body1 = TextStyle( 26 | fontFamily = FontFamily.Default, 27 | fontWeight = FontWeight.Normal, 28 | fontSize = 16.sp 29 | ), 30 | button = TextStyle( 31 | fontFamily = FontFamily.Default, 32 | fontWeight = FontWeight.W500, 33 | fontSize = 14.sp 34 | ), 35 | caption = TextStyle( 36 | fontFamily = FontFamily.Default, 37 | fontWeight = FontWeight.Normal, 38 | fontSize = 12.sp 39 | ) 40 | ) 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather/Weather.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather 17 | 18 | import com.example.androiddevchallenge.weather_unit.WeatherUnit 19 | import java.util.concurrent.TimeUnit 20 | 21 | data class Weather( 22 | val city: String, 23 | val weatherUnit: WeatherUnit, 24 | val type: Type, 25 | val temperature: Float, 26 | val humidity: Int, 27 | val pressure: Int, 28 | val timestampSecond: Long 29 | ) { 30 | 31 | init { 32 | if (timestampSecond < 10_000) { 33 | throw IllegalStateException("Timestamp < 10_000: $timestampSecond") 34 | } 35 | } 36 | 37 | enum class Type { 38 | CLEAR, 39 | THUNDERSTORM, 40 | DRIZZLE, 41 | CLOUDS, 42 | CLOUDS_SCATTERED_CLOUDS, 43 | CLOUDS_BROKEN_CLOUDS, 44 | CLOUDS_FEW_CLOUDS, 45 | RAIN, 46 | RAIN_FREEZING_RAIN, 47 | RAIN_VERY_HEAVY_RAIN, 48 | RAIN_HEAVY_INTENSITY, 49 | RAIN_MODERATE_RAIN, 50 | RAIN_LIGHT_RAIN, 51 | SNOW, 52 | SNOW_LIGHT_SNOW, 53 | MIST 54 | } 55 | 56 | companion object { 57 | 58 | val fakeWeathers = listOf( 59 | Weather( 60 | city = "Paris, France", 61 | weatherUnit = WeatherUnit.METRIC, 62 | type = Type.THUNDERSTORM, 63 | temperature = 19f, 64 | humidity = 90, 65 | pressure = 900, 66 | timestampSecond = 1616321094 67 | ), 68 | Weather( 69 | city = "Paris, France", 70 | weatherUnit = WeatherUnit.METRIC, 71 | type = Type.CLOUDS, 72 | temperature = 12f, 73 | humidity = 90, 74 | pressure = 900, 75 | timestampSecond = 1616321094 + TimeUnit.DAYS.toMillis(1) 76 | ), 77 | Weather( 78 | city = "Paris, France", 79 | weatherUnit = WeatherUnit.METRIC, 80 | type = Type.CLEAR, 81 | temperature = 30f, 82 | humidity = 90, 83 | pressure = 900, 84 | timestampSecond = 1616321094 + TimeUnit.DAYS.toMillis(2) 85 | ), 86 | Weather( 87 | city = "Paris, France", 88 | weatherUnit = WeatherUnit.METRIC, 89 | type = Type.SNOW, 90 | temperature = -2f, 91 | humidity = 90, 92 | pressure = 900, 93 | timestampSecond = 1616321094 + TimeUnit.DAYS.toMillis(3) 94 | ) 95 | ) 96 | 97 | fun List.getOrNull(index: Int): Weather? { 98 | if (index >= size) { 99 | return null 100 | } 101 | return get(index) 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather/WeatherManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather 17 | 18 | interface WeatherManager { 19 | 20 | fun load() 21 | 22 | /** 23 | * 0 is today, 1 is tomorrow... 24 | */ 25 | fun getWeathers(): List 26 | 27 | fun clearCache() 28 | 29 | fun addListener(listener: Listener) 30 | 31 | fun removeListener(listener: Listener) 32 | 33 | interface Listener { 34 | 35 | fun onChanged() 36 | 37 | fun onFailed() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather/WeatherManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather 17 | 18 | import com.example.androiddevchallenge.city.CityManager 19 | import com.example.androiddevchallenge.date.DateManager 20 | import com.example.androiddevchallenge.weather_api.WeatherApiException 21 | import com.example.androiddevchallenge.weather_api.WeatherApiManager 22 | import com.example.androiddevchallenge.weather_repository.WeatherRepository 23 | import com.example.androiddevchallenge.weather_unit.WeatherUnitManager 24 | 25 | class WeatherManagerImpl( 26 | private val weatherApiManager: WeatherApiManager, 27 | private val cityManager: CityManager, 28 | private val dateManager: DateManager, 29 | private val weatherRepository: WeatherRepository, 30 | private val weatherUnitManager: WeatherUnitManager, 31 | private val addOn: AddOn 32 | ) : WeatherManager { 33 | 34 | private val listeners = ArrayList() 35 | 36 | override fun load() { 37 | val city = cityManager.getCity() 38 | val weatherUnit = weatherUnitManager.getWeatherUnit() 39 | addOn.postWorkerThread { 40 | val weather = try { 41 | weatherApiManager.getWeather( 42 | city = city, 43 | weatherUnit = weatherUnit 44 | ) 45 | } catch (e: WeatherApiException) { 46 | null 47 | } 48 | val weatherForecastDaily = try { 49 | weatherApiManager.getWeatherForecastDaily( 50 | city = city, 51 | weatherUnit = weatherUnit, 52 | numberOfDays = 7 53 | ) 54 | } catch (e: WeatherApiException) { 55 | emptyList() 56 | } 57 | addOn.postMainThread { 58 | val succeeded = weather != null && weatherForecastDaily.isNotEmpty() 59 | if (!succeeded) { 60 | for (listener in listeners) { 61 | listener.onChanged() 62 | } 63 | for (listener in listeners) { 64 | listener.onFailed() 65 | } 66 | return@postMainThread 67 | } 68 | weatherRepository.setWeather(weather) 69 | weatherRepository.setWeatherForecastDaily(weatherForecastDaily) 70 | for (listener in listeners) { 71 | listener.onChanged() 72 | } 73 | } 74 | } 75 | } 76 | 77 | override fun getWeathers(): List { 78 | val weathers = ArrayList() 79 | val weather = weatherRepository.getWeather() ?: return weathers 80 | weathers.add(weather) 81 | weathers.addAll( 82 | weatherRepository.getWeatherForecastDaily().filter { 83 | dateManager.convertTimestampToSpecificFormat1(it.timestampSecond) != 84 | dateManager.convertTimestampToSpecificFormat1(weather.timestampSecond) 85 | } 86 | ) 87 | return weathers 88 | } 89 | 90 | override fun clearCache() { 91 | weatherRepository.setWeather(null) 92 | weatherRepository.setWeatherForecastDaily(emptyList()) 93 | for (listener in listeners) { 94 | listener.onChanged() 95 | } 96 | } 97 | 98 | override fun addListener(listener: WeatherManager.Listener) { 99 | if (listeners.contains(listener)) { 100 | return 101 | } 102 | listeners.add(listener) 103 | } 104 | 105 | override fun removeListener(listener: WeatherManager.Listener) { 106 | listeners.remove(listener) 107 | } 108 | 109 | interface AddOn { 110 | 111 | fun postWorkerThread(runnable: Runnable) 112 | 113 | fun postMainThread(runnable: Runnable) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather/WeatherModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather 17 | 18 | import android.os.Handler 19 | import android.os.HandlerThread 20 | import android.os.Looper 21 | import com.example.androiddevchallenge.graph.WeatherGraph 22 | import com.example.androiddevchallenge.weather_api.WeatherApiModule 23 | import com.example.androiddevchallenge.weather_repository.WeatherRepositoryModule 24 | 25 | class WeatherModule { 26 | 27 | fun createWeatherManager(): WeatherManager { 28 | return WeatherManagerImpl( 29 | WeatherApiModule().createWeatherApiManager(), 30 | WeatherGraph.getCityManager(), 31 | WeatherGraph.getDateManager(), 32 | WeatherRepositoryModule().createWeatherRepository(), 33 | WeatherGraph.getWeatherUnitManager(), 34 | createWeatherManagerImplAddOn() 35 | ) 36 | } 37 | 38 | private fun createWeatherManagerImplAddOn() = object : WeatherManagerImpl.AddOn { 39 | 40 | private val workerThread by lazy { createWorkerThread() } 41 | private val workerThreadHandler by lazy { Handler(workerThread.looper) } 42 | private val mainHandler by lazy { Handler(Looper.getMainLooper()) } 43 | 44 | override fun postWorkerThread(runnable: Runnable) { 45 | workerThreadHandler.post(runnable) 46 | } 47 | 48 | override fun postMainThread(runnable: Runnable) { 49 | mainHandler.post(runnable) 50 | } 51 | 52 | private fun createWorkerThread(): HandlerThread { 53 | val tmp = HandlerThread("weather_load") 54 | tmp.start() 55 | return tmp 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_api/WeatherApiException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_api 17 | 18 | class WeatherApiException( 19 | message: String, 20 | e: Throwable? = null 21 | ) : Exception( 22 | message, 23 | e 24 | ) 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_api/WeatherApiManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_api 17 | 18 | import androidx.annotation.IntRange 19 | import androidx.annotation.WorkerThread 20 | import com.example.androiddevchallenge.weather.Weather 21 | import com.example.androiddevchallenge.weather_unit.WeatherUnit 22 | 23 | interface WeatherApiManager { 24 | 25 | /** 26 | * @throws WeatherApiException 27 | */ 28 | @WorkerThread 29 | fun getWeather( 30 | city: String, 31 | weatherUnit: WeatherUnit 32 | ): Weather 33 | 34 | /** 35 | * @throws WeatherApiException 36 | */ 37 | @WorkerThread 38 | fun getWeatherForecastDaily( 39 | city: String, 40 | weatherUnit: WeatherUnit, 41 | @IntRange(from = 1, to = 16) 42 | numberOfDays: Int 43 | ): List 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_api/WeatherApiModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_api 17 | 18 | import com.example.androiddevchallenge.graph.WeatherGraph 19 | 20 | class WeatherApiModule { 21 | 22 | fun createWeatherApiManager(): WeatherApiManager { 23 | return WeatherApiManagerImpl( 24 | WeatherGraph.getNetworkManager() 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_icon_view/WeatherIconView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_icon_view 17 | 18 | import androidx.compose.foundation.Image 19 | import androidx.compose.foundation.layout.fillMaxHeight 20 | import androidx.compose.foundation.layout.fillMaxWidth 21 | import androidx.compose.runtime.Composable 22 | import androidx.compose.ui.Modifier 23 | import androidx.compose.ui.res.painterResource 24 | import com.example.androiddevchallenge.R 25 | import com.example.androiddevchallenge.weather.Weather 26 | 27 | @Composable 28 | fun WeatherIconView( 29 | modifier: Modifier = Modifier, 30 | weatherType: Weather.Type 31 | ) { 32 | Image( 33 | painter = painterResource(weatherType.toDrawableRes()), 34 | contentDescription = weatherType.toImageContentDescription(), 35 | modifier = modifier 36 | .fillMaxWidth() 37 | .fillMaxHeight() 38 | ) 39 | } 40 | 41 | private fun Weather.Type.toImageContentDescription(): String { 42 | return "Weather is: " + when (this) { 43 | Weather.Type.CLEAR -> "clear" 44 | Weather.Type.THUNDERSTORM -> "thunderstorm" 45 | Weather.Type.DRIZZLE -> "drizzle" 46 | Weather.Type.CLOUDS -> "clouds" 47 | Weather.Type.CLOUDS_SCATTERED_CLOUDS -> "scattered clouds" 48 | Weather.Type.CLOUDS_BROKEN_CLOUDS -> "broken clouds" 49 | Weather.Type.CLOUDS_FEW_CLOUDS -> "few clouds" 50 | Weather.Type.RAIN -> "rain" 51 | Weather.Type.RAIN_FREEZING_RAIN -> "freezing rain" 52 | Weather.Type.RAIN_VERY_HEAVY_RAIN -> "very heavy rain" 53 | Weather.Type.RAIN_HEAVY_INTENSITY -> "heavy intensity rain" 54 | Weather.Type.RAIN_MODERATE_RAIN -> "moderate rain" 55 | Weather.Type.RAIN_LIGHT_RAIN -> "light rain" 56 | Weather.Type.SNOW -> "snow" 57 | Weather.Type.SNOW_LIGHT_SNOW -> "light snow" 58 | Weather.Type.MIST -> "mist" 59 | } 60 | } 61 | 62 | private fun Weather.Type.toDrawableRes(): Int { 63 | return when (this) { 64 | Weather.Type.CLEAR -> R.drawable.weather_sun 65 | Weather.Type.THUNDERSTORM -> R.drawable.weather_storm 66 | Weather.Type.DRIZZLE -> R.drawable.weather_2_freezing_drizzle 67 | Weather.Type.CLOUDS -> R.drawable.weather_2_cloudy 68 | Weather.Type.CLOUDS_SCATTERED_CLOUDS -> R.drawable.weather_2_partly_cloudy_day 69 | Weather.Type.CLOUDS_BROKEN_CLOUDS -> R.drawable.weather_2_partly_cloudy_day 70 | Weather.Type.CLOUDS_FEW_CLOUDS -> R.drawable.weather_2_partly_cloudy_day 71 | Weather.Type.RAIN -> R.drawable.weather_rain 72 | Weather.Type.RAIN_FREEZING_RAIN -> R.drawable.weather_sun_cloud_angled_rain 73 | Weather.Type.RAIN_VERY_HEAVY_RAIN -> R.drawable.weather_sun_cloud_angled_rain 74 | Weather.Type.RAIN_HEAVY_INTENSITY -> R.drawable.weather_sun_cloud_angled_rain 75 | Weather.Type.RAIN_MODERATE_RAIN -> R.drawable.weather_sun_cloud_little_rain 76 | Weather.Type.RAIN_LIGHT_RAIN -> R.drawable.weather_rain 77 | Weather.Type.SNOW -> R.drawable.weather_mid_snow_fast_winds 78 | Weather.Type.SNOW_LIGHT_SNOW -> R.drawable.weather_snow 79 | Weather.Type.MIST -> R.drawable.weather_2_mist 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_repository/WeatherRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_repository 17 | 18 | import com.example.androiddevchallenge.weather.Weather 19 | 20 | interface WeatherRepository { 21 | 22 | fun getWeather(): Weather? 23 | 24 | fun setWeather(weather: Weather?) 25 | 26 | fun getWeatherForecastDaily(): List 27 | 28 | fun setWeatherForecastDaily(weathers: List) 29 | 30 | fun addListener(listener: Listener) 31 | 32 | fun removeListener(listener: Listener) 33 | 34 | interface Listener { 35 | 36 | fun onChanged() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_repository/WeatherRepositoryModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_repository 17 | 18 | import android.content.Context 19 | import android.content.SharedPreferences 20 | import com.example.androiddevchallenge.graph.WeatherGraph 21 | 22 | class WeatherRepositoryModule { 23 | 24 | fun createWeatherRepository(): WeatherRepository { 25 | return WeatherRepositoryImpl( 26 | createSharedPreferences() 27 | ) 28 | } 29 | 30 | private fun createSharedPreferences(): SharedPreferences { 31 | val context = WeatherGraph.getContext() 32 | return context.getSharedPreferences( 33 | WeatherRepositoryImpl.PREFERENCE_NAME, 34 | Context.MODE_PRIVATE 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_unit/WeatherUnit.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_unit 17 | 18 | enum class WeatherUnit { 19 | STANDARD, 20 | METRIC, 21 | IMPERIAL 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_unit/WeatherUnitManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_unit 17 | 18 | interface WeatherUnitManager { 19 | 20 | fun getWeatherUnit(): WeatherUnit 21 | 22 | fun setWeatherUnit(weatherUnit: WeatherUnit) 23 | 24 | fun addListener(listener: Listener) 25 | 26 | fun removeListener(listener: Listener) 27 | 28 | interface Listener { 29 | 30 | fun onChanged() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_unit/WeatherUnitManagerImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_unit 17 | 18 | import android.content.SharedPreferences 19 | 20 | class WeatherUnitManagerImpl( 21 | private val sharedPreferences: SharedPreferences 22 | ) : WeatherUnitManager { 23 | 24 | private val listeners = ArrayList() 25 | private var weatherUnit = WeatherUnit.METRIC 26 | private var loaded = false 27 | 28 | override fun getWeatherUnit(): WeatherUnit { 29 | loadIfNeeded() 30 | return weatherUnit 31 | } 32 | 33 | override fun setWeatherUnit(weatherUnit: WeatherUnit) { 34 | loadIfNeeded() 35 | if (this.weatherUnit == weatherUnit) { 36 | return 37 | } 38 | this.weatherUnit = weatherUnit 39 | save() 40 | for (listener in listeners) { 41 | listener.onChanged() 42 | } 43 | } 44 | 45 | override fun addListener(listener: WeatherUnitManager.Listener) { 46 | if (listeners.contains(listener)) { 47 | return 48 | } 49 | listeners.add(listener) 50 | } 51 | 52 | override fun removeListener(listener: WeatherUnitManager.Listener) { 53 | listeners.remove(listener) 54 | } 55 | 56 | private fun loadIfNeeded() { 57 | if (loaded) { 58 | return 59 | } 60 | weatherUnit = when (sharedPreferences.getString("unit", "metric")) { 61 | "standard" -> WeatherUnit.STANDARD 62 | "metric" -> WeatherUnit.METRIC 63 | "imperial" -> WeatherUnit.IMPERIAL 64 | else -> WeatherUnit.METRIC 65 | } 66 | loaded = true 67 | } 68 | 69 | private fun save() { 70 | sharedPreferences.edit() 71 | .putString( 72 | "unit", 73 | when (weatherUnit) { 74 | WeatherUnit.STANDARD -> "standard" 75 | WeatherUnit.METRIC -> "metric" 76 | WeatherUnit.IMPERIAL -> "imperial" 77 | } 78 | ).apply() 79 | } 80 | 81 | companion object { 82 | 83 | const val PREFERENCE_NAME = "weather_unit" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/androiddevchallenge/weather_unit/WeatherUnitModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.androiddevchallenge.weather_unit 17 | 18 | import android.content.Context 19 | import android.content.SharedPreferences 20 | import com.example.androiddevchallenge.graph.WeatherGraph 21 | 22 | class WeatherUnitModule { 23 | 24 | fun createWeatherUnitManager(): WeatherUnitManager { 25 | return WeatherUnitManagerImpl( 26 | createSharedPreferences() 27 | ) 28 | } 29 | 30 | private fun createSharedPreferences(): SharedPreferences { 31 | val context = WeatherGraph.getContext() 32 | return context.getSharedPreferences( 33 | WeatherUnitManagerImpl.PREFERENCE_NAME, 34 | Context.MODE_PRIVATE 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/drawable-night/city_edit_view_ic_outline_info_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/drawable-night/city_edit_view_loop.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/drawable/city_edit_view_ic_outline_info_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/drawable/city_edit_view_loop.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | Ville 13 | Cherche une ville 14 | C-Weather 15 | Fait par Jonathan Mercandalli (Mercandj sur GitHub) 16 | \n\n 17 | Fait pour le challenge de Jetpack compose de la semaine 4. 18 | \n\n 19 | Supporte les 2 themes: sombre et clair. L\'interface graphique est neumorphism. 20 | -------------------------------------------------------------------------------- /app/src/main/res/city_edit_view/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | City 13 | Search a city 14 | C-Weather 15 | Done by Jonathan Mercandalli (Mercandj on GitHub) 16 | \n\n 17 | Done for the Jetpack compose challenge week 4. 18 | \n\n 19 | Support Light and Dark theme. UI neumorphism. 20 | -------------------------------------------------------------------------------- /app/src/main/res/error_view/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | Pas trouvé 13 | Les raisons possibles: 14 | Image montrant que ça à raté 15 | - La ville rentrée n\'existe pas 16 | - Tu n\'as pas internet 17 | - Le server est OFF 18 | -------------------------------------------------------------------------------- /app/src/main/res/error_view/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | No weather found 13 | Possible reasons: 14 | Error image 15 | - The city is unknown 16 | - You do not have internet 17 | - The server is OFF 18 | -------------------------------------------------------------------------------- /app/src/main/res/icon/color/ic_launcher_background_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/icon/color/ic_launcher_background_gradient_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/icon/drawable-night/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/icon/drawable-v24/ic_foreground_weather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/drawable-v24/ic_foreground_weather.png -------------------------------------------------------------------------------- /app/src/main/res/icon/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/icon/drawable/ic_launcher_background_night.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/icon/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/icon/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/main/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/main/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | C-Weather 13 | -------------------------------------------------------------------------------- /app/src/main/res/main/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 24 | 25 | 29 | 30 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/main_activity_splash_dark/drawable-hdpi/main_activity_splash_image_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_activity_splash_dark/drawable-hdpi/main_activity_splash_image_dark.png -------------------------------------------------------------------------------- /app/src/main/res/main_activity_splash_dark/drawable-mdpi/main_activity_splash_image_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_activity_splash_dark/drawable-mdpi/main_activity_splash_image_dark.png -------------------------------------------------------------------------------- /app/src/main/res/main_activity_splash_dark/drawable-xhdpi/main_activity_splash_image_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_activity_splash_dark/drawable-xhdpi/main_activity_splash_image_dark.png -------------------------------------------------------------------------------- /app/src/main/res/main_activity_splash_dark/drawable-xxhdpi/main_activity_splash_image_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_activity_splash_dark/drawable-xxhdpi/main_activity_splash_image_dark.png -------------------------------------------------------------------------------- /app/src/main/res/main_activity_splash_dark/drawable-xxxhdpi/main_activity_splash_image_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_activity_splash_dark/drawable-xxxhdpi/main_activity_splash_image_dark.png -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable-hdpi/main_weather_animated_view_circle_with_shadow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view/drawable-hdpi/main_weather_animated_view_circle_with_shadow.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable-mdpi/main_weather_animated_view_circle_with_shadow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view/drawable-mdpi/main_weather_animated_view_circle_with_shadow.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable-xhdpi/main_weather_animated_view_circle_with_shadow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view/drawable-xhdpi/main_weather_animated_view_circle_with_shadow.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable-xxhdpi/main_weather_animated_view_circle_with_shadow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view/drawable-xxhdpi/main_weather_animated_view_circle_with_shadow.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable-xxxhdpi/main_weather_animated_view_circle_with_shadow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view/drawable-xxxhdpi/main_weather_animated_view_circle_with_shadow.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view/drawable/main_weather_animated_view_circle_gradient_yellow.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | 18 | 21 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_1.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_2.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_3.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_4.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_5.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_6.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_7.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-hdpi/main_weather_animated_view_figure_8.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_1.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_2.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_3.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_4.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_5.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_6.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_7.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-mdpi/main_weather_animated_view_figure_8.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_1.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_2.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_3.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_4.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_5.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_6.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_7.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xhdpi/main_weather_animated_view_figure_8.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_1.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_2.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_3.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_4.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_5.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_6.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_7.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxhdpi/main_weather_animated_view_figure_8.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_1.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_2.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_3.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_4.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_5.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_6.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_7.webp -------------------------------------------------------------------------------- /app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/main_weather_animated_view_figure/drawable-xxxhdpi/main_weather_animated_view_figure_8.webp -------------------------------------------------------------------------------- /app/src/main/res/theme/values-night/booleans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | -------------------------------------------------------------------------------- /app/src/main/res/theme/values/booleans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | -------------------------------------------------------------------------------- /app/src/main/res/theme/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | #FFEEF0F5 14 | #FF394253 15 | #FFEEF0F5 16 | #FF181C27 17 | -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_blizzard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_blizzard.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_clear.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_clear.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloud_rain_thunder.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloud_rain_thunder.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloud_sleet_snow_thunder.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloud_sleet_snow_thunder.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloudy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_cloudy.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_fog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_fog.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_drizzle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_drizzle.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_fog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_fog.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_freezing_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_rain_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_sleet_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_heavy_snow_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_rain_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_rain_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_rain_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_rain_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_sleet_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_sleet_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_sleet_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_sleet_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_snow_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_snow_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_snow_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_iso_snow_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mist.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mist.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_rain_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_sleet_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow_swrs_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow_swrs_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow_swrs_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_mod_snow_swrs_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_sleet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_sleet.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_occ_light_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_overcast.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_overcast.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_rain_thunder_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_rain_thunder_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_rain_thunder_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_rain_thunder_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_sleet_snow_thunder_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_sleet_snow_thunder_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_sleet_snow_thunder_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_part_cloud_sleet_snow_thunder_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_partly_cloudy_day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_partly_cloudy_day.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_partly_cloudy_night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_partly_cloudy_night.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_sunny.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_sunny.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_2_view/drawable-nodpi/weather_2_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_cloud_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_cloud_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_mid_snow_fast_winds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_mid_snow_fast_winds.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_cloud_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_cloud_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_cloud_mid_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_cloud_mid_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_moon_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun_cloud_angled_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun_cloud_angled_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun_cloud_little_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_sun_cloud_little_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-hdpi/weather_tornado.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-hdpi/weather_tornado.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_cloud_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_cloud_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_mid_snow_fast_winds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_mid_snow_fast_winds.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_cloud_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_cloud_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_cloud_mid_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_cloud_mid_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_moon_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun_cloud_angled_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun_cloud_angled_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun_cloud_little_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_sun_cloud_little_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-mdpi/weather_tornado.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-mdpi/weather_tornado.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_cloud_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_cloud_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_mid_snow_fast_winds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_mid_snow_fast_winds.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_cloud_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_cloud_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_cloud_mid_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_cloud_mid_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_moon_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun_cloud_angled_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun_cloud_angled_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun_cloud_little_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_sun_cloud_little_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xhdpi/weather_tornado.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xhdpi/weather_tornado.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_cloud_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_cloud_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_mid_snow_fast_winds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_mid_snow_fast_winds.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_cloud_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_cloud_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_cloud_mid_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_cloud_mid_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_moon_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun_cloud_angled_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun_cloud_angled_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun_cloud_little_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_sun_cloud_little_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_tornado.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxhdpi/weather_tornado.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_cloud_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_cloud_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_mid_snow_fast_winds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_mid_snow_fast_winds.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_cloud_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_cloud_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_cloud_mid_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_cloud_mid_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_fast_wind.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_moon_fast_wind.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_snow.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_snow.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_storm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_storm.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun_cloud_angled_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun_cloud_angled_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun_cloud_little_rain.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_sun_cloud_little_rain.webp -------------------------------------------------------------------------------- /app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_tornado.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/app/src/main/res/weather_icon_view/drawable-xxxhdpi/weather_tornado.webp -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | buildscript { 18 | ext.kotlin_version = '1.4.31' 19 | ext.compose_version = '1.0.0-beta02' 20 | ext.coroutines_version = '1.4.2' 21 | 22 | repositories { 23 | google() 24 | jcenter() 25 | } 26 | 27 | dependencies { 28 | classpath 'com.android.tools.build:gradle:7.0.0-rc01' 29 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 30 | } 31 | } 32 | 33 | plugins { 34 | id 'com.diffplug.spotless' version '5.7.0' 35 | } 36 | 37 | allprojects { 38 | repositories { 39 | maven { url "https://jitpack.io" } 40 | } 41 | } 42 | 43 | subprojects { 44 | repositories { 45 | google() 46 | jcenter() 47 | } 48 | 49 | apply plugin: 'com.diffplug.spotless' 50 | spotless { 51 | kotlin { 52 | target '**/*.kt' 53 | targetExclude("$buildDir/**/*.kt") 54 | targetExclude('bin/**/*.kt') 55 | 56 | ktlint("0.40.0") 57 | licenseHeaderFile rootProject.file('spotless/copyright.kt') 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/debug.keystore -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 24 18:05:51 CET 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /results/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/banner.jpg -------------------------------------------------------------------------------- /results/screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/screenshot_1.png -------------------------------------------------------------------------------- /results/screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/screenshot_2.png -------------------------------------------------------------------------------- /results/screenshot_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/screenshot_3.png -------------------------------------------------------------------------------- /results/screenshot_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/screenshot_4.png -------------------------------------------------------------------------------- /results/screenshot_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/screenshot_5.png -------------------------------------------------------------------------------- /results/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/video.mp4 -------------------------------------------------------------------------------- /results/video_as_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mercandj/android-dev-challenge-compose-4/d0b653174d7df1f5c72c7b146a35b37fe16e43f1/results/video_as_gif.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "android-dev-challenge-weather" 2 | include ':app' 3 | -------------------------------------------------------------------------------- /spotless/copyright.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright $YEAR The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | --------------------------------------------------------------------------------