- Code inspection

- Redundant resources removed
 - Resources moved the corresponding flavours
 - Deprecated dependencies upgraded
 - lint changes
This commit is contained in:
2023-08-08 22:20:39 +01:00
parent 9189a4412d
commit 9a0189c8ec
174 changed files with 1359 additions and 1245 deletions

View File

@@ -10,8 +10,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<application android:networkSecurityConfig="@xml/network_security_config" />
<uses-feature
android:name="android.hardware.location"
android:required="true" />
@@ -19,4 +17,8 @@
android:name="android.hardware.location.gps"
android:required="true" />
<application
android:networkSecurityConfig="@xml/network_security_config"
tools:ignore="MissingApplicationIcon" />
</manifest>

View File

@@ -14,9 +14,9 @@ class AppClass : BaseAppClass() {
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
) as WeatherApi
}

View File

@@ -9,21 +9,21 @@ import com.tomtom.online.sdk.search.data.common.Address
import com.tomtom.online.sdk.search.data.reversegeocoder.ReverseGeocoderSearchQueryBuilder
abstract class LocationHelper(
context: Context
context: Context
) {
private val key = BuildConfig.ParamTwo
private val searchApi = OnlineSearchApi.create(context, key)
suspend fun getAddressFromLatLong(
lat: Double, long: Double
lat: Double, long: Double
): Address? {
return createSuspend {
val revGeoQuery =
ReverseGeocoderSearchQueryBuilder(lat, long).build()
ReverseGeocoderSearchQueryBuilder(lat, long).build()
val resultSingle =
searchApi.reverseGeocoding(revGeoQuery)
searchApi.reverseGeocoding(revGeoQuery)
resultSingle.blockingGet()?.addresses?.get(0)?.address
}

View File

@@ -6,8 +6,8 @@ interface LocationProvider {
suspend fun getCurrentLatLong(): Pair<Double, Double>
fun getLatLongFromLocationName(location: String): Pair<Double, Double>
suspend fun getLocationNameFromLatLong(
lat: Double,
long: Double,
type: LocationType = LocationType.Town
lat: Double,
long: Double,
type: LocationType = LocationType.Town
): String
}

View File

@@ -9,12 +9,11 @@ import android.location.LocationManager
import android.os.HandlerThread
import androidx.annotation.RequiresPermission
import com.appttude.h_mal.atlas_weather.model.types.LocationType
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationRequest.PRIORITY_HIGH_ACCURACY
import com.google.android.gms.location.LocationRequest.PRIORITY_LOW_POWER
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.tasks.CancellationToken
import com.google.android.gms.tasks.OnTokenCanceledListener
import kotlinx.coroutines.tasks.await
@@ -28,8 +27,8 @@ class LocationProviderImpl(
private val applicationContext: Context
) : LocationProvider, LocationHelper(applicationContext) {
private var locationManager =
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
private val client = FusedLocationProviderClient(applicationContext)
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
private val client = LocationServices.getFusedLocationProviderClient(applicationContext)
private val geoCoder: Geocoder by lazy { Geocoder(applicationContext, Locale.getDefault()) }
@RequiresPermission(value = ACCESS_COARSE_LOCATION)
@@ -48,18 +47,19 @@ class LocationProviderImpl(
}
override suspend fun getLocationNameFromLatLong(
lat: Double, long: Double, type: LocationType
lat: Double, long: Double, type: LocationType
): String {
val address = getAddressFromLatLong(lat, long) ?: return "$lat $long"
return when (type) {
LocationType.Town -> {
val location = address
.municipalitySubdivision
?.takeIf { it.isNotBlank() }
?: address.municipality
.municipalitySubdivision
?.takeIf { it.isNotBlank() }
?: address.municipality
location ?: throw IOException("No location municipalitySubdivision or municipality")
}
LocationType.City -> {
address.municipality ?: throw IOException("No location municipality")
}
@@ -68,7 +68,7 @@ class LocationProviderImpl(
@SuppressLint("MissingPermission")
private suspend fun getAFreshLocation(): Location? {
return client.getCurrentLocation(PRIORITY_LOW_POWER, object : CancellationToken() {
return client.getCurrentLocation(Priority.PRIORITY_LOW_POWER, object : CancellationToken() {
override fun isCancellationRequested(): Boolean = false
override fun onCanceledRequested(p0: OnTokenCanceledListener): CancellationToken = this
}).await()
@@ -84,20 +84,30 @@ class LocationProviderImpl(
return suspendCoroutine { cont ->
val callback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
override fun onLocationResult(p0: LocationResult) {
client.removeLocationUpdates(this)
cont.resume(p0?.lastLocation)
cont.resume(p0.lastLocation)
}
}
with(locationManager!!) {
when {
isProviderEnabled(LocationManager.GPS_PROVIDER) -> {
client.requestLocationUpdates(createLocationRequest(PRIORITY_HIGH_ACCURACY), callback, looper)
client.requestLocationUpdates(
createLocationRequest(Priority.PRIORITY_HIGH_ACCURACY),
callback,
looper
)
}
isProviderEnabled(LocationManager.NETWORK_PROVIDER) -> {
client.requestLocationUpdates(createLocationRequest(PRIORITY_LOW_POWER), callback, looper)
client.requestLocationUpdates(
createLocationRequest(Priority.PRIORITY_LOW_POWER),
callback,
looper
)
}
else -> {
cont.resume(null)
}
@@ -108,7 +118,7 @@ class LocationProviderImpl(
}
private fun createLocationRequest(priority: Int) = LocationRequest.create()
.setPriority(priority)
.setNumUpdates(1)
.setExpirationDuration(1000)
.setPriority(priority)
.setNumUpdates(1)
.setExpirationDuration(1000)
}

View File

@@ -8,16 +8,16 @@ open class BaseNetworkModule {
// Declare the method we want/can change (no annotations)
open fun baseUrl() = "/"
inline fun <reified T: Api> invoke(
vararg interceptors: Interceptor
inline fun <reified T : Api> invoke(
vararg interceptors: Interceptor
): Api {
val okHttpClient = buildOkHttpClient(*interceptors)
return createRetrofit(
baseUrl(),
okHttpClient,
T::class.java
baseUrl(),
okHttpClient,
T::class.java
)
}
}

View File

@@ -7,9 +7,8 @@ import java.io.IOException
abstract class ResponseUnwrap {
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun <T : Any> responseUnwrap(
call: suspend () -> Response<T>
call: suspend () -> Response<T>
): T {
val response = call.invoke()

View File

@@ -6,14 +6,14 @@ import retrofit2.http.GET
import retrofit2.http.Query
interface WeatherApi: Api {
interface WeatherApi : Api {
@GET("onecall?")
suspend fun getFromApi(
@Query("lat") query: String,
@Query("lon") lon: String,
@Query("exclude") exclude: String = "minutely",
@Query("units") units: String = "metric"
@Query("lat") query: String,
@Query("lon") lon: String,
@Query("exclude") exclude: String = "minutely",
@Query("units") units: String = "metric"
): Response<WeatherResponse>
}

View File

@@ -12,7 +12,7 @@ class NetworkConnectionInterceptor(
private val applicationContext = context.applicationContext
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
if (!isInternetAvailable(applicationContext)){
if (!isInternetAvailable(applicationContext)) {
throw IOException("Make sure you have an active data connection")
}
return chain.proceed(chain.request())

View File

@@ -8,7 +8,7 @@ import okhttp3.Response
/**
* Interceptor used to add default query parameters to api calls
*/
class QueryParamsInterceptor : Interceptor{
class QueryParamsInterceptor : Interceptor {
val id = BuildConfig.ParamOne
@@ -16,8 +16,8 @@ class QueryParamsInterceptor : Interceptor{
val original = chain.request()
val url = original.url.newBuilder()
.addQueryParameter("appid", id)
.build()
.addQueryParameter("appid", id)
.build()
// Request customization: add request headers
val requestBuilder = original.newBuilder().url(url)

View File

@@ -9,12 +9,12 @@ import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
level = HttpLoggingInterceptor.Level.BODY
}
fun buildOkHttpClient(
vararg interceptor: Interceptor,
timeoutSeconds: Long = 30L
vararg interceptor: Interceptor,
timeoutSeconds: Long = 30L
): OkHttpClient {
val builder = OkHttpClient.Builder()
@@ -28,21 +28,21 @@ fun buildOkHttpClient(
}
builder.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
return builder.build()
}
fun <T> createRetrofit(
baseUrl: String,
okHttpClient: OkHttpClient,
service: Class<T>
baseUrl: String,
okHttpClient: OkHttpClient,
service: Class<T>
): T {
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(service)
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(service)
}

View File

@@ -4,45 +4,45 @@ import com.google.gson.annotations.SerializedName
data class Current(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
)

View File

@@ -4,48 +4,48 @@ import com.google.gson.annotations.SerializedName
data class DailyItem(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Temp? = null,
@field:SerializedName("temp")
val temp: Temp? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: FeelsLike? = null,
@field:SerializedName("feels_like")
val feelsLike: FeelsLike? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("pop")
val pop: Double? = null,
@field:SerializedName("pop")
val pop: Double? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null,
@field:SerializedName("rain")
val rain: Double? = null
@field:SerializedName("rain")
val rain: Double? = null
)

View File

@@ -4,15 +4,15 @@ import com.google.gson.annotations.SerializedName
data class FeelsLike(
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("morn")
val morn: Double? = null
@field:SerializedName("morn")
val morn: Double? = null
)

View File

@@ -4,45 +4,45 @@ import com.google.gson.annotations.SerializedName
data class Hour(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
)

View File

@@ -4,21 +4,21 @@ import com.google.gson.annotations.SerializedName
data class Response(
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("daily")
val daily: List<DailyItem?>? = null,
@field:SerializedName("daily")
val daily: List<DailyItem?>? = null,
@field:SerializedName("lon")
val lon: Double? = null,
@field:SerializedName("lon")
val lon: Double? = null,
@field:SerializedName("lat")
val lat: Double? = null
@field:SerializedName("lat")
val lat: Double? = null
)

View File

@@ -4,21 +4,21 @@ import com.google.gson.annotations.SerializedName
data class Temp(
@field:SerializedName("min")
val min: Double? = null,
@field:SerializedName("min")
val min: Double? = null,
@field:SerializedName("max")
val max: Double? = null,
@field:SerializedName("max")
val max: Double? = null,
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("morn")
val morn: Double? = null
@field:SerializedName("morn")
val morn: Double? = null
)

View File

@@ -4,15 +4,15 @@ import com.google.gson.annotations.SerializedName
data class WeatherItem(
@field:SerializedName("icon")
val icon: String? = null,
@field:SerializedName("icon")
val icon: String? = null,
@field:SerializedName("description")
val description: String? = null,
@field:SerializedName("description")
val description: String? = null,
@field:SerializedName("main")
val main: String? = null,
@field:SerializedName("main")
val main: String? = null,
@field:SerializedName("id")
val id: Int? = null
@field:SerializedName("id")
val id: Int? = null
)

View File

@@ -4,25 +4,25 @@ import com.google.gson.annotations.SerializedName
data class WeatherResponse(
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("hourly")
val hourly: List<Hour>? = null,
@field:SerializedName("hourly")
val hourly: List<Hour>? = null,
@field:SerializedName("daily")
val daily: List<DailyItem>? = null,
@field:SerializedName("daily")
val daily: List<DailyItem>? = null,
@field:SerializedName("lon")
val lon: Double = 0.00,
@field:SerializedName("lon")
val lon: Double = 0.00,
@field:SerializedName("lat")
val lat: Double = 0.00
@field:SerializedName("lat")
val lat: Double = 0.00
)

View File

@@ -9,9 +9,10 @@ import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
* Shared preferences to save & load last timestamp
*/
const val LOCATION_CONST = "location_"
class PreferenceProvider(
context: Context
){
) {
private val appContext = context.applicationContext
@@ -20,30 +21,30 @@ class PreferenceProvider(
fun saveLastSavedAt(locationName: String) {
preference.edit().putLong(
locationName,
System.currentTimeMillis()
locationName,
System.currentTimeMillis()
).apply()
}
fun getLastSavedAt(locationName: String): Long? {
return preference.getLong(locationName, 0L)
fun getLastSavedAt(locationName: String): Long {
return preference.getLong(locationName, 0L)
}
fun getAllKeys() = preference.all.keys.apply {
remove(CURRENT_LOCATION)
}
fun deleteLocation(locationName: String){
fun deleteLocation(locationName: String) {
preference.edit().remove(locationName).apply()
}
fun isNotificationsEnabled(): Boolean = preference.getBoolean("notif_boolean", true)
fun setFirstTimeRun(){
fun setFirstTimeRun() {
preference.edit().putBoolean("FIRST_TIME_RUN", false).apply()
}
fun isWidgetBlackground(): Boolean {
fun isWidgetBackground(): Boolean {
return preference.getBoolean("widget_black_background", false)
}

View File

@@ -10,7 +10,7 @@ interface Repository {
suspend fun saveCurrentWeatherToRoom(entityItem: EntityItem)
suspend fun saveWeatherListToRoom(list: List<EntityItem>)
fun loadRoomWeatherLiveData(): LiveData<List<EntityItem>>
suspend fun loadWeatherList() : List<String>
suspend fun loadWeatherList(): List<String>
fun loadCurrentWeatherFromRoom(id: String): LiveData<EntityItem>
suspend fun loadSingleCurrentWeatherFromRoom(id: String): EntityItem
fun isSearchValid(locationName: String): Boolean

View File

@@ -23,34 +23,34 @@ class RepositoryImpl(
return responseUnwrap { api.getFromApi(lat, long) }
}
override suspend fun saveCurrentWeatherToRoom(entityItem: EntityItem){
override suspend fun saveCurrentWeatherToRoom(entityItem: EntityItem) {
db.getSimpleDao().upsertFullWeather(entityItem)
}
override suspend fun saveWeatherListToRoom(
list: List<EntityItem>
){
list: List<EntityItem>
) {
db.getSimpleDao().upsertListOfFullWeather(list)
}
override fun loadRoomWeatherLiveData() = db.getSimpleDao().getAllFullWeatherWithoutCurrent()
override suspend fun loadWeatherList() : List<String>{
override suspend fun loadWeatherList(): List<String> {
return db.getSimpleDao()
.getWeatherListWithoutCurrent()
.map { it.id }
.getWeatherListWithoutCurrent()
.map { it.id }
}
override fun loadCurrentWeatherFromRoom(id: String)
= db.getSimpleDao().getCurrentFullWeather(id)
override fun loadCurrentWeatherFromRoom(id: String) =
db.getSimpleDao().getCurrentFullWeather(id)
override suspend fun loadSingleCurrentWeatherFromRoom(id: String)
= db.getSimpleDao().getCurrentFullWeatherSingle(id)
override suspend fun loadSingleCurrentWeatherFromRoom(id: String) =
db.getSimpleDao().getCurrentFullWeatherSingle(id)
override fun isSearchValid(locationName: String): Boolean {
val lastSaved = prefs
.getLastSavedAt("$LOCATION_CONST$locationName")
?: return true
.getLastSavedAt("$LOCATION_CONST$locationName")
?: return true
val difference = System.currentTimeMillis() - lastSaved
return difference > FALLBACK_TIME

View File

@@ -3,12 +3,12 @@ package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
class SettingsRepositoryImpl(
private val prefs: PreferenceProvider
) : SettingsRepository{
private val prefs: PreferenceProvider
) : SettingsRepository {
override fun isNotificationsEnabled(): Boolean = prefs.isNotificationsEnabled()
override fun setFirstTime() = prefs.setFirstTimeRun()
override fun isBlackBackground() = prefs.isWidgetBlackground()
override fun isBlackBackground() = prefs.isWidgetBackground()
}

View File

@@ -8,9 +8,9 @@ import androidx.room.TypeConverters
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
@Database(
entities = [EntityItem::class],
version = 1,
exportSchema = false
entities = [EntityItem::class],
version = 1,
exportSchema = false
)
@TypeConverters(Converter::class)
abstract class AppDatabase : RoomDatabase() {
@@ -31,12 +31,12 @@ abstract class AppDatabase : RoomDatabase() {
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"MyDatabase.db"
).addTypeConverter(Converter(context))
.build()
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"MyDatabase.db"
).addTypeConverter(Converter(context))
.build()
}
}

View File

@@ -18,16 +18,16 @@ interface WeatherDao {
fun upsertListOfFullWeather(items: List<EntityItem>)
@Query("SELECT * FROM EntityItem WHERE id = :userId LIMIT 1")
fun getCurrentFullWeather(userId: String) : LiveData<EntityItem>
fun getCurrentFullWeather(userId: String): LiveData<EntityItem>
@Query("SELECT * FROM EntityItem WHERE id = :userId LIMIT 1")
fun getCurrentFullWeatherSingle(userId: String) : EntityItem
fun getCurrentFullWeatherSingle(userId: String): EntityItem
@Query("SELECT * FROM EntityItem WHERE id != :id")
fun getAllFullWeatherWithoutCurrent(id: String = CURRENT_LOCATION) : LiveData<List<EntityItem>>
fun getAllFullWeatherWithoutCurrent(id: String = CURRENT_LOCATION): LiveData<List<EntityItem>>
@Query("SELECT * FROM EntityItem WHERE id != :id")
fun getWeatherListWithoutCurrent(id: String = CURRENT_LOCATION) : List<EntityItem>
fun getWeatherListWithoutCurrent(id: String = CURRENT_LOCATION): List<EntityItem>
@Query("DELETE FROM EntityItem WHERE id = :userId")
fun deleteEntry(userId: String): Int

View File

@@ -6,6 +6,7 @@ import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
const val CURRENT_LOCATION = "CurrentLocation"
@Entity
data class EntityItem(
@PrimaryKey(autoGenerate = false)

View File

@@ -1,7 +1,5 @@
package com.appttude.h_mal.atlas_weather.helper
import android.view.LayoutInflater
import android.view.ViewGroup
import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass

View File

@@ -26,9 +26,9 @@ import kotlin.coroutines.suspendCoroutine
class ServicesHelper(
private val repository: Repository,
private val settingsRepository: SettingsRepository,
private val locationProvider: LocationProvider
private val repository: Repository,
private val settingsRepository: SettingsRepository,
private val locationProvider: LocationProvider
) {
@RequiresPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
@@ -40,8 +40,9 @@ class ServicesHelper(
val latLong = locationProvider.getCurrentLatLong()
// Get weather from api
val weather = repository
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
val currentLocation = locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon)
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
val currentLocation =
locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon)
val fullWeather = FullWeather(weather).apply {
temperatureUnit = "°C"
locationString = currentLocation
@@ -61,7 +62,7 @@ class ServicesHelper(
return try {
val result = repository.loadSingleCurrentWeatherFromRoom(CURRENT_LOCATION)
val epoc = System.currentTimeMillis()
result.weather.let {
val bitmap = it.current?.icon
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon)

View File

@@ -23,7 +23,7 @@ data class Forecast(
val sunrise: String?,
val sunset: String?,
val cloud: String?
): Parcelable{
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),

View File

@@ -22,7 +22,7 @@ data class WeatherDisplay(
val lat: Double = 0.00,
val lon: Double = 0.00,
var displayName: String?
): Parcelable {
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readValue(Double::class.java.classLoader) as? Double,

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.atlas_weather.model.types
enum class LocationType{
enum class LocationType {
City,
Town
}

View File

@@ -5,49 +5,49 @@ import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
data class DailyWeather(
val dt: Int?,
val sunrise: Int?,
val sunset: Int?,
val min: Double? = null,
val max: Double? = null,
val average: Double? = null,
var feelsLike: Double?,
val pressure: Int?,
val humidity: Int?,
val dewPoint: Double?,
val windSpeed: Double?,
val windDeg: Int?,
val icon: String? = null,
val description: String? = null,
val main: String? = null,
val id: Int? = null,
val clouds: Int?,
val pop: Double?,
val uvi: Double?,
val rain: Double?
){
val dt: Int?,
val sunrise: Int?,
val sunset: Int?,
val min: Double? = null,
val max: Double? = null,
val average: Double? = null,
var feelsLike: Double?,
val pressure: Int?,
val humidity: Int?,
val dewPoint: Double?,
val windSpeed: Double?,
val windDeg: Int?,
val icon: String? = null,
val description: String? = null,
val main: String? = null,
val id: Int? = null,
val clouds: Int?,
val pop: Double?,
val uvi: Double?,
val rain: Double?
) {
constructor(dailyItem: DailyItem): this(
dailyItem.dt,
dailyItem.sunrise,
dailyItem.sunset,
dailyItem.temp?.min,
dailyItem.temp?.max,
dailyItem.temp?.day,
dailyItem.feelsLike?.day,
dailyItem.pressure,
dailyItem.humidity,
dailyItem.dewPoint,
dailyItem.windSpeed,
dailyItem.windDeg,
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
dailyItem.weather?.get(0)?.description,
dailyItem.weather?.get(0)?.main,
dailyItem.weather?.get(0)?.id,
dailyItem.clouds,
dailyItem.pop,
dailyItem.uvi,
dailyItem.rain
constructor(dailyItem: DailyItem) : this(
dailyItem.dt,
dailyItem.sunrise,
dailyItem.sunset,
dailyItem.temp?.min,
dailyItem.temp?.max,
dailyItem.temp?.day,
dailyItem.feelsLike?.day,
dailyItem.pressure,
dailyItem.humidity,
dailyItem.dewPoint,
dailyItem.windSpeed,
dailyItem.windDeg,
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
dailyItem.weather?.get(0)?.description,
dailyItem.weather?.get(0)?.main,
dailyItem.weather?.get(0)?.id,
dailyItem.clouds,
dailyItem.pop,
dailyItem.uvi,
dailyItem.rain
)

View File

@@ -3,26 +3,26 @@ package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
data class FullWeather(
val current: Current? = null,
val timezone: String? = null,
val timezoneOffset: Int? = null,
val hourly: List<Hour>? = null,
val daily: List<DailyWeather>? = null,
val lon: Double = 0.00,
val lat: Double = 0.00,
var locationString: String? = null,
var temperatureUnit: String? = null
val current: Current? = null,
val timezone: String? = null,
val timezoneOffset: Int? = null,
val hourly: List<Hour>? = null,
val daily: List<DailyWeather>? = null,
val lon: Double = 0.00,
val lat: Double = 0.00,
var locationString: String? = null,
var temperatureUnit: String? = null
) {
constructor(weatherResponse: WeatherResponse): this(
weatherResponse.current?.let { Current(it) },
weatherResponse.timezone,
weatherResponse.timezoneOffset,
weatherResponse.hourly?.subList(0,23)?.map { Hour(it) },
weatherResponse.daily?.map { DailyWeather(it) },
weatherResponse.lon,
weatherResponse.lat
)
constructor(weatherResponse: WeatherResponse) : this(
weatherResponse.current?.let { Current(it) },
weatherResponse.timezone,
weatherResponse.timezoneOffset,
weatherResponse.hourly?.subList(0, 23)?.map { Hour(it) },
weatherResponse.daily?.map { DailyWeather(it) },
weatherResponse.lon,
weatherResponse.lat
)
}

View File

@@ -10,7 +10,7 @@ data class Hour(
val dt: Int? = null,
val temp: Double? = null,
val icon: String? = null
): Parcelable {
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readValue(Int::class.java.classLoader) as? Int,

View File

@@ -3,26 +3,26 @@ package com.appttude.h_mal.atlas_weather.model.widget
import android.graphics.Bitmap
data class WidgetData(
val location: String?,
val icon: String?,
val currentTemp: String?,
val timeStamp: Long
val location: String?,
val icon: String?,
val currentTemp: String?,
val timeStamp: Long
)
data class InnerWidgetData(
val date: String?,
val icon: Bitmap?,
val highTemp: String?
val date: String?,
val icon: Bitmap?,
val highTemp: String?
)
data class InnerWidgetCellData(
val date: String?,
val icon: String?,
val highTemp: String?
val date: String?,
val icon: String?,
val highTemp: String?
)
data class WidgetWeatherCollection(
val widgetData: WidgetData,
val forecast: List<InnerWidgetCellData>
val widgetData: WidgetData,
val forecast: List<InnerWidgetCellData>
)

View File

@@ -14,11 +14,11 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
import com.appttude.h_mal.atlas_weather.utils.Event
import com.appttude.h_mal.atlas_weather.utils.displayToast
import com.appttude.h_mal.atlas_weather.utils.hide
import com.appttude.h_mal.atlas_weather.utils.show
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -27,6 +27,7 @@ import org.kodein.di.android.x.kodein
import org.kodein.di.generic.instance
import kotlin.properties.Delegates
@Suppress("EmptyMethod", "EmptyMethod")
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayoutId),
KodeinAware {

View File

@@ -1,8 +1,6 @@
package com.appttude.h_mal.atlas_weather.ui
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
@@ -12,7 +10,7 @@ import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.appttude.h_mal.atlas_weather.R
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_main_navigation.*
import kotlinx.android.synthetic.main.activity_main_navigation.toolbar
class MainActivity : AppCompatActivity() {
@@ -26,7 +24,7 @@ class MainActivity : AppCompatActivity() {
setSupportActionBar(toolbar)
navHost = supportFragmentManager
.findFragmentById(R.id.container) as NavHostFragment
.findFragmentById(R.id.container) as NavHostFragment
val navController = navHost.navController
navController.setGraph(R.navigation.main_navigation)

View File

@@ -6,31 +6,32 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
inline fun <reified T> parcelableCreator(
crossinline create: (Parcel) -> T) =
object : Parcelable.Creator<T> {
override fun createFromParcel(source: Parcel) = create(source)
override fun newArray(size: Int) = arrayOfNulls<T>(size)
}
crossinline create: (Parcel) -> T
) =
object : Parcelable.Creator<T> {
override fun createFromParcel(source: Parcel) = create(source)
override fun newArray(size: Int) = arrayOfNulls<T>(size)
}
suspend fun <T : Any?> tryOrNullSuspended(
call: suspend () -> T?
call: suspend () -> T?
): T? {
return try {
call.invoke()
}catch (e: Exception){
} catch (e: Exception) {
e.printStackTrace()
null
}
}
fun <T : Any?> tryOrNull(
call: () -> T?
call: () -> T?
): T? {
return try {
call.invoke()
}catch (e: Exception){
} catch (e: Exception) {
e.printStackTrace()
null
}
@@ -46,9 +47,9 @@ fun <T : Any?> tryOrNull(
*
* Both equal 2.
*/
suspend fun <T: Any> createSuspend(
call: () -> T?
): T?{
suspend fun <T : Any> createSuspend(
call: () -> T?
): T? {
return suspendCoroutine { cont ->
cont.resume(call())

View File

@@ -6,10 +6,10 @@ import androidx.navigation.NavDirections
import androidx.navigation.Navigation
import com.appttude.h_mal.atlas_weather.R
fun Fragment.navigateToFragment(newFragment: Fragment){
fun Fragment.navigateToFragment(newFragment: Fragment) {
childFragmentManager.beginTransaction()
.add(R.id.container, newFragment)
.commit()
.add(R.id.container, newFragment)
.commit()
}

View File

@@ -4,12 +4,10 @@ import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
fun isInternetAvailable(
context: Context
): Boolean {
fun isInternetAvailable(context: Context): Boolean {
var result = false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
connectivityManager?.let {
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
result = when {

View File

@@ -1,13 +1,13 @@
package com.appttude.h_mal.atlas_weather.utils
import android.os.Build
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.OffsetTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.Date
import java.util.Locale
fun Int.toDayString(): String {
return try {
@@ -46,13 +46,8 @@ fun Int.toSmallDayName(): String {
fun Int?.toTime(): String? {
return this?.makeMilliseconds()?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
OffsetTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("HH:mm"))
} else {
val date = Date(it)
val format = SimpleDateFormat("HH:mm", Locale.getDefault())
format.format(date)
}
OffsetTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC)
.format(DateTimeFormatter.ofPattern("HH:mm"))
}
}

View File

@@ -1,12 +1,12 @@
package com.appttude.h_mal.atlas_weather.utils
fun generateIconUrlString(icon: String?): String?{
fun generateIconUrlString(icon: String?): String? {
return icon?.let {
StringBuilder()
.append("http://openweathermap.org/img/wn/")
.append(it)
.append("@2x.png")
.toString()
.append("http://openweathermap.org/img/wn/")
.append(it)
.append("@2x.png")
.toString()
}
}

View File

@@ -2,7 +2,6 @@ package com.appttude.h_mal.atlas_weather.utils
import android.app.Activity
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -30,10 +29,10 @@ fun Fragment.displayToast(message: String) {
}
fun ViewGroup.generateView(layoutId: Int): View = LayoutInflater
.from(context)
.inflate(layoutId, this, false)
.from(context)
.inflate(layoutId, this, false)
fun ImageView.loadImage(url: String?){
fun ImageView.loadImage(url: String?) {
Picasso.get().load(url)
.placeholder(R.drawable.ic_baseline_cloud_queue_24)
.error(R.drawable.ic_baseline_cloud_off_24)

View File

@@ -13,10 +13,18 @@ class ApplicationViewModelFactory(
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
with(modelClass){
return when{
isAssignableFrom(WorldViewModel::class.java) -> WorldViewModel(locationProvider, repository)
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(locationProvider, repository)
with(modelClass) {
return when {
isAssignableFrom(WorldViewModel::class.java) -> WorldViewModel(
locationProvider,
repository
)
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(
locationProvider,
repository
)
else -> throw IllegalArgumentException("Unknown ViewModel class")
} as T
}

View File

@@ -17,7 +17,7 @@ import kotlinx.coroutines.launch
class MainViewModel(
private val locationProvider: LocationProvider,
private val repository: Repository
): WeatherViewModel(){
) : WeatherViewModel() {
val weatherLiveData = MutableLiveData<WeatherDisplay>()
@@ -35,8 +35,8 @@ class MainViewModel(
}
@RequiresPermission(value = Manifest.permission.ACCESS_COARSE_LOCATION)
fun fetchData(){
if (!repository.isSearchValid(CURRENT_LOCATION)){
fun fetchData() {
if (!repository.isSearchValid(CURRENT_LOCATION)) {
operationRefresh.postValue(Event(false))
return
}
@@ -48,16 +48,17 @@ class MainViewModel(
val latLong = locationProvider.getCurrentLatLong()
// Get weather from api
val weather = repository
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
val currentLocation = locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon)
.getWeatherFromApi(latLong.first.toString(), latLong.second.toString())
val currentLocation =
locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon)
val fullWeather = createFullWeather(weather, currentLocation)
val entityItem = EntityItem(CURRENT_LOCATION, fullWeather)
// Save data if not null
repository.saveLastSavedAt(CURRENT_LOCATION)
repository.saveCurrentWeatherToRoom(entityItem)
}catch (e: Exception){
} catch (e: Exception) {
operationError.postValue(Event(e.message!!))
}finally {
} finally {
operationState.postValue(Event(false))
operationRefresh.postValue(Event(false))
}

View File

@@ -15,6 +15,7 @@ import kotlinx.coroutines.launch
import java.io.IOException
const val ALL_LOADED = "all_loaded"
class WorldViewModel(
private val locationProvider: LocationProvider,
private val repository: Repository
@@ -40,7 +41,7 @@ class WorldViewModel(
}
}
fun getSingleLocation(locationName: String){
fun getSingleLocation(locationName: String) {
CoroutineScope(Dispatchers.IO).launch {
val entity = repository.getSingleWeather(locationName)
val item = WeatherDisplay(entity)
@@ -49,7 +50,7 @@ class WorldViewModel(
}
fun fetchDataForSingleLocation(locationName: String) {
if (!repository.isSearchValid(locationName)){
if (!repository.isSearchValid(locationName)) {
operationRefresh.postValue(Event(false))
return
}
@@ -72,7 +73,7 @@ class WorldViewModel(
CoroutineScope(Dispatchers.IO).launch {
operationState.postValue(Event(true))
// Check if location exists
if (repository.getSavedLocations().contains(locationName)){
if (repository.getSavedLocations().contains(locationName)) {
operationError.postValue(Event("$locationName already exists"))
return@launch
}
@@ -82,8 +83,12 @@ class WorldViewModel(
val entityItem = createWeatherEntity(locationName)
// retrieved location name
val retrievedLocation = locationProvider.getLocationNameFromLatLong(entityItem.weather.lat, entityItem.weather.lon, LocationType.City)
if (repository.getSavedLocations().contains(retrievedLocation)){
val retrievedLocation = locationProvider.getLocationNameFromLatLong(
entityItem.weather.lat,
entityItem.weather.lon,
LocationType.City
)
if (repository.getSavedLocations().contains(retrievedLocation)) {
operationError.postValue(Event("$retrievedLocation already exists"))
return@launch
}
@@ -101,7 +106,7 @@ class WorldViewModel(
}
fun fetchAllLocations() {
if (!repository.isSearchValid(ALL_LOADED)){
if (!repository.isSearchValid(ALL_LOADED)) {
operationRefresh.postValue(Event(false))
return
}
@@ -117,7 +122,8 @@ class WorldViewModel(
val entity = createWeatherEntity(locationName)
list.add(entity)
repository.saveLastSavedAt(locationName)
} catch (e: IOException) { }
} catch (e: IOException) {
}
}
repository.saveWeatherListToRoom(list)
repository.saveLastSavedAt(ALL_LOADED)
@@ -129,12 +135,12 @@ class WorldViewModel(
}
}
fun deleteLocation(locationName: String){
fun deleteLocation(locationName: String) {
CoroutineScope(Dispatchers.IO).launch {
operationState.postValue(Event(true))
try {
val success = repository.deleteSavedWeatherEntry(locationName)
if (!success){
if (!success) {
operationError.postValue(Event("Failed to delete"))
}
} catch (e: IOException) {
@@ -148,7 +154,7 @@ class WorldViewModel(
private suspend fun getWeather(locationName: String): WeatherResponse {
// Get location
val latLong =
locationProvider.getLatLongFromLocationName(locationName)
locationProvider.getLatLongFromLocationName(locationName)
val lat = latLong.first
val lon = latLong.second
@@ -158,8 +164,9 @@ class WorldViewModel(
private suspend fun createWeatherEntity(locationName: String): EntityItem {
val weather = getWeather(locationName)
val location = locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon, LocationType.City)
val location =
locationProvider.getLocationNameFromLatLong(weather.lat, weather.lon, LocationType.City)
val fullWeather = createFullWeather(weather, location)
return createWeatherEntity(location,fullWeather)
return createWeatherEntity(location, fullWeather)
}
}

View File

@@ -5,11 +5,11 @@ import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherRe
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
abstract class WeatherViewModel : ViewModel(){
abstract class WeatherViewModel : ViewModel() {
fun createFullWeather(
weather: WeatherResponse,
location: String
weather: WeatherResponse,
location: String
): FullWeather {
return FullWeather(weather).apply {
temperatureUnit = "°C"
@@ -18,9 +18,9 @@ abstract class WeatherViewModel : ViewModel(){
}
fun createWeatherEntity(
locationId: String,
weather: FullWeather
): EntityItem{
locationId: String,
weather: FullWeather
): EntityItem {
weather.apply {
locationString = locationId
}

View File

@@ -8,7 +8,6 @@ import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Intent
import android.os.Build
import android.widget.RemoteViews
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
@@ -34,8 +33,8 @@ abstract class BaseWidgetServiceIntentClass<T : AppWidgetProvider> : JobIntentSe
// Create pending intent commonly used for 'click to update' features
fun createUpdatePendingIntent(
appWidgetProvider: Class<T>,
appWidgetId: Int
appWidgetProvider: Class<T>,
appWidgetId: Int
): PendingIntent? {
val seconds = (System.currentTimeMillis() / 1000L).toInt()
val intentUpdate = Intent(applicationContext, appWidgetProvider)
@@ -43,11 +42,12 @@ abstract class BaseWidgetServiceIntentClass<T : AppWidgetProvider> : JobIntentSe
val idArray = intArrayOf(appWidgetId)
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(this, seconds, intentUpdate, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
} else {
PendingIntent.getBroadcast(this, seconds, intentUpdate, PendingIntent.FLAG_UPDATE_CURRENT)
}
return PendingIntent.getBroadcast(
this,
seconds,
intentUpdate,
PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
)
}
/**
@@ -58,15 +58,15 @@ abstract class BaseWidgetServiceIntentClass<T : AppWidgetProvider> : JobIntentSe
val clickIntentTemplate = Intent(this, activityClass)
return TaskStackBuilder.create(this)
.addNextIntentWithParentStack(clickIntentTemplate)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
.addNextIntentWithParentStack(clickIntentTemplate)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
}
fun setImageView(
path: String?,
views: RemoteViews,
@IdRes viewId: Int,
appWidgetId: Int
path: String?,
views: RemoteViews,
@IdRes viewId: Int,
appWidgetId: Int
) {
CoroutineScope(Dispatchers.Main).launch {
Picasso.get().load(path).into(views, viewId, intArrayOf(appWidgetId))

View File

@@ -11,7 +11,11 @@ import com.appttude.h_mal.atlas_weather.widget.WidgetJobServiceIntent.Companion.
*/
class NewAppWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
loadWidget(context)
@@ -23,9 +27,9 @@ class NewAppWidget : AppWidgetProvider() {
loadWidget(context)
}
override fun onDisabled(context: Context) { }
override fun onDisabled(context: Context) {}
private fun loadWidget(context: Context){
private fun loadWidget(context: Context) {
val mIntent = Intent(context, WidgetJobServiceIntent::class.java)
enqueueWork(context, mIntent)
}

View File

@@ -10,17 +10,16 @@ import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.icu.text.SimpleDateFormat
import android.os.PowerManager
import android.widget.RemoteViews
import android.os.Build
import androidx.core.app.ActivityCompat.checkSelfPermission
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.widget.WidgetState.*
import com.appttude.h_mal.atlas_weather.widget.WidgetState.Companion.getWidgetState
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
import com.appttude.h_mal.atlas_weather.widget.WidgetState.*
import com.appttude.h_mal.atlas_weather.widget.WidgetState.Companion.getWidgetState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -34,6 +33,7 @@ import java.util.*
* Implementation of a JobIntentService used for home screen widget
*/
const val HALF_DAY = 43200000L
class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
private val kodein = LateInitKodein()
@@ -77,7 +77,7 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
val pm = getSystemService(POWER_SERVICE) as PowerManager
val isScreenOn = pm.isInteractive
val locationGranted =
checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
val internetAvailable = isInternetAvailable(this.applicationContext)
return getWidgetState(locationGranted, isScreenOn, internetAvailable)
@@ -103,8 +103,8 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
}
private fun setupView(
appWidgetId: Int,
collection: WidgetWeatherCollection?
appWidgetId: Int,
collection: WidgetWeatherCollection?
) {
val views = createRemoteView(R.layout.weather_app_widget)
setLastUpdated(views, collection?.widgetData?.timeStamp)
@@ -118,17 +118,17 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
}
override fun bindErrorView(
widgetId: Int,
views: RemoteViews,
data: Any?
widgetId: Int,
views: RemoteViews,
data: Any?
) {
bindEmptyView(widgetId, views, data)
}
override fun bindEmptyView(
widgetId: Int,
views: RemoteViews,
data: Any?
widgetId: Int,
views: RemoteViews,
data: Any?
) {
val clickUpdate = createUpdatePendingIntent(NewAppWidget::class.java, widgetId)
@@ -167,6 +167,7 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
}
}
@SuppressLint("DiscouragedApi")
private fun loadCells(
appWidgetId: Int,
remoteViews: RemoteViews,
@@ -189,7 +190,7 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
}
private fun setLastUpdated(views: RemoteViews, timeStamp: Long?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && timeStamp != null) {
if (timeStamp != null) {
val difference = System.currentTimeMillis().minus(timeStamp)
val status = if (difference > HALF_DAY) {

View File

@@ -9,9 +9,9 @@ enum class WidgetState {
companion object {
fun getWidgetState(
locationAvailable: Boolean,
screenOn: Boolean,
connectionAvailable: Boolean
locationAvailable: Boolean,
screenOn: Boolean,
connectionAvailable: Boolean
): WidgetState {
return if (!locationAvailable)
NO_LOCATION

View File

@@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/black" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="128dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="128dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h0.71C7.37,7.69 9.48,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3s-1.34,3 -3,3z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM19,18H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h0.71C7.37,7.69 9.48,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3s-1.34,3 -3,3z" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z" />
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

View File

@@ -1,24 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="94dp"
android:height="275dp"
android:viewportWidth="94.0"
android:viewportHeight="275.0">
android:width="68dp"
android:height="200dp"
android:viewportWidth="94.0"
android:viewportHeight="275.0">
<path
android:fillColor="#FF000000"
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121
45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968
V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>
V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z" />
<path
android:name="inner"
android:fillColor="#ff0000"
android:pathData="M305.949,424.6c0-1.9,0-1.9,0-3.799v-95.602c0-11.5-7.6-19.1-19.099-19.1c-11.5,0-19.1,7.6-19.1,19.1v95.602
c0,1.898,0,1.898,0,3.799c-23,7.701-38.2,28.701-38.2,53.5c0,32.5,24.9,57.4,57.4,57.4c32.499,0,57.399-24.9,57.399-57.4
C344.25,453.301,328.949,432.301,305.949,424.6z"/>
<path android:fillColor="#000000"
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121 45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968 V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z"/>
C344.25,453.301,328.949,432.301,305.949,424.6z" />
<path
android:fillColor="#000000"
android:pathData="M75.1515587070021,188.25562584016225 V29.53767503746845 c0,-14.982132974790945 -11.77674089383421,-26.46075177701539 -27.147989048437097,-26.46075177701539 c-15.371248154602887,0 -27.147989048437097,12.354497345366072 -27.147989048437097,26.46075177701539 v158.672312920709 c-10.878114078642042,7.929466747673202 -18.067128600179394,21.15938164747398 -18.067128600179394,35.2656360791233 c0,24.66289582004048 19.911678378731743,44.07052038123121 45.21511764861649,44.07052038123121 c25.303439269884752,0 45.21464468713481,-19.407624561190733 45.21464468713481,-44.07052038123121 C93.21821434569982,209.36936960565146 85.98237663747612,196.1850925878354 75.1515587070021,188.25562584016225 zM48.003569658565006,258.78689799840873 c-19.911678378731743,0 -36.1815533485268,-15.857089540518738 -36.1815533485268,-35.2656360791233 c0,-13.229914899800779 7.236310669705359,-24.66289582004048 18.067128600179394,-30.83922251530968 V29.53767503746845 c0,-9.680762845249534 8.134937484897527,-17.60976860421582 18.067128600179394,-17.60976860421582 s18.06665563869771,7.929005758966285 18.06665563869771,17.60976860421582 v163.09734351840189 c10.878114078642042,6.177248672683036 18.06760156166107,17.610229592922735 18.06760156166107,30.840144492723518 C84.1851230070918,242.88278760978457 67.91477507581507,258.78689799840873 48.003569658565006,258.78689799840873 z" />
<path
android:name="inner"
android:fillColor="#ff0000"
android:pathData="M57.03666099717303,198.81272821726031 c0,-0.8758785431416244 0,-0.8758785431416244 0,-1.7512960975763323 v-44.07144235864505 c0,-5.301370129541411 -3.5945072607686748,-8.80488430210791 -9.033091338608017,-8.80488430210791 c-5.439057039321021,0 -9.033564300089697,3.503514172566498 -9.033564300089697,8.80488430210791 v44.07144235864505 c0,0.8749565657277916 0,0.8749565657277916 0,1.7512960975763323 c-10.878114078642042,3.550074031965079 -18.067128600179394,13.230836877214614 -18.067128600179394,24.66289582004048 c0,14.982132974790945 11.77674089383421,26.46075177701539 27.147989048437097,26.46075177701539 c15.370775193121208,0 27.147516086955417,-11.478618802224446 27.147516086955417,-26.46075177701539 C75.1515587070021,212.04356509447487 67.91477507581507,202.36280224922535 57.03666099717303,198.81272821726031 z"/>
android:pathData="M57.03666099717303,198.81272821726031 c0,-0.8758785431416244 0,-0.8758785431416244 0,-1.7512960975763323 v-44.07144235864505 c0,-5.301370129541411 -3.5945072607686748,-8.80488430210791 -9.033091338608017,-8.80488430210791 c-5.439057039321021,0 -9.033564300089697,3.503514172566498 -9.033564300089697,8.80488430210791 v44.07144235864505 c0,0.8749565657277916 0,0.8749565657277916 0,1.7512960975763323 c-10.878114078642042,3.550074031965079 -18.067128600179394,13.230836877214614 -18.067128600179394,24.66289582004048 c0,14.982132974790945 11.77674089383421,26.46075177701539 27.147989048437097,26.46075177701539 c15.370775193121208,0 27.147516086955417,-11.478618802224446 27.147516086955417,-26.46075177701539 C75.1515587070021,212.04356509447487 67.91477507581507,202.36280224922535 57.03666099717303,198.81272821726031 z" />
</vector>

View File

@@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment">
android:orientation="vertical">
<LinearLayout
@@ -18,20 +17,21 @@
<EditText
android:id="@+id/location_name_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:ems="10"
android:hint="@string/location_name"
android:inputType="textPersonName"
android:maxLines="2"
tools:text="Greater London"/>
tools:text="Greater London"
android:autofillHints="addressLocality" />
<Button
android:id="@+id/submit"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_gravity="end"
android:text="@string/submit"
android:textColor="#ffffff"
android:textStyle="bold" />
@@ -44,11 +44,12 @@
android:layout_height="match_parent"
android:background="@android:color/black"
android:visibility="gone">
<ProgressBar
android:layout_gravity="center"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>

View File

@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -15,13 +18,16 @@
<FrameLayout style="@style/icon_frame_style">
<ImageView
android:src="@drawable/somethingnew"
style="@style/icon_style__further_deatils" />
style="@style/icon_style__further_details"
android:contentDescription="@string/temperature"
android:src="@drawable/somethingnew" />
</FrameLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -41,16 +47,16 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Max: " />
android:text="@string/max_header" />
<TextView
android:id="@+id/maxtemp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="85%"
/>
tools:text="85%" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -59,16 +65,17 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Average: " />
android:text="@string/average_header" />
<TextView
android:id="@+id/averagetemp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="11mm"
/>
tools:ignore="InOrMmUsage"
tools:text="11mm" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -77,15 +84,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Min: " />
android:text="@string/min_header" />
<TextView
android:id="@+id/minimumtemp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="11mm"
/>
tools:ignore="InOrMmUsage"
tools:text="11mm" />
</LinearLayout>
@@ -94,21 +101,23 @@
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
style="@style/icon_frame_style">
<FrameLayout style="@style/icon_frame_style">
<ImageView
android:src="@drawable/breeze"
style="@style/icon_style__further_deatils" />
style="@style/icon_style__further_details"
android:contentDescription="@string/image_string"
android:src="@drawable/breeze" />
</FrameLayout>
<RelativeLayout
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_weight="2">
<LinearLayout
android:layout_width="match_parent"
@@ -118,41 +127,42 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_weight="3">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Wind: " />
android:text="@string/wind_header" />
<TextView
android:id="@+id/windtext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="7mph"
/>
tools:text="7mph" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
style="@style/icon_frame_style">
<FrameLayout style="@style/icon_frame_style">
<ImageView
android:src="@drawable/water_drop"
style="@style/icon_style__further_deatils" />
style="@style/icon_style__further_details"
android:contentDescription="@string/image_string"
android:src="@drawable/water_drop" />
</FrameLayout>
<RelativeLayout
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_weight="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -172,34 +182,34 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Humidity: " />
android:text="@string/humidity_header" />
<TextView
android:id="@+id/humiditytext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="85%"
/>
tools:text="85%" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Precip: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/preciptext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="11mm"
/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/precip_header" />
<TextView
android:id="@+id/preciptext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
tools:ignore="InOrMmUsage"
tools:text="11mm" />
</LinearLayout>
</LinearLayout>
@@ -207,21 +217,24 @@
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
style="@style/icon_frame_style">
<FrameLayout style="@style/icon_frame_style">
<ImageView
android:src="@drawable/cloud_symbol"
style="@style/icon_style__further_deatils" />
style="@style/icon_style__further_details"
android:contentDescription="@string/image_string"
android:src="@drawable/cloud_symbol" />
</FrameLayout>
<RelativeLayout
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_weight="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -241,14 +254,14 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Cloud:" />
android:text="@string/cloud_header" />
<TextView
android:id="@+id/cloudtext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="06:12pm" />
tools:text="06:12pm" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -256,21 +269,24 @@
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
style="@style/icon_frame_style">
<FrameLayout style="@style/icon_frame_style">
<ImageView
android:src="@drawable/sunrise"
style="@style/icon_style__further_deatils" />
style="@style/icon_style__further_details"
android:contentDescription="@string/image_string"
android:src="@drawable/sunrise" />
</FrameLayout>
<RelativeLayout
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_weight="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -283,22 +299,21 @@
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="UV: " />
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="@string/uv_header" />
<TextView
android:id="@+id/uvtext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="7"
/>
android:id="@+id/uvtext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
tools:text="7" />
</LinearLayout>
<LinearLayout
@@ -309,15 +324,16 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Sunrise:" />
android:text="@string/sunrise_header" />
<TextView
android:id="@+id/sunrisetext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="05:30am" />
tools:text="05:30am" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -326,15 +342,14 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Sunset:" />
android:text="@string/sunset_header" />
<TextView
android:id="@+id/sunsettext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="06:12pm"
/>
tools:text="06:12pm" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -16,7 +15,7 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/AppTheme.PopupOverlay"
tools:title="Atlas Weather"/>
tools:title="Atlas Weather" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
@@ -39,7 +38,7 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:layout="@layout/fragment_home"/>
tools:layout="@layout/fragment_home" />
<ProgressBar
android:layout_width="wrap_content"

View File

@@ -1,72 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="6dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="6dp"
android:layout_height="wrap_content">
android:orientation="horizontal">
<ImageView
android:id="@+id/db_icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:contentDescription="@string/icon"
tools:src="@drawable/cloud_symbol"
tools:tint="@color/colour_one" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/db_condition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="broken clouds" />
<TextView
android:id="@+id/db_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
tools:text="City of London" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="4dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/db_icon"
android:layout_width="64dp"
android:layout_height="64dp"
tools:src="@drawable/cloud_symbol"
tools:tint="@color/colour_one"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="15dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/db_condition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="broken clouds" />
<TextView
android:id="@+id/db_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
tools:text="City of London" />
</LinearLayout>
<LinearLayout
<TextView
android:id="@+id/db_main_temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginRight="4dp"
android:orientation="horizontal">
<TextView
android:id="@+id/db_main_temp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="28sp"
tools:text="28" />
<TextView
android:id="@+id/db_temp_unit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="°" />
</LinearLayout>
android:layout_height="match_parent"
android:gravity="center"
android:textSize="28sp"
tools:text="28" />
<TextView
android:id="@+id/db_temp_unit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/degree_sign" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -5,35 +5,37 @@
android:layout_height="match_parent">
<ImageView
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.45"
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/image_string"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
app:srcCompat="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/header_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/icon"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:text="@string/retrieve_warning"
android:textSize="16sp"
android:text="Unable to retrieve weather"/>
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon" />
<TextView
android:id="@+id/body_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/header_text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:gravity="center"
app:layout_constraintWidth_percent="0.65"
android:layout_marginTop="6dp"
android:gravity="center"
android:text="@string/empty_retrieve_warning"
android:textSize="12sp"
android:text="Make sure you are connected to the internet and have location permissions granted"/>
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_text"
app:layout_constraintWidth_percent="0.65" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,26 +6,26 @@
tools:context="com.appttude.h_mal.atlas_weather.ui.world.WorldFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/world_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
android:divider="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:id="@+id/world_recycler"
android:divider="@null"
tools:listitem="@layout/db_list_item">
</androidx.recyclerview.widget.RecyclerView>
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/db_list_item" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="20dp"
android:layout_alignParentBottom="true"
android:layout_marginEnd="20dp"
app:srcCompat="@drawable/ic_baseline_add_24"/>
android:layout_marginBottom="20dp"
android:contentDescription="@string/image_string"
app:srcCompat="@drawable/ic_baseline_add_24" />
<FrameLayout
android:id="@+id/progressBar"
@@ -34,10 +34,11 @@
android:background="@android:color/black"
android:visibility="gone"
tools:visibility="visible">
<ProgressBar
android:layout_gravity="center"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</RelativeLayout>

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:id="@+id/world_recycler"
android:divider="@null">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginBottom="36dp"
android:layout_marginEnd="24dp"
android:clickable="true"
app:srcCompat="@android:drawable/ic_input_add"
android:tint="@android:color/white"
app:elevation="0dp"
android:focusable="true" />
<ProgressBar
android:id="@+id/progressBar2"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="gone"
tools:visibility="visible"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,22 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/swipe_refresh">
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/forecast_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/forecast_listview"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/db_list_item">
</androidx.recyclerview.widget.RecyclerView>
tools:listitem="@layout/db_list_item"></androidx.recyclerview.widget.RecyclerView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@@ -27,11 +26,12 @@
android:background="@android:color/black"
android:visibility="gone"
tools:visibility="gone">
<ProgressBar
android:layout_gravity="center"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</RelativeLayout>

View File

@@ -1,5 +1,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/whole_widget_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -10,7 +11,6 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:orientation="horizontal">
@@ -51,8 +51,9 @@
android:layout_above="@id/location_container"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:layout_marginLeft="32dp"
android:layout_marginStart="32dp"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<LinearLayout
@@ -62,25 +63,27 @@
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:layout_marginBottom="1dp"
android:orientation="horizontal">
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/location_icon"
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="center"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
android:adjustViewBounds="true"
android:tint="@android:color/white"
android:contentDescription="@string/image_string"
app:tint="@android:color/white"
tools:src="@drawable/location_flag" />
<TextView
android:id="@+id/widget_current_location"
style="@style/widget_light_home_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:maxWidth="180dp"
android:maxLines="1"
style="@style/widget_light_home_text"
tools:text="Hammersmith Bridge" />
</LinearLayout>
@@ -88,15 +91,16 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginRight="12dp"
android:orientation="vertical">
android:layout_marginEnd="12dp"
android:orientation="vertical"
tools:ignore="RelativeOverlap">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_gravity="end"
android:orientation="horizontal">
<TextView
@@ -127,7 +131,6 @@
android:id="@+id/widget_listview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:columnCount="5"
android:rowCount="1">
@@ -153,6 +156,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
@@ -186,6 +190,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
@@ -219,6 +224,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
@@ -252,6 +258,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
@@ -284,6 +291,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView

View File

@@ -11,23 +11,24 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:textSize="12sp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:textSize="12sp"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
android:contentDescription="@string/image_string"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
@@ -35,14 +36,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:includeFontPadding="false"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="12sp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:textSize="12sp"
tools:text="20" />

View File

@@ -12,8 +12,7 @@
android:layout_gravity="center"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:text="Loading \nforecast..." />
android:text="@string/loading_nforecast"
android:textColor="#ffffff" />
</LinearLayout>

View File

@@ -4,8 +4,8 @@
tools:context=".legacy.ui.home.MainActivity">
<item
android:id="@+id/settings_fragment"
android:icon="@drawable/ic_round_settings_24"
android:orderInCategory="100"
android:title="@string/action_settings"
android:icon="@drawable/ic_round_settings_24"
app:showAsAction="ifRoom" />
</menu>

View File

@@ -5,12 +5,12 @@
android:id="@+id/nav_home"
android:icon="@drawable/ic_baseline_home_24"
android:title="@string/title_home"
app:showAsAction="ifRoom|withText"/>
app:showAsAction="ifRoom|withText" />
<item
android:id="@+id/nav_world"
android:icon="@drawable/ic_baseline_public_24"
android:title="@string/title_world"
app:showAsAction="always|withText"/>
app:showAsAction="always|withText" />
</menu>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
</resources>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="widget_light_text">
<item name="android:layout_gravity">center</item>
<item name="android:autoSizeMaxTextSize">100sp</item>
<item name="android:autoSizeMinTextSize">8sp</item>
<item name="android:autoSizeStepGranularity">2sp</item>
<item name="android:autoSizeTextType">uniform</item>
<item name="android:gravity">center</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textColor">#ffffff</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@@ -11,9 +11,23 @@
<string name="location_name">Enter Location name</string>
<string name="degrees_c">°C</string>
<string name="degrees">°</string>
<string name="min">Min:</string>
<string name="max">Max:</string>
<string name="average">Average:</string>
<string name="cancel">Cancel</string>
<string name="ok">OK</string>
<string name="icon">icon</string>
<string name="degree_sign">°</string>
<string name="temperature">Temperature</string>
<string name="wind_header">Wind:</string>
<string name="image_string">image</string>
<string name="humidity_header">Humidity:</string>
<string name="precip_header">Precip:</string>
<string name="sunset_header">Sunset:</string>
<string name="sunrise_header">Sunrise:</string>
<string name="uv_header">UV:</string>
<string name="cloud_header">Cloud:</string>
<string name="min_header">Min:</string>
<string name="average_header">Average:</string>
<string name="max_header">Max:</string>
<string name="loading_nforecast">Loading \nforecast…</string>
<string name="retrieve_warning">Unable to retrieve weather</string>
<string name="empty_retrieve_warning">Make sure you are connected to the internet and have location permissions granted</string>
</resources>

View File

@@ -28,7 +28,7 @@
<item name="android:textSize">12sp</item>
</style>
<style name="icon_style__further_deatils">
<style name="icon_style__further_details">
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:adjustViewBounds">true</item>