From 1c6c578322164713b7b45a1e7e6ed600c7042321 Mon Sep 17 00:00:00 2001 From: Daniel Waiguru Date: Sat, 6 Jan 2024 15:23:50 +0300 Subject: [PATCH 1/9] implement permissions screen and request permissions --- app/src/main/AndroidManifest.xml | 6 +- .../danielwaiguru/weatherapp/MainActivity.kt | 48 -------- .../{WeatherApp.kt => WeatherApplication.kt} | 2 +- .../weatherapp/activity/MainActivity.kt | 17 +++ .../navigation/WeatherAppNvaigation.kt | 32 ++++++ .../designsystem/components/Button.kt | 54 +++++++++ .../designsystem/components/TopBar.kt | 67 +++++++++++ .../previews/WeatherAppPreviews.kt | 10 ++ designsystem/src/main/res/values/strings.xml | 4 + gradle/libs.versions.toml | 3 + presentation/build.gradle.kts | 3 + .../navigation/ScreenDestination.kt | 27 +++++ .../permissions/PermissionsScreen.kt | 105 ++++++++++++++++++ .../PermissionsScreenDestination.kt | 29 +++++ .../presentation/weather/WeatherScreen.kt | 4 + .../navigation/WeatherScreenDestination.kt | 19 ++++ .../src/main/res/drawable/location.png | Bin 0 -> 4722 bytes .../src/main/res/raw/location_animation.json | 1 + presentation/src/main/res/values/strings.xml | 6 + 19 files changed, 386 insertions(+), 51 deletions(-) delete mode 100644 app/src/main/java/com/danielwaiguru/weatherapp/MainActivity.kt rename app/src/main/java/com/danielwaiguru/weatherapp/{WeatherApp.kt => WeatherApplication.kt} (76%) create mode 100644 app/src/main/java/com/danielwaiguru/weatherapp/activity/MainActivity.kt create mode 100644 app/src/main/java/com/danielwaiguru/weatherapp/navigation/WeatherAppNvaigation.kt create mode 100644 designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/Button.kt create mode 100644 designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/TopBar.kt create mode 100644 designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/previews/WeatherAppPreviews.kt create mode 100644 designsystem/src/main/res/values/strings.xml create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/navigation/ScreenDestination.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/PermissionsScreen.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/navigation/PermissionsScreenDestination.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt create mode 100644 presentation/src/main/res/drawable/location.png create mode 100644 presentation/src/main/res/raw/location_animation.json create mode 100644 presentation/src/main/res/values/strings.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 72dd55d..adc6354 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,9 +3,11 @@ xmlns:tools="http://schemas.android.com/tools"> + + diff --git a/app/src/main/java/com/danielwaiguru/weatherapp/MainActivity.kt b/app/src/main/java/com/danielwaiguru/weatherapp/MainActivity.kt deleted file mode 100644 index a599df0..0000000 --- a/app/src/main/java/com/danielwaiguru/weatherapp/MainActivity.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.danielwaiguru.weatherapp - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import com.danielwaiguru.weatherapp.designsystem.theme.WeatherAppTheme -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - WeatherAppTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { - Greeting("Android") - } - } - } - } -} - -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - com.danielwaiguru.weatherapp.designsystem.theme.WeatherAppTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/app/src/main/java/com/danielwaiguru/weatherapp/WeatherApp.kt b/app/src/main/java/com/danielwaiguru/weatherapp/WeatherApplication.kt similarity index 76% rename from app/src/main/java/com/danielwaiguru/weatherapp/WeatherApp.kt rename to app/src/main/java/com/danielwaiguru/weatherapp/WeatherApplication.kt index 7ff405b..e1aafd6 100644 --- a/app/src/main/java/com/danielwaiguru/weatherapp/WeatherApp.kt +++ b/app/src/main/java/com/danielwaiguru/weatherapp/WeatherApplication.kt @@ -4,4 +4,4 @@ import android.app.Application import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp -class WeatherApp: Application() \ No newline at end of file +class WeatherApplication: Application() \ No newline at end of file diff --git a/app/src/main/java/com/danielwaiguru/weatherapp/activity/MainActivity.kt b/app/src/main/java/com/danielwaiguru/weatherapp/activity/MainActivity.kt new file mode 100644 index 0000000..d785339 --- /dev/null +++ b/app/src/main/java/com/danielwaiguru/weatherapp/activity/MainActivity.kt @@ -0,0 +1,17 @@ +package com.danielwaiguru.weatherapp.activity + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import com.danielwaiguru.weatherapp.navigation.WeatherApp +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + WeatherApp() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/danielwaiguru/weatherapp/navigation/WeatherAppNvaigation.kt b/app/src/main/java/com/danielwaiguru/weatherapp/navigation/WeatherAppNvaigation.kt new file mode 100644 index 0000000..faacbd7 --- /dev/null +++ b/app/src/main/java/com/danielwaiguru/weatherapp/navigation/WeatherAppNvaigation.kt @@ -0,0 +1,32 @@ +package com.danielwaiguru.weatherapp.navigation + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.rememberNavController +import com.danielwaiguru.weatherapp.designsystem.theme.WeatherAppTheme +import com.danielwaiguru.weatherapp.presentation.permissions.navigation.PermissionsScreenDestination +import com.danielwaiguru.weatherapp.presentation.permissions.navigation.permissionsScreen +import com.danielwaiguru.weatherapp.presentation.weather.navigation.weatherScreen + +@Composable +fun WeatherApp() { + WeatherAppTheme { + val navController = rememberNavController() + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + NavHost( + navController = navController, + startDestination = PermissionsScreenDestination.route + ) { + permissionsScreen(navController = navController) + weatherScreen() + } + } + } +} \ No newline at end of file diff --git a/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/Button.kt b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/Button.kt new file mode 100644 index 0000000..dfdfce6 --- /dev/null +++ b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/Button.kt @@ -0,0 +1,54 @@ +package com.danielwaiguru.weatherapp.designsystem.components + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.dp +import com.danielwaiguru.weatherapp.designsystem.previews.DevicePreviews +import com.danielwaiguru.weatherapp.designsystem.theme.WeatherAppTheme + +@Composable +fun PrimaryButton( + text: String, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = ButtonDefaults.shape, + onClick: () -> Unit, + contentPadding: PaddingValues = PaddingValues( + top = 15.dp, + bottom = 15.dp + ) +) { + Button( + onClick = onClick, + enabled = enabled, + modifier = modifier + .testTag("primary_button"), + shape = shape, + contentPadding = contentPadding + ) { + Text( + text = text + ) + } +} +@DevicePreviews +@Composable +private fun PrimaryButtonPreview() { + WeatherAppTheme { + PrimaryButton( + text = "Click", + onClick = { /*TODO*/ }, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) + } +} \ No newline at end of file diff --git a/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/TopBar.kt b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/TopBar.kt new file mode 100644 index 0000000..9bd4c80 --- /dev/null +++ b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/TopBar.kt @@ -0,0 +1,67 @@ +package com.danielwaiguru.weatherapp.designsystem.components + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material.icons.rounded.Settings +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import com.danielwaiguru.weatherapp.designsystem.R +import com.danielwaiguru.weatherapp.designsystem.previews.DevicePreviews +import com.danielwaiguru.weatherapp.designsystem.theme.WeatherAppTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopAppBar( + modifier: Modifier = Modifier, + onNavIconPressed: (() -> Unit)? = null, + navigationIcon: ImageVector? = null, + title: String, + actions: @Composable RowScope.() -> Unit = {} +) { + CenterAlignedTopAppBar( + title = { + Text( + text = title + ) + }, + modifier = modifier, + navigationIcon = { + if (navigationIcon != null && onNavIconPressed != null) { + IconButton(onClick = onNavIconPressed) { + Icon( + imageVector = navigationIcon, + contentDescription = stringResource(id = R.string.nav_icon_content_desc) + ) + } + } + }, + actions = actions + ) +} + +@DevicePreviews +@Composable +fun TopAppBarPreview() { + WeatherAppTheme { + TopAppBar( + modifier = Modifier.fillMaxWidth(), + title = "Sample Title", + onNavIconPressed = {}, + navigationIcon = Icons.Outlined.ArrowBack, + actions = { + IconButton(onClick = {}) { + Icon(imageVector = Icons.Rounded.Settings, contentDescription = null) + } + } + ) + } +} \ No newline at end of file diff --git a/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/previews/WeatherAppPreviews.kt b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/previews/WeatherAppPreviews.kt new file mode 100644 index 0000000..b2e1f70 --- /dev/null +++ b/designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/previews/WeatherAppPreviews.kt @@ -0,0 +1,10 @@ +package com.danielwaiguru.weatherapp.designsystem.previews + +import androidx.compose.ui.tooling.preview.Preview + +@Preview( + name = "phone", + device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480", + showBackground = true +) +annotation class DevicePreviews \ No newline at end of file diff --git a/designsystem/src/main/res/values/strings.xml b/designsystem/src/main/res/values/strings.xml new file mode 100644 index 0000000..17c87fb --- /dev/null +++ b/designsystem/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Navigate back + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 58b5dbd..433e946 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ activity-compose = "1.8.2" compose-bom = "2023.10.01" androidxComposeCompiler = "1.5.7" appcompat = "1.6.1" +lottieCompose = "5.2.0" material = "1.11.0" hilt = "2.48.1" hiltExt = "1.1.0" @@ -47,6 +48,7 @@ core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanaryAndroid" } +lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottieCompose" } ui = { group = "androidx.compose.ui", name = "ui" } ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } @@ -61,6 +63,7 @@ androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-ru appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "googleAccompanist" } +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "googleAccompanist" } coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil" } coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index a0154e8..f4ff2e5 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -9,4 +9,7 @@ android { } dependencies { implementation(libs.accompanist.systemuicontroller) + implementation(libs.accompanist.permissions) + implementation(project(":designsystem")) + implementation(libs.lottie.compose) } \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/navigation/ScreenDestination.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/navigation/ScreenDestination.kt new file mode 100644 index 0000000..cb791db --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/navigation/ScreenDestination.kt @@ -0,0 +1,27 @@ +package com.danielwaiguru.weatherapp.presentation.navigation + +import androidx.annotation.StringRes + + +interface AppNavigationDestination { + /** + * Defines a specific route this destination belongs to. + * Route is a String that defines the path to your composable. + * You can think of it as an implicit deep link that leads to a specific destination. + * Each destination should have a unique route. + */ + val route: String + + /** + * Defines a specific destination ID. + * This is needed when using nested graphs via the navigation DLS, to differentiate a specific + * destination's route from the route of the entire nested graph it belongs to. + */ + val destination: String + + /** + * Defines a resource id for the Screen title + */ + @get:StringRes + val title: Int +} \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/PermissionsScreen.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/PermissionsScreen.kt new file mode 100644 index 0000000..4bbc342 --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/PermissionsScreen.kt @@ -0,0 +1,105 @@ +package com.danielwaiguru.weatherapp.presentation.permissions + +import android.Manifest +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition +import com.danielwaiguru.weatherapp.designsystem.components.PrimaryButton +import com.danielwaiguru.weatherapp.designsystem.components.TopAppBar +import com.danielwaiguru.weatherapp.presentation.R +import com.danielwaiguru.weatherapp.presentation.permissions.navigation.PermissionsScreenDestination +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.isGranted +import com.google.accompanist.permissions.rememberPermissionState + +@Composable +fun PermissionsRoute(onNavigateToWeather: () -> Unit) { + PermissionsScreen( + onNavigateToWeather = onNavigateToWeather, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp) + ) +} + +val locationPermissions = arrayOf( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, +) +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun PermissionsScreen( + onNavigateToWeather: () -> Unit, + modifier: Modifier = Modifier +) { + val locationPermissionsState = rememberPermissionState( + permission = Manifest.permission.ACCESS_FINE_LOCATION + ) + + LaunchedEffect(key1 = locationPermissionsState.status) { + if (locationPermissionsState.status.isGranted) { + onNavigateToWeather() + } + } + val composition by rememberLottieComposition( + LottieCompositionSpec.RawRes(R.raw.location_animation) + ) + val animationState = animateLottieCompositionAsState(composition = composition) + Scaffold( + topBar = { + TopAppBar( + modifier = Modifier + .fillMaxWidth(), + title = stringResource(id = PermissionsScreenDestination.title) + ) + }, + modifier = modifier + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.location_permission), + textAlign = TextAlign.Center + ) + LottieAnimation( + composition = composition, + progress = { animationState.progress }, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .size(300.dp), + contentScale = ContentScale.Fit + ) + PrimaryButton( + text = stringResource(id = R.string.get_started), + onClick = { + locationPermissionsState.launchPermissionRequest() + }, + modifier = Modifier + .fillMaxWidth() + ) + } + } +} diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/navigation/PermissionsScreenDestination.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/navigation/PermissionsScreenDestination.kt new file mode 100644 index 0000000..8739733 --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/permissions/navigation/PermissionsScreenDestination.kt @@ -0,0 +1,29 @@ +package com.danielwaiguru.weatherapp.presentation.permissions.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.danielwaiguru.weatherapp.presentation.R +import com.danielwaiguru.weatherapp.presentation.navigation.AppNavigationDestination +import com.danielwaiguru.weatherapp.presentation.permissions.PermissionsRoute +import com.danielwaiguru.weatherapp.presentation.weather.navigation.WeatherScreenDestination + +object PermissionsScreenDestination: AppNavigationDestination { + override val route: String = "com.danielwaiguru.weatherapp.PermissionsScreen" + override val destination: String = "com.danielwaiguru.weatherapp.PermissionsScreenDestination" + override val title: Int = R.string.grant_permissions +} + +fun NavGraphBuilder.permissionsScreen(navController: NavHostController) { + composable(route = PermissionsScreenDestination.route) { + PermissionsRoute( + onNavigateToWeather = { + navController.navigate(WeatherScreenDestination.route) { + popUpTo(navController.graph.id){ + inclusive = true + } + } + } + ) + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt new file mode 100644 index 0000000..fe4e571 --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt @@ -0,0 +1,4 @@ +package com.danielwaiguru.weatherapp.presentation.weather + +class WeatherScreen { +} \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt new file mode 100644 index 0000000..9b3ef7a --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt @@ -0,0 +1,19 @@ +package com.danielwaiguru.weatherapp.presentation.weather.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import com.danielwaiguru.weatherapp.presentation.navigation.AppNavigationDestination + + +object WeatherScreenDestination: AppNavigationDestination { + override val route: String = "com.danielwaiguru.weatherapp.WeatherScreen" + override val destination: String = "com.danielwaiguru.weatherapp.WeatherScreenDestination" + override val title: Int + get() = TODO("Not yet implemented") +} + +fun NavGraphBuilder.weatherScreen() { + composable(route = WeatherScreenDestination.route) { + + } +} \ No newline at end of file diff --git a/presentation/src/main/res/drawable/location.png b/presentation/src/main/res/drawable/location.png new file mode 100644 index 0000000000000000000000000000000000000000..afbad4451d9e6f34bb065a54ec6ce996095fbcf0 GIT binary patch literal 4722 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 A4FCWD literal 0 HcmV?d00001 diff --git a/presentation/src/main/res/raw/location_animation.json b/presentation/src/main/res/raw/location_animation.json new file mode 100644 index 0000000..d0fdcd8 --- /dev/null +++ b/presentation/src/main/res/raw/location_animation.json @@ -0,0 +1 @@ +{"v":"5.1.1","fr":30,"ip":0,"op":90,"w":368,"h":240,"nm":"02-B","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"pin Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.71,143.456,0],"ix":2},"a":{"a":0,"k":[42.579,115.457,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1.444,1.289,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"n":["0p833_1p444_0p167_0","0p833_1p289_0p167_0","0p833_1_0p167_0"],"t":22,"s":[100,100,100],"e":[92.917,112.992,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.99,0.967,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.073,0.135,0]},"n":["0p833_0p99_0p167_0p073","0p833_0p967_0p167_0p135","0p833_1_0p167_0"],"t":26,"s":[92.917,112.992,100],"e":[125.208,92.205,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.949,0.962,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.016,-0.081,0]},"n":["0p833_0p949_0p167_-0p016","0p833_0p962_0p167_-0p081","0p833_1_0p167_0"],"t":29,"s":[125.208,92.205,100],"e":[97.643,103.464,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.967,0.925,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.209,-0.098,0]},"n":["0p833_0p967_0p167_-0p209","0p833_0p925_0p167_-0p098","0p833_1_0p167_0"],"t":33,"s":[97.643,103.464,100],"e":[106.102,98,100]},{"i":{"x":[0.811,0.811,0.811],"y":[1.021,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.018,-0.082,0]},"n":["0p811_1p021_0p167_-0p018","0p811_1_0p167_-0p082","0p811_1_0p167_0"],"t":38,"s":[106.102,98,100],"e":[100,100,100]},{"t":40}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,7.781],[7.78,0],[0,-7.78],[-7.781,0]],"o":[[0,-7.78],[-7.781,0],[0,7.781],[7.78,0]],"v":[[14.089,0],[0,-14.088],[-14.089,0],[0,14.088]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.647000002394,0.184000007779,0.125,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[42.624,42.283],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,37.343],[23.454,0],[0,-23.455],[-1.368,0]],"o":[[0,-23.455],[-23.455,0],[0,37.343],[1.367,0]],"v":[[42.468,-14.644],[0,-57.113],[-42.469,-14.644],[0,57.113]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917999985639,0.337000020345,0.238999998803,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[42.468,57.113],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"line Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.6,144.956,0],"ix":2},"a":{"a":0,"k":[17.389,6,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1.733,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"n":["0p833_1p733_0p167_0","0p833_1_0p167_0","0p833_1_0p167_0"],"t":22,"s":[100,100,100],"e":[60,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.987,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.195,0,0]},"n":["0p833_0p987_0p167_0p195","0p833_1_0p167_0","0p833_1_0p167_0"],"t":26,"s":[60,100,100],"e":[173,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.987,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.022,0,0]},"n":["0p833_0p987_0p167_-0p022","0p833_1_0p167_0","0p833_1_0p167_0"],"t":29,"s":[173,100,100],"e":[81,100,100]},{"i":{"x":[0.635,0.635,0.635],"y":[0.714,1,1]},"o":{"x":[0.158,0.158,0.158],"y":[-0.067,0,0]},"n":["0p635_0p714_0p158_-0p067","0p635_1_0p158_0","0p635_1_0p158_0"],"t":33,"s":[81,100,100],"e":[102.444,100,100]},{"i":{"x":[0.811,0.811,0.811],"y":[1.42,1,1]},"o":{"x":[0.438,0.438,0.438],"y":[-1.206,0,0]},"n":["0p811_1p42_0p438_-1p206","0p811_1_0p438_0","0p811_1_0p438_0"],"t":38,"s":[102.444,100,100],"e":[100,100,100]},{"t":40}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6,6],[28.779,6]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.969000004787,0.74900004069,0.709999952129,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"horizontaal","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.5,120,0],"ix":2},"a":{"a":0,"k":[183.5,120,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[99.736,145.12],[265.745,145.12]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":21,"s":[0],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":33,"s":[0],"e":[0]},{"i":{"x":[0.518],"y":[1]},"o":{"x":[0.426],"y":[0]},"n":["0p518_1_0p426_0"],"t":73,"s":[0],"e":[100]},{"t":84}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.521],"y":[1]},"o":{"x":[0.496],"y":[0]},"n":["0p521_1_0p496_0"],"t":21,"s":[0],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":33,"s":[100],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":73,"s":[100],"e":[100]},{"t":84}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":100,"st":10,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"verticaal","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.5,120,0],"ix":2},"a":{"a":0,"k":[183.5,120,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[209.609,41.667],[209.609,200.667]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11,"s":[100],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"n":["0p667_1_0p167_0"],"t":23,"s":[100],"e":[100]},{"i":{"x":[0.412],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p412_1_0p333_0"],"t":63,"s":[100],"e":[0]},{"t":75}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.437],"y":[1]},"o":{"x":[0.427],"y":[0]},"n":["0p437_1_0p427_0"],"t":11,"s":[100],"e":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p833_1_0p333_0"],"t":23,"s":[0],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":63,"s":[0],"e":[0]},{"t":75}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"bocht","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.5,120,0],"ix":2},"a":{"a":0,"k":[183.5,120,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,-20.781],[0,0],[1.889,-4.513]],"o":[[0,0],[-20.568,0],[0,0],[0,5.208],[0,0]],"v":[[62.182,-47.966],[-22.005,-47.966],[-59.249,-10.339],[-59.249,33.285],[-62.182,47.967]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[204.09,147.818],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":11,"s":[100],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":23,"s":[100],"e":[100]},{"i":{"x":[0.514],"y":[1]},"o":{"x":[0.435],"y":[0]},"n":["0p514_1_0p435_0"],"t":72,"s":[100],"e":[0]},{"t":84}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.429],"y":[1]},"o":{"x":[0.444],"y":[0]},"n":["0p429_1_0p444_0"],"t":11,"s":[100],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":23,"s":[0],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":72,"s":[0],"e":[0]},{"t":84}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"blauw","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":20,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":32,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":63,"s":[100],"e":[0]},{"t":75}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.5,117,0],"ix":2},"a":{"a":0,"k":[183.5,120,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.741,-1.208],[-4.334,-45.689],[-1.422,-4.92],[0,0],[0,0],[-20.569,0],[0,0],[0,0]],"o":[[-45.689,4.334],[0.502,5.285],[0,0],[0,0],[0,-20.781],[0,0],[0,0],[-11.268,-4.122]],"v":[[21.165,-52.344],[-53.715,38.232],[-50.785,53.551],[-9.253,53.551],[-9.253,47.764],[27.99,10.136],[58.049,10.136],[57.512,-47.688]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.26699999641,0.344999994016,0.866999966491,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[154.094,89.716],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":20,"s":[0],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":32,"s":[0],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":63,"s":[0],"e":[100]},{"t":75}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":20,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":32,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":63,"s":[100],"e":[100]},{"t":75}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":9,"op":99,"st":9,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"groen","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":21,"s":[1],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":64,"s":[100],"e":[0]},{"t":76}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.5,117,0],"ix":2},"a":{"a":0,"k":[183.5,120,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[25.349,9.192],[0,0],[0,0]],"o":[[0,0],[0,0],[-6.91,-27.008]],"v":[[-26.104,-28.726],[-26.104,28.726],[26.104,28.726]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.301999978458,0.889999988032,0.728999956916,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[237.488,70.677],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":21,"s":[0],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[0],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":64,"s":[0],"e":[100]},{"t":76}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":21,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":33,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":64,"s":[100],"e":[100]},{"t":76}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":100,"st":10,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[183.355,117.117,0],"ix":2},"a":{"a":0,"k":[83.1,83.099,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.794,45.889],[45.886,0.794],[0.794,-45.888],[-45.888,-0.794]],"o":[[0.794,-45.888],[-45.889,-0.794],[-0.794,45.889],[45.887,0.794]],"v":[[83.087,1.437],[1.439,-83.087],[-83.087,-1.438],[-1.437,83.086]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.948999980852,0.948999980852,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[83.1,83.099],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":90,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml new file mode 100644 index 0000000..09dc441 --- /dev/null +++ b/presentation/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + Grant Location Permissions + Weather App requires location permissions to be able to show weather information for your location. Please grant permissions to be able to use this app. + Get Started + \ No newline at end of file From 0661c025a3b40e2ce3fd71e483774e580f7e24c5 Mon Sep 17 00:00:00 2001 From: Daniel Waiguru Date: Sat, 6 Jan 2024 15:56:44 +0300 Subject: [PATCH 2/9] add LocationService to handle retrieval of user current location --- app/src/main/AndroidManifest.xml | 2 - data/build.gradle.kts | 1 + data/src/main/AndroidManifest.xml | 3 +- .../weatherapp/data/AndroidLocationService.kt | 101 ++++++++++++++++++ .../weatherapp/data/di/DataSourceModule.kt | 7 ++ .../weatherapp/data/mappers/WeatherMapper.kt | 6 +- .../repositories/WeatherRepositoryImpl.kt | 14 +-- .../domain/location/LocationService.kt | 9 ++ .../domain/models/5DayWeatherForecast.kt | 3 - .../{Coordinates.kt => UserLocation.kt} | 2 +- .../weatherapp/domain/models/Weather.kt | 2 +- .../domain/repositories/WeatherRepository.kt | 6 +- .../usecases/GetCurrentWeatherUseCase.kt | 22 +++- .../weatherapp/domain/utils/ResultWrapper.kt | 11 +- gradle/libs.versions.toml | 2 + .../presentation/weather/WeatherScreen.kt | 39 ++++++- .../weather/WeatherScreenState.kt | 9 ++ .../presentation/weather/WeatherViewModel.kt | 66 ++++++++++++ .../navigation/WeatherScreenDestination.kt | 3 +- .../src/main/res/drawable/location.png | Bin 4722 -> 0 bytes .../src/main/res/drawable/sea_cloudy.png | Bin 0 -> 25472 bytes .../src/main/res/drawable/sea_rainy.png | Bin 0 -> 35024 bytes .../src/main/res/drawable/sea_sunnypng.png | Bin 0 -> 24147 bytes 23 files changed, 276 insertions(+), 32 deletions(-) create mode 100644 data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt create mode 100644 domain/src/main/java/com/danielwaiguru/weatherapp/domain/location/LocationService.kt delete mode 100644 domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/5DayWeatherForecast.kt rename domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/{Coordinates.kt => UserLocation.kt} (80%) create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreenState.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt delete mode 100644 presentation/src/main/res/drawable/location.png create mode 100644 presentation/src/main/res/drawable/sea_cloudy.png create mode 100644 presentation/src/main/res/drawable/sea_rainy.png create mode 100644 presentation/src/main/res/drawable/sea_sunnypng.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index adc6354..f9177f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,8 +3,6 @@ xmlns:tools="http://schemas.android.com/tools"> - - - + + \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt new file mode 100644 index 0000000..b9a3e97 --- /dev/null +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt @@ -0,0 +1,101 @@ +package com.danielwaiguru.weatherapp.data + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.PackageManager +import android.location.LocationManager +import com.danielwaiguru.weatherapp.domain.location.LocationService +import com.danielwaiguru.weatherapp.domain.models.UserLocation +import com.danielwaiguru.weatherapp.domain.utils.ResultWrapper +import com.google.android.gms.location.LocationServices +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.suspendCancellableCoroutine +import timber.log.Timber +import kotlin.coroutines.resume + +internal class AndroidLocationService( + @ApplicationContext private val context: Context, +): LocationService { + private val locationManager by lazy { + context.getSystemService(Context.LOCATION_SERVICE) as LocationManager + } + private val fusedLocationProviderClient by lazy { + LocationServices.getFusedLocationProviderClient(context) + } + override val isGpsEnabled: Boolean + get() { + return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || + locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) + } + + @SuppressLint("MissingPermission") + override suspend fun getCurrentLocation(): ResultWrapper { + if (isGpsEnabled.not()) { + return ResultWrapper.Error( + errorMessage = "Failed to get location. Enable gps services" + ) + } + if (hasLocationPermission().not()) { + return ResultWrapper.Error( + errorMessage = "Failed to get location. Please grant location permission." + ) + } + return suspendCancellableCoroutine { continuation -> + fusedLocationProviderClient.lastLocation + .apply { + if (isComplete) { + if (isSuccessful) { + continuation.resume( + ResultWrapper.Success( + UserLocation( + latitude = result.latitude, + longitude = result.longitude + ) + ) + ) + } else { + continuation.resume( + ResultWrapper.Error( + errorMessage = exception?.message + ) + ) + } + return@suspendCancellableCoroutine + } + addOnSuccessListener { + continuation.resume( + ResultWrapper.Success( + if (it != null) { + UserLocation( + latitude = it.latitude, + longitude = it.longitude + ) + } else { + null + } + + ) + ) + } + addOnFailureListener { + Timber.i(it) + continuation.resume( + ResultWrapper.Error( + errorMessage = it.message + ) + ) + } + addOnCanceledListener { + continuation.cancel() + } + } + } + } + + private fun hasLocationPermission(): Boolean { + return context.checkSelfPermission( + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED + } +} \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/DataSourceModule.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/DataSourceModule.kt index 86b3fa8..4656d44 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/DataSourceModule.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/DataSourceModule.kt @@ -1,9 +1,11 @@ package com.danielwaiguru.weatherapp.data.di +import com.danielwaiguru.weatherapp.data.AndroidLocationService import com.danielwaiguru.weatherapp.data.sources.local.LocalDataSource import com.danielwaiguru.weatherapp.data.sources.local.RoomDataSource import com.danielwaiguru.weatherapp.data.sources.remote.RemoteDataSource import com.danielwaiguru.weatherapp.data.sources.remote.RetrofitDataSource +import com.danielwaiguru.weatherapp.domain.location.LocationService import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -22,4 +24,9 @@ internal abstract class DataSourceModule { internal abstract fun bindLocalDataSource( roomDataSource: RoomDataSource ): LocalDataSource + + @[Singleton Binds] + internal abstract fun bindLocationService( + androidLocationService: AndroidLocationService + ): LocationService } \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/mappers/WeatherMapper.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/mappers/WeatherMapper.kt index 52aab69..fdb1f00 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/mappers/WeatherMapper.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/mappers/WeatherMapper.kt @@ -6,11 +6,11 @@ import com.danielwaiguru.weatherapp.data.models.entities.ForecastEntity import com.danielwaiguru.weatherapp.data.models.entities.WeatherEntity import com.danielwaiguru.weatherapp.data.models.responses.ForecastResponse import com.danielwaiguru.weatherapp.data.models.responses.WeatherDto -import com.danielwaiguru.weatherapp.domain.models.Coordinates +import com.danielwaiguru.weatherapp.domain.models.UserLocation import com.danielwaiguru.weatherapp.domain.models.Weather import com.danielwaiguru.weatherapp.domain.models.WeatherForecast -fun CoordinatesEntity.toCoordinates(): Coordinates = Coordinates( +fun CoordinatesEntity.toCoordinates(): UserLocation = UserLocation( latitude = latitude, longitude = longitude ) @@ -24,7 +24,7 @@ fun WeatherEntity.toWeather(): Weather = Weather( description = description, icon = icon, id = id, - coordinates = coordinates.toCoordinates(), + userLocation = coordinates.toCoordinates(), city = city, country = country, temp = temp, diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt index d5665b2..527e142 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt @@ -8,7 +8,7 @@ import com.danielwaiguru.weatherapp.data.models.entities.ForecastEntity import com.danielwaiguru.weatherapp.data.sources.local.LocalDataSource import com.danielwaiguru.weatherapp.data.sources.remote.RemoteDataSource import com.danielwaiguru.weatherapp.data.utils.networkBoundResource -import com.danielwaiguru.weatherapp.domain.models.Coordinates +import com.danielwaiguru.weatherapp.domain.models.UserLocation import com.danielwaiguru.weatherapp.domain.models.Weather import com.danielwaiguru.weatherapp.domain.models.WeatherForecast import com.danielwaiguru.weatherapp.domain.repositories.WeatherRepository @@ -28,7 +28,7 @@ internal class WeatherRepositoryImpl( @Dispatcher(DispatcherProvider.IO) private val ioDispatcher: CoroutineDispatcher ): WeatherRepository { override suspend fun getCurrentWeather( - coordinates: Coordinates + userLocation: UserLocation ): Flow> = networkBoundResource( query = { localDataSource.getCurrentWeather() @@ -36,8 +36,8 @@ internal class WeatherRepositoryImpl( }, fetch = { remoteDataSource.getCurrentWeather( - longitude = coordinates.longitude, - latitude = coordinates.latitude + longitude = userLocation.longitude, + latitude = userLocation.latitude ) }, saveFetchResult = { weatherResponse -> @@ -49,7 +49,7 @@ internal class WeatherRepositoryImpl( ).flowOn(ioDispatcher) override suspend fun getWeatherForecast( - coordinates: Coordinates + userLocation: UserLocation ): Flow>> = networkBoundResource( query = { localDataSource.getWeatherForecast() @@ -58,8 +58,8 @@ internal class WeatherRepositoryImpl( }, fetch = { remoteDataSource.getWeatherForecast( - latitude = coordinates.latitude, - longitude = coordinates.longitude + latitude = userLocation.latitude, + longitude = userLocation.longitude ) }, saveFetchResult = { forecastResponse -> diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/location/LocationService.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/location/LocationService.kt new file mode 100644 index 0000000..66b263f --- /dev/null +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/location/LocationService.kt @@ -0,0 +1,9 @@ +package com.danielwaiguru.weatherapp.domain.location + +import com.danielwaiguru.weatherapp.domain.models.UserLocation +import com.danielwaiguru.weatherapp.domain.utils.ResultWrapper + +interface LocationService { + suspend fun getCurrentLocation(): ResultWrapper + val isGpsEnabled: Boolean +} \ No newline at end of file diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/5DayWeatherForecast.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/5DayWeatherForecast.kt deleted file mode 100644 index 06e774c..0000000 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/5DayWeatherForecast.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.danielwaiguru.weatherapp.domain.models - -typealias FiveDayWeatherForecast = List \ No newline at end of file diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Coordinates.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/UserLocation.kt similarity index 80% rename from domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Coordinates.kt rename to domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/UserLocation.kt index a68c373..c8fdf23 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Coordinates.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/UserLocation.kt @@ -1,6 +1,6 @@ package com.danielwaiguru.weatherapp.domain.models -data class Coordinates( +data class UserLocation( val latitude: Double, val longitude: Double ) diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Weather.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Weather.kt index e0d05e6..548cfb1 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Weather.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/Weather.kt @@ -4,7 +4,7 @@ data class Weather( val description: String, val icon: String, val id: Int, - val coordinates: Coordinates, + val userLocation: UserLocation, val city: String, val country: String, val temp: Double, diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/repositories/WeatherRepository.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/repositories/WeatherRepository.kt index ac49b5e..43b7920 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/repositories/WeatherRepository.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/repositories/WeatherRepository.kt @@ -1,6 +1,6 @@ package com.danielwaiguru.weatherapp.domain.repositories -import com.danielwaiguru.weatherapp.domain.models.Coordinates +import com.danielwaiguru.weatherapp.domain.models.UserLocation import com.danielwaiguru.weatherapp.domain.models.Weather import com.danielwaiguru.weatherapp.domain.models.WeatherForecast import com.danielwaiguru.weatherapp.domain.utils.ResultWrapper @@ -8,10 +8,10 @@ import kotlinx.coroutines.flow.Flow interface WeatherRepository { suspend fun getCurrentWeather( - coordinates: Coordinates + userLocation: UserLocation ): Flow> suspend fun getWeatherForecast( - coordinates: Coordinates + userLocation: UserLocation ): Flow>> } \ No newline at end of file diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt index 8210446..f4bac5b 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt @@ -1,12 +1,26 @@ package com.danielwaiguru.weatherapp.domain.usecases -import com.danielwaiguru.weatherapp.domain.models.Coordinates +import com.danielwaiguru.weatherapp.domain.location.LocationService import com.danielwaiguru.weatherapp.domain.models.Weather import com.danielwaiguru.weatherapp.domain.repositories.WeatherRepository import com.danielwaiguru.weatherapp.domain.utils.ResultWrapper import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf -class GetCurrentWeatherUseCase(private val weatherRepository: WeatherRepository) { - suspend operator fun invoke(coordinates: Coordinates): Flow> = - weatherRepository.getCurrentWeather(coordinates) +class GetCurrentWeatherUseCase( + private val weatherRepository: WeatherRepository, + private val locationService: LocationService +) { + suspend operator fun invoke(): Flow> { + val userLocation = locationService.getCurrentLocation() + return if (userLocation is ResultWrapper.Success && userLocation.value != null) { + weatherRepository.getCurrentWeather(userLocation.value) + } else { + flowOf( + ResultWrapper.Error( + errorMessage = (userLocation as ResultWrapper.Error).errorMessage + ) + ) + } + } } \ No newline at end of file diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt index 4e35953..9260780 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt @@ -3,12 +3,13 @@ package com.danielwaiguru.weatherapp.domain.utils import com.squareup.moshi.Json sealed class ResultWrapper { - data class Success(val value: T) : ResultWrapper() - data class Error( - val errorMessage: String? - ) : ResultWrapper() + data class Success(val data: T) : ResultWrapper() + data class Error( + val errorMessage: String?, + val data: T? = null + ) : ResultWrapper() - data class Loading(val value: T? = null) : ResultWrapper() + data class Loading(val data: T? = null) : ResultWrapper() } data class ErrorResponse( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 433e946..6888d42 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,6 +42,7 @@ room = "2.6.1" targetSdk = "34" compileSdk = "34" minSdk = "24" +playServicesLocation = "21.0.1" [libraries] core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } @@ -116,6 +117,7 @@ robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectr android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } +play-services-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "playServicesLocation" } [plugins] com-android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt index fe4e571..3e59482 100644 --- a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreen.kt @@ -1,4 +1,41 @@ package com.danielwaiguru.weatherapp.presentation.weather -class WeatherScreen { +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.danielwaiguru.weatherapp.domain.models.Weather + +@Composable +fun WeatherRoute( + viewModel: WeatherViewModel = hiltViewModel() +) { + val uiState by viewModel.currentWeatherUIState.collectAsStateWithLifecycle() + WeatherScreen( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + state = uiState + ) +} + +@Composable +fun WeatherScreen( + modifier: Modifier = Modifier, + state: WeatherScreenState +) { + +} + + +@Composable +fun CurrentWeatherComponent( + modifier: Modifier = Modifier, + weather: Weather? +) { + } \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreenState.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreenState.kt new file mode 100644 index 0000000..1568479 --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherScreenState.kt @@ -0,0 +1,9 @@ +package com.danielwaiguru.weatherapp.presentation.weather + +import com.danielwaiguru.weatherapp.domain.models.Weather + +data class WeatherScreenState( + val isLoading: Boolean = false, + val currentWeather: Weather? = null, + val errorMessage: String? = null +) diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt new file mode 100644 index 0000000..8ca30a8 --- /dev/null +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt @@ -0,0 +1,66 @@ +package com.danielwaiguru.weatherapp.presentation.weather + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.danielwaiguru.weatherapp.domain.usecases.GetCurrentWeatherUseCase +import com.danielwaiguru.weatherapp.domain.utils.ResultWrapper +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class WeatherViewModel @Inject constructor( + private val getCurrentWeatherUseCase: GetCurrentWeatherUseCase +): ViewModel() { + private val _currentWeatherUIState = MutableStateFlow(WeatherScreenState()) + val currentWeatherUIState: StateFlow = _currentWeatherUIState.asStateFlow() + + init { + getCurrentWeather() + } + + private fun getCurrentWeather() { + viewModelScope.launch { + _currentWeatherUIState.update { currentState -> + currentState.copy( + isLoading = true, + errorMessage = null + ) + } + + getCurrentWeatherUseCase() + .onEach { result -> + when(result) { + is ResultWrapper.Error -> _currentWeatherUIState.update { currentState -> + currentState.copy( + isLoading = false, + errorMessage = result.errorMessage, + currentWeather = result.data + ) + } + is ResultWrapper.Loading -> _currentWeatherUIState.update { currentState -> + currentState.copy( + isLoading = result.data != null, + errorMessage = null, + currentWeather = result.data + ) + } + is ResultWrapper.Success -> _currentWeatherUIState.update { currentState -> + currentState.copy( + isLoading = false, + errorMessage = null, + currentWeather = result.data + ) + } + } + + }.launchIn(this) + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt index 9b3ef7a..c9720c9 100644 --- a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/navigation/WeatherScreenDestination.kt @@ -3,6 +3,7 @@ package com.danielwaiguru.weatherapp.presentation.weather.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import com.danielwaiguru.weatherapp.presentation.navigation.AppNavigationDestination +import com.danielwaiguru.weatherapp.presentation.weather.WeatherRoute object WeatherScreenDestination: AppNavigationDestination { @@ -14,6 +15,6 @@ object WeatherScreenDestination: AppNavigationDestination { fun NavGraphBuilder.weatherScreen() { composable(route = WeatherScreenDestination.route) { - + WeatherRoute() } } \ No newline at end of file diff --git a/presentation/src/main/res/drawable/location.png b/presentation/src/main/res/drawable/location.png deleted file mode 100644 index afbad4451d9e6f34bb065a54ec6ce996095fbcf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4722 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 A4FCWD diff --git a/presentation/src/main/res/drawable/sea_cloudy.png b/presentation/src/main/res/drawable/sea_cloudy.png new file mode 100644 index 0000000000000000000000000000000000000000..85c66544a8ca0dcd1659f2e015f1cb16de8a1415 GIT binary patch literal 25472 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 a(EkUrnHVP0C8QMq0000_-X}8TL*J*-jGd z*DEh=1sS;Naf*F7I4L-#x6-=)ua4WCJ~=D+Fp*@Z>-o5?-l`bjELjjr1(U|6GmFjuJ#zEj=zJUqm44r$NL* z2LDWumie$mqXJ(N^!4%Ex6wd@x#0D+I`G?_u~t2!fD0`>v6Jrv9(30EF_*b*9rb+b zUxd>~fWD6Oh>%kf*1=6#U15l2PDjGu=uIdTc=N5n#_0j_|4ta0k^s9Vj3fnLz6a+F-^IGI2=*GpMLj*C0_ zGWd$W7fJbtIBH$T1NX%QYB$~aL*e?T6SK-$g7gjo!ebnREy*8w<8F^H^0+&NS?o8vB*{jTPvJGw}s#^p|Tf1e~g#w_eRI&ty3G3@KM&`-u)J`i}Yq^o^YBm=(G2qnRtKm*pgtjO*e+XKV#*M5<0uuq1w!XeI6H&O56(5fuRJVT5Kxr>Q87!bMz zer&92w%VS5PEXm!Ro3y}7%3rHB176v0-+&=gTtIz$fRE|%o79BbdjEd@ zpLD3C1Hr6$kSeaYncCpl9=uRvRxPl<{MAhWd?C#>3@H;iFPV#Y#n| zY88JWmy?kl^aano8HU-Uvx?hR_`VrxdsFBi!_o4D$~jJLusiWNu$70~ll`CB}HcvhIhQ(r}bQq2B2nKF1{Q6slNtr2;|ip|=C$NsxG=rK2JgpE~1 zKbLzyg7Q-I&+(_-i(I_D2)(k_@#!QWbCu|}Na+9l2FF8YlyCzlNhAtg-NFab8O)VT z?}YEt8DIH_P1nwg^O~WPyhUT&Nxri5bdp2%7yRfep|7dusafRz2Kq1HW9npya|FyX zW!MZHa1+6)6`D#~f$tg*Vrx_WbE3@{syl*uVRf?OZ&qCy#$gmyjAaY&xSZA<#?%9R zBW`}&gk<_bME4^OL3EQzYLD&96G=_f*9B@DI$!D<81`S)OG+h=bvcV$^h=kbfg zzkHRPnrf!NQSBdDoxLw7Uw{E3dAQ5vhEo?JURzHoM5H5drg33&C zVBnn3&f{swg-PT0OT;6i@9Tqzp zRytGVj;yYLacYT+vZ}rmRHO)}I7UD3%SL<H04DVb1OG-8!KN2|<)yJuor{iK%c6K0dKq^?BriP^X zRqN=kkCJxm6Wg&L!cOlh%(Gm%?H$)AE=$6|%-qe;W~e60*_0tJy7tbqF}ra$-CW#9 zKk29&QBDiX>7+z3aXQNXyrPTHnp8Ko@~kF7IxW1ys{v9U?7^^L(n1F6SE$Ci)0Z;%FjBbsObe5ziGL#0uv4QJ^u=a`p=cpydDVZZ%`|3Vo+uOVWzjRjB16ow`PIQ}e%sJD_ z#9$%v|C2w9)|k*rrzH(dV7|%4`}ukyG(o4$lu5%R1h2pU#>`yG7b3d%1r}HqC2_sP zL0Sh8JSJ~)~i|!FUJT|hJ5Fok*#-`%<7QrfxmZXm~h>&?_VJR-b5=d z%nStVN%&p5>elKZFzY7M4Ofo0zR12C|q~G;3@!G z#iWkZbfGE385z=;%BQRog3I^(^(Ag!pspNYoZ1(N{2C9m_nWDGg$`(4$8hi(Crp+{ zelpxKk0LY2Fyo*e-;Sk|x73C*lUNgxU;xLk8Csq=sry!-*5^@coLl@0Kopkg?_yr< zm%=5YN1S&PMe=e-e*F5j*G%%`-rdwBBKCiQ8+uQGm?%4WNyvqg(U(QL-N#$$K)Cp0 z*5@9ct*7^#joahtT^&IaHCZ&ot*h^zxu@hW4*P-z0=%dQZLw*W4g5BKU!eRjJj+Ml zfPZljEiUy-YLrI2>+OnAUNWSrdRt}mfKy`@6F|916N4w*U2jFBBqyC)q1c~rP8XGb;M!FK;?g^}ZooIPa+9=$Uw}^Vs=p;-r+cvy;-0s_b%B_S zUI(9k)Z_bB>jFQzIS^&dyS-S`&^JCY$bH$`y=29IV5;<<`s^5u^V?+`tkNlN=U z?AR6D|2-P!z>%~|&oPRyFpz=DWmn_gk)02Vp(~CQLT$6NkH@cpDxNVD^luv!)OwH0 z{$lOoY)^&W=>W(ojTwc!wCfUuz#{5&u3=;E*=P7E+;{~RVd(^=yYKIv7VU@dLyd;S zy@j`{?vJ#Y!a(Opz&5Rwbi1{F%7;ST6-J((HAm<7ZmB9AM*i94nN2yFUtFVX7v_onU_lA#qX&BTnAK)js=n&Ze;BIV zqt!|5Mc}rVcSe_!RR4G{Kd9Beu(BO*LDJiMt`qM4q%=qWq50`;^!U9j<*&h-W5}C& z;c`*!4_VjjF6m0Vs!mcAX`62cDAPP(JL=ta&5Vur3pTrR8laAfKfjC&oEpSO$3#E! zQKY)pSXa2vl87Y*#_b$L5&pb9D6NYo0l)PTq|OZ5OL9fZTm6AVA$qe%YHWt*UB%=N zp3j`T0kl_|n?@toS~40!prRkM37OnGzg`lttd0BQtFK}}DS|V#v%zs1Rj5r&UR{Zu zfgn4aBkk|*x= zl(_YM@2&e2!1H48)qrY1E2*o{5#m!yU+U;3Pw7uXjW0c~kr0h|u^>+7Cu+pkeIw%$ zKT1Xvwml)`T-5-3a-vGYmZxJo=tq<%{yo`h{9```w))@`J{O)pg9qF$*ID+pydy#) z@t2~iCK9Ejrsf{prkFzUUI|%016j9WE?>@+WuCQWII7(f^R9A$KRn&2eaPs`yw%bH z&)DCKxbO|@W}`1Qy$yeK-Xuty$PqafCYF}|*xENTi%0AD`j6@r8nrwn6JVn3MO-Sd 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

nmdB_w!e$vo9$~rW-A~`jkqK%`~0DXj3 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 literal 0 HcmV?d00001 From 0d86b82ba9fb3c3e949153da22c5f84195688cf0 Mon Sep 17 00:00:00 2001 From: Daniel Waiguru Date: Sat, 6 Jan 2024 16:13:47 +0300 Subject: [PATCH 3/9] add AppIdInterceptor to add appid to requests --- .../weatherapp/data/AndroidLocationService.kt | 3 ++- .../weatherapp/data/di/NetworkingModule.kt | 2 ++ .../weatherapp/data/di/UseCasesModule.kt | 6 ++++-- .../data/repositories/WeatherRepositoryImpl.kt | 3 ++- .../remote/interceptors/AppIdInterceptor.kt | 16 ++++++++++++++++ .../data/sources/remote/utils/ApiEndpoints.kt | 6 +++--- .../data/utils/NetworkBoundResource.kt | 4 ++-- .../domain/usecases/GetCurrentWeatherUseCase.kt | 4 ++-- .../weatherapp/domain/utils/ResultWrapper.kt | 9 ++++----- .../presentation/weather/WeatherViewModel.kt | 6 ++---- 10 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/interceptors/AppIdInterceptor.kt diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt index b9a3e97..9695be4 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/AndroidLocationService.kt @@ -12,9 +12,10 @@ import com.google.android.gms.location.LocationServices import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.suspendCancellableCoroutine import timber.log.Timber +import javax.inject.Inject import kotlin.coroutines.resume -internal class AndroidLocationService( +internal class AndroidLocationService @Inject constructor( @ApplicationContext private val context: Context, ): LocationService { private val locationManager by lazy { diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/NetworkingModule.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/NetworkingModule.kt index d787ce5..b9b3978 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/NetworkingModule.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/NetworkingModule.kt @@ -5,6 +5,7 @@ import com.chuckerteam.chucker.api.ChuckerCollector import com.chuckerteam.chucker.api.ChuckerInterceptor import com.danielwaiguru.weatherapp.data.BuildConfig import com.danielwaiguru.weatherapp.data.sources.remote.api.WeatherAppApiService +import com.danielwaiguru.weatherapp.data.sources.remote.interceptors.AppIdInterceptor import com.danielwaiguru.weatherapp.data.sources.remote.interceptors.HeadersInterceptor import com.danielwaiguru.weatherapp.data.sources.remote.utils.ApiEndpoints.BASE_URL import dagger.Module @@ -45,6 +46,7 @@ internal object NetworkingModule { return OkHttpClient.Builder() .readTimeout(REQUEST_TIMEOUT_S, TimeUnit.SECONDS) .connectTimeout(REQUEST_TIMEOUT_S, TimeUnit.SECONDS) + .addInterceptor(AppIdInterceptor()) .addInterceptor(HeadersInterceptor()) .addInterceptor(logging) .addInterceptor(chuckerInterceptor) diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/UseCasesModule.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/UseCasesModule.kt index 9ab72ac..ec1957a 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/di/UseCasesModule.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/di/UseCasesModule.kt @@ -1,5 +1,6 @@ package com.danielwaiguru.weatherapp.data.di +import com.danielwaiguru.weatherapp.domain.location.LocationService import com.danielwaiguru.weatherapp.domain.repositories.WeatherRepository import com.danielwaiguru.weatherapp.domain.usecases.GetCurrentWeatherUseCase import dagger.Module @@ -13,6 +14,7 @@ import dagger.hilt.android.scopes.ViewModelScoped object UseCasesModule { @[Provides ViewModelScoped] fun provideGetCurrentWeatherUseCase( - weatherRepository: WeatherRepository - ): GetCurrentWeatherUseCase = GetCurrentWeatherUseCase(weatherRepository) + weatherRepository: WeatherRepository, + locationService: LocationService + ): GetCurrentWeatherUseCase = GetCurrentWeatherUseCase(weatherRepository, locationService) } \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt index 527e142..005a596 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/repositories/WeatherRepositoryImpl.kt @@ -21,8 +21,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext +import javax.inject.Inject -internal class WeatherRepositoryImpl( +internal class WeatherRepositoryImpl @Inject constructor( private val remoteDataSource: RemoteDataSource, private val localDataSource: LocalDataSource, @Dispatcher(DispatcherProvider.IO) private val ioDispatcher: CoroutineDispatcher diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/interceptors/AppIdInterceptor.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/interceptors/AppIdInterceptor.kt new file mode 100644 index 0000000..1fffe6d --- /dev/null +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/interceptors/AppIdInterceptor.kt @@ -0,0 +1,16 @@ +package com.danielwaiguru.weatherapp.data.sources.remote.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +class AppIdInterceptor: Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val url = request.url.newBuilder() + .addQueryParameter("appid", "bb90efd61c3112b077246f518207d544") + .build() + return chain.proceed( + request.newBuilder().url(url).build() + ) + } +} \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/utils/ApiEndpoints.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/utils/ApiEndpoints.kt index 6c033f3..6d2ce6d 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/utils/ApiEndpoints.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/sources/remote/utils/ApiEndpoints.kt @@ -1,7 +1,7 @@ package com.danielwaiguru.weatherapp.data.sources.remote.utils object ApiEndpoints { - const val CURRENT_WEATHER_ENDPOINT = "current" - const val WEATHER_FORECAST_ENDPOINT ="forecast5" - const val BASE_URL = "https://openweathermap.org/" + const val CURRENT_WEATHER_ENDPOINT = "weather" + const val WEATHER_FORECAST_ENDPOINT = "forecast" + const val BASE_URL = "https://api.openweathermap.org/data/2.5/" } \ No newline at end of file diff --git a/data/src/main/java/com/danielwaiguru/weatherapp/data/utils/NetworkBoundResource.kt b/data/src/main/java/com/danielwaiguru/weatherapp/data/utils/NetworkBoundResource.kt index 1c2aeb0..eb6d94f 100644 --- a/data/src/main/java/com/danielwaiguru/weatherapp/data/utils/NetworkBoundResource.kt +++ b/data/src/main/java/com/danielwaiguru/weatherapp/data/utils/NetworkBoundResource.kt @@ -17,7 +17,7 @@ inline fun networkBoundResource( if (shouldFetch(data)) { val loading = launch { - query().collect { send(ResultWrapper.Loading(it)) } + query().collect { send(ResultWrapper.Loading) } } try { @@ -27,7 +27,7 @@ inline fun networkBoundResource( query().collect { send(ResultWrapper.Success(it)) } } catch (t: Throwable) { loading.cancel() - query().collect { send(ResultWrapper.Error(t.message)) } + query().collect { send(ResultWrapper.Error(errorMessage = t.message)) } } } else { query().collect { send(ResultWrapper.Success(it)) } diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt index f4bac5b..4d07288 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetCurrentWeatherUseCase.kt @@ -13,8 +13,8 @@ class GetCurrentWeatherUseCase( ) { suspend operator fun invoke(): Flow> { val userLocation = locationService.getCurrentLocation() - return if (userLocation is ResultWrapper.Success && userLocation.value != null) { - weatherRepository.getCurrentWeather(userLocation.value) + return if (userLocation is ResultWrapper.Success && userLocation.data != null) { + weatherRepository.getCurrentWeather(userLocation.data) } else { flowOf( ResultWrapper.Error( diff --git a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt index 9260780..e8b6793 100644 --- a/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt +++ b/domain/src/main/java/com/danielwaiguru/weatherapp/domain/utils/ResultWrapper.kt @@ -4,12 +4,11 @@ import com.squareup.moshi.Json sealed class ResultWrapper { data class Success(val data: T) : ResultWrapper() - data class Error( - val errorMessage: String?, - val data: T? = null - ) : ResultWrapper() + data class Error( + val errorMessage: String? + ) : ResultWrapper() - data class Loading(val data: T? = null) : ResultWrapper() + data object Loading : ResultWrapper() } data class ErrorResponse( diff --git a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt index 8ca30a8..0def4e8 100644 --- a/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt +++ b/presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/weather/WeatherViewModel.kt @@ -41,14 +41,12 @@ class WeatherViewModel @Inject constructor( currentState.copy( isLoading = false, errorMessage = result.errorMessage, - currentWeather = result.data ) } is ResultWrapper.Loading -> _currentWeatherUIState.update { currentState -> currentState.copy( - isLoading = result.data != null, - errorMessage = null, - currentWeather = result.data + isLoading = true, + errorMessage = null ) } is ResultWrapper.Success -> _currentWeatherUIState.update { currentState -> From 3de34d56de5ced7016a8be55d5fd85df2dfcbb33 Mon Sep 17 00:00:00 2001 From: Daniel Waiguru Date: Mon, 8 Jan 2024 08:16:21 +0300 Subject: [PATCH 4/9] fetch and display current and 5 day weather forecast data --- .idea/gradle.xml | 2 + .idea/misc.xml | 1 - app/build.gradle.kts | 2 + .../java/AndroidLibraryConventionPlugin.kt | 1 + .../weatherapp/convention/KotlinAndroid.kt | 1 + .../1.json | 20 +- .../weatherapp/data/di/UseCasesModule.kt | 10 +- .../weatherapp/data/mappers/WeatherMapper.kt | 13 +- .../data/models/entities/ForecastEntity.kt | 1 + .../data/models/entities/WeatherEntity.kt | 14 +- .../repositories/WeatherRepositoryImpl.kt | 2 +- .../designsystem/components/Loader.kt | 24 ++ .../weatherapp/designsystem/theme/Color.kt | 6 +- .../weatherapp/designsystem/theme/Theme.kt | 5 +- .../weatherapp/designsystem/theme/Type.kt | 79 +---- .../designsystem/utils/SpDimensions.kt | 5 +- .../models/CurrentWeatherWithForecast.kt | 6 + .../weatherapp/domain/models/Weather.kt | 1 + .../domain/models/WeatherForecast.kt | 2 + .../usecases/GetCurrentWeatherUseCase.kt | 19 +- .../usecases/GetWeatherForecastUseCase.kt | 15 + gradle/libs.versions.toml | 4 + .../presentation/models/WeatherCondition.kt | 35 +++ .../presentation/utils/DateUtils.kt | 28 ++ .../presentation/utils/PresentationExt.kt | 23 ++ .../presentation/weather/WeatherScreen.kt | 287 +++++++++++++++++- .../weather/WeatherScreenState.kt | 11 +- .../presentation/weather/WeatherViewModel.kt | 84 ++++- .../src/main/res/drawable-mdpi/clear.png | Bin 0 -> 348 bytes .../main/res/drawable-mdpi/partlysunny.png | Bin 0 -> 365 bytes .../src/main/res/drawable-mdpi/rain.png | Bin 0 -> 366 bytes .../src/main/res/drawable-xhdpi/clear.png | Bin 0 -> 684 bytes .../main/res/drawable-xhdpi/partlysunny.png | Bin 0 -> 653 bytes .../src/main/res/drawable-xhdpi/rain.png | Bin 0 -> 730 bytes .../src/main/res/drawable-xxhdpi/clear.png | Bin 0 -> 1060 bytes .../main/res/drawable-xxhdpi/partlysunny.png | Bin 0 -> 1082 bytes .../src/main/res/drawable-xxhdpi/rain.png | Bin 0 -> 1239 bytes presentation/src/main/res/values/strings.xml | 6 + 38 files changed, 581 insertions(+), 126 deletions(-) create mode 100644 designsystem/src/main/java/com/danielwaiguru/weatherapp/designsystem/components/Loader.kt create mode 100644 domain/src/main/java/com/danielwaiguru/weatherapp/domain/models/CurrentWeatherWithForecast.kt create mode 100644 domain/src/main/java/com/danielwaiguru/weatherapp/domain/usecases/GetWeatherForecastUseCase.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/models/WeatherCondition.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/utils/DateUtils.kt create mode 100644 presentation/src/main/java/com/danielwaiguru/weatherapp/presentation/utils/PresentationExt.kt create mode 100644 presentation/src/main/res/drawable-mdpi/clear.png create mode 100644 presentation/src/main/res/drawable-mdpi/partlysunny.png create mode 100644 presentation/src/main/res/drawable-mdpi/rain.png create mode 100644 presentation/src/main/res/drawable-xhdpi/clear.png create mode 100644 presentation/src/main/res/drawable-xhdpi/partlysunny.png create mode 100644 presentation/src/main/res/drawable-xhdpi/rain.png create mode 100644 presentation/src/main/res/drawable-xxhdpi/clear.png create mode 100644 presentation/src/main/res/drawable-xxhdpi/partlysunny.png create mode 100644 presentation/src/main/res/drawable-xxhdpi/rain.png diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 2cd4d77..61a3d27 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,5 +1,6 @@ +