Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrated to material 3 with added temperature graph #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 6 additions & 9 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}

android {
compileSdk 32

defaultConfig {
applicationId "com.plcoding.weatherapp"
minSdk 21
minSdk 26
targetSdk 32
versionCode 1
versionName "1.0"
Expand Down Expand Up @@ -62,13 +60,12 @@ dependencies {
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'androidx.compose.material3:material3:1.0.0-alpha01'

//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.40.5"
kapt "com.google.dagger:hilt-android-compiler:2.40.5"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
kapt "androidx.hilt:hilt-compiler:1.0.0"
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
// Koin
implementation "io.insert-koin:koin-android:3.2.0-beta-1"
implementation "io.insert-koin:koin-androidx-navigation:3.2.0-beta-1"
implementation "io.insert-koin:koin-androidx-compose:3.2.0-beta-1"

// Location Services
implementation 'com.google.android.gms:play-services-location:20.0.0'
Expand Down
15 changes: 12 additions & 3 deletions app/src/main/java/com/plcoding/weatherapp/WeatherApp.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package com.plcoding.weatherapp

import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import com.plcoding.weatherapp.di.appModule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin

@HiltAndroidApp
class WeatherApp: Application()
class WeatherApp: Application(){
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@WeatherApp)
modules(appModule)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import com.google.android.gms.location.FusedLocationProviderClient
import com.plcoding.weatherapp.domain.location.LocationTracker
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.suspendCancellableCoroutine
import javax.inject.Inject
import kotlin.coroutines.resume

@ExperimentalCoroutinesApi
class DefaultLocationTracker @Inject constructor(
class DefaultLocationTracker (
private val locationClient: FusedLocationProviderClient,
private val application: Application
): LocationTracker {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.plcoding.weatherapp.data.remote

import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query

Expand All @@ -10,4 +12,15 @@ interface WeatherApi {
@Query("latitude") lat: Double,
@Query("longitude") long: Double
): WeatherDto

companion object{
private const val BASE_URL = "https://api.open-meteo.com/"
fun create() : WeatherApi{
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create(WeatherApi::class.java)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import com.plcoding.weatherapp.data.remote.WeatherApi
import com.plcoding.weatherapp.domain.repository.WeatherRepository
import com.plcoding.weatherapp.domain.util.Resource
import com.plcoding.weatherapp.domain.weather.WeatherInfo
import javax.inject.Inject

class WeatherRepositoryImpl @Inject constructor(
class WeatherRepositoryImpl (
private val api: WeatherApi
): WeatherRepository {

Expand Down
50 changes: 26 additions & 24 deletions app/src/main/java/com/plcoding/weatherapp/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
package com.plcoding.weatherapp.di

import android.app.Application
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.plcoding.weatherapp.data.location.DefaultLocationTracker
import com.plcoding.weatherapp.data.remote.WeatherApi
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.create
import javax.inject.Singleton
import com.plcoding.weatherapp.data.repository.WeatherRepositoryImpl
import com.plcoding.weatherapp.domain.location.LocationTracker
import com.plcoding.weatherapp.domain.repository.WeatherRepository
import com.plcoding.weatherapp.presentation.WeatherViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.koin.android.ext.koin.androidApplication
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@OptIn(ExperimentalCoroutinesApi::class)
val appModule = module {
single<WeatherApi> {
WeatherApi.create()
}

single<FusedLocationProviderClient> {
LocationServices.getFusedLocationProviderClient(androidContext())
}

@Provides
@Singleton
fun provideWeatherApi(): WeatherApi {
return Retrofit.Builder()
.baseUrl("https://api.open-meteo.com/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create()
single<LocationTracker> {
DefaultLocationTracker(get(), androidApplication())
}

@Provides
@Singleton
fun provideFusedLocationProviderClient(app: Application): FusedLocationProviderClient {
return LocationServices.getFusedLocationProviderClient(app)
single<WeatherRepository> {
WeatherRepositoryImpl(get())
}
viewModel {
WeatherViewModel(get(), get())
}
}
20 changes: 0 additions & 20 deletions app/src/main/java/com/plcoding/weatherapp/di/LocationModule.kt

This file was deleted.

24 changes: 0 additions & 24 deletions app/src/main/java/com/plcoding/weatherapp/di/RepositoryModule.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.width
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
Expand All @@ -20,7 +21,7 @@ import java.time.format.DateTimeFormatter
fun HourlyWeatherDisplay(
weatherData: WeatherData,
modifier: Modifier = Modifier,
textColor: Color = Color.White
textColor: Color = MaterialTheme.colorScheme.onBackground
) {
val formattedTime = remember(weatherData) {
weatherData.time.format(
Expand All @@ -34,7 +35,7 @@ fun HourlyWeatherDisplay(
) {
Text(
text = formattedTime,
color = Color.LightGray
color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.86f)
)
Image(
painter = painterResource(id = weatherData.weatherType.iconRes),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,28 @@ package com.plcoding.weatherapp.presentation

import android.Manifest
import android.os.Bundle
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.ProgressBar
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.plcoding.weatherapp.presentation.ui.theme.DarkBlue
import com.plcoding.weatherapp.presentation.ui.theme.DeepBlue
import androidx.compose.ui.viewinterop.AndroidView
import com.plcoding.weatherapp.presentation.ui.theme.WeatherAppTheme
import dagger.hilt.android.AndroidEntryPoint
import org.koin.androidx.viewmodel.ext.android.viewModel

@AndroidEntryPoint
class MainActivity : ComponentActivity() {

private val viewModel: WeatherViewModel by viewModels()
private val viewModel by viewModel<WeatherViewModel>()
private lateinit var permissionLauncher: ActivityResultLauncher<Array<String>>

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -34,39 +33,61 @@ class MainActivity : ComponentActivity() {
) {
viewModel.loadWeatherInfo()
}
permissionLauncher.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
))
permissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
)
)
setContent {
WeatherAppTheme {
Box(
modifier = Modifier.fillMaxSize()
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.primaryContainer
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(DarkBlue)
Box(
modifier = Modifier.fillMaxSize()
) {
WeatherCard(
state = viewModel.state,
backgroundColor = DeepBlue
)
Spacer(modifier = Modifier.height(16.dp))
WeatherForecast(state = viewModel.state)
}
if(viewModel.state.isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center)
)
}
viewModel.state.error?.let { error ->
Text(
text = error,
color = Color.Red,
textAlign = TextAlign.Center,
modifier = Modifier.align(Alignment.Center)
)
Column(
modifier = Modifier
.fillMaxSize()
) {
WeatherCard(
state = viewModel.state,
backgroundColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.25f),
modifier = Modifier.padding(16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
WeatherForecast(
state = viewModel.state,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
)
}
if (viewModel.state.isLoading) {
AndroidView(
factory = { c ->
val progressBar = ProgressBar(c).apply {
layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
progressBar
},
modifier = Modifier
.align(Alignment.Center)
)
}
viewModel.state.error?.let { error ->
Text(
text = error,
color = MaterialTheme.colorScheme.onError,
textAlign = TextAlign.Center,
modifier = Modifier.align(Alignment.Center)
)
}
}
}
}
Expand Down
Loading