├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── ezike
│ │ └── tobenna
│ │ └── myweather
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── ezike
│ │ │ └── tobenna
│ │ │ └── myweather
│ │ │ ├── AppCoroutineDispatcher.kt
│ │ │ ├── WeatherApplication.java
│ │ │ ├── data
│ │ │ ├── Resource.kt
│ │ │ ├── local
│ │ │ │ ├── LocalDataSource.kt
│ │ │ │ ├── LocalDataSourceImpl.kt
│ │ │ │ └── db
│ │ │ │ │ ├── WeatherDao.kt
│ │ │ │ │ ├── WeatherDatabase.kt
│ │ │ │ │ └── WeatherTypeConverter.kt
│ │ │ ├── model
│ │ │ │ ├── Current.kt
│ │ │ │ ├── Request.kt
│ │ │ │ ├── WeatherLocation.kt
│ │ │ │ └── WeatherResponse.kt
│ │ │ └── remote
│ │ │ │ ├── RemoteImpl.kt
│ │ │ │ ├── RemoteSource.kt
│ │ │ │ ├── api
│ │ │ │ └── ApiService.kt
│ │ │ │ └── interceptors
│ │ │ │ ├── ConnectivityInterceptor.kt
│ │ │ │ └── RequestInterceptor.kt
│ │ │ ├── di
│ │ │ ├── AppComponent.kt
│ │ │ ├── ViewModelKey.java
│ │ │ ├── ViewModelModule.java
│ │ │ └── module
│ │ │ │ ├── ActivityModule.java
│ │ │ │ ├── ApiModule.kt
│ │ │ │ ├── AppModule.kt
│ │ │ │ ├── DataSourceModule.java
│ │ │ │ ├── DatabaseModule.java
│ │ │ │ ├── LocationModule.java
│ │ │ │ └── UnitModule.java
│ │ │ ├── provider
│ │ │ ├── LocationProvider.java
│ │ │ ├── LocationProviderImpl.java
│ │ │ ├── PreferenceProvider.java
│ │ │ ├── UnitProvider.java
│ │ │ └── UnitProviderImpl.java
│ │ │ ├── repository
│ │ │ ├── Repository.kt
│ │ │ └── WeatherRepository.kt
│ │ │ ├── ui
│ │ │ ├── BindingAdapters.kt
│ │ │ ├── WeatherViewModel.kt
│ │ │ ├── activity
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── SplashActivity.java
│ │ │ └── fragment
│ │ │ │ ├── AboutFragment.java
│ │ │ │ ├── SettingsFragment.java
│ │ │ │ └── WeatherFragment.kt
│ │ │ ├── utils
│ │ │ ├── LocationHandler.java
│ │ │ ├── UnitSystem.java
│ │ │ ├── Utilities.java
│ │ │ ├── WeatherIconUtils.java
│ │ │ └── extensions.kt
│ │ │ ├── viewmodel
│ │ │ └── WeatherViewModelFactory.java
│ │ │ └── widget
│ │ │ ├── WeatherWidgetProvider.java
│ │ │ └── WidgetUpdateService.java
│ └── res
│ │ ├── drawable-nodpi
│ │ └── example_appwidget_preview.png
│ │ ├── drawable-v24
│ │ ├── day.png
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_settings.xml
│ │ ├── ic_today.xml
│ │ └── widget_bg.jpeg
│ │ ├── font
│ │ └── googlesans.ttf
│ │ ├── layout-land
│ │ ├── fragment_about.xml
│ │ └── fragment_weather.xml
│ │ ├── layout-v17
│ │ └── activity_main.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_splash.xml
│ │ ├── fragment_about.xml
│ │ ├── fragment_weather.xml
│ │ └── weather_widget.xml
│ │ ├── menu
│ │ ├── bottom_nav.xml
│ │ └── menu_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── navigation
│ │ └── mobile_navigation.xml
│ │ ├── transition
│ │ ├── explode.xml
│ │ └── slide_out.xml
│ │ ├── values-v14
│ │ └── dimens.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ ├── network_security_config.xml
│ │ ├── preferences.xml
│ │ └── weather_widget_info.xml
│ └── test
│ └── java
│ └── ezike
│ └── tobenna
│ └── myweather
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── weather.jks
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/android
3 | # Edit at https://www.gitignore.io/?templates=android
4 |
5 | ### Android ###
6 | # Built application files
7 | *.apk
8 | *.ap_
9 | *.aab
10 |
11 | # Files for the ART/Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Generated files
18 | bin/
19 | gen/
20 | out/
21 |
22 | # Gradle files
23 | .gradle/
24 | build/
25 |
26 | # ezike.tobenna.myweather.data.LocalTee configuration file (sdk path, etc)
27 | local.properties
28 |
29 | # Proguard folder generated by Eclipse
30 | proguard/
31 |
32 | # Log Files
33 | *.log
34 |
35 | # Android Studio Navigation editor temp files
36 | .navigation/
37 |
38 | # Android Studio captures folder
39 | captures/
40 |
41 | # IntelliJ
42 | *.iml
43 | .idea/workspace.xml
44 | .idea/tasks.xml
45 | .idea/gradle.xml
46 | .idea/assetWizardSettings.xml
47 | .idea/dictionaries
48 | .idea/libraries
49 | .idea/caches
50 | # Android Studio 3 in .gitignore file.
51 | .idea/caches/build_file_checksums.ser
52 | .idea/modules.xml
53 |
54 | # Keystore files
55 | # Uncomment the following lines if you do not want to check your keystore files in.
56 | #*.jks
57 | #*.keystore
58 |
59 | # External native build folder generated in Android Studio 2.2 and later
60 | .externalNativeBuild
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Version control
66 | vcs.xml
67 |
68 | # lint
69 | lint/intermediates/
70 | lint/generated/
71 | lint/outputs/
72 | lint/tmp/
73 | # lint/reports/
74 |
75 | ### Android Patch ###
76 | gen-external-apklibs
77 | output.json
78 |
79 | # End of https://www.gitignore.io/api/android
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MyWeather
2 | App shows real-time weather updates for your location and any custom location you set.
3 | Was initially written in Java but is now in Kotlin and uses coroutines. Data is from [Apixu Api](https://www.apixu.com/api.aspx)
4 |
5 | * You can clone the project and fix stuff or maybe write some tests 😉☺️
6 |
7 |
8 | 
9 |
10 |
11 | ## Features
12 | * kotlin coroutines for async operations
13 | * kotlin flow for data streaming
14 | * Local persistence using Room database
15 | * MVVM architecture
16 | * Databinding for binding data to views
17 | * Navigation component
18 | * Homescreen Widget that shows weather information
19 | * Dependency injection with Dagger 2
20 |
21 | #### 1. Clone or fork the repository (Master Branch) by running the command below
22 | on your git terminal
23 | ```
24 | git clone https://github.com/Ezike/MyWeather.git
25 | ```
26 |
27 | #### 2. Import the project in AndroidStudio, and add API Key
28 | 1. In Android Studio, go to File -> New -> Import project
29 | 2. Follow the dialog for set up instructions
30 | 3. Get your api key from [Apixu website](https://www.apixu.com/api.aspx)
31 | 4. Create a local `gradle.properties` file and store the api key there
32 |
33 | ```
34 | ApiXuKey="Your API Key here"
35 | ```
36 |
37 | ## Libraries
38 | * [Coroutines](https://developer.android.com/kotlin/coroutines)
39 | * [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)
40 | * [AndroidX](https://developer.android.com/jetpack/androidx/)
41 | * [Navigation component](https://developer.android.com/guide/navigation)
42 | * [Retrofit 2](https://github.com/square/retrofit)
43 | * [LiveData](https://developer.android.com/topic/libraries/architecture/livedata)
44 | * [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel)
45 | * [Room](https://developer.android.com/topic/libraries/architecture/room)
46 | * [Glide](https://github.com/bumptech/glide)
47 | * [DataBinding](https://developer.android.com/topic/libraries/data-binding)
48 | * [Dagger2](https://google.github.io/dagger/users-guide)
49 | * [Timber](https://github.com/JakeWharton/timber)
50 | * [WeatherIconView](https://github.com/pwittchen/WeatherIconView)
51 | * [Moshi](https://github.com/square/moshi)
52 | * [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP)
53 | * [OkHttp3](https://square.github.io/okhttp)
54 | * [Google Admob](https://developers.google.com/admob/android/quick-start)
55 |
56 | ## Author
57 | Ezike Tobenna
58 |
59 | ## License
60 | This project is licensed under the Apache License 2.0 - See: http://www.apache.org/licenses/LICENSE-2.0.txt
61 |
62 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/android
3 | # Edit at https://www.gitignore.io/?templates=android
4 |
5 | ### Android ###
6 | # Built application files
7 | *.apk
8 | *.ap_
9 | *.aab
10 |
11 | # Files for the ART/Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Generated files
18 | bin/
19 | gen/
20 | out/
21 |
22 | # Gradle files
23 | .gradle/
24 | build/
25 |
26 | # ezike.tobenna.myweather.data.LocalTee configuration file (sdk path, etc)
27 | local.properties
28 |
29 | # Proguard folder generated by Eclipse
30 | proguard/
31 |
32 | # Log Files
33 | *.log
34 |
35 | # Android Studio Navigation editor temp files
36 | .navigation/
37 |
38 | # Android Studio captures folder
39 | captures/
40 |
41 | # IntelliJ
42 | *.iml
43 | .idea/workspace.xml
44 | .idea/tasks.xml
45 | .idea/gradle.xml
46 | .idea/assetWizardSettings.xml
47 | .idea/dictionaries
48 | .idea/libraries
49 | .idea/caches
50 | # Android Studio 3 in .gitignore file.
51 | .idea/caches/build_file_checksums.ser
52 | .idea/modules.xml
53 |
54 | # Keystore files
55 | # Uncomment the following lines if you do not want to check your keystore files in.
56 | #*.jks
57 | #*.keystore
58 |
59 | # External native build folder generated in Android Studio 2.2 and later
60 | .externalNativeBuild
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Version control
66 | vcs.xml
67 |
68 | # lint
69 | lint/intermediates/
70 | lint/generated/
71 | lint/outputs/
72 | lint/tmp/
73 | # lint/reports/
74 |
75 | ### Android Patch ###
76 | gen-external-apklibs
77 | output.json
78 |
79 | # End of https://www.gitignore.io/api/android
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'com.google.gms.google-services'
5 | apply plugin: 'io.fabric'
6 | apply plugin: 'kotlin-kapt'
7 | apply plugin: "androidx.navigation.safeargs.kotlin"
8 |
9 | android {
10 | signingConfigs {
11 | keyWeather {
12 | keyAlias 'keyWeather'
13 | keyPassword '123456'
14 | storeFile file("..\\weather.jks")
15 | storePassword '123456'
16 | }
17 | }
18 |
19 | compileSdkVersion 29
20 |
21 | defaultConfig {
22 | applicationId "ezike.tobenna.myweather"
23 | minSdkVersion min_sdk_version
24 | targetSdkVersion compile_sdk_version
25 | multiDexEnabled true
26 | versionCode 1
27 | versionName "1.0"
28 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29 | }
30 |
31 | buildTypes {
32 | debug {
33 | buildConfigField 'String', "ApiKey", "\"e5235257b00adf728e360a7521c9e096\""
34 | buildConfigField 'String', "BaseUrl", "\"http://api.weatherstack.com/\""
35 | // resValue 'string', "api_key", "c1b490e5810e7515ef5bdcf47f8497ad"
36 | }
37 | release {
38 | minifyEnabled false
39 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
40 | buildConfigField 'String', "ApiKey", "c1b490e5810e7515ef5bdcf47f8497ad"
41 | buildConfigField 'String', "BaseUrl", "\"http://api.weatherstack.com/\""
42 | resValue 'string', "api_key", "c1b490e5810e7515ef5bdcf47f8497ad"
43 | signingConfig signingConfigs.keyWeather
44 | }
45 | }
46 |
47 | buildFeatures {
48 | dataBinding = true
49 | viewBinding = true
50 | }
51 |
52 |
53 | compileOptions {
54 | sourceCompatibility = '1.8'
55 | targetCompatibility = '1.8'
56 | }
57 |
58 | defaultConfig {
59 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
60 | }
61 |
62 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
63 | kotlinOptions {
64 | jvmTarget = "1.8"
65 | }
66 | }
67 | }
68 |
69 | dependencies {
70 | implementation fileTree (include: ['*.jar'], dir: 'libs')
71 | implementation libraries
72 | implementation arch_libraries
73 | kapt librariesKapt
74 |
75 | testImplementation testLibraries
76 | androidTestImplementation androidTestLibraries
77 | }
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "108354523106",
4 | "firebase_url": "https://myweather-a16e6.firebaseio.com",
5 | "project_id": "myweather-a16e6",
6 | "storage_bucket": "myweather-a16e6.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:108354523106:android:eb6b4cb7d114737a",
12 | "android_client_info": {
13 | "package_name": "ezike.tobenna.myweather"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "108354523106-s6r6mtsddus8i7joh0r1e8b5toef90df.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyCraUlQ_8hRIpGAh9I0HxovIRe7gIu5t6E"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/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
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/ezike/tobenna/myweather/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package ezike.tobenna.myweather;
2 |
3 | import android.content.Context;
4 |
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 |
8 | import androidx.test.core.app.ApplicationProvider;
9 | import androidx.test.ext.junit.runners.AndroidJUnit4;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 |
23 | // Use either Application Provider to get context or use Androidx InstrumentationRegistry below
24 | Context appContext = ApplicationProvider.getApplicationContext();
25 |
26 | // Context appContext = InstrumentationRegistry.getInstrumentation().getContext();
27 |
28 | assertEquals("ezike.tobenna.myweather", appContext.getPackageName());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
48 |
49 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ezike/MyWeatherKotlinFlow/495010e2b9664aa990c5a32a293be49cd95b63aa/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/ezike/tobenna/myweather/AppCoroutineDispatcher.kt:
--------------------------------------------------------------------------------
1 | package ezike.tobenna.myweather
2 |
3 | import kotlinx.coroutines.CoroutineDispatcher
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | data class AppCoroutineDispatchers(
7 | val io: CoroutineDispatcher = Dispatchers.IO,
8 | val default: CoroutineDispatcher = Dispatchers.Default,
9 | val main: CoroutineDispatcher = Dispatchers.Main
10 | )
11 |
--------------------------------------------------------------------------------
/app/src/main/java/ezike/tobenna/myweather/WeatherApplication.java:
--------------------------------------------------------------------------------
1 | package ezike.tobenna.myweather;
2 |
3 | import androidx.multidex.MultiDexApplication;
4 | import androidx.preference.PreferenceManager;
5 |
6 | import com.jakewharton.threetenabp.AndroidThreeTen;
7 |
8 | import javax.inject.Inject;
9 |
10 | import dagger.android.AndroidInjector;
11 | import dagger.android.DispatchingAndroidInjector;
12 | import dagger.android.HasAndroidInjector;
13 | import ezike.tobenna.myweather.di.DaggerAppComponent;
14 | import timber.log.Timber;
15 |
16 | /**
17 | * @author tobennaezike
18 | */
19 | public class WeatherApplication extends MultiDexApplication implements HasAndroidInjector {
20 |
21 | @Inject
22 | DispatchingAndroidInjector