diff --git a/.idea/misc.xml b/.idea/misc.xml index 2a4d5b5..8df56a3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,16 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index eb6b307..efe4032 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,12 +6,12 @@ plugins { } android { - compileSdk 31 + compileSdk 32 defaultConfig { applicationId "ru.itis.karakurik.androidLab2" minSdk 23 - targetSdk 31 + targetSdk 32 versionCode 1 versionName "1.0" @@ -19,7 +19,7 @@ android { } buildFeatures { - viewBinding true + viewBinding = true } buildTypes { @@ -46,10 +46,18 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1" + + //Timber + implementation 'com.jakewharton.timber:timber:5.0.1' + + //Coil + implementation "io.coil-kt:coil:1.1.1" def nav_version = "2.4.1" - implementation "androidx.navigation:navigation-fragment:$nav_version" - implementation "androidx.navigation:navigation-ui:$nav_version" + implementation "androidx.navigation:navigation-fragment:2.4.1" + implementation "androidx.navigation:navigation-ui:2.4.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 52ea1ca..4c5bf83 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/MainActivity.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/MainActivity.kt deleted file mode 100644 index 0e7574a..0000000 --- a/app/src/main/java/ru/itis/karakurik/androidLab2/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package ru.itis.karakurik.androidLab2 - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle - -class MainActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - } -} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/WeatherRepository.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/WeatherRepository.kt new file mode 100644 index 0000000..644a7ee --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/WeatherRepository.kt @@ -0,0 +1,87 @@ +package ru.itis.karakurik.androidLab2.data + +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import ru.itis.karakurik.androidLab2.BuildConfig +import ru.itis.karakurik.androidLab2.data.api.Api +import ru.itis.karakurik.androidLab2.data.api.interceptors.ApiKeyInterceptor +import ru.itis.karakurik.androidLab2.data.api.interceptors.LangInterceptor +import ru.itis.karakurik.androidLab2.data.api.interceptors.UnitsInterceptor +import ru.itis.karakurik.androidLab2.data.api.response.citiesResponse.City +import ru.itis.karakurik.androidLab2.data.api.response.weatherResponse.WeatherResponse +import ru.itis.karakurik.androidLab2.models.CityWeather +import ru.itis.karakurik.androidLab2.models.convertors.WindDegConvertor + +private const val BASE_URL = "https://api.openweathermap.org/data/2.5/" + +class WeatherRepository { + private val okhttp: OkHttpClient by lazy { + OkHttpClient.Builder() + .addInterceptor(ApiKeyInterceptor()) + .addInterceptor(UnitsInterceptor()) + .addInterceptor(LangInterceptor()) + .also { + if (BuildConfig.DEBUG) { + it.addInterceptor( + HttpLoggingInterceptor() + .setLevel( + HttpLoggingInterceptor.Level.BODY + ) + ) + } + } + .build() + } + + private val api: Api by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(okhttp) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(Api::class.java) + } + + suspend fun getWeather(city: String): CityWeather { + return getCityWeather(api.getWeather(city)) + } + + private fun getCityWeather(weatherResponse: WeatherResponse) : CityWeather { + weatherResponse.run { + return CityWeather( + id, + name, + coord.lat, + coord.lon, + main.temp, + main.humidity, + WindDegConvertor.convertWindDeg(wind.deg) + ) + } + } + + private fun getCityWeather(city: City) : CityWeather { + city.run { + return CityWeather( + id, + name, + coord.lat, + coord.lon, + main.temp, + main.humidity, + WindDegConvertor.convertWindDeg(wind.deg) + ) + } + } + + suspend fun getCities(lat: Double, lon: Double, cnt: Int): MutableList { + val citiesResponse = api.getWeatherCities(lat, lon, cnt) + val list = ArrayList(cnt) + for(i in 0 until cnt) { + list.add(getCityWeather(citiesResponse.list[i])) + } + return list + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/Api.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/Api.kt new file mode 100644 index 0000000..0af1938 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/Api.kt @@ -0,0 +1,18 @@ +package ru.itis.karakurik.androidLab2.data.api + +import retrofit2.http.GET +import retrofit2.http.Query +import ru.itis.karakurik.androidLab2.data.api.response.citiesResponse.CitiesResponse +import ru.itis.karakurik.androidLab2.data.api.response.weatherResponse.WeatherResponse + +interface Api { + @GET("weather") + suspend fun getWeather(@Query("q") city: String): WeatherResponse + + @GET("find") + suspend fun getWeatherCities( + @Query("lat") lat: Double, + @Query("lon") lon: Double, + @Query("cnt") cnt: Int + ) : CitiesResponse +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/ApiKeyInterceptor.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/ApiKeyInterceptor.kt new file mode 100644 index 0000000..d3d6561 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/ApiKeyInterceptor.kt @@ -0,0 +1,22 @@ +package ru.itis.karakurik.androidLab2.data.api.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +private const val API_KEY = "56fc6c6cb76c0864b4cd055080568268" +private const val QUERY_API_KEY = "appid" + +class ApiKeyInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val newUrl = request.url.newBuilder() + .addQueryParameter(QUERY_API_KEY, API_KEY) + .build() + + return chain.proceed( + request.newBuilder() + .url(newUrl) + .build() + ) + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/LangInterceptor.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/LangInterceptor.kt new file mode 100644 index 0000000..60ade9b --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/LangInterceptor.kt @@ -0,0 +1,22 @@ +package ru.itis.karakurik.androidLab2.data.api.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +private const val QUERY_LANG = "lang" +private const val LANG = "RU" + +class LangInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val newUrl = request.url.newBuilder() + .addQueryParameter(QUERY_LANG, LANG) + .build() + + return chain.proceed( + request.newBuilder() + .url(newUrl) + .build() + ) + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/UnitsInterceptor.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/UnitsInterceptor.kt new file mode 100644 index 0000000..5617666 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/interceptors/UnitsInterceptor.kt @@ -0,0 +1,22 @@ +package ru.itis.karakurik.androidLab2.data.api.interceptors + +import okhttp3.Interceptor +import okhttp3.Response + +private const val QUERY_UNITS = "units" +private const val UNITS = "metric" + +class UnitsInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val newUrl = request.url.newBuilder() + .addQueryParameter(QUERY_UNITS, UNITS) + .build() + + return chain.proceed( + request.newBuilder() + .url(newUrl) + .build() + ) + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/CitiesResponse.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/CitiesResponse.kt new file mode 100644 index 0000000..d98186c --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/CitiesResponse.kt @@ -0,0 +1,15 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class CitiesResponse( + @SerializedName("cod") + val cod: String, + @SerializedName("count") + val count: Int, + @SerializedName("list") + val list: List, + @SerializedName("message") + val message: String +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/City.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/City.kt new file mode 100644 index 0000000..799bca3 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/City.kt @@ -0,0 +1,29 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class City ( + @SerializedName("clouds") + val clouds: Clouds, + @SerializedName("coord") + val coord: Coord, + @SerializedName("dt") + val dt: Int, + @SerializedName("id") + val id: Int, + @SerializedName("main") + val main: Main, + @SerializedName("name") + val name: String, + @SerializedName("rain") + val rain: Any, + @SerializedName("snow") + val snow: Any, + @SerializedName("sys") + val sys: Sys, + @SerializedName("weather") + val weather: List, + @SerializedName("wind") + val wind: Wind +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Clouds.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Clouds.kt new file mode 100644 index 0000000..44c6324 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Clouds.kt @@ -0,0 +1,9 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Clouds( + @SerializedName("all") + val all: Int +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Coord.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Coord.kt new file mode 100644 index 0000000..7cdb5c3 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Coord.kt @@ -0,0 +1,11 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Coord( + @SerializedName("lat") + val lat: Double, + @SerializedName("lon") + val lon: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Main.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Main.kt new file mode 100644 index 0000000..763b83d --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Main.kt @@ -0,0 +1,23 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Main( + @SerializedName("feels_like") + val feelsLike: Double, + @SerializedName("grnd_level") + val grndLevel: Int, + @SerializedName("humidity") + val humidity: Int, + @SerializedName("pressure") + val pressure: Int, + @SerializedName("sea_level") + val seaLevel: Int, + @SerializedName("temp") + val temp: Double, + @SerializedName("temp_max") + val tempMax: Double, + @SerializedName("temp_min") + val tempMin: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Sys.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Sys.kt new file mode 100644 index 0000000..f96c00b --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Sys.kt @@ -0,0 +1,9 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Sys( + @SerializedName("country") + val country: String +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Weather.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Weather.kt new file mode 100644 index 0000000..a07bbb0 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Weather.kt @@ -0,0 +1,15 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Weather( + @SerializedName("description") + val description: String, + @SerializedName("icon") + val icon: String, + @SerializedName("id") + val id: Int, + @SerializedName("main") + val main: String +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Wind.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Wind.kt new file mode 100644 index 0000000..2e77cf2 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/citiesResponse/Wind.kt @@ -0,0 +1,11 @@ +package ru.itis.karakurik.androidLab2.data.api.response.citiesResponse + + +import com.google.gson.annotations.SerializedName + +data class Wind( + @SerializedName("deg") + val deg: Int, + @SerializedName("speed") + val speed: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Clouds.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Clouds.kt new file mode 100644 index 0000000..a8c2d26 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Clouds.kt @@ -0,0 +1,9 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Clouds( + @SerializedName("all") + val all: Int +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Coord.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Coord.kt new file mode 100644 index 0000000..da00620 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Coord.kt @@ -0,0 +1,11 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Coord( + @SerializedName("lat") + val lat: Double, + @SerializedName("lon") + val lon: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Main.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Main.kt new file mode 100644 index 0000000..0330e2e --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Main.kt @@ -0,0 +1,23 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Main( + @SerializedName("feels_like") + val feelsLike: Double, + @SerializedName("grnd_level") + val grndLevel: Int, + @SerializedName("humidity") + val humidity: Int, + @SerializedName("pressure") + val pressure: Int, + @SerializedName("sea_level") + val seaLevel: Int, + @SerializedName("temp") + val temp: Double, + @SerializedName("temp_max") + val tempMax: Double, + @SerializedName("temp_min") + val tempMin: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Sys.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Sys.kt new file mode 100644 index 0000000..825469f --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Sys.kt @@ -0,0 +1,17 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Sys( + @SerializedName("country") + val country: String, + @SerializedName("id") + val id: Int, + @SerializedName("sunrise") + val sunrise: Int, + @SerializedName("sunset") + val sunset: Int, + @SerializedName("type") + val type: Int +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Weather.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Weather.kt new file mode 100644 index 0000000..5de74ff --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Weather.kt @@ -0,0 +1,15 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Weather( + @SerializedName("description") + val description: String, + @SerializedName("icon") + val icon: String, + @SerializedName("id") + val id: Int, + @SerializedName("main") + val main: String +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/WeatherResponse.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/WeatherResponse.kt new file mode 100644 index 0000000..66a32ce --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/WeatherResponse.kt @@ -0,0 +1,33 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class WeatherResponse( + @SerializedName("base") + val base: String, + @SerializedName("clouds") + val clouds: Clouds, + @SerializedName("cod") + val cod: Int, + @SerializedName("coord") + val coord: Coord, + @SerializedName("dt") + val dt: Int, + @SerializedName("id") + val id: Int, + @SerializedName("main") + val main: Main, + @SerializedName("name") + val name: String, + @SerializedName("sys") + val sys: Sys, + @SerializedName("timezone") + val timezone: Int, + @SerializedName("visibility") + val visibility: Int, + @SerializedName("weather") + val weather: List, + @SerializedName("wind") + val wind: Wind +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Wind.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Wind.kt new file mode 100644 index 0000000..282cc9a --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/data/api/response/weatherResponse/Wind.kt @@ -0,0 +1,13 @@ +package ru.itis.karakurik.androidLab2.data.api.response.weatherResponse + + +import com.google.gson.annotations.SerializedName + +data class Wind( + @SerializedName("deg") + val deg: Int, + @SerializedName("gust") + val gust: Double, + @SerializedName("speed") + val speed: Double +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/extentions/ActivityExt.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/extentions/ActivityExt.kt new file mode 100644 index 0000000..61a4dd6 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/extentions/ActivityExt.kt @@ -0,0 +1,9 @@ +package ru.itis.karakurik.androidLab2.extentions + +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment + +fun AppCompatActivity.findController (id: Int) : NavController { + return (supportFragmentManager.findFragmentById(id) as NavHostFragment).navController +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/models/CityWeather.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/models/CityWeather.kt new file mode 100644 index 0000000..2c36485 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/models/CityWeather.kt @@ -0,0 +1,11 @@ +package ru.itis.karakurik.androidLab2.models + +data class CityWeather( + val id: Int, + val name: String, + val lat: Double, + val lon: Double, + val temp: Double, + val humidity: Int, + val windDeg: WindDeg +) diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/models/WindDeg.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/models/WindDeg.kt new file mode 100644 index 0000000..0227197 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/models/WindDeg.kt @@ -0,0 +1,13 @@ +package ru.itis.karakurik.androidLab2.models +enum class WindDeg ( + val deg: Int +) { + N(0), + NE(45), + E(90), + SE(135), + S(180), + SW(225), + W(270), + NW(315) +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/TempColorConverter.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/TempColorConverter.kt new file mode 100644 index 0000000..e2a60a7 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/TempColorConverter.kt @@ -0,0 +1,17 @@ +package ru.itis.karakurik.androidLab2.models.convertors + +import android.graphics.Color +import ru.itis.karakurik.androidLab2.R + +object TempColorConverter { + fun getColor(temp: Double): Int { + return when { + temp < -20 -> R.color.temp_less_minus20 + temp < 10 -> R.color.temp_minus20_minus10 + temp < 0 -> R.color.temp_minus10_0 + temp < 10 -> R.color.temp_0_10 + temp < 20 -> R.color.temp_10_20 + else -> R.color.temp_more20 + } + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/WindDegConvertor.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/WindDegConvertor.kt new file mode 100644 index 0000000..45d2f23 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/models/convertors/WindDegConvertor.kt @@ -0,0 +1,19 @@ +package ru.itis.karakurik.androidLab2.models.convertors + +import androidx.room.TypeConverter +import ru.itis.karakurik.androidLab2.models.WindDeg + +object WindDegConvertor { + fun convertWindDeg(deg: Int): WindDeg { + return when ((deg / 45 + 2* (deg%45) / 45) * 45 % 360) { + 0 -> WindDeg.N + 45 -> WindDeg.NE + 90 -> WindDeg.E + 135 -> WindDeg.SE + 180 -> WindDeg.S + 225 -> WindDeg.SW + 270 -> WindDeg.W + else -> WindDeg.NW + } + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/myTestsApi/Main.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/myTestsApi/Main.kt new file mode 100644 index 0000000..d8e1f8a --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/myTestsApi/Main.kt @@ -0,0 +1,25 @@ +package ru.itis.karakurik.androidLab2.myTestsApi + +import kotlinx.coroutines.runBlocking +import ru.itis.karakurik.androidLab2.data.WeatherRepository +import ru.itis.karakurik.androidLab2.models.convertors.WindDegConvertor + +private const val KAZAN_LON = 49.1221 +private const val KAZAN_LAT = 55.7887 + +fun main() { + val a = WindDegConvertor.convertWindDeg(350) + + val repository = WeatherRepository() + + runBlocking { + val weather = repository.getWeather("Kazan") + val lat = weather.lat + val lon = weather.lon + + val weatherCities = repository.getCities(lat, lon, 10) + for (wC in weatherCities) { + println(wC.name + " " + wC.temp) + } + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/activities/MainActivity.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/activities/MainActivity.kt new file mode 100644 index 0000000..96f4c4b --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/activities/MainActivity.kt @@ -0,0 +1,40 @@ +package ru.itis.karakurik.androidLab2.ui.activities + +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import androidx.navigation.NavController +import kotlinx.coroutines.launch +import ru.itis.karakurik.androidLab2.data.WeatherRepository +import ru.itis.karakurik.androidLab2.databinding.ActivityMainBinding +import ru.itis.karakurik.androidLab2.extentions.findController + +class MainActivity : AppCompatActivity() { + private var binding: ActivityMainBinding? = null + private var controller: NavController? = null + private val repository by lazy { + WeatherRepository() + } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding?.root) + controller = binding?.navHostFragmentMain?.id?.let { findController(it) } + + lifecycleScope.launch { + try { + val response = repository.getWeather("Kazan") + + } catch (ex: Exception) { + Log.e("arg", ex.message.toString()) + } + } + } + + override fun onDestroy() { + super.onDestroy() + binding = null + controller = null + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/DetailsFragment.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/DetailsFragment.kt new file mode 100644 index 0000000..e5e048c --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/DetailsFragment.kt @@ -0,0 +1,55 @@ +package ru.itis.karakurik.androidLab2.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.launch +import ru.itis.karakurik.androidLab2.R +import ru.itis.karakurik.androidLab2.data.WeatherRepository +import ru.itis.karakurik.androidLab2.databinding.FragmentDetailsBinding +import ru.itis.karakurik.androidLab2.models.CityWeather + +class DetailsFragment : Fragment(R.layout.fragment_details) { + private var cityName: String? = null + private var weather: CityWeather? = null + + private val repository by lazy { + WeatherRepository() + } + + private var binding: FragmentDetailsBinding? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_details, container, false) + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentDetailsBinding.bind(view) + + arguments?.let { + cityName = it.getString("CITY_NAME") + } + + lifecycleScope.launch { + weather = cityName?.let { repository.getWeather(it) } + } + + binding?.run { + tvCity.text = weather?.name + tvTemp.text = weather?.temp.toString() + "°C" + tvHumidityValue.text = weather?.humidity.toString() + "%" + tvWindDegValue.text = weather?.windDeg.toString() + } + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/SearchFragment.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/SearchFragment.kt new file mode 100644 index 0000000..b453154 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/SearchFragment.kt @@ -0,0 +1,145 @@ +package ru.itis.karakurik.androidLab2.ui.fragments.list + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.appcompat.widget.SearchView +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import kotlinx.coroutines.* +import ru.itis.karakurik.androidLab2.R +import ru.itis.karakurik.androidLab2.data.WeatherRepository +import ru.itis.karakurik.androidLab2.databinding.FragmentSearchBinding +import ru.itis.karakurik.androidLab2.models.CityWeather +import ru.itis.karakurik.androidLab2.models.WindDeg +import ru.itis.karakurik.androidLab2.ui.fragments.list.recycler.ListRecyclerAdapter +import timber.log.Timber + +private const val COUNT_OF_CITIES_IN_RECYCLER_VIEW = 10 +private const val HARDCODE_LAT = 55.7887 +private const val HARDCODE_LON = 49.1221 + +class SearchFragment() : Fragment() { + private var binding: FragmentSearchBinding? = null + private val repository by lazy { + WeatherRepository() + } + private var listRecyclerAdapter: ListRecyclerAdapter? = null + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return inflater.inflate(R.layout.fragment_search, container, false) + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentSearchBinding.bind(view) + + initRecyclerView() + + binding?.svSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + Timber.d("Pressed query button") +// getWeatherList(query) + try { + getWeather(query) + + } catch (ex: Exception) { + Toast.makeText( + context, + "Не удалось найти", + Toast.LENGTH_LONG + ).show() + } + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + Timber.d("Query text changed") + return false + } + }) + } + + private fun getWeather(city: String) { + scope.launch { + withContext(Dispatchers.IO) { + val weather = repository.getWeather(city) + showDetailsFragment(weather.name) + } + } + } + + private fun getCities(city: String?) { + var weather: CityWeather? + scope.launch { + try { + withContext(Dispatchers.IO) { + weather = city?.let { repository.getWeather(it) } + } + var weatherCities: MutableList? = null + withContext(Dispatchers.IO) { + weather?.let { weather -> + weatherCities = + repository + .getCities( + weather.lat, + weather.lon, + COUNT_OF_CITIES_IN_RECYCLER_VIEW + ) + } + } + listRecyclerAdapter?.submitList(weatherCities) + } catch (ex: Exception) { + Toast.makeText( + context, + "Не удалось найти", + Toast.LENGTH_LONG + ).show() + } + } + } + + + private fun initRecyclerView() { + binding?.rvSearch?.run { + listRecyclerAdapter = ListRecyclerAdapter { city -> + showDetailsFragment(city) + } + adapter = listRecyclerAdapter + } + listRecyclerAdapter?.submitList( + arrayListOf( + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + CityWeather(551487, "Kazan", 0.0, 0.0, 0.0, 250, WindDeg.NW), + ) + ) +// getCities("Kazan") + getCities(HARDCODE_LAT, HARDCODE_LON, COUNT_OF_CITIES_IN_RECYCLER_VIEW) + } + + private fun getCities(lat: Double, lon: Double, cnt: Int) { + // TODO: + } + + private fun showDetailsFragment(city: String) { + val bundle = bundleOf( + "CITY_NAME" to city + ) + findNavController().navigate(R.id.action_searchFragment_to_detailsFragment, bundle) + } +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/CityWeatherDiffCallback.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/CityWeatherDiffCallback.kt new file mode 100644 index 0000000..9a53238 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/CityWeatherDiffCallback.kt @@ -0,0 +1,15 @@ +package ru.itis.karakurik.androidLab2.ui.fragments.list.recycler + +import androidx.recyclerview.widget.DiffUtil +import ru.itis.karakurik.androidLab2.models.CityWeather + +object CityWeatherDiffCallback : DiffUtil.ItemCallback(){ + override fun areItemsTheSame(oldItem: CityWeather, newItem: CityWeather): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: CityWeather, newItem: CityWeather): Boolean { + return oldItem == newItem + } + +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListItemViewHolder.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListItemViewHolder.kt new file mode 100644 index 0000000..69ed1b6 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListItemViewHolder.kt @@ -0,0 +1,31 @@ +package ru.itis.karakurik.androidLab2.ui.fragments.list.recycler; + +import android.annotation.SuppressLint +import android.graphics.Color +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import ru.itis.karakurik.androidLab2.R +import ru.itis.karakurik.androidLab2.databinding.ListItemCityBinding +import ru.itis.karakurik.androidLab2.models.CityWeather +import ru.itis.karakurik.androidLab2.models.convertors.TempColorConverter +import ru.itis.karakurik.androidLab2.models.convertors.TempColorConverter.getColor + +class ListItemViewHolder( + itemView: View, + private val onItemClick: (city: String) -> Unit +) : RecyclerView.ViewHolder(itemView) { + private val binding = ListItemCityBinding.bind(itemView) + + fun bind(cityWeather: CityWeather) { + with(binding) { + tvCityItem.text = cityWeather.name + tvTempItem.text = cityWeather.temp.toString() + tvTempItem.setTextColor(getColor(cityWeather.temp)) + + root.setOnClickListener { + onItemClick(cityWeather.name) + } + } + } + +} diff --git a/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListRecyclerAdapter.kt b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListRecyclerAdapter.kt new file mode 100644 index 0000000..77c8ba5 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/androidLab2/ui/fragments/list/recycler/ListRecyclerAdapter.kt @@ -0,0 +1,34 @@ +package ru.itis.karakurik.androidLab2.ui.fragments.list.recycler; + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import ru.itis.karakurik.androidLab2.R +import ru.itis.karakurik.androidLab2.models.CityWeather +import java.util.ArrayList + +class ListRecyclerAdapter( + private val onItemClick: (city: String) -> Unit +) : ListAdapter(CityWeatherDiffCallback) { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ) = ListItemViewHolder( + LayoutInflater + .from(parent.context) + .inflate(R.layout.list_item_city, parent, false), + onItemClick + ) + + override fun onBindViewHolder( + holder: ListItemViewHolder, + position: Int + ) = holder.bind( + getItem(position) + ) + + override fun submitList(list: MutableList?) { + super.submitList(if (list == null) null else ArrayList(list)) + } + +} diff --git a/app/src/main/res/drawable/air.xml b/app/src/main/res/drawable/air.xml new file mode 100644 index 0000000..634be77 --- /dev/null +++ b/app/src/main/res/drawable/air.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 16f09a2..e4e5d57 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,18 +1,22 @@ - - + android:orientation="vertical" + tools:context=".ui.activities.MainActivity"> + + - + diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml new file mode 100644 index 0000000..7c66c2b --- /dev/null +++ b/app/src/main/res/layout/fragment_details.xml @@ -0,0 +1,113 @@ + + + + + + + + app:layout_constraintStart_toStartOf="parent" + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..d8f28a2 --- /dev/null +++ b/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_item_city.xml b/app/src/main/res/layout/list_item_city.xml new file mode 100644 index 0000000..3290255 --- /dev/null +++ b/app/src/main/res/layout/list_item_city.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/app/src/main/res/navigation/nav_graph_main.xml b/app/src/main/res/navigation/nav_graph_main.xml new file mode 100644 index 0000000..59d79cc --- /dev/null +++ b/app/src/main/res/navigation/nav_graph_main.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ca1931b..242226f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,15 @@ #FF018786 #FF000000 #FFFFFFFF + + #B2C1D0 + + #00008B + #0000EE + #63B8FF + #00FF7F + #00CD66 + #FFFF00 + #FF3030 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 93bdd74..7aa2fd3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,8 @@ - Android-lab-2 - \ No newline at end of file + Weather App + + Hello blank fragment + Найти погоду в городе + Max Temp: 05:05 PM + Min Temp: 05:05 AM + diff --git a/build.gradle b/build.gradle index a36524f..a13c474 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.1' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10" // NOTE: Do not place your application dependencies here; they belong @@ -15,6 +15,7 @@ buildscript { plugins { id "io.gitlab.arturbosch.detekt" version "1.18.1" + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false } task clean(type: Delete) {