diff --git a/.gitignore b/.gitignore index 47da38f68..9ea96b57d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ API_KEY.txt google-services.json /.privado/ /.detekt -/.kotlin \ No newline at end of file +/.kotlin +/.skills \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 6a5687ae8..c0cce840a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,7 @@ plugins { id 'com.android.application' id 'androidx.navigation.safeargs' - id 'kotlin-android' - id 'kotlin-kapt' + id 'com.android.legacy-kapt' id 'com.google.devtools.ksp' } @@ -18,11 +17,11 @@ android { targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() // NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code (Android: 0, WearOS: 1) // ex) 345100131 = (34, 5.10, 013, 0) - versionCode 365130140 - versionName "5.13.0" + versionCode 375140110 + versionName "5.14.0" vectorDrawables { - useSupportLibrary true + useSupportLibrary = true } } @@ -47,18 +46,19 @@ android { dataBinding true viewBinding true buildConfig true + resValues true } compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true // Sets Java compatibility to Java 8 - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } kotlin { - jvmToolchain(17) + jvmToolchain(21) } sourceSets { diff --git a/app/src/androidTestFullgms/java/com/thewizrd/simpleweather/test/UnitTests.kt b/app/src/androidTestFullgms/java/com/thewizrd/simpleweather/test/UnitTests.kt index 21c556d02..58b8d04dc 100644 --- a/app/src/androidTestFullgms/java/com/thewizrd/simpleweather/test/UnitTests.kt +++ b/app/src/androidTestFullgms/java/com/thewizrd/simpleweather/test/UnitTests.kt @@ -682,6 +682,17 @@ class UnitTests { settingsManager.setPersonalKey(WeatherAPI.GOOGLE, false) } + @Throws(WeatherException::class) + @Test + fun getOpenMeteoWeather() { + runBlocking(Dispatchers.Default) { + val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.OPENMETEO) + val weather = + getWeather(provider, Coordinate(52.52, 13.41)) // ~ Berlin + assertTrue(weather.isValid && WeatherUiModel(weather).isValid) + } + } + @Throws(WeatherException::class) @Test fun getGooglePollen() { diff --git a/app/src/androidTestNongms/java/com/thewizrd/simpleweather/test/UnitTests.kt b/app/src/androidTestNongms/java/com/thewizrd/simpleweather/test/UnitTests.kt index 8fd5a3e81..5663823ad 100644 --- a/app/src/androidTestNongms/java/com/thewizrd/simpleweather/test/UnitTests.kt +++ b/app/src/androidTestNongms/java/com/thewizrd/simpleweather/test/UnitTests.kt @@ -12,20 +12,23 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.thewizrd.common.CommonModule import com.thewizrd.common.commonModule import com.thewizrd.common.controls.WeatherUiModel -import com.thewizrd.shared_resources.* +import com.thewizrd.shared_resources.AppState +import com.thewizrd.shared_resources.ApplicationLib +import com.thewizrd.shared_resources.SharedModule +import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.locationdata.WeatherLocationProvider import com.thewizrd.shared_resources.locationdata.toLocationData import com.thewizrd.shared_resources.preferences.SettingsManager +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Coordinate import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.utils.JSONParser import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherProvider import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.viewmodels.WeatherNowViewModel import com.thewizrd.weather_api.aqicn.AQICNProvider import com.thewizrd.weather_api.google.location.getFromLocationAsync import com.thewizrd.weather_api.google.location.getFromLocationNameAsync @@ -41,7 +44,10 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.junit.After -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -49,7 +55,7 @@ import java.io.IOException import java.time.Duration import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -import java.util.* +import java.util.Locale @RunWith(AndroidJUnit4::class) class UnitTests { @@ -546,4 +552,15 @@ class UnitTests { assertTrue(weather.isValid && WeatherUiModel(weather).isValid) } } + + @Throws(WeatherException::class) + @Test + fun getOpenMeteoWeather() { + runBlocking(Dispatchers.Default) { + val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.OPENMETEO) + val weather = + getWeather(provider, Coordinate(52.52, 13.41)) // ~ Berlin + assertTrue(weather.isValid && WeatherUiModel(weather).isValid) + } + } } \ No newline at end of file diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt index cd430fb4c..e0e5764a8 100644 --- a/app/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt @@ -9,6 +9,7 @@ import com.google.firebase.remoteconfig.ConfigUpdate import com.google.firebase.remoteconfig.ConfigUpdateListener import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfigException +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.utils.AnalyticsProps import com.thewizrd.shared_resources.utils.ContextUtils.isLargeTablet @@ -38,7 +39,7 @@ object FirebaseConfigurator { isCrashlyticsCollectionEnabled = true sendUnsentReports() } - FirebaseRemoteConfig.getInstance().setDefaultsAsync(R.xml.remote_config_defaults) + FirebaseRemoteConfig.getInstance().setDefaultsAsync(sharedRes.xml.remote_config_defaults) if (!BuildConfig.DEBUG) { Logger.registerLogger(CrashlyticsLoggingTree()) diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt index 920222391..cbb2363d9 100644 --- a/app/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt @@ -32,6 +32,7 @@ import com.thewizrd.simpleweather.utils.NavigationUtils.safeNavigate import kotlinx.coroutines.launch import kotlinx.coroutines.tasks.await import timber.log.Timber +import com.thewizrd.extras.R as extrasRes fun initializeExtras() { extrasModule.initialize() @@ -84,7 +85,7 @@ fun BaseSettingsFragment.navigateToPremiumFragment() { showSnackbar( Snackbar.make( rootView.context, - R.string.message_premium_required, + extrasRes.string.message_premium_required, Snackbar.Duration.SHORT ), null @@ -102,7 +103,7 @@ fun SettingsFragment.IconsFragment.navigateUnsupportedIconPack() { showSnackbar( Snackbar.make( rootView.context, - R.string.message_premium_required, + extrasRes.string.message_premium_required, Snackbar.Duration.SHORT ), null @@ -124,7 +125,7 @@ fun isPremiumSupported(): Boolean { } fun isRadarInteractionEnabled(): Boolean { - return extrasModule.isAtLeastProEnabled() + return true } fun areNotificationExtrasEnabled(): Boolean { @@ -133,8 +134,8 @@ fun areNotificationExtrasEnabled(): Boolean { fun SettingsFragment.createPremiumPreference(): Preference { val premiumPref = Preference(requireContext()).apply { - title = context.getString(R.string.pref_title_premium) - summary = context.getString(R.string.pref_summary_premium) + title = context.getString(extrasRes.string.pref_title_premium) + summary = context.getString(extrasRes.string.pref_summary_premium) setIcon(R.drawable.ic_star_24dp) order = 0 } @@ -147,7 +148,7 @@ fun SettingsFragment.createPremiumPreference(): Preference { showSnackbar( Snackbar.make( rootView.context, - R.string.message_premium_required, + extrasRes.string.message_premium_required, Snackbar.Duration.SHORT ), null diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt index 07ec11bba..ca497a007 100644 --- a/app/src/fullgms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt @@ -333,7 +333,7 @@ class RainViewerViewProvider(context: Context, rootView: ViewGroup) : MapTileRad */ private fun checkTileExists(x: Int, y: Int, zoom: Int): Boolean { val minZoom = MIN_ZOOM_LEVEL - val maxZoom = MAX_ZOOM_LEVEL + val maxZoom = 7 return zoom in minZoom..maxZoom } diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt index 9cc99b86b..d1d2db53a 100644 --- a/app/src/fullgms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt @@ -20,6 +20,7 @@ import com.thewizrd.shared_resources.utils.Coordinate import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.simpleweather.databinding.RadarAnimateContainerBinding +import com.thewizrd.simpleweather.extras.isRadarInteractionEnabled import com.thewizrd.simpleweather.radar.CachingUrlTileProvider import com.thewizrd.simpleweather.radar.MapTileRadarViewProvider import com.thewizrd.weather_api.keys.Keys @@ -88,7 +89,7 @@ class TomorrowIoRadarViewProvider(context: Context, rootView: ViewGroup) : override fun updateRadarView() { radarContainerBinding!!.radarToolbar.visibility = - if (interactionsEnabled()/* && isRadarInteractionEnabled()*/) View.VISIBLE else View.GONE + if (interactionsEnabled() && isRadarInteractionEnabled()) View.VISIBLE else View.GONE mapView.getMapAsync(this) } diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt new file mode 100644 index 000000000..2604c8407 --- /dev/null +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt @@ -0,0 +1,302 @@ +package com.thewizrd.simpleweather.radar.weatherapi + +import android.content.Context +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.format.DateFormat +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import androidx.core.view.isEmpty +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.model.TileOverlay +import com.google.android.gms.maps.model.TileOverlayOptions +import com.google.android.material.slider.Slider +import com.thewizrd.shared_resources.DateTimeConstants +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.DateTimeUtils +import com.thewizrd.simpleweather.databinding.RadarAnimateContainerBinding +import com.thewizrd.simpleweather.extras.isRadarInteractionEnabled +import com.thewizrd.simpleweather.radar.CachingUrlTileProvider +import com.thewizrd.simpleweather.radar.MapTileRadarViewProvider +import java.time.ZoneOffset +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit + +@RequiresApi(value = Build.VERSION_CODES.LOLLIPOP) +class WeatherApiRadarViewProvider(context: Context, rootView: ViewGroup) : + MapTileRadarViewProvider(context, rootView) { + companion object { + private const val DEFAULT_TRANSPARENCY = 0.5f + } + + private val availableRadarFrames: MutableList + private val radarLayers: MutableMap + + private var googleMap: GoogleMap? = null + private var radarContainerBinding: RadarAnimateContainerBinding? = null + + private var animationPosition = 0 + private val mMainHandler: Handler + private var mProcessingFrames: Boolean = false + + init { + availableRadarFrames = ArrayList() + radarLayers = HashMap() + mMainHandler = Handler(Looper.getMainLooper()) + } + + override fun onCreateView(savedInstanceState: Bundle?) { + super.onCreateView(savedInstanceState) + + radarContainerBinding = RadarAnimateContainerBinding.inflate(LayoutInflater.from(context)) + viewContainer.addView(radarContainerBinding!!.root) + + radarContainerBinding!!.playButton.addOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + mMainHandler.post(animationRunnable) + } else { + mMainHandler.removeCallbacks(animationRunnable) + } + } + + radarContainerBinding!!.animationSeekbar.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser -> + if (fromUser) { + mMainHandler.removeCallbacks(animationRunnable) + showFrame(value.toInt()) + } + }) + + radarContainerBinding!!.animationSeekbar.value = 0f + if (radarContainerBinding!!.radarContainer.isEmpty()) { + radarContainerBinding!!.radarContainer.addView(mapView) + } + } + + override fun onPause() { + super.onPause() + // Remove animation callbacks + radarContainerBinding?.playButton?.isChecked = false + } + + override fun onViewCreated(coordinates: Coordinate) { + super.onViewCreated(coordinates) + } + + override fun updateRadarView() { + radarContainerBinding!!.radarToolbar.visibility = + if (interactionsEnabled() && isRadarInteractionEnabled()) View.VISIBLE else View.GONE + mapView.getMapAsync(this) + } + + override fun onDestroyView() { + super.onDestroyView() + this.googleMap = null + availableRadarFrames.clear() + radarLayers.clear() + radarContainerBinding = null + } + + override fun onMapReady(googleMap: GoogleMap) { + super.onMapReady(googleMap) + this.googleMap = googleMap + + getRadarFrames() + } + + private fun getRadarFrames() { + mProcessingFrames = true + + // Remove already added tile overlays + val overlaysToDelete = radarLayers.values.toList() + radarLayers.clear() + for (overlay in overlaysToDelete) { + mMainHandler.post { overlay.remove() } + } + + availableRadarFrames.clear() + animationPosition = 0 + + val now = ZonedDateTime.now(ZoneOffset.UTC) + .truncatedTo(ChronoUnit.HOURS) // 2024-05-05T14:00:00.000Z + val start = now + val end = now.plus(12, ChronoUnit.HOURS) + + var current = start + var nowIndex = -1 + + while (current <= end) { + availableRadarFrames.add(RadarFrame(current)) + + if (current == now) { + nowIndex = availableRadarFrames.size - 1 + } + + current = current.plus(1, ChronoUnit.HOURS) + } + + mProcessingFrames = false + + mMainHandler.post { + if (isViewAlive) { + val lastPastFramePosition = nowIndex + showFrame(lastPastFramePosition) + } + } + } + + private fun addLayer(mapFrame: RadarFrame) { + if (mProcessingFrames) return + + if (!radarLayers.containsKey(mapFrame.timestamp)) { + val overlay = googleMap!!.addTileOverlay( + TileOverlayOptions().tileProvider(WeatherApiTileProvider(context, mapFrame)) + .transparency(1f) + ) + if (overlay != null) { + radarLayers[mapFrame.timestamp] = overlay + } + } + + radarContainerBinding!!.animationSeekbar.stepSize = 1f + radarContainerBinding!!.animationSeekbar.valueFrom = 0f + radarContainerBinding!!.animationSeekbar.valueTo = (availableRadarFrames.size - 1).toFloat() + } + + private fun changeRadarPosition(pos: Int, preloadOnly: Boolean = false) { + if (mProcessingFrames) return + + var position = pos + while (position >= availableRadarFrames.size) { + position -= availableRadarFrames.size + } + while (position < 0) { + position += availableRadarFrames.size + } + + if (availableRadarFrames.isEmpty() || animationPosition >= availableRadarFrames.size || position >= availableRadarFrames.size) { + return + } + + val currentFrame = availableRadarFrames[animationPosition] ?: return + val currentTimeStamp = currentFrame.timestamp + + val nextFrame = availableRadarFrames[position] ?: return + val nextTimeStamp = nextFrame.timestamp + + addLayer(nextFrame) + + if (preloadOnly) { + return + } + + animationPosition = position + + // 0 is opaque; 1 is transparent + if (radarLayers.containsKey(currentTimeStamp)) { + val currentOverlay = radarLayers[currentTimeStamp] + if (currentOverlay != null) { + currentOverlay.transparency = 1f + } + } + val nextOverlay = radarLayers[nextTimeStamp] + if (nextOverlay != null) { + nextOverlay.transparency = DEFAULT_TRANSPARENCY + } + + updateToolbar(position, nextFrame) + } + + private fun updateToolbar( + position: Int, + mapFrame: RadarFrame = availableRadarFrames[position] + ) { + radarContainerBinding!!.animationSeekbar.value = position.toFloat() + + val dateTime = mapFrame.timestamp.withZoneSameInstant(ZoneOffset.systemDefault()) + val fmt = if (DateFormat.is24HourFormat(context)) { + DateTimeUtils.ofPatternForUserLocale( + DateTimeUtils.getBestPatternForSkeleton( + DateTimeConstants.SKELETON_DAYOFWEEK_AND_24HR + ) + ) + } else { + DateTimeUtils.ofPatternForUserLocale(DateTimeConstants.ABBREV_DAYOFWEEK_AND_12HR_MIN_AMPM) + } + radarContainerBinding!!.timestampText.text = dateTime.format(fmt) + } + + /** + * Check availability and show particular frame position from the timestamps list + */ + private fun showFrame(nextPosition: Int) { + if (mProcessingFrames) return + + val preloadingDirection = if (nextPosition - animationPosition > 0) 1 else -1 + + changeRadarPosition(nextPosition) + + // preload next next frame (typically, +1 frame) + // if don't do that, the animation will be blinking at the first loop + changeRadarPosition(nextPosition + preloadingDirection, true) + } + + private val animationRunnable = object : Runnable { + override fun run() { + if (isViewAlive) { + showFrame(animationPosition + 1) + mMainHandler.postDelayed(this, 500) + } else { + mMainHandler.removeCallbacks(this) + } + } + } + + private class WeatherApiTileProvider(context: Context, private val mapFrame: RadarFrame?) : + CachingUrlTileProvider(context, 256, 256) { + private val dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd") + + override fun getTileUrl(x: Int, y: Int, zoom: Int): String? { + if (!checkTileExists(x, y, zoom)) { + return null + } + + if (mapFrame != null) { + val date = mapFrame.timestamp.toLocalDate().format(dateFormatter) + val hour = mapFrame.timestamp.hour + val url = + "https://weathermaps.weatherapi.com/precip/tiles/%s%02d/%d/%d/%d.png".format( + date, + hour, + zoom, + x, + y + ) + return url + } + + return null + } + + /* + * Check that the tile server supports the requested x, y and zoom. + * Complete this stub according to the tile range you support. + * If you support a limited range of tiles at different zoom levels, then you + * need to define the supported x, y range at each zoom level. + */ + private fun checkTileExists(x: Int, y: Int, zoom: Int): Boolean { + val minZoom = MIN_ZOOM_LEVEL + val maxZoom = 6 + + return zoom in minZoom..maxZoom + } + } + + private data class RadarFrame( + val timestamp: ZonedDateTime + ) +} \ No newline at end of file diff --git a/app/src/fullgms/java/com/thewizrd/simpleweather/services/AppUpdaterWorker.kt b/app/src/fullgms/java/com/thewizrd/simpleweather/services/AppUpdaterWorker.kt index 236f66f7b..467ddbbb4 100644 --- a/app/src/fullgms/java/com/thewizrd/simpleweather/services/AppUpdaterWorker.kt +++ b/app/src/fullgms/java/com/thewizrd/simpleweather/services/AppUpdaterWorker.kt @@ -13,6 +13,7 @@ import androidx.core.app.NotificationCompat import androidx.work.* import com.thewizrd.common.helpers.areNotificationsEnabled import com.thewizrd.common.utils.LiveDataUtils.awaitWithTimeout +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.helpers.toImmutableCompatFlag import com.thewizrd.shared_resources.preferences.UpdateSettings import com.thewizrd.shared_resources.utils.Colors @@ -94,7 +95,7 @@ class AppUpdaterWorker(context: Context, workerParams: WorkerParameters) : initChannel(mNotifyMgr) val mNotif = NotificationCompat.Builder(applicationContext, NOT_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_error_white) + .setSmallIcon(sharedRes.drawable.ic_error_white) .setContentTitle(applicationContext.getString(R.string.prompt_update_title)) .setContentText(applicationContext.getString(R.string.prompt_update_available)) .setContentIntent(getLaunchUpdatesIntent(applicationContext)) diff --git a/app/src/fullgms/res/raw/wear_keep.xml b/app/src/fullgms/res/raw/wear_keep.xml new file mode 100644 index 000000000..dd32bc1f3 --- /dev/null +++ b/app/src/fullgms/res/raw/wear_keep.xml @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/app/src/fullgms/res/values/wear.xml b/app/src/fullgms/res/values/wear.xml index 97a0b4283..a8a910d57 100644 --- a/app/src/fullgms/res/values/wear.xml +++ b/app/src/fullgms/res/values/wear.xml @@ -1,6 +1,6 @@ - - + + com.thewizrd.simpleweather_phone_app \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fdf4957a1..f2316884c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -117,6 +117,19 @@ android:name="android.appwidget.provider" android:resource="@xml/app_widget_1x1_info" /> + + + + + + + + () { fun bindModel(aqiData: AirQualityViewModel?) { binding.viewModel = aqiData binding.executePendingBindings() - binding.aqiDateLabel.text = context.getString(R.string.time_current) + binding.aqiDateLabel.text = context.getString(sharedRes.string.time_current) } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/FavoritesPanelAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/FavoritesPanelAdapter.kt index b6e0fc07a..40b58d8bc 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/FavoritesPanelAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/FavoritesPanelAdapter.kt @@ -16,8 +16,10 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListUpdateCallback import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar +import com.thewizrd.common.R as commonRes import com.thewizrd.common.helpers.ObservableArrayList import com.thewizrd.common.helpers.OnListChangedListener +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.localBroadcastManager @@ -197,7 +199,8 @@ class FavoritesPanelAdapter : LocationPanelAdapter(), ItemTouchHelperAdapter, return when (viewType) { LocationPanelItemType.HEADER_FAV -> { HeaderViewHolder( - LayoutInflater.from(context).inflate(R.layout.locations_header, parent, false) + LayoutInflater.from(context) + .inflate(commonRes.layout.locations_header, parent, false) ).also { headerViewHolder = it } @@ -444,10 +447,10 @@ class FavoritesPanelAdapter : LocationPanelAdapter(), ItemTouchHelperAdapter, class HeaderViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView), HeaderSetterInterface { - private var header = itemView.findViewById(R.id.header) + private var header = itemView.findViewById(commonRes.id.header) override fun setHeader() { - header.setText(R.string.label_favoritelocations) + header.setText(sharedRes.string.label_favoritelocations) header.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_star_24dp, 0, 0, 0) } @@ -534,7 +537,7 @@ class FavoritesPanelAdapter : LocationPanelAdapter(), ItemTouchHelperAdapter, mSnackMgr?.show( com.thewizrd.simpleweather.snackbar.Snackbar.make( context, - R.string.message_needfavorite, + sharedRes.string.message_needfavorite, com.thewizrd.simpleweather.snackbar.Snackbar.Duration.SHORT ), null ) @@ -552,10 +555,10 @@ class FavoritesPanelAdapter : LocationPanelAdapter(), ItemTouchHelperAdapter, // Make SnackBar val snackbar = com.thewizrd.simpleweather.snackbar.Snackbar.make( context, - R.string.message_locationremoved, + sharedRes.string.message_locationremoved, com.thewizrd.simpleweather.snackbar.Snackbar.Duration.SHORT ) - snackbar.setAction(R.string.undo) { undoAction() } + snackbar.setAction(sharedRes.string.undo) { undoAction() } val callback = object : Snackbar.Callback() { override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/FeaturesAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/FeaturesAdapter.kt index f57e5f905..35b3dcdab 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/FeaturesAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/FeaturesAdapter.kt @@ -10,8 +10,10 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel +import com.thewizrd.common.R as commonRes import com.thewizrd.common.helpers.ObservableArrayList import com.thewizrd.common.helpers.OnListChangedListener +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.controls.FeatureItem @@ -62,7 +64,7 @@ class FeaturesAdapter : RecyclerView.Adapter(), Item KEY_FEATURE_UV to R.string.pref_title_feature_uv, KEY_FEATURE_BEAUFORT to R.string.pref_title_feature_beaufort, KEY_FEATURE_AQINDEX to R.string.pref_title_feature_aqindex, - KEY_FEATURE_POLLEN to R.string.label_pollen_count, + KEY_FEATURE_POLLEN to sharedRes.string.label_pollen_count, KEY_FEATURE_MOONPHASE to R.string.pref_title_feature_moonphase, KEY_FEATURE_SUNPHASE to R.string.pref_title_feature_sunphase, KEY_FEATURE_RADAR to R.string.pref_title_feature_radar, @@ -208,7 +210,7 @@ class FeaturesAdapter : RecyclerView.Adapter(), Item ) { val baseShapeModel = ShapeAppearanceModel.builder( context, - R.style.ShapeAppearance_Material3_Corner_Large, + com.google.android.material.R.style.ShapeAppearance_Material3_Corner_Large, 0 ) val smallCornerSize = context.dpToPx(4f) diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/GPSPanelAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/GPSPanelAdapter.kt index 42000ead1..2dc5c70f5 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/GPSPanelAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/GPSPanelAdapter.kt @@ -6,6 +6,8 @@ import android.view.ViewGroup import android.widget.TextView import androidx.core.widget.TextViewCompat import androidx.recyclerview.widget.RecyclerView +import com.thewizrd.common.R as commonRes +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColor import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColorStateList import com.thewizrd.simpleweather.R @@ -32,12 +34,12 @@ class GPSPanelAdapter : LocationPanelAdapter() { inner class HeaderViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView), HeaderSetterInterface { - private val header = itemView.findViewById(R.id.header) + private val header = itemView.findViewById(commonRes.id.header) override fun setHeader() { - header.setText(R.string.label_currentlocation) + header.setText(sharedRes.string.label_currentlocation) header.setCompoundDrawablesRelativeWithIntrinsicBounds( - R.drawable.ic_place_white_24dp, + sharedRes.drawable.ic_place_white_24dp, 0, 0, 0 @@ -74,7 +76,7 @@ class GPSPanelAdapter : LocationPanelAdapter() { LocationPanelItemType.HEADER_GPS -> { HeaderViewHolder( LayoutInflater.from(context) - .inflate(R.layout.locations_header, parent, false) + .inflate(commonRes.layout.locations_header, parent, false) ) } else -> { diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryAdapter.kt index 2020496b6..05453f9f3 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryAdapter.kt @@ -85,7 +85,7 @@ class LocationQueryAdapter : private fun updateItemCorners(cardView: MaterialCardView, @CornersType cornersType: Int) { val baseShapeModel = ShapeAppearanceModel.builder( cardView.context, - R.style.ShapeAppearance_Material3_Corner_Large, + com.google.android.material.R.style.ShapeAppearance_Material3_Corner_Large, 0 ) val smallCornerSize = cardView.context.dpToPx(4f) diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryFooterAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryFooterAdapter.kt index 98a3339cd..a89200a07 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryFooterAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/LocationQueryFooterAdapter.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.thewizrd.common.R +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.weather_api.weatherModule @@ -24,7 +25,7 @@ class LocationQueryFooterAdapter : val entry = WeatherAPI.LocationAPIs.find { lapi -> locationAPI == lapi.value } val credit = String.format( "%s %s", - context.getString(R.string.credit_prefix), + context.getString(sharedRes.string.credit_prefix), entry?.toString() ?: WeatherIcons.EM_DASH ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/adapters/MoonPhaseAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/adapters/MoonPhaseAdapter.kt index 38ad286da..b80409dbf 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/adapters/MoonPhaseAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/adapters/MoonPhaseAdapter.kt @@ -50,6 +50,7 @@ class MoonPhaseAdapter : RecyclerView.Adapter 0.35f } } + view.shouldAnimate = isSelected } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/AQIProgressBar.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/AQIProgressBar.kt index eff839016..d2de459bd 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/AQIProgressBar.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/AQIProgressBar.kt @@ -48,10 +48,11 @@ class AQIProgressBar @JvmOverloads constructor( thumbDrawable = MaterialShapeDrawable().apply { shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS fillColor = ColorStateList.valueOf(THUMB_COLOR) - elevation = context.resources.getDimension(R.dimen.m3_slider_thumb_elevation) + elevation = + context.resources.getDimension(com.google.android.material.R.dimen.m3_slider_thumb_elevation) thumbSize = - context.resources.getDimensionPixelSize(R.dimen.mtrl_slider_thumb_radius) * 3 / 4 + context.resources.getDimensionPixelSize(com.google.android.material.R.dimen.mtrl_slider_thumb_radius) * 3 / 4 shapeAppearanceModel = ShapeAppearanceModel.builder() .setAllCorners(CornerFamily.ROUNDED, thumbSize / 2f) diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/ClockToolbar.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/ClockToolbar.kt index d7bcac1ac..6c13a0926 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/ClockToolbar.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/ClockToolbar.kt @@ -31,7 +31,7 @@ import java.time.format.DateTimeFormatter class ClockToolbar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.toolbarStyle + defStyleAttr: Int = androidx.appcompat.R.attr.toolbarStyle ) : MaterialToolbar(context, attrs, defStyleAttr) { private var mFormat12: CharSequence? = null private var mFormat24: CharSequence? = null @@ -107,7 +107,10 @@ class ClockToolbar @JvmOverloads constructor( val a = context.obtainStyledAttributes(attrs, R.styleable.ClockToolbar) ViewCompat.saveAttributeDataForStyleable( this, context, R.styleable.ClockToolbar, - attrs, a, defStyleAttr, R.style.Widget_MaterialComponents_Toolbar + attrs, + a, + defStyleAttr, + com.google.android.material.R.style.Widget_MaterialComponents_Toolbar ) try { diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/CustomSearchView.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/CustomSearchView.kt index 8f8442269..d42c30708 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/CustomSearchView.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/CustomSearchView.kt @@ -4,9 +4,9 @@ import android.content.Context import android.util.AttributeSet import android.view.View import androidx.annotation.ColorInt +import com.google.android.material.R import com.google.android.material.elevation.ElevationOverlayProvider import com.google.android.material.search.SearchView -import com.thewizrd.simpleweather.R open class CustomSearchView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/DetailCard.java b/app/src/main/java/com/thewizrd/simpleweather/controls/DetailCard.java index 3ed3fb7af..e8e5c4bb2 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/DetailCard.java +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/DetailCard.java @@ -78,7 +78,7 @@ private void initialize(@NonNull Context context) { binding = CardWeatherDetailBinding.inflate(inflater, this, true); bgDrawable = new MaterialShapeDrawable( - ShapeAppearanceModel.builder(context, R.style.ShapeAppearance_Material3_MediumComponent, 0) + ShapeAppearanceModel.builder(context, com.google.android.material.R.style.ShapeAppearance_Material3_MediumComponent, 0) .build()); bgDrawable.initializeElevationOverlay(context); bgDrawable.setElevation(ContextUtils.dpToPx(context, 1f)); @@ -92,19 +92,19 @@ private void initialize(@NonNull Context context) { Resources.Theme currentTheme = context.getTheme(); TypedArray array; - array = currentTheme.obtainStyledAttributes(R.style.ShadowText, new int[]{android.R.attr.shadowRadius}); + array = currentTheme.obtainStyledAttributes(com.thewizrd.shared_resources.R.style.ShadowText, new int[]{android.R.attr.shadowRadius}); mShadowRadius = array.getFloat(0, 0); array.recycle(); - array = currentTheme.obtainStyledAttributes(R.style.ShadowText, new int[]{android.R.attr.shadowDx}); + array = currentTheme.obtainStyledAttributes(com.thewizrd.shared_resources.R.style.ShadowText, new int[]{android.R.attr.shadowDx}); mShadowDx = array.getFloat(0, 0); array.recycle(); - array = currentTheme.obtainStyledAttributes(R.style.ShadowText, new int[]{android.R.attr.shadowDy}); + array = currentTheme.obtainStyledAttributes(com.thewizrd.shared_resources.R.style.ShadowText, new int[]{android.R.attr.shadowDy}); mShadowDy = array.getFloat(0, 0); array.recycle(); - array = currentTheme.obtainStyledAttributes(R.style.ShadowText, new int[]{android.R.attr.shadowColor}); + array = currentTheme.obtainStyledAttributes(com.thewizrd.shared_resources.R.style.ShadowText, new int[]{android.R.attr.shadowColor}); mShadowColor = array.getColor(0, 0); array.recycle(); @@ -112,9 +112,10 @@ private void initialize(@NonNull Context context) { } private void updateColors() { - setBackgroundColor(ContextUtils.getAttrColor(getContext(), R.attr.colorSurfaceContainer)); - ImageViewCompat.setImageTintList(binding.detailIcon, ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), R.attr.colorPrimary))); - bgDrawable.setStrokeColor(ContextCompat.getColorStateList(getContext(), R.color.m3_card_stroke_color)); + setBackgroundColor(ContextUtils.getAttrColor(getContext(), com.google.android.material.R.attr.colorSurfaceContainer)); + ImageViewCompat.setImageTintList(binding.detailIcon, ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), androidx.appcompat.R.attr.colorPrimary))); + binding.detailIcon.setShowAsMonochrome(binding.detailIcon.getShowAsMonochrome()); + bgDrawable.setStrokeColor(ContextCompat.getColorStateList(getContext(), com.google.android.material.R.color.m3_card_stroke_color)); } @Override diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/FeatureItem.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/FeatureItem.kt index 4ef3772df..07de4d2a8 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/FeatureItem.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/FeatureItem.kt @@ -20,10 +20,9 @@ import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColor -import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColorStateList -import com.thewizrd.shared_resources.utils.ContextUtils.getAttrDrawable import com.thewizrd.shared_resources.utils.UserThemeMode import com.thewizrd.simpleweather.R +import com.google.android.material.R as materialRes class FeatureItem @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null @@ -63,18 +62,18 @@ class FeatureItem @JvmOverloads constructor( fillColor = ColorStateList.valueOf( if (settingsManager.getUserThemeMode() == UserThemeMode.AMOLED_DARK) { ColorUtils.compositeColors( - context.getAttrColor(R.attr.colorSurfaceDim), + context.getAttrColor(materialRes.attr.colorSurfaceDim), Colors.BLACK ) } else { - context.getAttrColor(R.attr.colorSurfaceBright) + context.getAttrColor(materialRes.attr.colorSurfaceBright) } ) initializeElevationOverlay(context) elevation = 0f shapeAppearanceModel = ShapeAppearanceModel.builder( context, - R.style.ShapeAppearance_Material3_Corner_LargeIncreased, + materialRes.style.ShapeAppearance_Material3_Corner_LargeIncreased, 0 ).build() }, diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/ForecastBarGraphView.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/ForecastBarGraphView.kt index 14db16af4..6aed189d4 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/ForecastBarGraphView.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/ForecastBarGraphView.kt @@ -15,6 +15,8 @@ import androidx.core.view.isGone import androidx.core.view.updateLayoutParams import androidx.databinding.DataBindingUtil import com.thewizrd.shared_resources.helpers.RecyclerOnClickListenerInterface +import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.controls.graphs.BarGraphData @@ -23,6 +25,7 @@ import com.thewizrd.simpleweather.controls.viewmodels.ForecastType import com.thewizrd.simpleweather.databinding.LayoutBarBinding import com.thewizrd.simpleweather.databinding.LayoutBarViewBinding import kotlin.math.max +import com.thewizrd.shared_resources.R as sharedRes class ForecastBarGraphView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null @@ -156,7 +159,10 @@ class ForecastBarGraphView @JvmOverloads constructor( // Update icon item.barIcon.rotation = data.xIconRotation.toFloat() - item.barIcon.setImageResource(getIconResourceFromForecastType(forecastType)) + item.barIcon.setImageResource( + getIconResourceFromWeatherIcon(data.xWeatherIcon) + ?: getIconResourceFromForecastType(forecastType) + ) if (getChildAt(i) == null) { addView( @@ -215,17 +221,25 @@ class ForecastBarGraphView @JvmOverloads constructor( return heightChanged } + @DrawableRes + private fun getIconResourceFromWeatherIcon(icon: String?): Int? { + return when (icon) { + WeatherIcons.NA, null -> null + else -> sharedDeps.weatherIconsManager.iconProvider.getWeatherIconResource(icon) + } + } + @DrawableRes private fun getIconResourceFromForecastType(forecastType: ForecastType?): Int { return when (forecastType) { ForecastType.TEMPERATURE -> 0 - ForecastType.MINUTELY -> R.drawable.wi_raindrop - ForecastType.PRECIPITATION -> R.drawable.wi_raindrop - ForecastType.WIND -> R.drawable.wi_direction_up_2x - ForecastType.HUMIDITY -> R.drawable.material_humidity_percentage + ForecastType.MINUTELY -> sharedRes.drawable.wi_raindrop + ForecastType.PRECIPITATION -> sharedRes.drawable.wi_raindrop + ForecastType.WIND -> sharedRes.drawable.wi_direction_up_2x + ForecastType.HUMIDITY -> sharedRes.drawable.material_humidity_percentage ForecastType.UVINDEX -> 0 - ForecastType.RAIN -> R.drawable.material_water_drop - ForecastType.SNOW -> R.drawable.wi_snowflake_cold + ForecastType.RAIN -> sharedRes.drawable.material_water_drop + ForecastType.SNOW -> sharedRes.drawable.wi_snowflake_cold ForecastType.AIRQUALITY -> 0 null -> 0 } diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/LoadingIndicatorRefreshLayout.java b/app/src/main/java/com/thewizrd/simpleweather/controls/LoadingIndicatorRefreshLayout.java index 122441df9..85c233519 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/LoadingIndicatorRefreshLayout.java +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/LoadingIndicatorRefreshLayout.java @@ -354,11 +354,11 @@ private void createProgressView() { mCircleView = new AnimationFrameLayout(getContext()); mCircleView.setLayoutParams(new LayoutParams(containerWidth, containerHeight)); mCircleView.setBackground(new ShapeDrawable(new OvalShape())); - mCircleView.setBackgroundTintList(ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), R.attr.colorPrimaryContainer))); + mCircleView.setBackgroundTintList(ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), com.google.android.material.R.attr.colorPrimaryContainer))); mCircleView.setClipToOutline(true); mLoadingIndicator = new LoadingIndicator(getContext()); - mLoadingIndicator.setIndicatorColor(ContextUtils.getAttrColor(getContext(), R.attr.colorPrimary)); + mLoadingIndicator.setIndicatorColor(ContextUtils.getAttrColor(getContext(), androidx.appcompat.R.attr.colorPrimary)); mLoadingIndicator.setContainerWidth(containerWidth); mLoadingIndicator.setContainerHeight(containerHeight); mLoadingIndicator.setIndicatorSize(indicatorSize); @@ -367,7 +367,7 @@ private void createProgressView() { mStaticLoadingView = new AppCompatImageView(getContext()); mStaticLoadingView.setImageResource(R.drawable.loading_indicator); - mStaticLoadingView.setImageTintList(ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), R.attr.colorPrimary))); + mStaticLoadingView.setImageTintList(ColorStateList.valueOf(ContextUtils.getAttrColor(getContext(), androidx.appcompat.R.attr.colorPrimary))); mStaticLoadingView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); mStaticLoadingView.setAdjustViewBounds(true); mStaticLoadingView.setLayoutParams(new FrameLayout.LayoutParams(indicatorSize, indicatorSize, Gravity.CENTER)); diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanel.kt index c1e3e0680..bf8b70d93 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanel.kt @@ -25,6 +25,7 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.BitmapImageViewTarget import com.bumptech.glide.request.transition.Transition +import com.google.android.material.R as materialRes import com.google.android.material.card.MaterialCardView import com.google.android.material.shape.ShapeAppearanceModel import com.thewizrd.common.controls.TextViewDrawableCompat @@ -95,10 +96,14 @@ class LocationPanel : MaterialCardView { } shapeAppearanceModel = - ShapeAppearanceModel.builder(context, R.style.ShapeAppearance_Material3_Corner_Large, 0) + ShapeAppearanceModel.builder( + context, + materialRes.style.ShapeAppearance_Material3_Corner_Large, + 0 + ) .build() - setCardBackgroundColor(context.getAttrColor(R.attr.colorSurface)) + setCardBackgroundColor(context.getAttrColor(materialRes.attr.colorSurface)) overlayDrawable = ContextCompat.getDrawable(context, R.drawable.background_overlay) cardElevation = context.dpToPx(2f) @@ -115,7 +120,7 @@ class LocationPanel : MaterialCardView { checkedIconTint = if (FeatureSettings.isLocationPanelImageEnabled) { ColorStateList.valueOf(Colors.WHITE) } else ColorStateList.valueOf( - context.getAttrColor(R.attr.colorPrimary) + context.getAttrColor(androidx.appcompat.R.attr.colorPrimary) ) setRippleColorResource( if (FeatureSettings.isLocationPanelImageEnabled) { @@ -266,7 +271,7 @@ object LocationPanelBindingAdapter { view.setTextColor(Colors.WHITE) } else { view.setShadowLayer(0f, view.shadowDx, view.shadowDy, Colors.TRANSPARENT) - view.setTextColor(view.context.getAttrColor(R.attr.colorOnSurface)) + view.setTextColor(view.context.getAttrColor(materialRes.attr.colorOnSurface)) } } @@ -281,7 +286,7 @@ object LocationPanelBindingAdapter { if (panelImageEnabled) { Colors.WHITE } else { - view.context.getAttrColor(R.attr.colorOnSurface) + view.context.getAttrColor(materialRes.attr.colorOnSurface) } ) ) @@ -296,7 +301,7 @@ object LocationPanelBindingAdapter { if (panelImageEnabled) { Colors.WHITE } else { - view.context.getAttrColor(R.attr.colorOnSurface) + view.context.getAttrColor(materialRes.attr.colorOnSurface) } ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanelUiModel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanelUiModel.kt index 6eb919d72..d3ec0cd06 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanelUiModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationPanelUiModel.kt @@ -11,7 +11,7 @@ import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.LocationType import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R import com.thewizrd.simpleweather.images.getImageData import com.thewizrd.weather_api.weatherModule import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationSearchView.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationSearchView.kt index 8552c9a44..7330f3bbe 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/LocationSearchView.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/LocationSearchView.kt @@ -16,7 +16,7 @@ import com.thewizrd.common.helpers.SimpleGestureListener import com.thewizrd.shared_resources.helpers.ListAdapterOnClickInterface import com.thewizrd.shared_resources.locationdata.LocationQuery import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx -import com.thewizrd.simpleweather.R +import com.google.android.material.R import com.thewizrd.simpleweather.adapters.LocationQueryAdapter import com.thewizrd.simpleweather.adapters.LocationQueryFooterAdapter diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/WeatherDetailItem.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/WeatherDetailItem.kt index 1cc698ce2..de525089e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/WeatherDetailItem.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/WeatherDetailItem.kt @@ -18,7 +18,7 @@ import com.google.android.material.shape.ShapeAppearanceModel import com.thewizrd.common.controls.BaseForecastItemViewModel import com.thewizrd.common.controls.ForecastItemViewModel import com.thewizrd.common.controls.HourlyForecastItemViewModel -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R import com.thewizrd.simpleweather.adapters.DetailsItemGridAdapter import com.thewizrd.simpleweather.databinding.WeatherDetailPanelBinding import java.util.Locale diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityDataMapper.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityDataMapper.kt index b969cf3d1..74aeb8436 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityDataMapper.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityDataMapper.kt @@ -5,7 +5,7 @@ import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.utils.AirQualityUtils import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.weatherdata.model.AirQuality -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R import com.thewizrd.simpleweather.controls.graphs.BarGraphData import com.thewizrd.simpleweather.controls.graphs.BarGraphDataSet import com.thewizrd.simpleweather.controls.graphs.BarGraphEntry diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityForecastViewModel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityForecastViewModel.kt index d5a892731..a089cf69c 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityForecastViewModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/AirQualityForecastViewModel.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch class AirQualityForecastViewModel(app: Application) : AndroidViewModel(app) { @@ -46,7 +47,8 @@ class AirQualityForecastViewModel(app: Application) : AndroidViewModel(app) { flowScope?.cancel() currentForecastsData = - weatherDAO.getLiveForecastData(location.query).distinctUntilChanged() + weatherDAO.getLiveForecastData(location.query).filterNotNull() + .distinctUntilChanged() flowScope = CoroutineScope(SupervisorJob()) flowScope?.launch { diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ChartsViewModel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ChartsViewModel.kt index f3fb3b0bb..3cf97a645 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ChartsViewModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ChartsViewModel.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch import java.time.ZoneOffset import java.time.ZonedDateTime @@ -60,7 +61,8 @@ class ChartsViewModel(app: Application) : AndroidViewModel(app) { ZonedDateTime.now(location.tzOffset).truncatedTo(ChronoUnit.HOURS) ).distinctUntilChanged() currentForecastsData = - weatherDAO.getLiveForecastData(location.query).distinctUntilChanged() + weatherDAO.getLiveForecastData(location.query).filterNotNull() + .distinctUntilChanged() flowScope = CoroutineScope(SupervisorJob()) flowScope?.launch { @@ -84,7 +86,7 @@ class ChartsViewModel(app: Application) : AndroidViewModel(app) { ?: ZoneOffset.UTC ).truncatedTo(ChronoUnit.HOURS) Pair( - input.first?.minForecast?.filter { !it.date.isBefore(now) }?.take(60), + input.first?.minForecast?.filter { !it.date.isBefore(now) }, input.second ) } else { diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastGraphViewModel.java b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastGraphViewModel.java index 8cc9b99f9..d80bc4204 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastGraphViewModel.java +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastGraphViewModel.java @@ -7,6 +7,7 @@ import androidx.core.content.ContextCompat; import com.thewizrd.shared_resources.DateTimeConstants; +import com.thewizrd.shared_resources.icons.WeatherIcons; import com.thewizrd.shared_resources.preferences.SettingsManager; import com.thewizrd.shared_resources.utils.Colors; import com.thewizrd.shared_resources.utils.ConversionMethods; @@ -18,7 +19,6 @@ import com.thewizrd.shared_resources.weatherdata.model.Forecast; import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast; import com.thewizrd.shared_resources.weatherdata.model.MinutelyForecast; -import com.thewizrd.simpleweather.R; import com.thewizrd.simpleweather.controls.graphs.BarGraphData; import com.thewizrd.simpleweather.controls.graphs.BarGraphDataSet; import com.thewizrd.simpleweather.controls.graphs.BarGraphEntry; @@ -239,7 +239,7 @@ private void addEntryData(BaseForecast forecast, LineDataSeries series, @NonNull } private void addMinutelyEntryData(@NonNull MinutelyForecast forecast, LineDataSeries series) { - if (forecast.getRainMm() != null && forecast.getRainMm() >= 0) { + if ((forecast.getRainMm() != null && forecast.getRainMm() >= 0) || (forecast.getSnowMm() != null && forecast.getSnowMm() >= 0)) { final DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(LocaleUtils.getLocale()); df.applyPattern("0.##"); @@ -254,13 +254,17 @@ private void addMinutelyEntryData(@NonNull MinutelyForecast forecast, LineDataSe final String unit = settingsMgr.getPrecipitationUnit(); float precipValue; + float rainMm = forecast.getRainMm() != null ? forecast.getRainMm() : 0f; + float snowMm = forecast.getSnowMm() != null ? forecast.getSnowMm() : 0f; + boolean isSnow = snowMm > rainMm; + switch (unit) { case Units.INCHES: default: - precipValue = ConversionMethods.mmToIn(forecast.getRainMm()); + precipValue = ConversionMethods.mmToIn(isSnow ? snowMm : rainMm); break; case Units.MILLIMETERS: - precipValue = forecast.getRainMm(); + precipValue = isSnow ? snowMm : rainMm; break; } @@ -280,7 +284,7 @@ private LineDataSeries createSeriesData(List entryData, @NonNull default: case PRECIPITATION: series = new LineDataSeries(entryData); - series.setSeriesColors(ContextCompat.getColor(context, R.color.colorPrimary)); + series.setSeriesColors(ContextCompat.getColor(context, com.thewizrd.shared_resources.R.color.colorPrimary)); series.setSeriesMinMax(0f, 100f); break; case WIND: @@ -407,7 +411,7 @@ private void addEntryData(@NonNull BaseForecast forecast, @NonNull BarGraphDataS entry = new BarGraphEntry(date, new YEntryData(0f, "0%")); } - entry.setFillColor(ContextCompat.getColor(context, R.color.colorPrimary)); + entry.setFillColor(ContextCompat.getColor(context, com.thewizrd.shared_resources.R.color.colorPrimary)); dataSet.addEntry(entry); } case WIND -> { @@ -509,7 +513,7 @@ private void addEntryData(@NonNull BaseForecast forecast, @NonNull BarGraphDataS } private void addMinutelyEntryData(@NonNull MinutelyForecast forecast, BarGraphDataSet dataSet) { - if (forecast.getRainMm() != null && forecast.getRainMm() >= 0) { + if ((forecast.getRainMm() != null && forecast.getRainMm() >= 0) || (forecast.getSnowMm() != null && forecast.getSnowMm() >= 0)) { final DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(LocaleUtils.getLocale()); df.applyPattern("0.##"); @@ -524,18 +528,18 @@ private void addMinutelyEntryData(@NonNull MinutelyForecast forecast, BarGraphDa final String unit = settingsMgr.getPrecipitationUnit(); float precipValue; - switch (unit) { - case Units.INCHES: - default: - precipValue = ConversionMethods.mmToIn(forecast.getRainMm()); - break; - case Units.MILLIMETERS: - precipValue = forecast.getRainMm(); - break; - } + float rainMm = forecast.getRainMm() != null ? forecast.getRainMm() : 0f; + float snowMm = forecast.getSnowMm() != null ? forecast.getSnowMm() : 0f; + boolean isSnow = snowMm > rainMm; + + precipValue = switch (unit) { + default -> ConversionMethods.mmToIn(isSnow ? snowMm : rainMm); + case Units.MILLIMETERS -> isSnow ? snowMm : rainMm; + }; final BarGraphEntry entry = new BarGraphEntry(date, new YEntryData(precipValue, String.format(LocaleUtils.getLocale(), "%s", df.format(precipValue)))); - entry.setFillColor(Colors.DEEPSKYBLUE); + entry.setXWeatherIcon(isSnow ? WeatherIcons.SNOWFLAKE_COLD : WeatherIcons.RAINDROP); + entry.setFillColor(isSnow ? Colors.SKYBLUE : Colors.DEEPSKYBLUE); dataSet.addEntry(entry); } } @@ -545,7 +549,7 @@ private String getDateFromForecast(BaseForecast forecast) { if (forecast instanceof Forecast) { Forecast fcast = (Forecast) forecast; - date = fcast.getDate().format(DateTimeUtils.ofPatternForUserLocale(context.getString(R.string.forecast_date_format))); + date = fcast.getDate().format(DateTimeUtils.ofPatternForUserLocale(context.getString(com.thewizrd.shared_resources.R.string.forecast_date_format))); } else if (forecast instanceof HourlyForecast) { HourlyForecast fcast = (HourlyForecast) forecast; diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastsNowViewModel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastsNowViewModel.kt index d60ed05c2..c759f32e6 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastsNowViewModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/ForecastsNowViewModel.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.last import kotlinx.coroutines.launch import java.time.ZoneOffset @@ -39,7 +40,7 @@ class ForecastsNowViewModel(app: Application) : AndroidViewModel(app) { private val weatherDAO = WeatherDatabase.getWeatherDAO(app.applicationContext) - private var forecastData = MutableStateFlow??>(null) + private var forecastData = MutableStateFlow?>(null) private var hourlyForecastsData = MutableStateFlow?>(null) private var minutelyForecastData = MutableStateFlow?>(null) @@ -81,12 +82,13 @@ class ForecastsNowViewModel(app: Application) : AndroidViewModel(app) { iconProvider = settingsManager.getIconsProvider() currentForecastsData = - weatherDAO.getLiveForecastData(location.query).distinctUntilChanged() + weatherDAO.getLiveForecastData(location.query).filterNotNull() + .distinctUntilChanged() flowScope?.launch { currentForecastsData.collect { forecastData.emit(it.forecast) - minutelyForecastData.emit(it.minForecast) + minutelyForecastData.emit(minForecastMapper.apply(it)) } } @@ -123,13 +125,12 @@ class ForecastsNowViewModel(app: Application) : AndroidViewModel(app) { input?.map { HourlyForecastNowViewModel(it) } ?: emptyList() } - private val precipMinGraphMapper = Function?> { input -> - val hrInterval = weatherModule.weatherManager.getHourlyForecastInterval() + private val minForecastMapper = Function?> { input -> val now = ZonedDateTime.now( locationData?.tzOffset ?: ZoneOffset.UTC - ).minusHours((hrInterval * 0.5).toLong()).truncatedTo(ChronoUnit.HOURS) - input?.minForecast?.filter { !it.date.isBefore(now) }?.takeUnless { it.isEmpty() }?.take(60) + ).truncatedTo(ChronoUnit.HOURS) + input?.minForecast?.filter { !it.date.isBefore(now) } } override fun onCleared() { diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/GraphModelUtils.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/GraphModelUtils.kt index fec85da7d..f2d0d4d7a 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/GraphModelUtils.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/GraphModelUtils.kt @@ -1,7 +1,7 @@ package com.thewizrd.simpleweather.controls.viewmodels import android.content.Context -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R object GraphModelUtils { @JvmStatic diff --git a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/HourlyForecastNowViewModel.kt b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/HourlyForecastNowViewModel.kt index f99f25293..104e1453c 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/HourlyForecastNowViewModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/controls/viewmodels/HourlyForecastNowViewModel.kt @@ -87,7 +87,7 @@ class HourlyForecastNowViewModel(forecast: HourlyForecast) { condition = if (wm.supportsWeatherLocale()) forecast.condition ?: context.getString(R.string.weather_notavailable) else wm.getWeatherCondition(forecast.icon) - if (forecast.windMph != null && forecast.windKph != null && forecast.windMph >= 0 && forecast.windDegrees != null && forecast.windDegrees >= 0) { + if (forecast.extras?.windMph != null && forecast.extras?.windKph != null && forecast.extras.windMph >= 0 && forecast.extras?.windDegrees != null && forecast.extras.windDegrees >= 0) { val unit = settingsManager.getSpeedUnit() val speedVal: Int val speedUnit: String @@ -116,7 +116,7 @@ class HourlyForecastNowViewModel(forecast: HourlyForecast) { } } - windDirection = forecast.windDegrees.getValueOrDefault(0) + 180 + windDirection = forecast.extras?.windDegrees.getValueOrDefault(0) + 180 windSpeed = String.format(LocaleUtils.getLocale(), "%d %s", speedVal, speedUnit) } diff --git a/app/src/main/java/com/thewizrd/simpleweather/databinding/ViewBindingAdapter.java b/app/src/main/java/com/thewizrd/simpleweather/databinding/ViewBindingAdapter.java index 1ea4915de..cd479aa6b 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/databinding/ViewBindingAdapter.java +++ b/app/src/main/java/com/thewizrd/simpleweather/databinding/ViewBindingAdapter.java @@ -1,5 +1,6 @@ package com.thewizrd.simpleweather.databinding; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.PorterDuff; @@ -44,6 +45,7 @@ public static void updateProgressColor(@NonNull BaseProgressIndicator progres progressBar.setIndicatorColor(progressColor); } + @SuppressLint("RestrictedApi") @BindingAdapter("progressBackgroundColor") public static void updateProgressBackgroundColor(ProgressBar progressBar, @ColorInt int progressBackgroundColor) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -68,7 +70,7 @@ public static void updateProgressBackgroundColor(ProgressBar progressBar, @Color @BindingAdapter("attribution") public static void updateAttribution(final TextView view, final CharSequence attrib) { if (!TextUtils.isEmpty(attrib)) { - view.setText(String.format(Locale.ROOT, "%s %s", view.getContext().getString(R.string.credit_prefix), attrib)); + view.setText(String.format(Locale.ROOT, "%s %s", view.getContext().getString(com.thewizrd.shared_resources.R.string.credit_prefix), attrib)); view.setVisibility(View.VISIBLE); } else { view.setText(""); diff --git a/app/src/main/java/com/thewizrd/simpleweather/databinding/WeatherNowBindingAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/databinding/WeatherNowBindingAdapter.kt index ad10abc1b..fed20b5de 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/databinding/WeatherNowBindingAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/databinding/WeatherNowBindingAdapter.kt @@ -22,7 +22,7 @@ import com.thewizrd.shared_resources.utils.StringUtils.removeNonDigitChars import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.utils.getColorFromTempF import com.thewizrd.shared_resources.weatherdata.model.MoonPhase.MoonPhaseType -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R import com.thewizrd.simpleweather.adapters.DetailsItemAdapter import com.thewizrd.simpleweather.adapters.DetailsItemGridAdapter import com.thewizrd.simpleweather.adapters.HourlyForecastItemAdapter diff --git a/app/src/main/java/com/thewizrd/simpleweather/fragments/AbstractWeatherListDetailFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/fragments/AbstractWeatherListDetailFragment.kt index ed20c2ba6..c22f4f58d 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/fragments/AbstractWeatherListDetailFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/fragments/AbstractWeatherListDetailFragment.kt @@ -29,9 +29,9 @@ import androidx.core.content.res.use import androidx.core.view.doOnLayout import androidx.fragment.app.FragmentContainerView import androidx.fragment.app.commit +import androidx.navigation.fragment.R import androidx.navigation.fragment.NavHostFragment import androidx.slidingpanelayout.widget.SlidingPaneLayout -import com.thewizrd.simpleweather.R /** * A fragment supports adaptive two-pane layout. The first child is a list pane, which could be a diff --git a/app/src/main/java/com/thewizrd/simpleweather/fragments/CollapsingToolbarFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/fragments/CollapsingToolbarFragment.kt index d630fb477..b110e8088 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/fragments/CollapsingToolbarFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/fragments/CollapsingToolbarFragment.kt @@ -9,6 +9,7 @@ import androidx.annotation.CallSuper import androidx.annotation.IdRes import androidx.annotation.StringRes import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.R as materialRes import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.MaterialToolbar @@ -19,7 +20,6 @@ import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColor import com.thewizrd.shared_resources.utils.ContextUtils.getAttrResourceId import com.thewizrd.shared_resources.utils.UserThemeMode -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.databinding.FragmentCollapsingtoolbarLayoutBinding abstract class CollapsingToolbarFragment : WindowColorFragment() { @@ -66,7 +66,7 @@ abstract class CollapsingToolbarFragment : WindowColorFragment() { protected fun setNavigationIconVisible(visible: Boolean) { if (visible) { - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) } else { toolbar.navigationIcon = null } @@ -82,7 +82,7 @@ abstract class CollapsingToolbarFragment : WindowColorFragment() { override fun updateWindowColors() { context?.let { ctx -> var backgroundColor = ctx.getAttrColor(android.R.attr.colorBackground) - var statusBarColor = ctx.getAttrColor(R.attr.colorSurface) + var statusBarColor = ctx.getAttrColor(materialRes.attr.colorSurface) if (settingsManager.getUserThemeMode() === UserThemeMode.AMOLED_DARK) { statusBarColor = Colors.BLACK backgroundColor = statusBarColor diff --git a/app/src/main/java/com/thewizrd/simpleweather/fragments/LargeCollapsingToolbarFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/fragments/LargeCollapsingToolbarFragment.kt index bc572a6f9..4672f24fd 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/fragments/LargeCollapsingToolbarFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/fragments/LargeCollapsingToolbarFragment.kt @@ -9,6 +9,7 @@ import androidx.annotation.CallSuper import androidx.annotation.IdRes import androidx.annotation.StringRes import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.R as materialRes import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.MaterialToolbar @@ -19,9 +20,7 @@ import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColor import com.thewizrd.shared_resources.utils.ContextUtils.getAttrResourceId import com.thewizrd.shared_resources.utils.UserThemeMode -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.databinding.FragmentCollapsingtoolbarLargeLayoutBinding -import com.thewizrd.simpleweather.databinding.FragmentCollapsingtoolbarLayoutBinding abstract class LargeCollapsingToolbarFragment : WindowColorFragment() { // Views @@ -67,7 +66,7 @@ abstract class LargeCollapsingToolbarFragment : WindowColorFragment() { protected fun setNavigationIconVisible(visible: Boolean) { if (visible) { - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) } else { toolbar.navigationIcon = null } @@ -83,7 +82,7 @@ abstract class LargeCollapsingToolbarFragment : WindowColorFragment() { override fun updateWindowColors() { context?.let { ctx -> var backgroundColor = ctx.getAttrColor(android.R.attr.colorBackground) - var statusBarColor = ctx.getAttrColor(R.attr.colorSurface) + var statusBarColor = ctx.getAttrColor(materialRes.attr.colorSurface) if (settingsManager.getUserThemeMode() === UserThemeMode.AMOLED_DARK) { statusBarColor = Colors.BLACK backgroundColor = statusBarColor diff --git a/app/src/main/java/com/thewizrd/simpleweather/fragments/ToolbarFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/fragments/ToolbarFragment.kt index 53642f899..fa8a70910 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/fragments/ToolbarFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/fragments/ToolbarFragment.kt @@ -9,6 +9,7 @@ import androidx.annotation.CallSuper import androidx.annotation.IdRes import androidx.annotation.StringRes import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.R as materialRes import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.shape.MaterialShapeDrawable @@ -63,7 +64,7 @@ abstract class ToolbarFragment : WindowColorFragment() { protected fun setNavigationIconVisible(visible: Boolean) { if (visible) { - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) } else { toolbar.navigationIcon = null } @@ -79,7 +80,7 @@ abstract class ToolbarFragment : WindowColorFragment() { override fun updateWindowColors() { context?.let { ctx -> var backgroundColor = ctx.getAttrColor(android.R.attr.colorBackground) - var statusBarColor = ctx.getAttrColor(R.attr.colorSurface) + var statusBarColor = ctx.getAttrColor(materialRes.attr.colorSurface) if (settingsManager.getUserThemeMode() === UserThemeMode.AMOLED_DARK) { statusBarColor = Colors.BLACK backgroundColor = statusBarColor diff --git a/app/src/main/java/com/thewizrd/simpleweather/helpers/ItemTouchHelperCallback.java b/app/src/main/java/com/thewizrd/simpleweather/helpers/ItemTouchHelperCallback.java index e283d729e..a7f04aa01 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/helpers/ItemTouchHelperCallback.java +++ b/app/src/main/java/com/thewizrd/simpleweather/helpers/ItemTouchHelperCallback.java @@ -41,7 +41,7 @@ public ItemTouchHelperCallback(@NonNull Context context, @NonNull ItemTouchHelpe mAdapter = adapter; Drawable deleteIcoDrawable = ContextCompat.getDrawable(context, R.drawable.ic_delete_outline_24dp); deleteIcon = DrawableCompat.wrap(deleteIcoDrawable); - DrawableCompat.setTint(deleteIcon, ContextUtils.getAttrColor(context, R.attr.colorOnError)); + DrawableCompat.setTint(deleteIcon, ContextUtils.getAttrColor(context, com.google.android.material.R.attr.colorOnError)); deleteBackground = ContextCompat.getDrawable(context, R.drawable.swipe_delete); iconMargin = context.getResources().getDimensionPixelSize(R.dimen.delete_icon_margin); } diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/LocationsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/LocationsFragment.kt index ba25fce03..d2aae39d2 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/LocationsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/LocationsFragment.kt @@ -18,6 +18,7 @@ import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.launch import androidx.annotation.ColorInt +import androidx.appcompat.R as appcompatRes import androidx.appcompat.widget.Toolbar import androidx.core.animation.doOnEnd import androidx.core.app.ActivityOptionsCompat @@ -44,6 +45,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.ItemDecoration import androidx.transition.TransitionManager +import com.google.android.material.R as materialRes import com.google.android.material.animation.ArgbEvaluatorCompat import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.snackbar.BaseTransientBottomBar @@ -56,6 +58,7 @@ import com.thewizrd.common.helpers.OnListChangedListener import com.thewizrd.common.utils.ActivityUtils.setLightStatusBar import com.thewizrd.common.utils.ErrorMessage import com.thewizrd.common.viewmodels.LocationSearchResult +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.localBroadcastManager @@ -136,7 +139,7 @@ class LocationsFragment : ToolbarFragment() { private lateinit var onBackPressedCallback: OnBackPressedCallback override val titleResId: Int - get() = R.string.label_nav_locations + get() = sharedRes.string.label_nav_locations override fun createSnackManager(activity: Activity): SnackbarManager { return SnackbarManager(rootView).apply { @@ -199,7 +202,7 @@ class LocationsFragment : ToolbarFragment() { showSnackbar( Snackbar.make( it, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -632,7 +635,7 @@ class LocationsFragment : ToolbarFragment() { ErrorStatus.NETWORKERROR, ErrorStatus.NOWEATHER -> { val snackbar = Snackbar.make(rootView.context, wEx.message, Snackbar.Duration.LONG) - snackbar.setAction(R.string.action_retry) { + snackbar.setAction(sharedRes.string.action_retry) { locationsViewModel.refreshLocations() } showSnackbar(snackbar) @@ -640,7 +643,7 @@ class LocationsFragment : ToolbarFragment() { ErrorStatus.LOCATIONNOTSUPPORTED -> { showSnackbar( Snackbar.make(rootView.context, wEx.message, Snackbar.Duration.LONG).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { rootView.findNavController() .safeNavigate(NavGraphDirections.actionGlobalSettingsFragment()) @@ -787,11 +790,11 @@ class LocationsFragment : ToolbarFragment() { if (inEditMode) { val navIcon = - ContextCompat.getDrawable(toolbar.context, R.drawable.ic_close_white_24dp)!! + ContextCompat.getDrawable(toolbar.context, sharedRes.drawable.ic_close_white_24dp)!! .mutate() DrawableCompat.setTint( navIcon, - toolbar.context.getAttrColor(R.attr.colorOnPrimary) + toolbar.context.getAttrColor(materialRes.attr.colorOnPrimary) ) toolbar.navigationIcon = navIcon toolbar.setNavigationOnClickListener { @@ -812,7 +815,7 @@ class LocationsFragment : ToolbarFragment() { toolbar.setTitle(titleResId) toolbar.setTitleTextAppearance( toolbar.context, - toolbar.context.getAttrResourceId(R.attr.textAppearanceHeadline6) + toolbar.context.getAttrResourceId(materialRes.attr.textAppearanceHeadline6) ) (activity as? WindowColorManager)?.updateWindowColors() } @@ -834,14 +837,14 @@ class LocationsFragment : ToolbarFragment() { } MenuItemCompat.setIconTintList( it, - ColorStateList.valueOf(toolbar.context.getAttrColor(R.attr.colorOnPrimary)) + ColorStateList.valueOf(toolbar.context.getAttrColor(materialRes.attr.colorOnPrimary)) ) } R.id.action_done -> { it.isVisible = inEditMode MenuItemCompat.setIconTintList( it, - ColorStateList.valueOf(toolbar.context.getAttrColor(R.attr.colorOnPrimary)) + ColorStateList.valueOf(toolbar.context.getAttrColor(materialRes.attr.colorOnPrimary)) ) } else -> it.isVisible = !inEditMode @@ -850,9 +853,9 @@ class LocationsFragment : ToolbarFragment() { runAppBarAnimation( if (inEditMode) { - appBarLayout.context.getAttrColor(R.attr.colorPrimary) + appBarLayout.context.getAttrColor(appcompatRes.attr.colorPrimary) } else { - appBarLayout.context.getAttrColor(R.attr.colorSurface) + appBarLayout.context.getAttrColor(materialRes.attr.colorSurface) } ) } @@ -870,7 +873,7 @@ class LocationsFragment : ToolbarFragment() { if (mEditMode) { activity?.let { - val statusBarColor = it.getAttrColor(R.attr.colorPrimary) + val statusBarColor = it.getAttrColor(appcompatRes.attr.colorPrimary) if (appBarLayout.background is MaterialShapeDrawable) { val materialShapeDrawable = appBarLayout.background as MaterialShapeDrawable @@ -895,7 +898,7 @@ class LocationsFragment : ToolbarFragment() { materialShapeDrawable.fillColor?.defaultColor } else { (appBarLayout.background as? ColorDrawable)?.color - } ?: appBarLayout.context.getAttrColor(R.attr.colorSurface) + } ?: appBarLayout.context.getAttrColor(materialRes.attr.colorSurface) if (colorFrom != colorTo) { if (mAppBarAnimator?.isRunning == true) { mAppBarAnimator?.cancel() diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt b/app/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt index 5831e5061..1b2d909b7 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt @@ -394,7 +394,7 @@ class MainActivity : WindowColorActivity() { private fun updateWindowColors(mode: UserThemeMode) { var backgroundColor = getAttrColor(android.R.attr.colorBackground) - var navBarColor = getAttrColor(R.attr.colorSurface) + var navBarColor = getAttrColor(com.google.android.material.R.attr.colorSurface) if (mode == UserThemeMode.AMOLED_DARK) { backgroundColor = Colors.BLACK navBarColor = Colors.BLACK diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAQIFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAQIFragment.kt index 8d07abb21..dcf2ecaf3 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAQIFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAQIFragment.kt @@ -18,6 +18,7 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.BaseTransientBottomBar import com.thewizrd.common.controls.AirQualityViewModel import com.thewizrd.common.helpers.SimpleRecyclerViewAdapterObserver +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.locationdata.LocationData @@ -118,7 +119,7 @@ class WeatherAQIFragment : CollapsingToolbarFragment() { binding.lifecycleOwner = viewLifecycleOwner // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } // use this setting to improve performance if you know that changes @@ -246,7 +247,7 @@ class WeatherAQIFragment : CollapsingToolbarFragment() { } override val titleResId: Int - get() = R.string.label_airquality + get() = sharedRes.string.label_airquality private fun initialize() { if (locationData == null) { diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAlertFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAlertFragment.kt index d72b0655d..a8e08e0a0 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAlertFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherAlertFragment.kt @@ -17,6 +17,7 @@ import com.google.android.material.transition.MaterialFadeThrough import com.thewizrd.common.adapters.WeatherAlertPanelAdapter import com.thewizrd.common.controls.WeatherAlertsViewModel import com.thewizrd.common.helpers.SimpleRecyclerViewAdapterObserver +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.locationdata.LocationData @@ -73,7 +74,7 @@ class WeatherAlertFragment : CollapsingToolbarFragment() { binding.lifecycleOwner = viewLifecycleOwner // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } // use this setting to improve performance if you know that changes @@ -126,7 +127,7 @@ class WeatherAlertFragment : CollapsingToolbarFragment() { } override val titleResId: Int - get() = R.string.title_fragment_alerts + get() = sharedRes.string.title_fragment_alerts private suspend fun initialize() { if (locationData == null) { diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherChartsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherChartsFragment.kt index 04f03eae0..fb836877f 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherChartsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherChartsFragment.kt @@ -49,6 +49,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import com.thewizrd.shared_resources.R as sharedRes class WeatherChartsFragment : CollapsingToolbarFragment() { private val wNowViewModel: WeatherNowViewModel by activityViewModels() @@ -115,7 +116,7 @@ class WeatherChartsFragment : CollapsingToolbarFragment() { binding.lifecycleOwner = viewLifecycleOwner // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } // use this setting to improve performance if you know that changes @@ -224,7 +225,7 @@ class WeatherChartsFragment : CollapsingToolbarFragment() { } override val titleResId: Int - get() = R.string.label_forecast + get() = sharedRes.string.label_forecast private fun initialize() { if (locationData == null) { @@ -309,8 +310,8 @@ class WeatherChartsFragment : CollapsingToolbarFragment() { if (hrfcasts.firstOrNull()?.extras?.pop != null || hrfcasts.lastOrNull()?.extras?.pop != null) { popData = ForecastGraphViewModel(ctx) } - if (hrfcasts.firstOrNull()?.windMph != null && hrfcasts.firstOrNull()?.windKph != null || - hrfcasts.lastOrNull()?.windMph != null && hrfcasts.lastOrNull()?.windKph != null + if (hrfcasts.firstOrNull()?.extras?.windMph != null && hrfcasts.firstOrNull()?.extras?.windKph != null || + hrfcasts.lastOrNull()?.extras?.windMph != null && hrfcasts.lastOrNull()?.extras?.windKph != null ) { windData = ForecastGraphViewModel(ctx) } @@ -343,7 +344,7 @@ class WeatherChartsFragment : CollapsingToolbarFragment() { } } if (windData != null) { - if (hrfcast.windMph != null && hrfcast.windKph != null) { + if (hrfcast.extras?.windMph != null && hrfcast.extras?.windKph != null) { windData.addForecastData( hrfcast, ForecastType.WIND, diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherListFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherListFragment.kt index 1edd4f81b..88ae4e496 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherListFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherListFragment.kt @@ -25,6 +25,7 @@ import com.thewizrd.common.controls.ForecastsListViewModel import com.thewizrd.common.controls.HourlyForecastItemViewModel import com.thewizrd.common.controls.WeatherAlertsViewModel import com.thewizrd.common.helpers.SimpleRecyclerViewAdapterObserver +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.locationdata.LocationData @@ -146,7 +147,7 @@ class WeatherListFragment : CollapsingToolbarFragment() { binding.lifecycleOwner = viewLifecycleOwner // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } // use this setting to improve performance if you know that changes @@ -249,9 +250,9 @@ class WeatherListFragment : CollapsingToolbarFragment() { override val titleResId: Int get() = when (weatherListType) { - WeatherListType.FORECAST, WeatherListType.HOURLYFORECAST -> R.string.label_forecast - WeatherListType.ALERTS -> R.string.title_fragment_alerts - else -> R.string.label_nav_weathernow + WeatherListType.FORECAST, WeatherListType.HOURLYFORECAST -> sharedRes.string.label_forecast + WeatherListType.ALERTS -> sharedRes.string.title_fragment_alerts + else -> sharedRes.string.label_nav_weathernow } private fun initialize() { diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherNowFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherNowFragment.kt index 1e634356f..84a57d56e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherNowFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherNowFragment.kt @@ -56,11 +56,13 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.Target +import com.google.android.material.R as materialRes import com.google.android.material.color.DynamicColorsOptions import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.transition.MaterialFadeThrough +import com.thewizrd.common.R as commonRes import com.thewizrd.common.controls.IconControl import com.thewizrd.common.controls.WeatherAlertsViewModel import com.thewizrd.common.helpers.ColorsUtils @@ -70,6 +72,7 @@ import com.thewizrd.common.location.LocationResult import com.thewizrd.common.utils.ActivityUtils.recreateCompat import com.thewizrd.common.utils.ErrorMessage import com.thewizrd.common.utils.isTextTruncated +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager @@ -261,7 +264,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt showSnackbar( Snackbar.make( binding.rootView.context, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ), null ) @@ -444,8 +447,8 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt // SwipeRefresh binding.refreshLayout.setRefreshingDelay(350) - binding.refreshLayout.setContainerColor(requireContext().getAttrColor(R.attr.colorPrimaryContainer)) - binding.refreshLayout.setIndicatorColor(requireContext().getAttrColor(R.attr.colorPrimary)) + binding.refreshLayout.setContainerColor(requireContext().getAttrColor(materialRes.attr.colorPrimaryContainer)) + binding.refreshLayout.setIndicatorColor(requireContext().getAttrColor(androidx.appcompat.R.attr.colorPrimary)) binding.refreshLayout.setOnRefreshListener { AnalyticsLogger.logEvent("WeatherNowFragment: onRefresh") wNowViewModel.refreshWeather(true) @@ -953,10 +956,10 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt showBanner( Banner.make( binding.root.context, - R.string.prompt_location_not_set + sharedRes.string.prompt_location_not_set ).apply { - setBannerIcon(R.drawable.ic_location_off_24dp) - setPrimaryAction(R.string.label_fab_add_location) { + setBannerIcon(sharedRes.drawable.ic_location_off_24dp) + setPrimaryAction(sharedRes.string.label_fab_add_location) { binding.root.findNavController().safeNavigate( WeatherNowFragmentDirections.actionWeatherNowFragmentToLocationsFragment() ) @@ -1143,8 +1146,8 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - binding.refreshLayout.setContainerColor(requireContext().getAttrColor(R.attr.colorPrimaryContainer)) - binding.refreshLayout.setIndicatorColor(requireContext().getAttrColor(R.attr.colorPrimary)) + binding.refreshLayout.setContainerColor(requireContext().getAttrColor(materialRes.attr.colorPrimaryContainer)) + binding.refreshLayout.setIndicatorColor(requireContext().getAttrColor(androidx.appcompat.R.attr.colorPrimary)) // Resize necessary views adjustConditionPanelLayout() @@ -1186,7 +1189,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt wEx.message, Snackbar.Duration.LONG ).apply { - setAction(R.string.action_retry) { + setAction(sharedRes.string.action_retry) { wNowViewModel.refreshWeather(false) } }) @@ -1194,7 +1197,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt ErrorStatus.LOCATIONNOTSUPPORTED -> { showSnackbar( Snackbar.make(binding.root.context, wEx.message, Snackbar.Duration.LONG).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { binding.root.findNavController() .safeNavigate(WeatherNowFragmentDirections.actionWeatherNowFragmentToSettingsFragment()) @@ -1224,7 +1227,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt if (forceReload || (!ObjectsCompat.equals( imageView.tag, imageURI - ) || imageView.getTag(R.id.glide_custom_view_target_tag) == null) + ) || imageView.getTag(com.bumptech.glide.R.id.glide_custom_view_target_tag) == null) ) { imageView.tag = imageURI if (!imageURI.isNullOrBlank()) { @@ -1274,7 +1277,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt .contentBasedSeedColor val dominantColor = seedColor ?: imageView.context.run { - getColor(R.color.colorPrimary) + getColor(sharedRes.color.colorPrimary) } val backgroundColor = @@ -1490,7 +1493,7 @@ class WeatherNowFragment : AbstractWeatherListDetailFragment(), BannerManagerInt override fun updateWindowColors() { context?.let { var backgroundColor = it.getAttrColor(android.R.attr.colorBackground) - var navBarColor = it.getAttrColor(R.attr.colorSurface) + var navBarColor = it.getAttrColor(materialRes.attr.colorSurface) var statusBarColor = navBarColor if (settingsManager.getUserThemeMode() == UserThemeMode.AMOLED_DARK) { backgroundColor = Colors.BLACK diff --git a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherRadarFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherRadarFragment.kt index ae3c2dff1..d6574a506 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/main/WeatherRadarFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/main/WeatherRadarFragment.kt @@ -17,6 +17,7 @@ import androidx.lifecycle.repeatOnLifecycle import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialFadeThrough +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.utils.AnalyticsLogger import com.thewizrd.shared_resources.utils.ContextUtils.getAttrResourceId import com.thewizrd.simpleweather.R @@ -62,7 +63,7 @@ class WeatherRadarFragment : ToolbarFragment() { ViewCompat.setTransitionName(binding.radarWebviewContainer, "radar") // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } toolbar.inflateMenu(R.menu.radar) @@ -147,5 +148,5 @@ class WeatherRadarFragment : ToolbarFragment() { } override val titleResId: Int - get() = R.string.label_radar + get() = sharedRes.string.label_radar } \ No newline at end of file diff --git a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherAlertNotificationBuilder.kt b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherAlertNotificationBuilder.kt index 6979f7162..2b7d68c8e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherAlertNotificationBuilder.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherAlertNotificationBuilder.kt @@ -1,5 +1,7 @@ package com.thewizrd.simpleweather.notifications +import android.Manifest +import android.annotation.SuppressLint import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager @@ -9,12 +11,14 @@ import android.content.Intent import android.graphics.drawable.Icon import android.os.Build import android.os.SystemClock +import androidx.annotation.RequiresPermission import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.net.toUri import com.thewizrd.common.controls.WeatherAlertViewModel import com.thewizrd.common.helpers.areNotificationsEnabled import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.helpers.toImmutableCompatFlag @@ -40,6 +44,7 @@ object WeatherAlertNotificationBuilder { private const val MIN_GROUPCOUNT = 3 private const val SUMMARY_ID = -1 + @SuppressLint("MissingPermission") suspend fun createNotifications(location: LocationData, alerts: Collection) = withContext(Dispatchers.Default) { val context = appLib.context @@ -75,7 +80,7 @@ object WeatherAlertNotificationBuilder { val alertIconResId = alertVM.alertType.getDrawableFromAlertType() val notification = NotificationUtils.createNotificationBuilder(context, NOT_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_error) + .setSmallIcon(sharedRes.drawable.ic_error) .setStyle(Notification.BigTextStyle().bigText(alertVM.alertBodyMessage)) .setContentTitle(title) .setContentText(contentText) @@ -161,16 +166,16 @@ object WeatherAlertNotificationBuilder { inboxStyle.addLine(notif.value) } - inboxStyle.setBigContentTitle(context.getString(R.string.title_fragment_alerts)) - inboxStyle.setSummaryText(context.getString(R.string.app_name)) + inboxStyle.setBigContentTitle(context.getString(sharedRes.string.title_fragment_alerts)) + inboxStyle.setSummaryText(context.getString(sharedRes.string.app_name)) } else { - inboxStyle.setSummaryText(context.getString(R.string.title_fragment_alerts)) + inboxStyle.setSummaryText(context.getString(sharedRes.string.title_fragment_alerts)) } val mSummaryBuilder = NotificationCompat.Builder(context, NOT_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_error) - .setContentTitle(context.getString(R.string.title_fragment_alerts)) - .setContentText(context.getString(R.string.app_name)) + .setSmallIcon(sharedRes.drawable.ic_error) + .setContentTitle(context.getString(sharedRes.string.title_fragment_alerts)) + .setContentText(context.getString(sharedRes.string.app_name)) .setStyle(inboxStyle) .setGroup(TAG) .setGroupSummary(true) @@ -245,8 +250,10 @@ object WeatherAlertNotificationBuilder { val mNotifyMgr = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager var mChannel = mNotifyMgr.getNotificationChannel(NOT_CHANNEL_ID) - val notchannel_name = context.resources.getString(R.string.not_channel_name_alerts) - val notchannel_desc = context.resources.getString(R.string.not_channel_desc_alerts) + val notchannel_name = + context.resources.getString(sharedRes.string.not_channel_name_alerts) + val notchannel_desc = + context.resources.getString(sharedRes.string.not_channel_desc_alerts) if (mChannel == null) { mChannel = NotificationChannel(NOT_CHANNEL_ID, notchannel_name, NotificationManager.IMPORTANCE_DEFAULT) } diff --git a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationBuilder.kt b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationBuilder.kt index c2512ff75..258a71055 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationBuilder.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationBuilder.kt @@ -13,12 +13,15 @@ import android.widget.RemoteViews import androidx.annotation.IdRes import androidx.annotation.LayoutRes import androidx.core.app.NotificationCompat -import com.thewizrd.common.controls.* +import com.thewizrd.common.controls.BaseForecastItemViewModel +import com.thewizrd.common.controls.ForecastItemViewModel +import com.thewizrd.common.controls.HourlyForecastItemViewModel +import com.thewizrd.common.controls.WeatherDetailsType +import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.utils.ImageUtils.bitmapFromDrawable import com.thewizrd.common.utils.ImageUtils.rotateBitmap import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.preferences.SettingsManager import com.thewizrd.shared_resources.sharedDeps @@ -47,7 +50,6 @@ object WeatherNotificationBuilder { viewModel: WeatherUiModel ): Notification { val wim = sharedDeps.weatherIconsManager - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) // Build update val updateViews = RemoteViews( @@ -118,7 +120,7 @@ object WeatherNotificationBuilder { if (chanceModel != null) { updateViews.setImageViewResource( R.id.weather_popicon, - wip.getWeatherIconResource(chanceModel.icon) + wim.getWeatherIconResource(chanceModel.icon) ) updateViews.setTextViewText(R.id.weather_pop, chanceModel.value) updateViews.setViewVisibility(R.id.weather_pop_layout, View.VISIBLE) @@ -134,7 +136,7 @@ object WeatherNotificationBuilder { } if (windModel != null) { - val windIconResId = wip.getWeatherIconResource(WeatherIcons.WIND_DIRECTION) + val windIconResId = wim.getWeatherIconResource(WeatherIcons.WIND_DIRECTION) if (windModel.iconRotation != 0) { bigUpdateViews.setImageViewBitmap( R.id.weather_windicon, @@ -157,7 +159,7 @@ object WeatherNotificationBuilder { if (humidityModel != null) { bigUpdateViews.setImageViewResource( R.id.humidity_icon, - wip.getWeatherIconResource(humidityModel.icon) + wim.getWeatherIconResource(humidityModel.icon) ) bigUpdateViews.setTextViewText(R.id.humidity, humidityModel.value) bigUpdateViews.setViewVisibility(R.id.humidity_layout, View.VISIBLE) @@ -166,7 +168,7 @@ object WeatherNotificationBuilder { if (windGustModel != null) { bigUpdateViews.setImageViewResource( R.id.windgust_icon, - wip.getWeatherIconResource(windGustModel.icon) + wim.getWeatherIconResource(windGustModel.icon) ) bigUpdateViews.setTextViewText(R.id.windgust, windGustModel.value) bigUpdateViews.setViewVisibility(R.id.windgust_layout, View.VISIBLE) @@ -191,7 +193,7 @@ object WeatherNotificationBuilder { weatherIconResId } else { // Use default icon pack here; animated icons are not supported here - wip.getWeatherIconResource(viewModel.weatherIcon) + wim.getWeatherIconResource(viewModel.weatherIcon) } } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationWorker.kt b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationWorker.kt index 85b1ff5d0..4d27ce582 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationWorker.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/notifications/WeatherNotificationWorker.kt @@ -17,6 +17,7 @@ import com.thewizrd.common.helpers.areNotificationsEnabled import com.thewizrd.common.weatherdata.WeatherDataLoader import com.thewizrd.common.weatherdata.WeatherRequest import com.thewizrd.common.weatherdata.WeatherResult +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.preferences.SettingsManager import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.simpleweather.R @@ -165,8 +166,10 @@ class WeatherNotificationWorker(context: Context, workerParams: WorkerParameters if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { var mChannel = mNotifyMgr.getNotificationChannel(NOT_CHANNEL_ID) - val notchannel_name = context.resources.getString(R.string.not_channel_name_weather) - val notchannel_desc = context.resources.getString(R.string.not_channel_desc_weather) + val notchannel_name = + context.resources.getString(sharedRes.string.not_channel_name_weather) + val notchannel_desc = + context.resources.getString(sharedRes.string.not_channel_desc_weather) if (mChannel == null) { mChannel = NotificationChannel(NOT_CHANNEL_ID, notchannel_name, NotificationManager.IMPORTANCE_LOW) diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/ArrayMultiSelectListPreference.java b/app/src/main/java/com/thewizrd/simpleweather/preferences/ArrayMultiSelectListPreference.java index 6b6a2afc0..4eb825012 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/ArrayMultiSelectListPreference.java +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/ArrayMultiSelectListPreference.java @@ -13,8 +13,6 @@ import androidx.preference.ListPreference; import androidx.preference.MultiSelectListPreference; -import com.thewizrd.simpleweather.R; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -208,7 +206,7 @@ public static ArrayMultiSelectListPreference.SimpleSummaryProvider getInstance() @Override public CharSequence provideSummary(ArrayMultiSelectListPreference preference) { if (preference.getValues() == null || preference.getValues().isEmpty()) { - return (preference.getContext().getString(R.string.not_set)); + return (preference.getContext().getString(androidx.preference.R.string.not_set)); } else { SpannableStringBuilder sb = new SpannableStringBuilder(); diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/BaseSettingsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/BaseSettingsFragment.kt index cd3a481a0..59e44dbd7 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/BaseSettingsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/BaseSettingsFragment.kt @@ -10,6 +10,7 @@ import com.google.android.material.timepicker.TimeFormat import com.thewizrd.common.helpers.LocationPermissionLauncher import com.thewizrd.common.helpers.backgroundLocationPermissionEnabled import com.thewizrd.common.helpers.getBackgroundLocationRationale +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.preferences.timepickerpreference.TimePickerPreference @@ -44,7 +45,7 @@ abstract class BaseSettingsFragment : ToolbarPreferenceFragmentCompat() { showSnackbar( Snackbar.make( it, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/DevSettingsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/DevSettingsFragment.kt index f6741fb91..72bd1adbe 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/DevSettingsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/DevSettingsFragment.kt @@ -12,11 +12,11 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.SwitchPreference import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.simpleweather.BuildConfig -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.extras.updateFirebaseIdPreference import timber.log.Timber import java.io.File @@ -25,7 +25,7 @@ import java.io.FileOutputStream class DevSettingsFragment : ToolbarPreferenceFragmentCompat() { override val titleResId: Int - get() = R.string.title_dev_settings + get() = sharedRes.string.title_dev_settings private lateinit var intentLauncher: ActivityResultLauncher private var mLogFile: File? = null diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsFragment.kt index 2306663be..cdba42541 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsFragment.kt @@ -121,6 +121,8 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import com.google.android.material.R as materialRes +import com.thewizrd.shared_resources.R as sharedRes class SettingsFragment : BaseSettingsFragment(), OnSharedPreferenceChangeListener, @@ -165,7 +167,7 @@ class SettingsFragment : BaseSettingsFragment(), } override val titleResId: Int - get() = R.string.title_activity_settings + get() = sharedRes.string.title_activity_settings /** * Registers a listener. @@ -220,7 +222,7 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.message_enter_apikey, + sharedRes.string.message_enter_apikey, Snackbar.Duration.LONG ) ) @@ -247,7 +249,7 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -425,7 +427,7 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.error_enable_location_services, + sharedRes.string.error_enable_location_services, Snackbar.Duration.SHORT ) ) @@ -456,11 +458,11 @@ class SettingsFragment : BaseSettingsFragment(), } intervalPref = findPreference(SettingsManager.KEY_REFRESHINTERVAL)!! if (enableAdditionalRefreshIntervals()) { - intervalPref.setEntries(R.array.premium_refreshinterval_entries) - intervalPref.setEntryValues(R.array.premium_refreshinterval_values) + intervalPref.setEntries(sharedRes.array.premium_refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.premium_refreshinterval_values) } else { - intervalPref.setEntries(R.array.refreshinterval_entries) - intervalPref.setEntryValues(R.array.refreshinterval_values) + intervalPref.setEntries(sharedRes.array.refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.refreshinterval_values) } themePref = findPreference(SettingsManager.KEY_USERTHEME)!! @@ -786,7 +788,7 @@ class SettingsFragment : BaseSettingsFragment(), val code = langCodes[i] if (TextUtils.isEmpty(code)) { - langEntries[i] = requireContext().getString(R.string.summary_default) + langEntries[i] = requireContext().getString(sharedRes.string.summary_default) } else { val localeCode = code.toString() val locale = LocaleUtils.getLocaleForTag(localeCode) @@ -797,7 +799,7 @@ class SettingsFragment : BaseSettingsFragment(), languagePref.summaryProvider = SummaryProvider { preference -> if (preference.value.isNullOrBlank()) { - preference.context.getString(R.string.summary_default) + preference.context.getString(sharedRes.string.summary_default) } else { LocaleUtils.getLocaleDisplayName() } @@ -859,7 +861,7 @@ class SettingsFragment : BaseSettingsFragment(), findPreference(KEY_WEATHERNOTIFICATION)?.apply { summary = - "${getString(R.string.pref_title_onnotification)}, ${getString(R.string.not_channel_name_dailynotification)}".toPascalCase() + "${getString(sharedRes.string.pref_title_onnotification)}, ${getString(R.string.not_channel_name_dailynotification)}".toPascalCase() setOnPreferenceClickListener { // Display the fragment as the main content. activity?.findNavController(R.id.fragment_container) @@ -870,7 +872,7 @@ class SettingsFragment : BaseSettingsFragment(), findPreference(KEY_ALERTS)?.apply { summary = - "${getString(R.string.pref_title_alerts)}, ${getString(R.string.not_channel_name_precipnotification)}".toPascalCase() + "${getString(sharedRes.string.pref_title_alerts)}, ${getString(R.string.not_channel_name_precipnotification)}".toPascalCase() setOnPreferenceClickListener { // Display the fragment as the main content. activity?.findNavController(R.id.fragment_container) @@ -925,7 +927,7 @@ class SettingsFragment : BaseSettingsFragment(), } else { Toast.makeText( it.context, - R.string.message_keyinvalid, + sharedRes.string.message_keyinvalid, Toast.LENGTH_SHORT ).show() } @@ -974,12 +976,14 @@ class SettingsFragment : BaseSettingsFragment(), val keyVerified = settingsManager.isKeyVerified(providerPref.value) val colorSpan = ForegroundColorSpan(if (keyVerified) Color.GREEN else Color.RED) val summary = SpannableString( - if (keyVerified) getString(R.string.message_keyverified) else getString(R.string.message_keyinvalid) + if (keyVerified) getString(sharedRes.string.message_keyverified) else getString( + sharedRes.string.message_keyinvalid + ) ) summary.setSpan(colorSpan, 0, summary.length, 0) keyEntry.summary = summary } else { - keyEntry.summary = getString(R.string.pref_summary_apikey, providerAPI) + keyEntry.summary = getString(sharedRes.string.pref_summary_apikey, providerAPI) } } @@ -1066,7 +1070,7 @@ class SettingsFragment : BaseSettingsFragment(), private var unitsChanged = false override val titleResId: Int - get() = R.string.pref_title_units + get() = sharedRes.string.pref_title_units override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_units, null) @@ -1087,8 +1091,8 @@ class SettingsFragment : BaseSettingsFragment(), Preference.OnPreferenceClickListener { activity?.let { MaterialAlertDialogBuilder(it) - .setTitle(R.string.pref_title_units) - .setItems(R.array.default_units) { dialog, which -> + .setTitle(sharedRes.string.pref_title_units) + .setItems(sharedRes.array.default_units) { dialog, which -> val isFahrenheit: Boolean = which == 0 tempUnitPref.value = if (isFahrenheit) Units.FAHRENHEIT else Units.CELSIUS @@ -1129,7 +1133,7 @@ class SettingsFragment : BaseSettingsFragment(), class IconsFragment : IconProviderPickerFragment() { override val titleResId: Int - get() = R.string.pref_title_icons + get() = sharedRes.string.pref_title_icons override fun getDefaultKey(): String { return settingsManager.getIconsProvider() @@ -1167,6 +1171,10 @@ class SettingsFragment : BaseSettingsFragment(), return } super.onRadioButtonConfirmed(selectedKey) + AnalyticsLogger.logEvent("W_Icon_Selected", Bundle().apply { + putString("iconProvider", selectedKey) + }) + AnalyticsLogger.setUserProperty(AnalyticsProps.ICON_PROVIDER, selectedKey) } } @@ -1192,7 +1200,7 @@ class SettingsFragment : BaseSettingsFragment(), binding.lifecycleOwner = this.viewLifecycleOwner // Setup Actionbar - toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(R.attr.homeAsUpIndicator)) + toolbar.setNavigationIcon(toolbar.context.getAttrResourceId(androidx.appcompat.R.attr.homeAsUpIndicator)) toolbar.setNavigationOnClickListener { activity?.onBackPressedDispatcher?.onBackPressed() } appBarLayout.setExpanded(false) @@ -1220,7 +1228,7 @@ class SettingsFragment : BaseSettingsFragment(), }.also { nonOrderableFeaturesAdapter = it }, SpacerAdapter(requireContext().dpToPx(4f).toInt()), ButtonAdapter( - resId = R.string.action_reset, + resId = sharedRes.string.action_reset, padding = context?.dpToPx(8f)?.toInt() ?: 0, gravity = Gravity.CENTER ) { @@ -1334,8 +1342,8 @@ class SettingsFragment : BaseSettingsFragment(), @SuppressLint("MissingSuperCall") override fun updateWindowColors() { context?.let { ctx -> - var backgroundColor = ctx.getAttrColor(R.attr.colorSurfaceContainer) - var statusBarColor = ctx.getAttrColor(R.attr.colorSurfaceContainer) + var backgroundColor = ctx.getAttrColor(materialRes.attr.colorSurfaceContainer) + var statusBarColor = ctx.getAttrColor(materialRes.attr.colorSurfaceContainer) if (settingsManager.getUserThemeMode() === UserThemeMode.AMOLED_DARK) { statusBarColor = Colors.BLACK backgroundColor = Colors.BLACK @@ -1369,7 +1377,7 @@ class SettingsFragment : BaseSettingsFragment(), private lateinit var onGoingNotifPermissionLauncher: PermissionLauncher override val titleResId: Int - get() = R.string.pref_title_onnotification + get() = sharedRes.string.pref_title_onnotification override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -1382,10 +1390,10 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.notification_perm_denied, + sharedRes.string.notification_perm_denied, Snackbar.Duration.SHORT ).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.context.openAppNotificationSettingsActivity() @@ -1487,7 +1495,7 @@ class SettingsFragment : BaseSettingsFragment(), private lateinit var popChanceNotifPermissionLauncher: PermissionLauncher override val titleResId: Int - get() = R.string.label_nav_alerts + get() = sharedRes.string.label_nav_alerts override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -1500,10 +1508,10 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.notification_perm_denied, + sharedRes.string.notification_perm_denied, Snackbar.Duration.SHORT ).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.context.openAppNotificationSettingsActivity() @@ -1525,10 +1533,10 @@ class SettingsFragment : BaseSettingsFragment(), showSnackbar( Snackbar.make( it, - R.string.notification_perm_denied, + sharedRes.string.notification_perm_denied, Snackbar.Duration.SHORT ).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.context.openAppNotificationSettingsActivity() @@ -1614,7 +1622,7 @@ class SettingsFragment : BaseSettingsFragment(), private fun updateAlertPreference(enable: Boolean) { alertNotification.isEnabled = enable alertNotification.summary = - if (enable) getString(R.string.pref_summary_alerts) else getString(R.string.pref_summary_alerts_disabled) + if (enable) getString(sharedRes.string.pref_summary_alerts) else getString(sharedRes.string.pref_summary_alerts_disabled) } } @@ -1633,7 +1641,7 @@ class SettingsFragment : BaseSettingsFragment(), private lateinit var devSettingsController: DevSettingsController override val titleResId: Int - get() = R.string.pref_title_about + get() = sharedRes.string.pref_title_about override fun onCreate(savedInstanceState: Bundle?) { devSettingsController = DevSettingsController(this, KEY_ABOUTVERSION) @@ -1708,7 +1716,7 @@ class SettingsFragment : BaseSettingsFragment(), } override val titleResId: Int - get() = R.string.pref_title_credits + get() = sharedRes.string.pref_title_credits override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_credits, null) @@ -1748,7 +1756,7 @@ class SettingsFragment : BaseSettingsFragment(), class OSSCreditsFragment : BaseSettingsFragment() { override val titleResId: Int - get() = R.string.pref_title_oslibs + get() = sharedRes.string.pref_title_oslibs override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_oslibs, null) diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsPreferenceGroupAdapter.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsPreferenceGroupAdapter.kt index 64a23de45..f41753286 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsPreferenceGroupAdapter.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/SettingsPreferenceGroupAdapter.kt @@ -29,6 +29,7 @@ import androidx.preference.PreferenceCategory import androidx.preference.PreferenceGroup import androidx.preference.PreferenceGroupAdapter import androidx.preference.PreferenceViewHolder +import com.google.android.material.R as materialRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getAttrColor @@ -187,7 +188,7 @@ class SettingsPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) : if (settingsManager.getUserThemeMode() == UserThemeMode.AMOLED_DARK) { v.backgroundTintList = ColorStateList.valueOf( ColorUtils.compositeColors( - v.context.getAttrColor(R.attr.colorSurfaceDim), + v.context.getAttrColor(materialRes.attr.colorSurfaceDim), Colors.BLACK ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/ToolbarPreferenceFragmentCompat.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/ToolbarPreferenceFragmentCompat.kt index 6036e7cbb..55e4d3474 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/ToolbarPreferenceFragmentCompat.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/ToolbarPreferenceFragmentCompat.kt @@ -14,6 +14,7 @@ import androidx.annotation.StringRes import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.preference.Preference import androidx.preference.PreferenceGroup +import com.google.android.material.R as materialRes import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior import com.google.android.material.appbar.CollapsingToolbarLayout @@ -84,7 +85,7 @@ abstract class ToolbarPreferenceFragmentCompat : WindowColorPreferenceFragmentCo override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - preferenceScreen.tintIcons(requireContext().getAttrColor(R.attr.colorPrimary)) + preferenceScreen.tintIcons(requireContext().getAttrColor(androidx.appcompat.R.attr.colorPrimary)) // Toolbar binding.toolbar.setTitle(titleResId) @@ -99,8 +100,8 @@ abstract class ToolbarPreferenceFragmentCompat : WindowColorPreferenceFragmentCo @SuppressLint("NotifyDataSetChanged") protected fun updateWindowColors(mode: UserThemeMode) { activity?.let { - var backgroundColor = it.getAttrColor(R.attr.colorSurfaceContainer) - var statusBarColor = it.getAttrColor(R.attr.colorSurfaceContainer) + var backgroundColor = it.getAttrColor(materialRes.attr.colorSurfaceContainer) + var statusBarColor = it.getAttrColor(materialRes.attr.colorSurfaceContainer) if (mode == UserThemeMode.AMOLED_DARK) { statusBarColor = Colors.BLACK backgroundColor = Colors.BLACK diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/chippreference/ChipPreference.kt b/app/src/main/java/com/thewizrd/simpleweather/preferences/chippreference/ChipPreference.kt index 42b4858a1..763c3e93c 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/chippreference/ChipPreference.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/chippreference/ChipPreference.kt @@ -14,6 +14,7 @@ import androidx.core.content.res.use import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceViewHolder +import com.google.android.material.R as materialRes import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import com.google.android.material.shape.RelativeCornerSize @@ -91,7 +92,10 @@ class ChipPreference @JvmOverloads constructor( ), intArrayOf( Colors.TRANSPARENT, - ContextCompat.getColor(context, R.color.material_on_surface_stroke) + ContextCompat.getColor( + context, + materialRes.color.material_on_surface_stroke + ) ) ) shapeAppearanceModel = if (index == 0 && entries.isNotEmpty()) { @@ -113,8 +117,8 @@ class ChipPreference @JvmOverloads constructor( intArrayOf(-android.R.attr.state_checked) ), intArrayOf( - context.getAttrColor(R.attr.colorPrimaryDark), - context.getAttrColor(R.attr.colorSurfaceContainer) + context.getAttrColor(androidx.appcompat.R.attr.colorPrimaryDark), + context.getAttrColor(materialRes.attr.colorSurfaceContainer) ) ) setTextColor( @@ -124,8 +128,8 @@ class ChipPreference @JvmOverloads constructor( intArrayOf(-android.R.attr.state_checked) ), intArrayOf( - context.getAttrColor(R.attr.colorOnPrimary), - context.getAttrColor(R.attr.colorOnSurface) + context.getAttrColor(materialRes.attr.colorOnPrimary), + context.getAttrColor(materialRes.attr.colorOnSurface) ) ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/preferences/colorpreference/ColorPreference.java b/app/src/main/java/com/thewizrd/simpleweather/preferences/colorpreference/ColorPreference.java index 5ea9c477b..6cd768497 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/preferences/colorpreference/ColorPreference.java +++ b/app/src/main/java/com/thewizrd/simpleweather/preferences/colorpreference/ColorPreference.java @@ -46,7 +46,7 @@ public ColorPreference(Context context) { @SuppressLint("RestrictedApi") public ColorPreference(Context context, AttributeSet attrs) { - this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle, + this(context, attrs, TypedArrayUtils.getAttr(context, androidx.preference.R.attr.preferenceStyle, android.R.attr.preferenceStyle)); } diff --git a/app/src/main/java/com/thewizrd/simpleweather/radar/RadarProvider.kt b/app/src/main/java/com/thewizrd/simpleweather/radar/RadarProvider.kt index d2aa24a44..b0df5d283 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/radar/RadarProvider.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/radar/RadarProvider.kt @@ -11,11 +11,13 @@ import com.thewizrd.shared_resources.controls.ProviderEntry import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.weatherdata.WeatherAPI +import com.thewizrd.shared_resources.weatherdata.WeatherAPI.WEATHERAPI import com.thewizrd.simpleweather.radar.eccc.ECCCRadarViewProvider import com.thewizrd.simpleweather.radar.nws.NWSRadarViewProvider import com.thewizrd.simpleweather.radar.openweather.OWMRadarViewProvider import com.thewizrd.simpleweather.radar.rainviewer.RainViewerViewProvider import com.thewizrd.simpleweather.radar.tomorrowio.TomorrowIoRadarViewProvider +import com.thewizrd.simpleweather.radar.weatherapi.WeatherApiRadarViewProvider import com.thewizrd.weather_api.weatherModule object RadarProvider { @@ -26,7 +28,8 @@ object RadarProvider { WeatherAPI.NWS, WeatherAPI.ECCC, WeatherAPI.OPENWEATHERMAP, - WeatherAPI.TOMORROWIO + WeatherAPI.TOMORROWIO, + WeatherAPI.WEATHERAPI ) @Retention(AnnotationRetention.SOURCE) annotation class RadarProviders @@ -70,6 +73,10 @@ object RadarProvider { ProviderEntry( "Tomorrow.io", WeatherAPI.TOMORROWIO, "https://www.tomorrow.io/weather-api/", "https://www.tomorrow.io/weather-api/" + ), + ProviderEntry( + "WeatherAPI.com", WEATHERAPI, + "https://weatherapi.com", "https://weatherapi.com/api" ) ) @@ -77,19 +84,19 @@ object RadarProvider { @RadarProviders fun getRadarProvider(): String { val prefs = appLib.preferences - val provider = prefs.getString(KEY_RADARPROVIDER, WeatherAPI.RAINVIEWER)!! + val provider = prefs.getString(KEY_RADARPROVIDER, WeatherAPI.WEATHERAPI)!! if (provider == WeatherAPI.OPENWEATHERMAP) { val owm = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.OPENWEATHERMAP) // Fallback to default since API KEY is unavailable if (owm.getAPIKey() == null && settingsManager.getAPIKey(WeatherAPI.OPENWEATHERMAP) == null) { - return WeatherAPI.RAINVIEWER + return WeatherAPI.WEATHERAPI } } else if (provider == WeatherAPI.TOMORROWIO) { val tmr = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.TOMORROWIO) // Fallback to default since API KEY is unavailable if (tmr.getAPIKey() == null && settingsManager.getAPIKey(WeatherAPI.TOMORROWIO) == null) { - return WeatherAPI.RAINVIEWER + return WeatherAPI.WEATHERAPI } } @@ -102,18 +109,34 @@ object RadarProvider { val radarProvider = getRadarProvider() val isEnabled = isRadarProviderEnabled(radarProvider) - return if (radarProvider == WeatherAPI.OPENWEATHERMAP && isEnabled) { - OWMRadarViewProvider(context, rootView) - } else if (radarProvider == WeatherAPI.TOMORROWIO && isEnabled) { - TomorrowIoRadarViewProvider(context, rootView) - } else if (radarProvider == WeatherAPI.NWS && isEnabled) { - NWSRadarViewProvider(context, rootView) - } else if (radarProvider == WeatherAPI.ECCC && isEnabled) { - ECCCRadarViewProvider(context, rootView) - } else if (radarProvider == WeatherAPI.RAINVIEWER && isEnabled) { - RainViewerViewProvider(context, rootView) - } else { - EmptyRadarViewProvider(context, rootView) + return when (radarProvider) { + WeatherAPI.OPENWEATHERMAP if isEnabled -> { + OWMRadarViewProvider(context, rootView) + } + + WeatherAPI.TOMORROWIO if isEnabled -> { + TomorrowIoRadarViewProvider(context, rootView) + } + + WeatherAPI.NWS if isEnabled -> { + NWSRadarViewProvider(context, rootView) + } + + WeatherAPI.ECCC if isEnabled -> { + ECCCRadarViewProvider(context, rootView) + } + + WeatherAPI.RAINVIEWER if isEnabled -> { + RainViewerViewProvider(context, rootView) + } + + WeatherAPI.WEATHERAPI if isEnabled -> { + WeatherApiRadarViewProvider(context, rootView) + } + + else -> { + EmptyRadarViewProvider(context, rootView) + } } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt b/app/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt index 80e7f24ca..3ab11bcdf 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt @@ -9,6 +9,7 @@ import android.content.Intent import android.os.Build import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.helpers.toImmutableCompatFlag import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.notifications.NotificationUtils @@ -22,7 +23,7 @@ internal object ServiceNotificationHelper { // Gets an instance of the NotificationManager service val mNotifyMgr = context.getSystemService(NotificationManager::class.java) var mChannel = mNotifyMgr.getNotificationChannel(NOT_CHANNEL_ID) - val notchannel_name = context.resources.getString(R.string.not_channel_name_general) + val notchannel_name = context.resources.getString(sharedRes.string.not_channel_name_general) if (mChannel == null) { mChannel = NotificationChannel(NOT_CHANNEL_ID, notchannel_name, NotificationManager.IMPORTANCE_LOW) } @@ -38,7 +39,7 @@ internal object ServiceNotificationHelper { internal fun createForegroundNotification(context: Context): Notification { val notif = NotificationCompat.Builder(context, NOT_CHANNEL_ID).apply { setSmallIcon(R.drawable.wi_cloud_refresh) - setSubText(context.getString(R.string.app_name)) + setSubText(context.getString(sharedRes.string.app_name)) setContentTitle(context.getString(R.string.message_widgetservice_running)) setOnlyAlertOnce(true) setSilent(true) diff --git a/app/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt b/app/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt index 5eb385cd6..ce5a59cec 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt @@ -1,5 +1,6 @@ package com.thewizrd.simpleweather.services +import android.annotation.SuppressLint import android.app.Notification import android.content.Context import android.content.Intent @@ -23,6 +24,7 @@ import androidx.work.WorkManager import androidx.work.WorkerParameters import androidx.work.multiprocess.RemoteWorkManager import com.thewizrd.common.helpers.locationPermissionEnabled +import com.thewizrd.common.helpers.notificationPermissionEnabled import com.thewizrd.common.location.LocationProvider import com.thewizrd.common.location.LocationResult import com.thewizrd.common.utils.ErrorMessage @@ -30,6 +32,7 @@ import com.thewizrd.common.utils.LiveDataUtils.awaitWithTimeout import com.thewizrd.common.weatherdata.WeatherDataLoader import com.thewizrd.common.weatherdata.WeatherRequest import com.thewizrd.common.weatherdata.WeatherResult +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.preferences.SettingsManager @@ -150,9 +153,9 @@ class WeatherUpdaterWorker(context: Context, workerParams: WorkerParameters) : C } return NotificationCompat.Builder(context, NOT_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_launcher_monochrome) - .setContentTitle(context.getString(R.string.not_title_weather_update)) - .setColor(ContextCompat.getColor(context, R.color.colorPrimary)) + .setSmallIcon(sharedRes.drawable.ic_launcher_monochrome) + .setContentTitle(context.getString(sharedRes.string.not_title_weather_update)) + .setColor(ContextCompat.getColor(context, sharedRes.color.colorPrimary)) .setOnlyAlertOnce(true) .setSilent(true) .setPriority(NotificationCompat.PRIORITY_LOW) @@ -170,6 +173,7 @@ class WeatherUpdaterWorker(context: Context, workerParams: WorkerParameters) : C } private object WeatherUpdaterHelper { + @SuppressLint("MissingPermission") suspend fun executeWork(context: Context): Result { var result = Result.success() @@ -333,7 +337,7 @@ class WeatherUpdaterWorker(context: Context, workerParams: WorkerParameters) : C val locMan = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager? if (locMan == null || !LocationManagerCompat.isLocationEnabled(locMan)) { - return LocationResult.Error(errorMessage = ErrorMessage.Resource(R.string.error_retrieve_location)) + return LocationResult.Error(errorMessage = ErrorMessage.Resource(sharedRes.string.error_retrieve_location)) } return locationProvider.getLatestLocationData(settingsManager.getLastGPSLocData()) diff --git a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupActivity.kt b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupActivity.kt index 1511982f3..8297341e8 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupActivity.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupActivity.kt @@ -19,6 +19,7 @@ import androidx.navigation.NavOptions import androidx.navigation.findNavController import androidx.navigation.fragment.NavHostFragment import androidx.transition.TransitionManager +import com.google.android.material.R as materialRes import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback import com.thewizrd.common.utils.ActivityUtils.setTransparentWindow import com.thewizrd.shared_resources.Constants @@ -77,7 +78,7 @@ class SetupActivity : UserLocaleActivity() { insets } - val color = getAttrColor(R.attr.colorPrimarySurface) + val color = getAttrColor(materialRes.attr.colorPrimarySurface) window.setTransparentWindow(color) lifecycleScope.launch { diff --git a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupLocationFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupLocationFragment.kt index 0232d0ba7..c144a5d1f 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupLocationFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupLocationFragment.kt @@ -20,6 +20,7 @@ import com.thewizrd.common.helpers.locationPermissionEnabled import com.thewizrd.common.utils.ErrorMessage import com.thewizrd.common.viewmodels.LocationSearchResult import com.thewizrd.common.viewmodels.LocationSearchViewModel +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.locationdata.LocationData @@ -85,7 +86,7 @@ class SetupLocationFragment : CustomFragment() { showSnackbar( Snackbar.make( requireContext(), - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupProviderFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupProviderFragment.kt index a2062bdea..42d65e4b1 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupProviderFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupProviderFragment.kt @@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.transition.MaterialSharedAxis import com.thewizrd.common.preferences.KeyEntryPreferenceDialogFragment +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.controls.ProviderEntry import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.exceptions.WeatherException @@ -273,7 +274,7 @@ class SetupProviderFragment : CustomPreferenceFragmentCompat(), StepperFragment fragment.dialog?.dismiss() } else { - showToast(R.string.message_keyinvalid, Toast.LENGTH_SHORT) + showToast(sharedRes.string.message_keyinvalid, Toast.LENGTH_SHORT) } } catch (e: WeatherException) { Logger.writeLine(Log.ERROR, e) @@ -297,13 +298,16 @@ class SetupProviderFragment : CustomPreferenceFragmentCompat(), StepperFragment val keyVerified = settingsManager.isKeyVerified(providerPref.value) val colorSpan = ForegroundColorSpan(if (keyVerified) Color.GREEN else Color.RED) val summary = SpannableString( - if (keyVerified) getString(R.string.message_keyverified) else getString(R.string.message_keyinvalid) + if (keyVerified) getString(sharedRes.string.message_keyverified) else getString( + sharedRes.string.message_keyinvalid + ) ) summary.setSpan(colorSpan, 0, summary.length, 0) keyEntry.summary = summary } else { val colorSpan = ForegroundColorSpan(Color.RED) - val summary = SpannableString(getString(R.string.pref_summary_apikey, providerAPI)) + val summary = + SpannableString(getString(sharedRes.string.pref_summary_apikey, providerAPI)) summary.setSpan(colorSpan, 0, summary.length, 0) keyEntry.summary = summary } @@ -333,7 +337,7 @@ class SetupProviderFragment : CustomPreferenceFragmentCompat(), StepperFragment showSnackbar( Snackbar.make( it, - R.string.message_enter_apikey, + sharedRes.string.message_enter_apikey, Snackbar.Duration.LONG ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupSettingsFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupSettingsFragment.kt index ab01fdf83..4ac8450ab 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/setup/SetupSettingsFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/setup/SetupSettingsFragment.kt @@ -27,6 +27,7 @@ import com.thewizrd.shared_resources.preferences.SettingsManager import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx import com.thewizrd.shared_resources.utils.Units +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.adapters.SpacerAdapter import com.thewizrd.simpleweather.databinding.FragmentSetupSettingsBinding @@ -67,10 +68,10 @@ class SetupSettingsFragment : CustomPreferenceFragmentCompat() { showSnackbar( Snackbar.make( it, - R.string.notification_perm_denied, + sharedRes.string.notification_perm_denied, Snackbar.Duration.SHORT ).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.context.openAppNotificationSettingsActivity() @@ -92,10 +93,10 @@ class SetupSettingsFragment : CustomPreferenceFragmentCompat() { showSnackbar( Snackbar.make( it, - R.string.notification_perm_denied, + sharedRes.string.notification_perm_denied, Snackbar.Duration.SHORT ).apply { - setAction(R.string.action_settings) { + setAction(sharedRes.string.action_settings) { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.context.openAppNotificationSettingsActivity() @@ -179,11 +180,11 @@ class SetupSettingsFragment : CustomPreferenceFragmentCompat() { } if (enableAdditionalRefreshIntervals()) { - intervalPref.setEntries(R.array.premium_refreshinterval_entries) - intervalPref.setEntryValues(R.array.premium_refreshinterval_values) + intervalPref.setEntries(sharedRes.array.premium_refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.premium_refreshinterval_values) } else { - intervalPref.setEntries(R.array.refreshinterval_entries) - intervalPref.setEntryValues(R.array.refreshinterval_values) + intervalPref.setEntries(sharedRes.array.refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.refreshinterval_values) } onGoingPref.setOnPreferenceChangeListener { preference, newValue -> diff --git a/app/src/main/java/com/thewizrd/simpleweather/snackbar/SnackbarManager.java b/app/src/main/java/com/thewizrd/simpleweather/snackbar/SnackbarManager.java index 0e2808427..2ffe084f9 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/snackbar/SnackbarManager.java +++ b/app/src/main/java/com/thewizrd/simpleweather/snackbar/SnackbarManager.java @@ -15,7 +15,6 @@ import com.google.android.material.snackbar.BaseTransientBottomBar; import com.thewizrd.shared_resources.ApplicationLibKt; -import com.thewizrd.simpleweather.R; import java.util.Stack; @@ -168,18 +167,15 @@ public boolean canSwipeDismissView(View child) { mSnackbarView.setText(snackPair.snackbar.getMessageText()); mSnackbarView.setAction(snackPair.snackbar.getActionText(), snackPair.snackbar.getAction()); // Override Snackbar action click listener to prevent it from being dismissed on click - mSnackbarView.getView().findViewById(R.id.snackbar_action).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (snackPair.snackbar.getAction() != null) { - snackPair.snackbar.getAction().onClick(v); - } - // Now dismiss the Snackbar - if (snackPair.callback != null) - snackPair.callback.onDismissed(mSnackbarView, BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_ACTION); - if (!mSnacks.isEmpty()) mSnacks.pop(); - updateView(); + mSnackbarView.getView().findViewById(com.google.android.material.R.id.snackbar_action).setOnClickListener(v -> { + if (snackPair.snackbar.getAction() != null) { + snackPair.snackbar.getAction().onClick(v); } + // Now dismiss the Snackbar + if (snackPair.callback != null) + snackPair.callback.onDismissed(mSnackbarView, BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_ACTION); + if (!mSnacks.isEmpty()) mSnacks.pop(); + updateView(); }); if (!mSnackbarView.isShown()) mSnackbarView.show(); diff --git a/app/src/main/java/com/thewizrd/simpleweather/stepper/BottomStepperNavigationBar.java b/app/src/main/java/com/thewizrd/simpleweather/stepper/BottomStepperNavigationBar.java index 23ed48d42..e37bb0700 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/stepper/BottomStepperNavigationBar.java +++ b/app/src/main/java/com/thewizrd/simpleweather/stepper/BottomStepperNavigationBar.java @@ -90,11 +90,11 @@ private void initialize(Context context, @Nullable AttributeSet attrs, @AttrRes private void initDefaultValues(Context context) { mBackgroundColor = ContextUtils.getAttrResourceId(context, android.R.attr.colorBackground); - mForegroundColor = ContextUtils.getAttrColorStateList(context, R.attr.colorAccent); + mForegroundColor = ContextUtils.getAttrColorStateList(context, androidx.appcompat.R.attr.colorAccent); - mBackButtonText = context.getString(R.string.label_back); - mStartButtonText = mNextButtonText = context.getString(R.string.label_next); - mCompleteButtonText = context.getString(R.string.abc_action_mode_done); + mBackButtonText = context.getString(com.thewizrd.shared_resources.R.string.label_back); + mStartButtonText = mNextButtonText = context.getString(com.thewizrd.shared_resources.R.string.label_next); + mCompleteButtonText = context.getString(androidx.appcompat.R.string.abc_action_mode_done); mBackButtonIcon = ContextCompat.getDrawable(context, R.drawable.ic_chevron_left); mNextButtonIcon = ContextCompat.getDrawable(context, R.drawable.ic_chevron_right); diff --git a/app/src/main/java/com/thewizrd/simpleweather/viewmodels/LocationsViewModel.kt b/app/src/main/java/com/thewizrd/simpleweather/viewmodels/LocationsViewModel.kt index 0bf7775bd..f7422437a 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/viewmodels/LocationsViewModel.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/viewmodels/LocationsViewModel.kt @@ -21,6 +21,7 @@ import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.utils.CommonActions import com.thewizrd.shared_resources.weatherdata.model.LocationType +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.controls.LocationPanelUiModel import kotlinx.coroutines.Dispatchers @@ -263,7 +264,7 @@ class LocationsViewModel(app: Application) : AndroidViewModel(app) { getApplication().getSystemService(Context.LOCATION_SERVICE) as? LocationManager if (locMan == null || !LocationManagerCompat.isLocationEnabled(locMan)) { - return LocationResult.Error(errorMessage = ErrorMessage.Resource(R.string.error_retrieve_location)) + return LocationResult.Error(errorMessage = ErrorMessage.Resource(sharedRes.string.error_retrieve_location)) } return locationProvider.getLatestLocationData() diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/AppChoiceDialogBuilder.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/AppChoiceDialogBuilder.kt index 55028f564..ca99d94f6 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/AppChoiceDialogBuilder.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/AppChoiceDialogBuilder.kt @@ -20,7 +20,7 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.thewizrd.common.helpers.SimpleRecyclerViewAdapterObserver import com.thewizrd.shared_resources.helpers.ListAdapterOnClickInterface -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R import com.thewizrd.simpleweather.databinding.AppItemLayoutBinding import com.thewizrd.simpleweather.databinding.DialogAppchooserBinding import kotlinx.coroutines.CoroutineScope @@ -75,7 +75,7 @@ class AppChoiceDialogBuilder(private val context: Context) { fun show() { val dialog = MaterialAlertDialogBuilder(context) - .setTitle(R.string.abc_activitychooserview_choose_application) + .setTitle(androidx.appcompat.R.string.abc_activitychooserview_choose_application) .setCancelable(true) .setView(createView()) .setNegativeButton(android.R.string.cancel) { dialog, which -> dialog.cancel() } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider.kt index 05fb0792c..8721d7b06 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider.kt @@ -8,6 +8,7 @@ import android.os.Bundle import android.util.Log import android.widget.RemoteViews import android.widget.Toast +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.simpleweather.BuildConfig import com.thewizrd.simpleweather.R @@ -50,7 +51,7 @@ abstract class WeatherWidgetProvider : AppWidgetProvider() { Toast.makeText( context, - context.getString(R.string.action_refresh) + "...", + context.getString(sharedRes.string.action_refresh) + "...", Toast.LENGTH_SHORT ).show() refreshWidget(context, intArrayOf(appWidgetId)) diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider1x1Custom.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider1x1Custom.kt new file mode 100644 index 000000000..552efeb2a --- /dev/null +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WeatherWidgetProvider1x1Custom.kt @@ -0,0 +1,28 @@ +package com.thewizrd.simpleweather.widgets + +import com.thewizrd.simpleweather.R + +class WeatherWidgetProvider1x1Custom : WeatherWidgetProvider() { + override val info: WidgetProviderInfo by lazy { Info.getInstance() } + + class Info private constructor() : WidgetProviderInfo() { + override val className: String + get() = WeatherWidgetProvider1x1Custom::class.java.name + override val widgetType: WidgetType + get() = WidgetType.Widget1x1Custom + override val widgetLayoutId: Int + get() = R.layout.app_widget_1x1_custom + + companion object { + private var _instance: WidgetProviderInfo? = null + + @JvmStatic + fun getInstance(): WidgetProviderInfo { + if (_instance == null) { + _instance = Info() + } + return _instance!! + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetGraphType.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetGraphType.kt index a6ebd4ec2..1c6c03ffb 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetGraphType.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetGraphType.kt @@ -16,7 +16,7 @@ enum class WidgetGraphType(val value: Int) { private val map = SparseArray() init { - for (type in values()) { + for (type in entries) { map.put(type.value, type) } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetType.java b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetType.java index 9540b0e4c..eb841b499 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetType.java +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetType.java @@ -22,7 +22,8 @@ public enum WidgetType { Widget4x2Tomorrow(15), Widget2x2M3(16), Widget4x4M3(17), - Widget4x2M3(18); + Widget4x2M3(18), + Widget1x1Custom(19); private final int value; diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUpdaterHelper.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUpdaterHelper.kt index 491959ee4..5fcddff47 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUpdaterHelper.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUpdaterHelper.kt @@ -20,6 +20,7 @@ import com.thewizrd.common.controls.HourlyForecastItemViewModel import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.helpers.toImmutableCompatFlag @@ -439,7 +440,7 @@ object WidgetUpdaterHelper { val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUtils.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUtils.kt index ef5d3e909..0c4c3873b 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUtils.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/WidgetUtils.kt @@ -10,6 +10,7 @@ import android.util.Log import android.util.SparseArray import androidx.annotation.ColorInt import androidx.core.content.edit +import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager @@ -20,8 +21,10 @@ import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.verifyActivityInfo import com.thewizrd.shared_resources.utils.JSONParser import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.simpleweather.widgets.preferences.KEY_WEATHERDETAILSTYPEOPTION import com.thewizrd.simpleweather.widgets.remoteviews.AbstractWidgetRemoteViewCreator import com.thewizrd.simpleweather.widgets.remoteviews.WeatherWidget1x1Creator +import com.thewizrd.simpleweather.widgets.remoteviews.WeatherWidget1x1CustomCreator import com.thewizrd.simpleweather.widgets.remoteviews.WeatherWidget2x2Creator import com.thewizrd.simpleweather.widgets.remoteviews.WeatherWidget2x2M3Creator import com.thewizrd.simpleweather.widgets.remoteviews.WeatherWidget2x2MaterialYouCreator @@ -258,6 +261,9 @@ object WidgetUtils { WidgetType.Widget1x1 -> { mAppWidgetManager.getAppWidgetIds(WeatherWidgetProvider1x1.Info.getInstance().componentName) } + WidgetType.Widget1x1Custom -> { + mAppWidgetManager.getAppWidgetIds(WeatherWidgetProvider1x1Custom.Info.getInstance().componentName) + } WidgetType.Widget2x2 -> { mAppWidgetManager.getAppWidgetIds(WeatherWidgetProvider2x2.Info.getInstance().componentName) } @@ -306,11 +312,9 @@ object WidgetUtils { WidgetType.Widget2x2M3 -> mAppWidgetManager.getAppWidgetIds( WeatherWidgetProvider2x2M3.Info.getInstance().componentName ) - WidgetType.Widget4x4M3 -> mAppWidgetManager.getAppWidgetIds( WeatherWidgetProvider4x4M3.Info.getInstance().componentName ) - WidgetType.Widget4x2M3 -> mAppWidgetManager.getAppWidgetIds( WeatherWidgetProvider4x2M3.Info.getInstance().componentName ) @@ -321,6 +325,7 @@ object WidgetUtils { return when (widgetType) { WidgetType.Unknown -> null WidgetType.Widget1x1 -> WeatherWidgetProvider1x1.Info.getInstance() + WidgetType.Widget1x1Custom -> WeatherWidgetProvider1x1Custom.Info.getInstance() WidgetType.Widget2x2 -> WeatherWidgetProvider2x2.Info.getInstance() WidgetType.Widget4x1 -> WeatherWidgetProvider4x1.Info.getInstance() WidgetType.Widget4x2 -> WeatherWidgetProvider4x2.Info.getInstance() @@ -663,7 +668,8 @@ object WidgetUtils { val widgetWidth = getMinSizeForCell( when (widgetType) { WidgetType.Unknown -> 0 - WidgetType.Widget1x1 -> 1 + WidgetType.Widget1x1, + WidgetType.Widget1x1Custom -> 1 WidgetType.Widget2x2 -> 2 WidgetType.Widget4x1 -> 4 WidgetType.Widget4x2 -> 4 @@ -688,7 +694,8 @@ object WidgetUtils { val widgetHeight = getMinSizeForCell( when (widgetType) { WidgetType.Unknown -> 0 - WidgetType.Widget1x1 -> 1 + WidgetType.Widget1x1, + WidgetType.Widget1x1Custom -> 1 WidgetType.Widget2x2 -> 2 WidgetType.Widget4x1 -> 1 WidgetType.Widget4x2 -> 2 @@ -769,6 +776,9 @@ object WidgetUtils { WeatherWidgetProvider1x1.Info.getInstance().widgetLayoutId -> { return WidgetType.Widget1x1 } + WeatherWidgetProvider1x1Custom.Info.getInstance().widgetLayoutId -> { + return WidgetType.Widget1x1Custom + } WeatherWidgetProvider2x2.Info.getInstance().widgetLayoutId -> { return WidgetType.Widget2x2 } @@ -835,6 +845,7 @@ object WidgetUtils { return when (getWidgetTypeFromID(appWidgetId)) { WidgetType.Unknown -> throw IllegalArgumentException("Unknown widget type") WidgetType.Widget1x1 -> WeatherWidget1x1Creator(context) + WidgetType.Widget1x1Custom -> WeatherWidget1x1CustomCreator(context) WidgetType.Widget2x2 -> WeatherWidget2x2Creator(context) WidgetType.Widget4x1 -> WeatherWidget4x1Creator(context) WidgetType.Widget4x2 -> WeatherWidget4x2Creator(context) @@ -922,7 +933,7 @@ object WidgetUtils { } fun isLocationNameOptionalWidget(widgetType: WidgetType): Boolean { - return widgetType == WidgetType.Widget1x1 || widgetType == WidgetType.Widget4x1 || widgetType == WidgetType.Widget4x1Google || widgetType == WidgetType.Widget4x2Clock || widgetType == WidgetType.Widget4x2Graph + return widgetType == WidgetType.Widget1x1 || widgetType == WidgetType.Widget1x1Custom || widgetType == WidgetType.Widget4x1 || widgetType == WidgetType.Widget4x1Google || widgetType == WidgetType.Widget4x2Clock || widgetType == WidgetType.Widget4x2Graph } fun isSettingsButtonOptional(widgetType: WidgetType): Boolean { @@ -1185,6 +1196,20 @@ object WidgetUtils { } } + fun getWidgetDetailsType(widgetId: Int): WeatherDetailsType { + val prefs = getPreferences(widgetId) + + val value = prefs.getInt(KEY_WEATHERDETAILSTYPEOPTION, 0) + + return WeatherDetailsType.valueOf(value) + } + + fun setWidgetDetailsType(widgetId: Int, value: Int) { + getPreferences(widgetId).edit(true) { + putInt(KEY_WEATHERDETAILSTYPEOPTION, value) + } + } + fun getCustomTextSizeMultiplier(widgetId: Int): Float { val prefs = getPreferences(widgetId) return prefs.getFloat(KEY_CUSTOMTXTMULTIPLIER, 1f) diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/AbstractWeatherWidgetPreferenceFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/AbstractWeatherWidgetPreferenceFragment.kt index 860a9bbca..e678ee320 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/AbstractWeatherWidgetPreferenceFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/AbstractWeatherWidgetPreferenceFragment.kt @@ -55,6 +55,7 @@ import com.thewizrd.shared_resources.utils.ContextUtils.isNightMode import com.thewizrd.shared_resources.utils.ContextUtils.isSmallestWidth import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.model.AirQuality +import com.thewizrd.shared_resources.weatherdata.model.Astronomy import com.thewizrd.shared_resources.weatherdata.model.Atmosphere import com.thewizrd.shared_resources.weatherdata.model.Beaufort import com.thewizrd.shared_resources.weatherdata.model.Condition @@ -64,6 +65,7 @@ import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Location import com.thewizrd.shared_resources.weatherdata.model.LocationType import com.thewizrd.shared_resources.weatherdata.model.MinutelyForecast +import com.thewizrd.shared_resources.weatherdata.model.MoonPhase import com.thewizrd.shared_resources.weatherdata.model.Pollen import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.UV @@ -90,6 +92,7 @@ import kotlin.math.min import kotlin.math.roundToInt import kotlin.properties.Delegates import kotlin.random.Random +import com.thewizrd.shared_resources.R as sharedRes abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragmentCompat() { // Widget id for ConfigurationActivity @@ -191,7 +194,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme showSnackbar( Snackbar.make( it, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -206,7 +209,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme showSnackbar( Snackbar.make( it, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -467,7 +470,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme requireContext().getSystemService(Context.LOCATION_SERVICE) as? LocationManager if (locMan == null || !LocationManagerCompat.isLocationEnabled(locMan)) { - return LocationResult.Error(errorMessage = ErrorMessage.Resource(R.string.error_retrieve_location)) + return LocationResult.Error(errorMessage = ErrorMessage.Resource(sharedRes.string.error_retrieve_location)) } return locationProvider.getLatestLocationData() @@ -483,6 +486,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme } } + @SuppressLint("RestrictedApi") protected fun updateMockLocation(locationName: String, locationQuery: String) { mockLocationData.name = locationName mockLocationData.query = locationQuery @@ -518,7 +522,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme highC = 23f + index / 2f lowF = 60f - index lowC = 17f - index / 2f - condition = getString(R.string.weather_sunny) + condition = getString(sharedRes.string.weather_sunny) icon = WeatherIcons.DAY_SUNNY extras = ForecastExtras().apply { feelslikeF = 80f @@ -550,10 +554,8 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme date = ZonedDateTime.now().plusHours(index.toLong()) highF = 70f + index highC = 23f + index / 2f - condition = getString(R.string.weather_sunny) + condition = getString(sharedRes.string.weather_sunny) icon = WeatherIcons.DAY_SUNNY - windMph = 5f - windKph = 8f extras = ForecastExtras().apply { feelslikeF = 80f feelslikeC = 26f @@ -596,7 +598,7 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme } } condition = Condition().apply { - weather = getString(R.string.weather_sunny) + weather = getString(sharedRes.string.weather_sunny) tempF = 70f tempC = 21f windDegrees = 292 @@ -622,7 +624,22 @@ abstract class AbstractWeatherWidgetPreferenceFragment : ToolbarPreferenceFragme ragweedPollenCount = Pollen.PollenCount.MODERATE } } - atmosphere = Atmosphere() + atmosphere = Atmosphere().apply { + humidity = 80 + pressureIn = 30.06f + pressureMb = 1018f + visibilityMi = 10f + visibilityKm = 16f + dewpointF = 62f + dewpointC = 16.6f + } + astronomy = Astronomy().apply { + sunrise = LocalDate.now().atTime(5, 30) + sunset = LocalDate.now().atTime(20, 0) + moonrise = LocalDate.now().atTime(15, 0) + moonset = LocalDate.now().atTime(3, 0) + moonPhase = MoonPhase(MoonPhase.MoonPhaseType.WAXING_GIBBOUS) + } precipitation = Precipitation().apply { pop = 15 cloudiness = 25 diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/BaseWeatherWidgetPreferenceFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/BaseWeatherWidgetPreferenceFragment.kt index 2d48dfd9b..66e4c9d4e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/BaseWeatherWidgetPreferenceFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/BaseWeatherWidgetPreferenceFragment.kt @@ -16,6 +16,7 @@ import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.request.RequestOptions import com.thewizrd.common.preferences.SliderPreference import com.thewizrd.common.utils.glide.TransparentOverlay +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.preferences.colorpreference.ColorPreference import com.thewizrd.simpleweather.widgets.AppChoiceDialogBuilder @@ -286,7 +287,7 @@ abstract class BaseWeatherWidgetPreferenceFragment : AbstractWeatherWidgetPrefer } } - clockPref.setSummary(R.string.summary_default) + clockPref.setSummary(sharedRes.string.summary_default) } private fun updateCalPreference(context: Context) { @@ -304,7 +305,7 @@ abstract class BaseWeatherWidgetPreferenceFragment : AbstractWeatherWidgetPrefer } } - calPref.setSummary(R.string.summary_default) + calPref.setSummary(sharedRes.string.summary_default) } protected fun updateBackground() { diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidget4x3LocationFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidget4x3LocationFragment.kt index cfb5eb437..25615c841 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidget4x3LocationFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidget4x3LocationFragment.kt @@ -22,6 +22,7 @@ import com.google.android.material.snackbar.BaseTransientBottomBar import com.thewizrd.common.helpers.backgroundLocationPermissionEnabled import com.thewizrd.common.helpers.getBackgroundLocationRationale import com.thewizrd.common.location.LocationResult +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.localBroadcastManager import com.thewizrd.shared_resources.di.settingsManager @@ -265,7 +266,7 @@ class WeatherWidget4x3LocationFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_retrieve_location, + sharedRes.string.error_retrieve_location, Snackbar.Duration.SHORT ) ) @@ -295,7 +296,11 @@ class WeatherWidget4x3LocationFragment : BaseWeatherWidgetPreferenceFragment() { finalizeWidgetUpdate() } else { showSnackbar( - Snackbar.make(ctx, R.string.prompt_location_not_set, Snackbar.Duration.SHORT) + Snackbar.make( + ctx, + sharedRes.string.prompt_location_not_set, + Snackbar.Duration.SHORT + ) ) } } @@ -336,7 +341,7 @@ class WeatherWidget4x3LocationFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_enable_location_services, + sharedRes.string.error_enable_location_services, Snackbar.Duration.SHORT ) ) @@ -359,7 +364,7 @@ class WeatherWidget4x3LocationFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -369,7 +374,7 @@ class WeatherWidget4x3LocationFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_retrieve_location, + sharedRes.string.error_retrieve_location, Snackbar.Duration.SHORT ) ) diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidgetPreferenceFragment.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidgetPreferenceFragment.kt index ec9217a2f..c04338025 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidgetPreferenceFragment.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WeatherWidgetPreferenceFragment.kt @@ -25,6 +25,8 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.SwitchPreference import com.google.android.material.snackbar.BaseTransientBottomBar +import com.thewizrd.common.controls.DetailItemViewModel +import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.common.helpers.backgroundLocationPermissionEnabled import com.thewizrd.common.helpers.getBackgroundLocationRationale import com.thewizrd.common.helpers.locationPermissionEnabled @@ -56,6 +58,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import com.google.android.material.snackbar.Snackbar as materialSnackbar +import com.thewizrd.shared_resources.R as sharedRes class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { private lateinit var favorites: MutableCollection @@ -68,6 +71,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { private lateinit var fcastOptPref: ListPreference private lateinit var tap2switchPref: SwitchPreference private lateinit var graphTypePref: ListPreference + private lateinit var detailsTypePref: ListPreference override fun getPreferencesResId(): Int = R.xml.pref_widgetconfig @@ -79,7 +83,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { lifecycleScope.launch { locationPref.addEntry(R.string.pref_item_gpslocation, Constants.KEY_GPS) - locationPref.addEntry(R.string.label_btn_add_location, Constants.KEY_SEARCH) + locationPref.addEntry(sharedRes.string.label_btn_add_location, Constants.KEY_SEARCH) val favs = settingsManager.getFavorites() favorites.addAll(favs) @@ -244,6 +248,32 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { fcastOptPref.setValueIndex(WidgetUtils.ForecastOption.FULL.value) findPreference(KEY_FORECAST)!!.isVisible = false } + + if (mWidgetType == WidgetType.Widget1x1Custom) { + detailsTypePref = findPreference(KEY_WEATHERDETAILSTYPEOPTION)!! + + val entries = WeatherDetailsType.entries + + detailsTypePref.entries = entries.map { + DetailItemViewModel(it, "").label + }.toTypedArray() + detailsTypePref.entryValues = entries.map { it.value.toString() }.toTypedArray() + + detailsTypePref.onPreferenceChangeListener = + Preference.OnPreferenceChangeListener { _, newValue -> + mWidgetOptions.putSerializable( + KEY_WEATHERDETAILSTYPEOPTION, + WeatherDetailsType.valueOf(newValue.toString().toInt()) + ) + updateWidgetView() + true + } + detailsTypePref.isVisible = true + + val detailsType = WidgetUtils.getWidgetDetailsType(mAppWidgetId) + detailsTypePref.value = detailsType.value.toString() + detailsTypePref.callChangeListener(detailsTypePref.value) + } } override fun onSetupActivityResult(result: ActivityResult) { @@ -347,6 +377,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { 96f * when (mWidgetType) { WidgetType.Unknown -> 4 WidgetType.Widget1x1 -> 1 + WidgetType.Widget1x1Custom -> 1 WidgetType.Widget2x2 -> 2 WidgetType.Widget4x1 -> 1 WidgetType.Widget4x2 -> 2 @@ -371,6 +402,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { 96f * when (mWidgetType) { WidgetType.Unknown -> 4 WidgetType.Widget1x1 -> 1 + WidgetType.Widget1x1Custom -> 1 WidgetType.Widget2x2 -> 4 /* 2 is too small */ WidgetType.Widget4x1 -> 4 WidgetType.Widget4x2 -> 4 @@ -412,7 +444,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { locationPref.findEntryFromValue(it)?.toString() } ?: locationView.context.getString(R.string.pref_location)).run { if (WidgetUtils.isBackgroundOptionalWidget(mWidgetType) && txtShadowPref.isChecked) { - applySpan(TextAppearanceSpan(locationView.context, R.style.ShadowText)) + applySpan(TextAppearanceSpan(locationView.context, sharedRes.style.ShadowText)) } else { this } @@ -491,7 +523,11 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { } else { context?.let { showSnackbar( - Snackbar.make(it, R.string.error_retrieve_location, Snackbar.Duration.SHORT) + Snackbar.make( + it, + sharedRes.string.error_retrieve_location, + Snackbar.Duration.SHORT + ) ) } } @@ -527,7 +563,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_enable_location_services, + sharedRes.string.error_enable_location_services, Snackbar.Duration.SHORT ) ) @@ -550,7 +586,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_location_denied, + sharedRes.string.error_location_denied, Snackbar.Duration.SHORT ) ) @@ -560,7 +596,7 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { showSnackbar( Snackbar.make( ctx, - R.string.error_retrieve_location, + sharedRes.string.error_retrieve_location, Snackbar.Duration.SHORT ) ) @@ -625,6 +661,9 @@ class WeatherWidgetPreferenceFragment : BaseWeatherWidgetPreferenceFragment() { if (mWidgetType == WidgetType.Widget4x2Graph) { WidgetUtils.setWidgetGraphType(mAppWidgetId, graphTypePref.value.toInt()) } + if (mWidgetType == WidgetType.Widget1x1Custom) { + WidgetUtils.setWidgetDetailsType(mAppWidgetId, detailsTypePref.value.toInt()) + } super.finalizeWidgetUpdate() } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WidgetPreferenceKeys.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WidgetPreferenceKeys.kt index 8f13c894d..cb28e20f2 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WidgetPreferenceKeys.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/preferences/WidgetPreferenceKeys.kt @@ -22,6 +22,7 @@ internal const val KEY_FORECAST = "key_forecast" internal const val KEY_FORECASTOPTION = "key_fcastoption" internal const val KEY_TAP2SWITCH = "key_tap2switch" internal const val KEY_GRAPHTYPEOPTION = "key_graphtypeoption" +internal const val KEY_WEATHERDETAILSTYPEOPTION = "key_weatherdetailstypeoption" internal const val KEY_CATCUSTOMSIZE = "key_custom_size" internal const val KEY_TEXTSIZE = "key_textsize" diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/CustomBackgroundWidgetRemoteViewCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/CustomBackgroundWidgetRemoteViewCreator.kt index c2042912b..fb90222ff 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/CustomBackgroundWidgetRemoteViewCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/CustomBackgroundWidgetRemoteViewCreator.kt @@ -21,6 +21,7 @@ import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.utils.ImageUtils import com.thewizrd.common.utils.glide.CustomRoundedCorners import com.thewizrd.common.utils.glide.TransparentOverlay +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx @@ -96,7 +97,7 @@ abstract class CustomBackgroundWidgetRemoteViewCreator( updateViews.setColorAttr( R.id.panda_container, "setBackgroundColor", - R.attr.colorSurface + com.google.android.material.R.attr.colorSurface ) } else { updateViews.addView( diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1Creator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1Creator.kt index ff4d1df39..7b97387d2 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1Creator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1Creator.kt @@ -10,6 +10,7 @@ import android.widget.RemoteViews import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx @@ -64,7 +65,7 @@ class WeatherWidget1x1Creator(context: Context) : WidgetRemoteViewCreator(contex ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -121,7 +122,7 @@ class WeatherWidget1x1Creator(context: Context) : WidgetRemoteViewCreator(contex updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -129,7 +130,10 @@ class WeatherWidget1x1Creator(context: Context) : WidgetRemoteViewCreator(contex updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1CustomCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1CustomCreator.kt new file mode 100644 index 000000000..172d47f21 --- /dev/null +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget1x1CustomCreator.kt @@ -0,0 +1,359 @@ +package com.thewizrd.simpleweather.widgets.remoteviews + +import android.appwidget.AppWidgetManager +import android.content.Context +import android.os.Bundle +import android.text.style.TextAppearanceSpan +import android.util.TypedValue +import android.view.View +import android.widget.RemoteViews +import com.thewizrd.common.controls.DetailItemViewModel +import com.thewizrd.common.controls.WeatherDetailsType +import com.thewizrd.common.controls.WeatherUiModel +import com.thewizrd.common.helpers.ColorsUtils +import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.locationdata.LocationData +import com.thewizrd.shared_resources.sharedDeps +import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride +import com.thewizrd.shared_resources.utils.TextUtils.applySpan +import com.thewizrd.shared_resources.weatherdata.model.UV +import com.thewizrd.simpleweather.R +import com.thewizrd.simpleweather.widgets.WeatherWidgetProvider1x1Custom +import com.thewizrd.simpleweather.widgets.WidgetProviderInfo +import com.thewizrd.simpleweather.widgets.WidgetUtils +import com.thewizrd.simpleweather.widgets.preferences.KEY_BGCOLORCODE +import com.thewizrd.simpleweather.widgets.preferences.KEY_HIDELOCNAME +import com.thewizrd.simpleweather.widgets.preferences.KEY_HIDEREFRESHBTN +import com.thewizrd.simpleweather.widgets.preferences.KEY_HIDESETTINGSBTN +import com.thewizrd.simpleweather.widgets.preferences.KEY_ICONSIZE +import com.thewizrd.simpleweather.widgets.preferences.KEY_TEXTSIZE +import com.thewizrd.simpleweather.widgets.preferences.KEY_TXTCOLORCODE +import com.thewizrd.simpleweather.widgets.preferences.KEY_TXTSHADOW +import com.thewizrd.simpleweather.widgets.preferences.KEY_WEATHERDETAILSTYPEOPTION +import com.thewizrd.shared_resources.R as sharedRes + +class WeatherWidget1x1CustomCreator(context: Context) : WidgetRemoteViewCreator(context) { + private fun generateRemoteViews(): RemoteViews { + return RemoteViews(context.packageName, info.widgetLayoutId) + } + + override val info: WidgetProviderInfo + get() = WeatherWidgetProvider1x1Custom.Info.getInstance() + + override suspend fun buildUpdate( + appWidgetId: Int, + weather: WeatherUiModel, + location: LocationData, + newOptions: Bundle + ): RemoteViews { + return buildLayout(appWidgetId, weather, location, newOptions) + } + + private suspend fun buildLayout( + appWidgetId: Int, + weather: WeatherUiModel, location: LocationData, + newOptions: Bundle + ): RemoteViews { + // Build an update that holds the updated widget contents + val updateViews = generateRemoteViews() + + val backgroundColor = + newOptions.get(KEY_BGCOLORCODE) as? Int ?: WidgetUtils.getBackgroundColor(appWidgetId) + val textColor = + newOptions.get(KEY_TXTCOLORCODE) as? Int ?: WidgetUtils.getTextColor(appWidgetId) + val useTextShadow = + newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) + val viewCtx = context.getThemeContextOverride( + ColorsUtils.isSuperLight(backgroundColor) + ) + val textAppearanceSpan = if (useTextShadow) { + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) + } else { + null + } + + val txtSizeMultiplier = + newOptions.get(KEY_TEXTSIZE) as? Float ?: WidgetUtils.getCustomTextSizeMultiplier( + appWidgetId + ) + val icoSizeMultiplier = + newOptions.get(KEY_ICONSIZE) as? Float ?: WidgetUtils.getCustomIconSizeMultiplier( + appWidgetId + ) + + updateViews.setInt(R.id.refresh_button, "setColorFilter", textColor) + updateViews.setInt(R.id.settings_button, "setColorFilter", textColor) + + // original icon size: 24dp + val scaledIconSize = (context.dpToPx(16f) * txtSizeMultiplier).toInt() + + // Refresh icon + updateViews.setImageViewBitmap(R.id.refresh_button, null) + + updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) + updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) + + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) + + // Setting icon + updateViews.setImageViewBitmap(R.id.settings_button, null) + + updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) + updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) + + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) + + // Location Name + updateViews.setTextViewText( + R.id.location_name, + weather.location?.applySpan(textAppearanceSpan) + ) + updateViews.setTextColor(R.id.location_name, textColor) + + // WeatherDetailsType + val detailsType = + newOptions.getSerializable(KEY_WEATHERDETAILSTYPEOPTION) as? WeatherDetailsType + ?: WidgetUtils.getWidgetDetailsType(appWidgetId) + + var detailItemModel = weather.weatherDetailsMap[detailsType] + val notAvailValue: CharSequence = context.getString(sharedRes.string.weather_notavailable) + + when (detailsType) { + WeatherDetailsType.SUNRISE -> { + if (detailItemModel == null) { + detailItemModel = + DetailItemViewModel(detailsType, weather.sunPhase?.sunrise ?: notAvailValue) + } + } + + WeatherDetailsType.SUNSET -> { + if (detailItemModel == null) { + detailItemModel = + DetailItemViewModel(detailsType, weather.sunPhase?.sunset ?: notAvailValue) + } + } + + WeatherDetailsType.MOONPHASE -> { + if (detailItemModel == null) { + detailItemModel = weather.moonPhase?.moonPhase ?: DetailItemViewModel( + detailsType, + notAvailValue + ) + } + } + + WeatherDetailsType.BEAUFORT -> { + if (detailItemModel == null) { + detailItemModel = weather.beaufort?.beaufort ?: DetailItemViewModel( + detailsType, + notAvailValue + ) + } + } + + WeatherDetailsType.UV -> { + if (detailItemModel == null) { + detailItemModel = + weather.uvIndex?.index?.toFloat()?.let { DetailItemViewModel(UV(it)) } + ?: DetailItemViewModel(detailsType, notAvailValue) + } + } + + WeatherDetailsType.AIRQUALITY -> { + if (detailItemModel == null) { + detailItemModel = weather.airQuality?.airQuality ?: DetailItemViewModel( + detailsType, + notAvailValue + ) + } + } + + WeatherDetailsType.TREEPOLLEN -> { + if (detailItemModel == null) { + detailItemModel = weather.pollen?.let { pollenVM -> + DetailItemViewModel( + WeatherDetailsType.TREEPOLLEN, + pollenVM.treePollenDesc.toString(), + pollenVM.treePollenShortDesc.toString(), + 0 + ) + } + } + } + + WeatherDetailsType.GRASSPOLLEN -> { + if (detailItemModel == null) { + detailItemModel = weather.pollen?.let { pollenVM -> + DetailItemViewModel( + WeatherDetailsType.GRASSPOLLEN, + pollenVM.grassPollenDesc.toString(), + pollenVM.grassPollenShortDesc.toString(), + 0 + ) + } + } + } + + WeatherDetailsType.RAGWEEDPOLLEN -> { + if (detailItemModel == null) { + detailItemModel = weather.pollen?.let { pollenVM -> + DetailItemViewModel( + WeatherDetailsType.RAGWEEDPOLLEN, + pollenVM.ragweedPollenDesc.toString(), + pollenVM.ragweedPollenShortDesc.toString(), + 0 + ) + } + } + } + + else -> { + if (detailItemModel == null) { + detailItemModel = DetailItemViewModel(detailsType, notAvailValue) + } + } + } + + val wim = sharedDeps.weatherIconsManager + // icon size: 36dp + val maxIconSize = context.dpToPx(36f) * icoSizeMultiplier + updateViews.setImageViewBitmap( + R.id.weather_icon, + ImageUtils.rotateBitmap( + ImageUtils.bitmapFromDrawable( + viewCtx, + wim.getWeatherIconResource(detailItemModel?.icon ?: WeatherIcons.NA), + maxIconSize, + maxIconSize + ), + detailItemModel?.iconRotation?.toFloat() ?: 0f + ) + ) + if (wim.isFontIcon) { + updateViews.setInt(R.id.weather_icon, "setColorFilter", textColor) + } else { + updateViews.setInt(R.id.weather_icon, "setColorFilter", 0) + } + updateViews.setContentDescription( + R.id.weather_icon, + detailItemModel?.label + ) + + updateViews.setTextViewText(R.id.condition_title, detailItemModel?.label) + updateViews.setTextViewText(R.id.condition_value, detailItemModel?.shortValue) + + updateViews.setTextColor(R.id.condition_title, textColor) + updateViews.setTextColor(R.id.condition_value, textColor) + + // Visibility + updateViews.setViewVisibility( + R.id.location_name, + if (newOptions.get(KEY_HIDELOCNAME) as? Boolean ?: WidgetUtils.isLocationNameHidden( + appWidgetId + ) + ) View.GONE else View.VISIBLE + ) + updateViews.setViewVisibility( + R.id.settings_button, + if (newOptions.get(KEY_HIDESETTINGSBTN) as? Boolean + ?: WidgetUtils.isSettingsButtonHidden(appWidgetId) + ) View.GONE else View.VISIBLE + ) + updateViews.setViewVisibility( + R.id.refresh_button, + if (newOptions.get(KEY_HIDEREFRESHBTN) as? Boolean ?: WidgetUtils.isRefreshButtonHidden( + appWidgetId + ) + ) View.GONE else View.VISIBLE + ) + + // Resizing + updateViewSizes(updateViews, appWidgetId, newOptions) + + setOnClickIntent(location, updateViews) + setOnSettingsClickIntent(updateViews, location, appWidgetId) + setOnRefreshClickIntent(updateViews, appWidgetId) + + return updateViews + } + + override fun resizeWidget( + info: WidgetProviderInfo, + appWidgetManager: AppWidgetManager, + appWidgetId: Int, + newOptions: Bundle + ) { + val updateViews = generateRemoteViews() + + updateViewSizes(updateViews, appWidgetId, newOptions) + + resizeWidgetBackground(info, appWidgetId, updateViews, newOptions) + + appWidgetManager.partiallyUpdateAppWidget(appWidgetId, updateViews) + } + + private fun updateViewSizes( + updateViews: RemoteViews, + appWidgetId: Int, + newOptions: Bundle + ) { + // Widget dimensions + val minHeight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + val minWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) + val cellHeight = WidgetUtils.getCellsForSize(minHeight) + val cellWidth = WidgetUtils.getCellsForSize(minWidth) + + val txtSizeMultiplier: Float = + newOptions.get(KEY_TEXTSIZE) as? Float ?: WidgetUtils.getCustomTextSizeMultiplier( + appWidgetId + ) + + if (cellWidth > 1 && cellHeight > 1) { + updateViews.setTextViewTextSize( + R.id.location_name, + TypedValue.COMPLEX_UNIT_SP, + 14f * txtSizeMultiplier + ) + updateViews.setTextViewTextSize( + R.id.condition_title, + TypedValue.COMPLEX_UNIT_SP, + 14f * txtSizeMultiplier + ) + } else { + updateViews.setTextViewTextSize( + R.id.location_name, + TypedValue.COMPLEX_UNIT_SP, + 12f * txtSizeMultiplier + ) + updateViews.setTextViewTextSize( + R.id.condition_title, + TypedValue.COMPLEX_UNIT_SP, + 12f * txtSizeMultiplier + ) + } + if (cellWidth > 2 && cellHeight > 2) { + updateViews.setTextViewTextSize( + R.id.condition_value, + TypedValue.COMPLEX_UNIT_SP, + 24f * txtSizeMultiplier + ) + } else if (cellWidth > 1 && cellHeight > 1) { + updateViews.setTextViewTextSize( + R.id.condition_value, + TypedValue.COMPLEX_UNIT_SP, + 18f * txtSizeMultiplier + ) + } else { + updateViews.setTextViewTextSize( + R.id.condition_value, + TypedValue.COMPLEX_UNIT_SP, + 16f * txtSizeMultiplier + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget2x2Creator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget2x2Creator.kt index a6f7475df..e1d658e63 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget2x2Creator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget2x2Creator.kt @@ -14,6 +14,7 @@ import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.locationdata.LocationData @@ -135,7 +136,7 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -195,7 +196,7 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) R.id.hi_icon, ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_direction_up, + sharedRes.drawable.wi_direction_up, Colors.WHITE, tempArrowIconSize, tempArrowIconSize @@ -205,7 +206,7 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) R.id.lo_icon, ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_direction_down, + sharedRes.drawable.wi_direction_down, Colors.WHITE, tempArrowIconSize, tempArrowIconSize @@ -227,8 +228,8 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) updateViews.setInt(R.id.hi_icon, "setMaxWidth", tempArrowIconSize.toInt()) updateViews.setInt(R.id.lo_icon, "setMaxWidth", tempArrowIconSize.toInt()) - updateViews.setImageViewResource(R.id.hi_icon, R.drawable.wi_direction_up) - updateViews.setImageViewResource(R.id.lo_icon, R.drawable.wi_direction_down) + updateViews.setImageViewResource(R.id.hi_icon, sharedRes.drawable.wi_direction_up) + updateViews.setImageViewResource(R.id.lo_icon, sharedRes.drawable.wi_direction_down) } val chanceModel = weather.weatherDetailsMap[WeatherDetailsType.POPCHANCE] @@ -411,7 +412,7 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -419,7 +420,10 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -587,13 +591,14 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_ampm_format)) + val timeStr12hr = + SpannableString(context.getText(sharedRes.string.clock_12_hours_ampm_format)) val start12hr = timeStr12hr.length - 2 timeStr12hr.setSpan( RelativeSizeSpan(0.875f), @@ -608,7 +613,8 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) var clockTextSize = @@ -639,7 +645,7 @@ class WeatherWidget2x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1Creator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1Creator.kt index 2db31ff07..0b3eb7094 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1Creator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1Creator.kt @@ -8,6 +8,7 @@ import android.util.TypedValue import android.view.View import android.widget.RemoteViews import com.thewizrd.common.controls.WeatherUiModel +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx import com.thewizrd.shared_resources.utils.TextUtils.applySpan @@ -69,7 +70,7 @@ class WeatherWidget4x1Creator(context: Context) : WidgetRemoteViewCreator(contex val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -98,7 +99,7 @@ class WeatherWidget4x1Creator(context: Context) : WidgetRemoteViewCreator(contex updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -106,7 +107,10 @@ class WeatherWidget4x1Creator(context: Context) : WidgetRemoteViewCreator(contex updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) if (!hideLocationName) { updateViews.setViewVisibility( diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1GoogleCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1GoogleCreator.kt index 16098d575..d83ba6f7e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1GoogleCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1GoogleCreator.kt @@ -10,6 +10,7 @@ import android.widget.RemoteViews import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.sharedDeps @@ -68,7 +69,7 @@ class WeatherWidget4x1GoogleCreator(context: Context) : WidgetRemoteViewCreator( ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -136,7 +137,7 @@ class WeatherWidget4x1GoogleCreator(context: Context) : WidgetRemoteViewCreator( updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -144,7 +145,10 @@ class WeatherWidget4x1GoogleCreator(context: Context) : WidgetRemoteViewCreator( updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -289,7 +293,7 @@ class WeatherWidget4x1GoogleCreator(context: Context) : WidgetRemoteViewCreator( val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextHeavy) + TextAppearanceSpan(context, sharedRes.style.ShadowTextHeavy) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1NotificationCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1NotificationCreator.kt index 9a437a73b..f2e48136c 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1NotificationCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x1NotificationCreator.kt @@ -11,6 +11,7 @@ import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.sharedDeps @@ -68,7 +69,7 @@ class WeatherWidget4x1NotificationCreator(context: Context) : WidgetRemoteViewCr ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -114,7 +115,7 @@ class WeatherWidget4x1NotificationCreator(context: Context) : WidgetRemoteViewCr R.id.hi_icon, ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_direction_up, + sharedRes.drawable.wi_direction_up, textColor, tempArrowIconSize, tempArrowIconSize @@ -124,7 +125,7 @@ class WeatherWidget4x1NotificationCreator(context: Context) : WidgetRemoteViewCr R.id.lo_icon, ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_direction_down, + sharedRes.drawable.wi_direction_down, textColor, tempArrowIconSize, tempArrowIconSize @@ -245,7 +246,7 @@ class WeatherWidget4x1NotificationCreator(context: Context) : WidgetRemoteViewCr updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -253,7 +254,10 @@ class WeatherWidget4x1NotificationCreator(context: Context) : WidgetRemoteViewCr updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2ClockCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2ClockCreator.kt index 4abcac58c..ffcc399fd 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2ClockCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2ClockCreator.kt @@ -11,6 +11,7 @@ import android.widget.RemoteViews import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.sharedDeps @@ -72,7 +73,7 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -146,7 +147,7 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -154,7 +155,10 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -306,13 +310,13 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextHeavy) + TextAppearanceSpan(context, sharedRes.style.ShadowTextHeavy) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_format)) + val timeStr12hr = SpannableString(context.getText(sharedRes.string.clock_12_hours_format)) views.setCharSequence( R.id.clock_panel, "setFormat12Hour", @@ -320,7 +324,8 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) views.setTextViewTextSize( @@ -346,7 +351,7 @@ class WeatherWidget4x2ClockCreator(context: Context) : WidgetRemoteViewCreator(c val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2Creator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2Creator.kt index a4853c318..33fee92bf 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2Creator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2Creator.kt @@ -14,6 +14,7 @@ import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.sharedDeps @@ -97,7 +98,7 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -207,7 +208,7 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -215,7 +216,10 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -398,13 +402,14 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_ampm_format)) + val timeStr12hr = + SpannableString(context.getText(sharedRes.string.clock_12_hours_ampm_format)) val start12hr = timeStr12hr.length - 2 timeStr12hr.setSpan( RelativeSizeSpan(0.875f), @@ -419,7 +424,8 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) var clockTextSize = 32f @@ -444,7 +450,7 @@ class WeatherWidget4x2Creator(context: Context, loadBackground: Boolean = true) val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2GraphCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2GraphCreator.kt index 9f07b9aab..6df9f874e 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2GraphCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2GraphCreator.kt @@ -16,6 +16,7 @@ import androidx.core.view.forEach import androidx.databinding.DataBindingUtil import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.dpToPx @@ -98,7 +99,7 @@ class WeatherWidget4x2GraphCreator(context: Context) : WidgetRemoteViewCreator(c val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -120,7 +121,7 @@ class WeatherWidget4x2GraphCreator(context: Context) : WidgetRemoteViewCreator(c updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -128,7 +129,10 @@ class WeatherWidget4x2GraphCreator(context: Context) : WidgetRemoteViewCreator(c updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -206,7 +210,7 @@ class WeatherWidget4x2GraphCreator(context: Context) : WidgetRemoteViewCreator(c val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -243,46 +247,47 @@ class WeatherWidget4x2GraphCreator(context: Context) : WidgetRemoteViewCreator(c WidgetGraphType.HourlyForecast -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_hourlyforecast) + context.getString(sharedRes.string.label_hourlyforecast) .applySpan(textAppearanceSpan) ) } WidgetGraphType.Precipitation -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_precipitation) + context.getString(sharedRes.string.label_precipitation) .applySpan(textAppearanceSpan) ) } WidgetGraphType.Wind -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_wind).applySpan(textAppearanceSpan) + context.getString(sharedRes.string.label_wind).applySpan(textAppearanceSpan) ) } WidgetGraphType.Humidity -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_humidity).applySpan(textAppearanceSpan) + context.getString(sharedRes.string.label_humidity) + .applySpan(textAppearanceSpan) ) } WidgetGraphType.UVIndex -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_uv).applySpan(textAppearanceSpan) + context.getString(sharedRes.string.label_uv).applySpan(textAppearanceSpan) ) } WidgetGraphType.AirQuality -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_airquality_short) + context.getString(sharedRes.string.label_airquality_short) .applySpan(textAppearanceSpan) ) } WidgetGraphType.Minutely -> { updateViews.setTextViewText( R.id.graph_label, - context.getString(R.string.label_precipitation) + context.getString(sharedRes.string.label_precipitation) .applySpan(textAppearanceSpan) ) } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2HuaweiCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2HuaweiCreator.kt index 8c490ae54..3b8dc67b6 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2HuaweiCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2HuaweiCreator.kt @@ -11,6 +11,7 @@ import android.widget.RemoteViews import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.locationdata.LocationData @@ -73,7 +74,7 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -165,7 +166,7 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -173,7 +174,10 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -275,13 +279,13 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextHeavy) + TextAppearanceSpan(context, sharedRes.style.ShadowTextHeavy) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_format)) + val timeStr12hr = SpannableString(context.getText(sharedRes.string.clock_12_hours_format)) views.setCharSequence( R.id.clock_panel, "setFormat12Hour", @@ -289,7 +293,8 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) views.setTextViewTextSize( @@ -315,7 +320,7 @@ class WeatherWidget4x2HuaweiCreator(context: Context) : WidgetRemoteViewCreator( val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2TomorrowCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2TomorrowCreator.kt index ecf341a1f..0585965ea 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2TomorrowCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x2TomorrowCreator.kt @@ -15,6 +15,7 @@ import com.thewizrd.common.controls.WeatherDetailsType import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.icons.WeatherIcons @@ -127,7 +128,7 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } @@ -279,7 +280,8 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean updateViews.setTextViewText( R.id.aqi_label, - context.getString(R.string.label_airquality_short).applySpan(textAppearanceSpan) + context.getString(sharedRes.string.label_airquality_short) + .applySpan(textAppearanceSpan) ) updateViews.setTextViewText( R.id.aqi_level, @@ -315,7 +317,9 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean } updateViews.setTextViewText( R.id.label_updatetime, - "${context.getString(R.string.update_prefix)} $dateStr".applySpan(textAppearanceSpan) + "${context.getString(sharedRes.string.update_prefix)} $dateStr".applySpan( + textAppearanceSpan + ) ) updateViews.setTextViewTextSize( R.id.label_updatetime, @@ -336,7 +340,7 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -344,7 +348,10 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) // Location Name updateViews.setTextViewText( @@ -737,13 +744,14 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_ampm_format)) + val timeStr12hr = + SpannableString(context.getText(sharedRes.string.clock_12_hours_ampm_format)) val start12hr = timeStr12hr.length - 2 timeStr12hr.setSpan( RelativeSizeSpan(0.875f), @@ -758,7 +766,8 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) var clockTextSize = 32f @@ -783,7 +792,7 @@ class WeatherWidget4x2TomorrowCreator(context: Context, loadBackground: Boolean val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextClock) + TextAppearanceSpan(context, sharedRes.style.ShadowTextClock) } else { null } diff --git a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x3LocationsCreator.kt b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x3LocationsCreator.kt index 3bde32978..7e4a5c2e7 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x3LocationsCreator.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/widgets/remoteviews/WeatherWidget4x3LocationsCreator.kt @@ -14,6 +14,7 @@ import androidx.core.graphics.alpha import com.thewizrd.common.controls.WeatherUiModel import com.thewizrd.common.helpers.ColorsUtils import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.locationdata.LocationData @@ -101,7 +102,7 @@ class WeatherWidget4x3LocationsCreator(context: Context) : ColorsUtils.isSuperLight(backgroundColor) ) val textAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(viewCtx, R.style.ShadowText) + TextAppearanceSpan(viewCtx, sharedRes.style.ShadowText) } else { null } @@ -254,7 +255,7 @@ class WeatherWidget4x3LocationsCreator(context: Context) : updateViews.setInt(R.id.refresh_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.refresh_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.refresh_button, R.drawable.ic_refresh) + updateViews.setImageViewResource(R.id.refresh_button, sharedRes.drawable.ic_refresh) // Setting icon updateViews.setImageViewBitmap(R.id.settings_button, null) @@ -262,7 +263,10 @@ class WeatherWidget4x3LocationsCreator(context: Context) : updateViews.setInt(R.id.settings_button, "setMaxWidth", scaledIconSize) updateViews.setInt(R.id.settings_button, "setMaxHeight", scaledIconSize) - updateViews.setImageViewResource(R.id.settings_button, R.drawable.ic_outline_settings_24) + updateViews.setImageViewResource( + R.id.settings_button, + sharedRes.drawable.ic_outline_settings_24 + ) updateViews.setViewVisibility( R.id.settings_button, @@ -387,20 +391,21 @@ class WeatherWidget4x3LocationsCreator(context: Context) : val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowTextHeavy) + TextAppearanceSpan(context, sharedRes.style.ShadowTextHeavy) } else { null } // Update clock widgets - val timeStr12hr = SpannableString(context.getText(R.string.clock_12_hours_format)) + val timeStr12hr = SpannableString(context.getText(sharedRes.string.clock_12_hours_format)) views.setCharSequence( R.id.clock_panel, "setFormat12Hour", timeStr12hr.applySpan(textClockAppearanceSpan) ) views.setCharSequence( R.id.clock_panel, "setFormat24Hour", - context.getText(R.string.clock_24_hours_format).applySpan(textClockAppearanceSpan) + context.getText(sharedRes.string.clock_24_hours_format) + .applySpan(textClockAppearanceSpan) ) views.setTextViewTextSize( @@ -421,7 +426,7 @@ class WeatherWidget4x3LocationsCreator(context: Context) : val useTextShadow = newOptions.get(KEY_TXTSHADOW) as? Boolean ?: WidgetUtils.useTextShadow(appWidgetId) val textClockAppearanceSpan = if (useTextShadow) { - TextAppearanceSpan(context, R.style.ShadowText) + TextAppearanceSpan(context, sharedRes.style.ShadowText) } else { null } diff --git a/app/src/main/res/drawable-nodpi/appwidget_preview_1x1_custom.png b/app/src/main/res/drawable-nodpi/appwidget_preview_1x1_custom.png new file mode 100644 index 000000000..59e3f1f96 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/appwidget_preview_1x1_custom.png differ diff --git a/app/src/main/res/layout-v31/weather_notification_layout.xml b/app/src/main/res/layout-v31/weather_notification_layout.xml index 3dd31998e..e2f900950 100644 --- a/app/src/main/res/layout-v31/weather_notification_layout.xml +++ b/app/src/main/res/layout-v31/weather_notification_layout.xml @@ -143,8 +143,7 @@ android:layout_marginEnd="4dp" android:adjustViewBounds="true" android:scaleType="fitCenter" - android:src="@drawable/wi_wind_direction" - android:tint="@color/colorTextPrimary" /> + android:src="@drawable/wi_wind_direction" /> + android:src="@drawable/wi_humidity" /> + android:src="@drawable/wi_strong_wind" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_widget_1x1_custom_preview.xml b/app/src/main/res/layout/app_widget_1x1_custom_preview.xml new file mode 100644 index 000000000..560804f4c --- /dev/null +++ b/app/src/main/res/layout/app_widget_1x1_custom_preview.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/weather_notification_layout.xml b/app/src/main/res/layout/weather_notification_layout.xml index bc2d9b389..5d20286b1 100644 --- a/app/src/main/res/layout/weather_notification_layout.xml +++ b/app/src/main/res/layout/weather_notification_layout.xml @@ -138,8 +138,7 @@ android:adjustViewBounds="true" android:contentDescription="@string/label_wind" android:scaleType="fitCenter" - android:src="@drawable/wi_wind_direction" - android:tint="@color/colorTextPrimary" /> + android:src="@drawable/wi_wind_direction" /> + android:src="@drawable/wi_humidity" /> + android:src="@drawable/wi_strong_wind" /> + + @@ -59,11 +61,12 @@ app:layout_constraintEnd_toStartOf="@id/grasspollen_label" app:layout_constraintHorizontal_chainStyle="packed" /> - - - + diff --git a/app/src/main/res/xml/pref_credits.xml b/app/src/main/res/xml/pref_credits.xml index 9c60f88d6..850f6a8e4 100644 --- a/app/src/main/res/xml/pref_credits.xml +++ b/app/src/main/res/xml/pref_credits.xml @@ -61,14 +61,6 @@ android:data="https://aqicn.org" /> - - - - @@ -101,6 +93,14 @@ android:data="https://www.weather.gc.ca/" /> + + + + + + + app:isPreferenceVisible="false" + tools:isPreferenceVisible="true" /> + app:isPreferenceVisible="false" + tools:isPreferenceVisible="true" /> + app:isPreferenceVisible="false" + tools:isPreferenceVisible="true" /> @@ -121,7 +134,8 @@ android:summary="%s" android:title="@string/pref_title_bgstyle" app:iconSpaceReserved="false" - app:isPreferenceVisible="false" /> + app:isPreferenceVisible="false" + tools:isPreferenceVisible="true" /> @@ -189,7 +203,8 @@ android:summary="%s" android:title="@string/pref_title_widgetgraphtype" app:iconSpaceReserved="false" - app:isPreferenceVisible="false" /> + app:isPreferenceVisible="false" + tools:isPreferenceVisible="true" /> diff --git a/app/src/nongms/java/com/thewizrd/simpleweather/radar/OSMUtils.kt b/app/src/nongms/java/com/thewizrd/simpleweather/radar/OSMUtils.kt index d4c9e5ca0..bc40717f9 100644 --- a/app/src/nongms/java/com/thewizrd/simpleweather/radar/OSMUtils.kt +++ b/app/src/nongms/java/com/thewizrd/simpleweather/radar/OSMUtils.kt @@ -3,6 +3,7 @@ package com.thewizrd.simpleweather.radar import android.content.Context import android.content.pm.PackageInfo import com.thewizrd.shared_resources.Constants +import com.thewizrd.simpleweather.BuildConfig import org.osmdroid.config.Configuration import java.io.File @@ -15,10 +16,13 @@ fun Context.initializeMap() { String.format("v%s", packageInfo.versionName) }.getOrDefault("") - Configuration.getInstance().userAgentValue = - String.format("SimpleWeather (${Constants.SUPPORT_EMAIL_ADDRESS}) %s", version) - Configuration.getInstance().osmdroidTileCache = File(cacheDir, "tiles") - Configuration.getInstance().osmdroidBasePath = File(noBackupFilesDir, "osmdroid") + Configuration.getInstance().run { + userAgentValue = + String.format("SimpleWeather (${Constants.SUPPORT_EMAIL_ADDRESS}) %s", version) + osmdroidTileCache = File(cacheDir, "tiles") + osmdroidBasePath = File(noBackupFilesDir, "osmdroid") + isDebugMapTileDownloader = BuildConfig.DEBUG + } mapInitialized = true } diff --git a/app/src/nongms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt b/app/src/nongms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt index ed91d3527..abcb8fcad 100644 --- a/app/src/nongms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt +++ b/app/src/nongms/java/com/thewizrd/simpleweather/radar/rainviewer/RainViewerViewProvider.kt @@ -333,7 +333,7 @@ class RainViewerViewProvider(context: Context, rootView: ViewGroup) : XYTileSource( "RainViewer", MIN_ZOOM_LEVEL, - MAX_ZOOM_LEVEL, + 7, 256, "${mapFrame?.timeStamp ?: ""}.png", arrayOf(mapFrame?.host) diff --git a/app/src/nongms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt b/app/src/nongms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt index 8790243e4..0a2f51f3a 100644 --- a/app/src/nongms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt +++ b/app/src/nongms/java/com/thewizrd/simpleweather/radar/tomorrowio/TomorrowIoRadarViewProvider.kt @@ -18,6 +18,7 @@ import com.thewizrd.shared_resources.utils.Coordinate import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.simpleweather.databinding.RadarAnimateContainerBinding +import com.thewizrd.simpleweather.extras.isRadarInteractionEnabled import com.thewizrd.simpleweather.radar.MapTileRadarViewProvider import com.thewizrd.weather_api.keys.Keys import org.osmdroid.tileprovider.MapTileProviderBasic @@ -92,7 +93,7 @@ class TomorrowIoRadarViewProvider(context: Context, rootView: ViewGroup) : override fun updateRadarView() { super.updateRadarView() radarContainerBinding!!.radarToolbar.visibility = - if (interactionsEnabled()/* && isRadarInteractionEnabled()*/) View.VISIBLE else View.GONE + if (interactionsEnabled() && isRadarInteractionEnabled()) View.VISIBLE else View.GONE } override fun onDestroyView() { diff --git a/app/src/nongms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt b/app/src/nongms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt new file mode 100644 index 000000000..152e2e4d9 --- /dev/null +++ b/app/src/nongms/java/com/thewizrd/simpleweather/radar/weatherapi/WeatherApiRadarViewProvider.kt @@ -0,0 +1,317 @@ +package com.thewizrd.simpleweather.radar.weatherapi + +import android.content.Context +import android.graphics.ColorMatrix +import android.graphics.ColorMatrixColorFilter +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.format.DateFormat +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import androidx.core.view.isEmpty +import com.google.android.material.slider.Slider +import com.thewizrd.shared_resources.DateTimeConstants +import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.DateTimeUtils +import com.thewizrd.simpleweather.databinding.RadarAnimateContainerBinding +import com.thewizrd.simpleweather.extras.isRadarInteractionEnabled +import com.thewizrd.simpleweather.radar.MapTileRadarViewProvider +import org.osmdroid.tileprovider.MapTileProviderBasic +import org.osmdroid.tileprovider.modules.TileWriter +import org.osmdroid.tileprovider.tilesource.XYTileSource +import org.osmdroid.util.GeoPoint +import org.osmdroid.util.MapTileIndex +import org.osmdroid.views.overlay.Marker +import org.osmdroid.views.overlay.TilesOverlay +import java.time.ZoneOffset +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit + +@RequiresApi(value = Build.VERSION_CODES.LOLLIPOP) +class WeatherApiRadarViewProvider(context: Context, rootView: ViewGroup) : + MapTileRadarViewProvider(context, rootView) { + companion object { + private const val DEFAULT_TRANSPARENCY = 0.5f + private val alphaMatrix = ColorMatrix( + floatArrayOf( + 1f, 0f, 0f, 0f, 0f, + 0f, 1f, 0f, 0f, 0f, + 0f, 0f, 1f, 0f, 0f, + 0f, 0f, 0f, DEFAULT_TRANSPARENCY, 0f + ) + ) + } + + private val availableRadarFrames: MutableList + private val radarLayers: MutableMap + + private var radarContainerBinding: RadarAnimateContainerBinding? = null + + private var animationPosition = 0 + private val mMainHandler: Handler + private var mProcessingFrames: Boolean = false + + init { + availableRadarFrames = ArrayList() + radarLayers = HashMap() + mMainHandler = Handler(Looper.getMainLooper()) + } + + override fun onCreateView(savedInstanceState: Bundle?) { + super.onCreateView(savedInstanceState) + + radarContainerBinding = RadarAnimateContainerBinding.inflate(LayoutInflater.from(context)) + viewContainer.addView(radarContainerBinding!!.root) + + radarContainerBinding!!.playButton.addOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + mMainHandler.post(animationRunnable) + } else { + mMainHandler.removeCallbacks(animationRunnable) + } + } + + radarContainerBinding!!.animationSeekbar.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser -> + if (fromUser) { + mMainHandler.removeCallbacks(animationRunnable) + showFrame(value.toInt()) + } + }) + + radarContainerBinding!!.animationSeekbar.value = 0f + if (radarContainerBinding!!.radarContainer.isEmpty()) { + radarContainerBinding!!.radarContainer.addView(mapView) + } + } + + override fun onPause() { + super.onPause() + // Remove animation callbacks + radarContainerBinding?.playButton?.isChecked = false + } + + override fun onViewCreated(coordinates: Coordinate) { + super.onViewCreated(coordinates) + } + + override fun updateRadarView() { + super.updateRadarView() + radarContainerBinding!!.radarToolbar.visibility = + if (interactionsEnabled() && isRadarInteractionEnabled()) View.VISIBLE else View.GONE + } + + override fun onDestroyView() { + super.onDestroyView() + availableRadarFrames.clear() + radarLayers.clear() + radarContainerBinding = null + } + + override fun onMapReady() { + super.onMapReady() + + mapCameraPosition?.let { cameraPosition -> + if (interactionsEnabled()) { + if (locationMarker == null) { + locationMarker = Marker(mapView) + locationMarker.setDefaultIcon() + mapView.overlays.add(locationMarker) + } + locationMarker.position = + GeoPoint(cameraPosition.latitude, cameraPosition.longitude) + } + } + + getRadarFrames() + } + + private fun getRadarFrames() { + mProcessingFrames = true + + availableRadarFrames.clear() + animationPosition = 0 + + val now = ZonedDateTime.now(ZoneOffset.UTC) + .truncatedTo(ChronoUnit.HOURS) // 2024-05-05T14:00:00.000Z + val start = now + val end = now.plus(12, ChronoUnit.HOURS) + + var current = start + var nowIndex = -1 + + while (current <= end) { + availableRadarFrames.add(RadarFrame(current)) + + if (current == now) { + nowIndex = availableRadarFrames.size - 1 + } + + current = current.plus(1, ChronoUnit.HOURS) + } + + mProcessingFrames = false + + mMainHandler.post { + if (isViewAlive) { + val lastPastFramePosition = nowIndex + showFrame(lastPastFramePosition) + } + } + } + + private fun addLayer(mapFrame: RadarFrame) { + if (mProcessingFrames) return + + if (!radarLayers.containsKey(mapFrame.timestamp)) { + val overlay = TilesOverlay( + MapTileProviderBasic(context, WeatherApiTileProvider(mapFrame), TileWriter()), + context, + false, + false + ) + overlay.loadingBackgroundColor = Colors.TRANSPARENT + overlay.loadingLineColor = Colors.TRANSPARENT + overlay.setColorFilter(ColorMatrixColorFilter(alphaMatrix)) + + overlay.isEnabled = false + mapView.overlays.add(overlay) + radarLayers[mapFrame.timestamp] = overlay + } + + radarContainerBinding!!.animationSeekbar.stepSize = 1f + radarContainerBinding!!.animationSeekbar.valueFrom = 0f + radarContainerBinding!!.animationSeekbar.valueTo = (availableRadarFrames.size - 1).toFloat() + } + + private fun changeRadarPosition(pos: Int, preloadOnly: Boolean = false) { + if (mProcessingFrames) return + + var position = pos + while (position >= availableRadarFrames.size) { + position -= availableRadarFrames.size + } + while (position < 0) { + position += availableRadarFrames.size + } + + if (availableRadarFrames.isEmpty() || animationPosition >= availableRadarFrames.size || position >= availableRadarFrames.size) { + return + } + + val currentFrame = availableRadarFrames[animationPosition] ?: return + val currentTimeStamp = currentFrame.timestamp + + val nextFrame = availableRadarFrames[position] ?: return + val nextTimeStamp = nextFrame.timestamp + + addLayer(nextFrame) + + if (preloadOnly) { + return + } + + animationPosition = position + + // 0 is opaque; 1 is transparent + if (radarLayers.containsKey(currentTimeStamp)) { + val currentOverlay = radarLayers[currentTimeStamp] + if (currentOverlay != null) { + currentOverlay.isEnabled = false + } + } + val nextOverlay = radarLayers[nextTimeStamp] + if (nextOverlay != null) { + nextOverlay.isEnabled = true + } + + mapView.postInvalidate() + + updateToolbar(position, nextFrame) + } + + private fun updateToolbar( + position: Int, + mapFrame: RadarFrame = availableRadarFrames[position] + ) { + radarContainerBinding!!.animationSeekbar.value = position.toFloat() + + val dateTime = mapFrame.timestamp.withZoneSameInstant(ZoneOffset.systemDefault()) + val fmt = if (DateFormat.is24HourFormat(context)) { + DateTimeUtils.ofPatternForUserLocale( + DateTimeUtils.getBestPatternForSkeleton( + DateTimeConstants.SKELETON_DAYOFWEEK_AND_24HR + ) + ) + } else { + DateTimeUtils.ofPatternForUserLocale(DateTimeConstants.ABBREV_DAYOFWEEK_AND_12HR_MIN_AMPM) + } + radarContainerBinding!!.timestampText.text = dateTime.format(fmt) + } + + /** + * Check availability and show particular frame position from the timestamps list + */ + private fun showFrame(nextPosition: Int) { + if (mProcessingFrames) return + + val preloadingDirection = if (nextPosition - animationPosition > 0) 1 else -1 + + changeRadarPosition(nextPosition) + + // preload next next frame (typically, +1 frame) + // if don't do that, the animation will be blinking at the first loop + changeRadarPosition(nextPosition + preloadingDirection, true) + } + + private val animationRunnable = object : Runnable { + override fun run() { + if (isViewAlive) { + showFrame(animationPosition + 1) + mMainHandler.postDelayed(this, 500) + } else { + mMainHandler.removeCallbacks(this) + } + } + } + + private class WeatherApiTileProvider(private val mapFrame: RadarFrame?) : XYTileSource( + "WeatherApi", + MIN_ZOOM_LEVEL, + 6, + 256, + "${mapFrame?.timestamp ?: ""}.png", + arrayOf("https://weathermaps.weatherapi.com") + ) { + private val dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd") + + override fun getTileURLString(pMapTileIndex: Long): String? { + val zoom = MapTileIndex.getZoom(pMapTileIndex) + val x = MapTileIndex.getX(pMapTileIndex) + val y = MapTileIndex.getY(pMapTileIndex) + + if (mapFrame != null) { + val date = mapFrame.timestamp.toLocalDate().format(dateFormatter) + val hour = mapFrame.timestamp.hour + return "https://weathermaps.weatherapi.com/precip/tiles/%s%02d/%d/%d/%d.png".format( + date, + hour, + zoom, + x, + y + ) + } + + return null + } + } + + private data class RadarFrame( + val timestamp: ZonedDateTime + ) +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0872f1478..3cf77e038 100644 --- a/build.gradle +++ b/build.gradle @@ -4,18 +4,18 @@ buildscript { repositories { mavenCentral() google() - maven { url 'https://jitpack.io' } + maven { url = 'https://jitpack.io' } } dependencies { classpath libs.gradle + classpath libs.legacy.kapt.plugin classpath libs.com.google.devtools.ksp.gradle.plugin classpath libs.google.services classpath libs.firebase.crashlytics.gradle classpath libs.firebase.perf.plugin classpath libs.nav.safe.args.plugin classpath libs.room.plugin - classpath libs.kotlin.gradle.plugin classpath libs.compose.compiler.gradle.plugin // NOTE: Do not place your application dependencies here; they belong @@ -27,7 +27,7 @@ allprojects { repositories { mavenCentral() google() - maven { url 'https://jitpack.io' } + maven { url = 'https://jitpack.io' } } } diff --git a/common/build.gradle b/common/build.gradle index 3a18584f6..1e51e16be 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,7 +1,6 @@ plugins { id 'com.android.library' - id 'kotlin-android' - id 'kotlin-kapt' + id 'com.android.legacy-kapt' } android { @@ -9,7 +8,6 @@ android { defaultConfig { minSdk libs.versions.minSdkVersion.get().toInteger() - targetSdk libs.versions.targetSdkVersion.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -34,12 +32,12 @@ android { compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } kotlin { - jvmToolchain(17) + jvmToolchain(21) } flavorDimensions 'gms' @@ -54,6 +52,12 @@ android { } } namespace 'com.thewizrd.common' + lint { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } + testOptions { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } } dependencies { diff --git a/common/src/fullgms/java/com/thewizrd/common/location/LocationProvider.kt b/common/src/fullgms/java/com/thewizrd/common/location/LocationProvider.kt index 793a51e21..5769ebab7 100644 --- a/common/src/fullgms/java/com/thewizrd/common/location/LocationProvider.kt +++ b/common/src/fullgms/java/com/thewizrd/common/location/LocationProvider.kt @@ -16,10 +16,10 @@ import com.google.android.gms.tasks.CancellationTokenSource import com.google.android.gms.tasks.Task import com.google.android.gms.tasks.Tasks import com.google.android.gms.wearable.Wearable -import com.thewizrd.common.R import com.thewizrd.common.helpers.locationPermissionEnabled import com.thewizrd.common.utils.ErrorMessage import com.thewizrd.common.wearable.WearableHelper +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData diff --git a/common/src/main/java/com/thewizrd/common/controls/DetailItemViewModel.java b/common/src/main/java/com/thewizrd/common/controls/DetailItemViewModel.java index 20f23db8f..c47adebed 100644 --- a/common/src/main/java/com/thewizrd/common/controls/DetailItemViewModel.java +++ b/common/src/main/java/com/thewizrd/common/controls/DetailItemViewModel.java @@ -72,7 +72,7 @@ public DetailItemViewModel(@NonNull WeatherDetailsType detailsType, CharSequence break; case VISIBILITY: this.label = context.getString(R.string.label_visibility); - this.icon = WeatherIcons.FOG; + this.icon = WeatherIcons.VISIBILITY; break; case POPCHANCE: this.label = context.getString(R.string.label_chance); @@ -112,11 +112,11 @@ public DetailItemViewModel(@NonNull WeatherDetailsType detailsType, CharSequence break; case UV: this.label = context.getString(R.string.label_uv); - this.icon = WeatherIcons.DAY_SUNNY; + this.icon = WeatherIcons.UV_INDEX; break; case AIRQUALITY: this.label = context.getString(R.string.label_airquality); - this.icon = WeatherIcons.CLOUDY_GUSTS; + this.icon = WeatherIcons.AIR_QUALITY; break; case TREEPOLLEN: this.label = context.getString(R.string.label_tree_pollen); @@ -257,7 +257,7 @@ public DetailItemViewModel(@NonNull AirQuality aqi) { final Context context = SharedModuleKt.getSharedDeps().getContext(); this.detailsType = WeatherDetailsType.AIRQUALITY; this.label = context.getString(R.string.label_airquality_short); - this.icon = WeatherIcons.CLOUDY_GUSTS; + this.icon = WeatherIcons.AIR_QUALITY; this.iconRotation = 0; if (aqi.getIndex() < 51) { @@ -281,7 +281,6 @@ public DetailItemViewModel(@NonNull UV uv) { final Context context = SharedModuleKt.getSharedDeps().getContext(); this.detailsType = WeatherDetailsType.UV; this.label = context.getString(R.string.label_uv); - this.icon = WeatherIcons.DAY_SUNNY; this.iconRotation = 0; if (uv.getIndex() < 3) { @@ -296,6 +295,21 @@ public DetailItemViewModel(@NonNull UV uv) { this.value = context.getString(R.string.uv_11); } + switch (uv.getIndex().intValue()) { + case 1 -> icon = WeatherIcons.UV_INDEX_1; + case 2 -> icon = WeatherIcons.UV_INDEX_2; + case 3 -> icon = WeatherIcons.UV_INDEX_3; + case 4 -> icon = WeatherIcons.UV_INDEX_4; + case 5 -> icon = WeatherIcons.UV_INDEX_5; + case 6 -> icon = WeatherIcons.UV_INDEX_6; + case 7 -> icon = WeatherIcons.UV_INDEX_7; + case 8 -> icon = WeatherIcons.UV_INDEX_8; + case 9 -> icon = WeatherIcons.UV_INDEX_9; + case 10 -> icon = WeatherIcons.UV_INDEX_10; + case 11 -> icon = WeatherIcons.UV_INDEX_11; + default -> icon = WeatherIcons.UV_INDEX; + } + this.shortValue = String.format(LocaleUtils.getLocale(), "%d", Math.round(uv.getIndex())); } diff --git a/common/src/main/java/com/thewizrd/common/controls/HourlyForecastItemViewModel.java b/common/src/main/java/com/thewizrd/common/controls/HourlyForecastItemViewModel.java index 27dd238d9..88da7f5d7 100644 --- a/common/src/main/java/com/thewizrd/common/controls/HourlyForecastItemViewModel.java +++ b/common/src/main/java/com/thewizrd/common/controls/HourlyForecastItemViewModel.java @@ -78,10 +78,10 @@ public HourlyForecastItemViewModel(@NonNull HourlyForecast forecast) { Logger.writeLine(Log.ERROR, nFe); } - if (forecast.getWindMph() != null && forecast.getWindKph() != null && forecast.getWindMph() >= 0 && - forecast.getWindDegrees() != null && forecast.getWindDegrees() >= 0) { - windDirection = NumberUtils.getValueOrDefault(forecast.getWindDegrees(), 0); - windDir = WeatherUtils.getWindDirection(forecast.getWindDegrees()); + if (forecast.getExtras() != null && forecast.getExtras().getWindMph() != null && forecast.getExtras().getWindKph() != null && forecast.getExtras().getWindMph() >= 0 && + forecast.getExtras().getWindDegrees() != null && forecast.getExtras().getWindDegrees() >= 0) { + windDirection = NumberUtils.getValueOrDefault(forecast.getExtras().getWindDegrees(), 0); + windDir = WeatherUtils.getWindDirection(forecast.getExtras().getWindDegrees()); final String unit = settingsMgr.getSpeedUnit(); int speedVal; diff --git a/common/src/main/java/com/thewizrd/common/controls/IconControl.kt b/common/src/main/java/com/thewizrd/common/controls/IconControl.kt index 772707c17..903f063aa 100644 --- a/common/src/main/java/com/thewizrd/common/controls/IconControl.kt +++ b/common/src/main/java/com/thewizrd/common/controls/IconControl.kt @@ -166,7 +166,11 @@ class IconControl : AppCompatImageView { } private fun updateIconTint() { - if (showAsMonochrome || wim.isFontIcon) { + val wip = wim.getIconProvider( + iconProvider ?: SettingsManager(context).getIconsProvider() + ) + + if (showAsMonochrome || wip.isFontIcon) { ImageViewCompat.setImageTintList(this, mIconTint) } else { val tint = mIconTint diff --git a/common/src/main/java/com/thewizrd/common/controls/WeatherAlertPanel.java b/common/src/main/java/com/thewizrd/common/controls/WeatherAlertPanel.java index b36e64c9e..61405cd32 100644 --- a/common/src/main/java/com/thewizrd/common/controls/WeatherAlertPanel.java +++ b/common/src/main/java/com/thewizrd/common/controls/WeatherAlertPanel.java @@ -17,7 +17,7 @@ import androidx.transition.TransitionManager; import androidx.transition.TransitionSet; -import com.thewizrd.common.R; +import com.thewizrd.shared_resources.R; import com.thewizrd.common.databinding.WeatherAlertPanelBinding; public class WeatherAlertPanel extends FrameLayout { diff --git a/common/src/main/java/com/thewizrd/common/migrations/VersionMigrations.kt b/common/src/main/java/com/thewizrd/common/migrations/VersionMigrations.kt index 341dd87b4..8a5ef9e31 100644 --- a/common/src/main/java/com/thewizrd/common/migrations/VersionMigrations.kt +++ b/common/src/main/java/com/thewizrd/common/migrations/VersionMigrations.kt @@ -157,6 +157,7 @@ object VersionMigrations { "API_IsInternalKey", (!settingsMgr.usePersonalKey(settingsMgr.getAPI())).toString() ) + putString("IconProvider", settingsMgr.getIconsProvider()) putLong("VersionCode", settingsMgr.getVersionCode()) putLong("CurrentVersionCode", versionCode) } @@ -172,6 +173,10 @@ object VersionMigrations { AnalyticsProps.USER_LOCALE, LocaleUtils.getLocale().toLanguageTag() ) + AnalyticsLogger.setUserProperty( + AnalyticsProps.ICON_PROVIDER, + settingsMgr.getIconsProvider() + ) } if (versionCode > 0) { diff --git a/common/src/main/java/com/thewizrd/common/preferences/KeyEntryPreferenceDialogFragment.kt b/common/src/main/java/com/thewizrd/common/preferences/KeyEntryPreferenceDialogFragment.kt index c94686ba5..80b3dec9f 100644 --- a/common/src/main/java/com/thewizrd/common/preferences/KeyEntryPreferenceDialogFragment.kt +++ b/common/src/main/java/com/thewizrd/common/preferences/KeyEntryPreferenceDialogFragment.kt @@ -17,6 +17,7 @@ import androidx.preference.EditTextPreference import androidx.preference.PreferenceDialogFragmentCompat import com.google.android.material.textfield.TextInputLayout import com.thewizrd.common.R +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.auth.AuthType @@ -143,7 +144,7 @@ class KeyEntryPreferenceDialogFragment : PreferenceDialogFragmentCompat() { if (apiProvider == WeatherAPI.HERE) { this.hint = "Access Key ID" } else { - this.setHint(R.string.hint_appid) + this.setHint(sharedRes.string.hint_appid) } editText?.let { editText -> editText.requestFocus() @@ -159,7 +160,7 @@ class KeyEntryPreferenceDialogFragment : PreferenceDialogFragmentCompat() { if (apiProvider == WeatherAPI.HERE) { this.hint = "Access Key Secret" } else { - this.setHint(R.string.hint_appcode) + this.setHint(sharedRes.string.hint_appcode) } editText?.let { editText -> editText.setText(credentials?.appCode ?: "") @@ -174,7 +175,7 @@ class KeyEntryPreferenceDialogFragment : PreferenceDialogFragmentCompat() { val credentials = providerKey as? BasicAuthProviderKey view.findViewById(R.id.keyentry1_layout)?.apply { - this.setHint(R.string.hint_username) + this.setHint(sharedRes.string.hint_username) editText?.let { editText -> editText.requestFocus() editText.setText(credentials?.username ?: "") @@ -186,7 +187,7 @@ class KeyEntryPreferenceDialogFragment : PreferenceDialogFragmentCompat() { } } view.findViewById(R.id.keyentry2_layout)?.apply { - this.setHint(R.string.hint_password) + this.setHint(sharedRes.string.hint_password) endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE passwordVisibilityToggleRequested(true) @@ -201,7 +202,7 @@ class KeyEntryPreferenceDialogFragment : PreferenceDialogFragmentCompat() { } else -> { view.findViewById(R.id.keyentry1_layout)?.apply { - this.setHint(R.string.key_hint) + this.setHint(sharedRes.string.key_hint) editText?.let { editText -> editText.requestFocus() editText.setText(key ?: "") diff --git a/common/src/main/java/com/thewizrd/common/preferences/SliderPreference.kt b/common/src/main/java/com/thewizrd/common/preferences/SliderPreference.kt index 0439bc28d..0d640df1f 100644 --- a/common/src/main/java/com/thewizrd/common/preferences/SliderPreference.kt +++ b/common/src/main/java/com/thewizrd/common/preferences/SliderPreference.kt @@ -12,6 +12,7 @@ import androidx.core.view.isVisible import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import com.google.android.material.slider.Slider +import com.thewizrd.common.R as commonRes import com.thewizrd.shared_resources.R import java.math.BigDecimal import java.math.MathContext @@ -99,8 +100,8 @@ class SliderPreference : Preference { override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - mSlider = holder.findViewById(R.id.seekbar) as Slider? - mSliderValueTextView = holder.findViewById(R.id.seekbar_value) as TextView? + mSlider = holder.findViewById(commonRes.id.seekbar) as Slider? + mSliderValueTextView = holder.findViewById(commonRes.id.seekbar_value) as TextView? val summaryView = holder.findViewById(android.R.id.summary) as TextView? if (mShowSliderValue) { diff --git a/common/src/main/java/com/thewizrd/common/viewmodels/LocationSearchViewModel.kt b/common/src/main/java/com/thewizrd/common/viewmodels/LocationSearchViewModel.kt index 7689051b7..7feaeebad 100644 --- a/common/src/main/java/com/thewizrd/common/viewmodels/LocationSearchViewModel.kt +++ b/common/src/main/java/com/thewizrd/common/viewmodels/LocationSearchViewModel.kt @@ -5,10 +5,10 @@ import androidx.annotation.StringRes import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.thewizrd.common.BuildConfig -import com.thewizrd.common.R import com.thewizrd.common.location.LocationProvider import com.thewizrd.common.location.LocationResult import com.thewizrd.common.utils.ErrorMessage +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData diff --git a/common/src/main/java/com/thewizrd/common/weatherdata/WeatherDataLoader.kt b/common/src/main/java/com/thewizrd/common/weatherdata/WeatherDataLoader.kt index 7df770b84..9340fb5e6 100644 --- a/common/src/main/java/com/thewizrd/common/weatherdata/WeatherDataLoader.kt +++ b/common/src/main/java/com/thewizrd/common/weatherdata/WeatherDataLoader.kt @@ -11,9 +11,20 @@ import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.remoteconfig.remoteConfigService -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.CommonActions +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.utils.NumberUtils.getValueOrDefault -import com.thewizrd.shared_resources.weatherdata.model.* +import com.thewizrd.shared_resources.utils.createUnsupportedLocationException +import com.thewizrd.shared_resources.utils.getBeaufortScale +import com.thewizrd.shared_resources.weatherdata.model.Beaufort +import com.thewizrd.shared_resources.weatherdata.model.Forecasts +import com.thewizrd.shared_resources.weatherdata.model.HourlyForecasts +import com.thewizrd.shared_resources.weatherdata.model.LocationType +import com.thewizrd.shared_resources.weatherdata.model.UV +import com.thewizrd.shared_resources.weatherdata.model.Weather +import com.thewizrd.shared_resources.weatherdata.model.WeatherAlert import com.thewizrd.weather_api.weatherModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ensureActive @@ -25,6 +36,7 @@ import java.time.ZonedDateTime import java.time.temporal.ChronoUnit import kotlin.coroutines.coroutineContext import kotlin.math.max +import kotlin.math.roundToInt class WeatherDataLoader { companion object { @@ -441,13 +453,13 @@ class WeatherDataLoader { weather.condition!!.tempF = hrf.highF weather.condition!!.tempC = hrf.highC - weather.condition!!.windMph = hrf.windMph - weather.condition!!.windKph = hrf.windKph - weather.condition!!.windDegrees = hrf.windDegrees + weather.condition!!.windMph = hrf.extras?.windMph + weather.condition!!.windKph = hrf.extras?.windKph + weather.condition!!.windDegrees = hrf.extras?.windDegrees - if (hrf.windMph != null) { + if (hrf.extras?.windMph != null) { weather.condition!!.beaufort = - Beaufort(getBeaufortScale(Math.round(hrf.windMph))) + Beaufort(getBeaufortScale(hrf.extras.windMph.roundToInt())) } weather.condition!!.feelslikeF = hrf.extras?.feelslikeF weather.condition!!.feelslikeC = hrf.extras?.feelslikeC diff --git a/common/src/main/res/layout/credit_openmeteo.xml b/common/src/main/res/layout/credit_openmeteo.xml new file mode 100644 index 000000000..870ab33e2 --- /dev/null +++ b/common/src/main/res/layout/credit_openmeteo.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/common/src/nongms/java/com/thewizrd/common/location/LocationProvider.kt b/common/src/nongms/java/com/thewizrd/common/location/LocationProvider.kt index db648a88c..3932c5ad8 100644 --- a/common/src/nongms/java/com/thewizrd/common/location/LocationProvider.kt +++ b/common/src/nongms/java/com/thewizrd/common/location/LocationProvider.kt @@ -11,6 +11,7 @@ import androidx.core.os.CancellationSignal import com.thewizrd.common.R import com.thewizrd.common.helpers.locationPermissionEnabled import com.thewizrd.common.utils.ErrorMessage +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationData @@ -106,7 +107,7 @@ class LocationProvider(private val context: Context) { suspend fun getLatestLocationData(previousLocation: LocationData? = null): LocationResult { if (!LocationManagerCompat.isLocationEnabled(mLocationMgr)) { return LocationResult.Error( - errorMessage = ErrorMessage.Resource(R.string.error_enable_location_services) + errorMessage = ErrorMessage.Resource(sharedRes.string.error_enable_location_services) ) } if (!context.locationPermissionEnabled()) return LocationResult.PermissionDenied() @@ -164,7 +165,7 @@ class LocationProvider(private val context: Context) { if (view == null || view.locationQuery.isNullOrBlank()) { // Stop since there is no valid query - return LocationResult.Error(errorMessage = ErrorMessage.Resource(R.string.error_retrieve_location)) + return LocationResult.Error(errorMessage = ErrorMessage.Resource(sharedRes.string.error_retrieve_location)) } else if (view.locationTZLong.isNullOrBlank() && view.locationLat != 0.0 && view.locationLong != 0.0) { val tzId = weatherModule.tzdbService.getTimeZone(view.locationLat, view.locationLong) diff --git a/gradle.properties b/gradle.properties index 13908a335..81306c04c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,6 +20,5 @@ android.useAndroidX=true android.enableJetifier=false # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -android.nonTransitiveRClass=false -android.nonFinalResIds=false -org.gradle.configuration-cache=false \ No newline at end of file +org.gradle.configuration-cache=false +android.r8.strictFullModeForKeepRules=false \ No newline at end of file diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 000000000..baa28d154 --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,13 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7083b89563e7ce20943037b8cd2b8cc2/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/060bbb778a1f55ea705fdebd2ccfeab9/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/d09679dc60fe5aa05ef7d03efdefac20/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ed4e3bf2f5e7c5d9aabc4cbd8acd555e/redirect +toolchainVendor=JETBRAINS +toolchainVersion=21 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f45f47e3b..660d0c700 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,41 +1,42 @@ [versions] -compileSdkVersion = "36" +compileSdkVersion = "37" minSdkVersion = "23" -targetSdkVersion = "36" +targetSdkVersion = "37" +wearTargetSdkVersion = "36" -gradleVersion = "8.13.2" -kotlin_version = '2.1.20' -kotlinx_version = '1.10.2' -ksp_version = '2.1.20-2.0.1' +gradleVersion = "9.3.1" +kotlin_version = "2.3.21" +kotlinx_version = "1.11.0" +ksp_version = "2.3.6" desugar_version = '2.1.5' -firebase_version = "34.7.0" -firebaseCrashlyticsGradleVersion = "3.0.6" +firebase_version = "34.16.0" +firebaseCrashlyticsGradleVersion = "3.0.7" firebasePerfPluginVersion = "2.0.2" -gms_location_version = '21.3.0' -gms_base_version = '18.9.0' -gms_basement_version = '18.9.0' -gms_tasks_version = '18.4.0' -gms_wearable_version = '19.0.0' +gms_location_version = "21.4.0" +gms_base_version = "18.10.0" +gms_basement_version = "18.10.0" +gms_tasks_version = "18.4.1" +gms_wearable_version = "20.0.1" googleServicesVersion = "4.4.4" -annotation_version = '1.9.1' -activity_version = "1.12.1" +annotation_version = "1.10.0" +activity_version = "1.13.0" appcompat_version = '1.7.1' constraintlayout_version = '2.2.1' -core_version = '1.17.0' +core_version = "1.19.0" arch_core_runtime_version = '2.2.0' fragment_version = '1.8.9' -lifecycle_version = "2.10.0" -nav_version = "2.9.6" -paging_version = '3.3.6' +lifecycle_version = "2.11.0" +nav_version = "2.9.8" +paging_version = "3.5.0" preference_version = '1.2.1' recyclerview_version = '1.4.0' room_version = "2.8.4" coresplash_version = "1.2.0" vectordrawable_version = '1.2.0' -work_version = '2.11.0' +work_version = "2.11.2" test_core_version = '1.7.0' test_runner_version = '1.7.0' @@ -46,30 +47,32 @@ androidx_truth_version = '1.7.0' google_truth_version = '1.4.5' espresso_core_version = "3.7.0" -material_version = "1.14.0-alpha07" -material_compose_version = "1.5.0-alpha10" +material_version = "1.14.0" +material_compose_version = "1.5.0-alpha24" compose_compiler_version = '1.5.15' -compose_bom_version = "2025.12.00" -wear_version = '1.3.0' -wear_compose_version = "1.5.6" +compose_bom_version = "2026.06.01" +wear_version = "1.4.0" +wear_compose_version = "1.6.2" wear_input_version = '1.2.0' -wear_tiles_version = '1.5.0' -wear_watchface_version = '1.2.1' +wear_protolayout_version = "1.4.1" +wear_tiles_version = "1.6.1" +wear_watchface_version = "1.3.0" horologist_version = '0.7.15' accompanist_version = '0.37.3' -glide_version = '5.0.5' -icu4j_version = "78.1" +glide_version = "5.0.9" +icu4j_version = "78.3" jjwt_version = '0.13.0' moshi_version = '1.15.2' -okhttp_version = "5.3.2" +okhttp_version = "5.4.0" timber_version = '5.0.1' -revcat_version = "9.15.4" +revcat_version = "10.15.1" [libraries] com-google-devtools-ksp-gradle-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp_version" } +legacy-kapt-plugin = { module = "com.android.legacy-kapt:com.android.legacy-kapt.gradle.plugin", version.ref = "gradleVersion" } compose-compiler-gradle-plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin_version" } espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso_core_version" } junit = { module = "junit:junit", version.ref = "junit_version" } @@ -79,7 +82,6 @@ firebase-crashlytics-gradle = { module = "com.google.firebase:firebase-crashlyti google-services = { module = "com.google.gms:google-services", version.ref = "googleServicesVersion" } gradle = { module = "com.android.tools.build:gradle", version.ref = "gradleVersion" } firebase-perf-plugin = { module = "com.google.firebase:perf-plugin", version.ref = "firebasePerfPluginVersion" } -kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } nav-safe-args-plugin = { module = "androidx.navigation:navigation-safe-args-gradle-plugin", version.ref = "nav_version" } room-plugin = { module = "androidx.room:room-gradle-plugin", version.ref = "room_version" } @@ -134,8 +136,8 @@ work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "w wear = { module = "androidx.wear:wear", version.ref = "wear_version" } wear-input = { module = "androidx.wear:wear-input", version.ref = "wear_input_version" } wear-input-testing = { module = "androidx.wear:wear-input-testing", version.ref = "wear_input_version" } -wear-phone-interactions = { module = "androidx.wear:wear-phone-interactions", version = "1.1.0" } -wear-remote-interactions = { module = "androidx.wear:wear-remote-interactions", version = "1.1.0" } +wear-phone-interactions = { module = "androidx.wear:wear-phone-interactions", version = "1.1.1" } +wear-remote-interactions = { module = "androidx.wear:wear-remote-interactions", version = "1.2.0" } wear-watchface-complications-data = { module = "androidx.wear.watchface:watchface-complications-data", version.ref = "wear_watchface_version" } wear-watchface-complications-data-source-ktx = { module = "androidx.wear.watchface:watchface-complications-data-source-ktx", version.ref = "wear_watchface_version" } wear-tiles = { module = "androidx.wear.tiles:tiles", version.ref = "wear_tiles_version" } @@ -143,8 +145,8 @@ wear-tiles-renderer = { module = "androidx.wear.tiles:tiles-renderer", version.r wear-tiles-testing = { module = "androidx.wear.tiles:tiles-testing", version.ref = "wear_tiles_version" } wear-tiles-tooling = { module = "androidx.wear.tiles:tiles-tooling", version.ref = "wear_tiles_version" } wear-tiles-tooling-preview = { module = "androidx.wear.tiles:tiles-tooling-preview", version.ref = "wear_tiles_version" } -wear-protolayout-material = { module = "androidx.wear.protolayout:protolayout-material", version.ref = "wear_version" } -wear-protolayout-material3 = { module = "androidx.wear.protolayout:protolayout-material3", version.ref = "wear_version" } +wear-protolayout-material = { module = "androidx.wear.protolayout:protolayout-material", version.ref = "wear_protolayout_version" } +wear-protolayout-material3 = { module = "androidx.wear.protolayout:protolayout-material3", version.ref = "wear_protolayout_version" } horologist-tiles = { module = "com.google.android.horologist:horologist-tiles", version.ref = "horologist_version" } activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity_version" } compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compose_compiler_version" } @@ -163,7 +165,7 @@ wear-tooling-preview = { module = "androidx.wear:wear-tooling-preview", version accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist_version" } horologist-compose-layout = { module = "com.google.android.horologist:horologist-compose-layout", version.ref = "horologist_version" } horologist-compose-tools = { module = "com.google.android.horologist:horologist-compose-tools", version.ref = "horologist_version" } -reorderable = { module = "sh.calvin.reorderable:reorderable", version = "3.0.0" } +reorderable = { module = "sh.calvin.reorderable:reorderable", version = "3.1.0" } compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } firebase-perf = { module = "com.google.firebase:firebase-perf" } @@ -176,9 +178,9 @@ navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-kt navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "nav_version" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide_version" } glide-ksp = { module = "com.github.bumptech.glide:ksp", version.ref = "glide_version" } -colorpickerview = { module = "com.github.skydoves:colorpickerview", version = "2.3.0" } +colorpickerview = { module = "com.github.skydoves:colorpickerview", version = "2.4.0" } firebase-messaging = { module = "com.google.firebase:firebase-messaging" } -gms-play-services-maps = { module = "com.google.android.gms:play-services-maps", version = "19.2.0" } +gms-play-services-maps = { module = "com.google.android.gms:play-services-maps", version = "20.0.0" } play-app-update-ktx = { module = "com.google.android.play:app-update-ktx", version = "2.1.0" } play-feature-delivery-ktx = { module = "com.google.android.play:feature-delivery-ktx", version = "2.1.0" } play-review-ktx = { module = "com.google.android.play:review-ktx", version = "2.0.2" } @@ -187,6 +189,7 @@ jjwt-api = { module = "io.jsonwebtoken:jjwt-api", version.ref = "jjwt_version" } jjwt-impl = { module = "io.jsonwebtoken:jjwt-impl", version.ref = "jjwt_version" } jjwt-orgjson = { module = "io.jsonwebtoken:jjwt-orgjson", version.ref = "jjwt_version" } moshi-java-codegen = { module = "com.github.nename0:moshi-java-codegen", version = "1.1.1" } +#noinspection GradleDependency places = { module = "com.google.android.libraries.places:places", version = "4.4.1" } volley = { module = "com.android.volley:volley", version = "1.2.1" } gms-play-services-basement = { module = "com.google.android.gms:play-services-basement", version.ref = "gms_basement_version" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 54fddc2e5..96eb87e06 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Aug 31 15:05:29 EDT 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index bab1dc216..e1e4682d4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,6 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' +} include ':extras' include ':weathericons' include ':app', ':wearapp', ':shared_resources' diff --git a/shared_resources/build.gradle b/shared_resources/build.gradle index 188db7a4b..233152155 100644 --- a/shared_resources/build.gradle +++ b/shared_resources/build.gradle @@ -1,6 +1,5 @@ plugins { id 'com.android.library' - id 'kotlin-android' id 'com.google.devtools.ksp' id 'androidx.room' } @@ -10,7 +9,6 @@ android { defaultConfig { minSdk libs.versions.minSdkVersion.get().toInteger() - targetSdk libs.versions.targetSdkVersion.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -28,6 +26,7 @@ android { buildFeatures { buildConfig true + resValues true } buildTypes { @@ -44,12 +43,12 @@ android { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true // Sets Java compatibility to Java 8 - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } kotlin { - jvmToolchain(17) + jvmToolchain(21) } room { @@ -76,6 +75,12 @@ android { } namespace 'com.thewizrd.shared_resources' + lint { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } + testOptions { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } } dependencies { diff --git a/shared_resources/src/fullgms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt b/shared_resources/src/fullgms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt index 055780be3..0cae9a4c9 100644 --- a/shared_resources/src/fullgms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt +++ b/shared_resources/src/fullgms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt @@ -89,6 +89,10 @@ class RemoteConfigServiceImpl : RemoteConfigService { WeatherAPI.ECCC } + LocationUtils.isOpenMeteoSupported(location) && isProviderEnabled(WeatherAPI.OPENMETEO) -> { + WeatherAPI.OPENMETEO + } + else -> { getDefaultWeatherProvider() } @@ -114,6 +118,10 @@ class RemoteConfigServiceImpl : RemoteConfigService { WeatherAPI.ECCC } + LocationUtils.isOpenMeteoSupported(location) && isProviderEnabled(WeatherAPI.OPENMETEO) -> { + WeatherAPI.OPENMETEO + } + else -> { getDefaultWeatherProvider() } diff --git a/shared_resources/src/fullgms/res/xml/remote_config_defaults.xml b/shared_resources/src/fullgms/res/xml/remote_config_defaults.xml index de85383eb..45e3378a9 100644 --- a/shared_resources/src/fullgms/res/xml/remote_config_defaults.xml +++ b/shared_resources/src/fullgms/res/xml/remote_config_defaults.xml @@ -64,9 +64,9 @@ wunlocked { - "enabled": true, + "enabled": false, "locSource": "android", - "newWeatherSource": "" + "newWeatherSource": "weatherapi" } @@ -180,9 +180,19 @@ } + + open_meteo + + { + "enabled": true, + "locSource": "weatherapi", + "newWeatherSource": "" + } + + default_weather_provider - weatherapi + open_meteo key_imagedb_valid_days diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/SharedModule.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/SharedModule.kt index ba5e92873..7d71f910e 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/SharedModule.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/SharedModule.kt @@ -28,7 +28,13 @@ abstract class SharedModule { GMSSecurityProvider.installAsync(context) // Initialize logger - Logger.init(context) + runCatching { + Logger.init(context) + }.getOrElse { + if (!BuildConfig.DEBUG) { + throw it + } + } } open val httpClient: OkHttpClient by lazy { diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/database/WeatherDAO.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/database/WeatherDAO.kt index e7abd5119..97196aa8e 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/database/WeatherDAO.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/database/WeatherDAO.kt @@ -97,7 +97,7 @@ interface WeatherDAO { suspend fun getForecastData(query: String): Forecasts? @Query("SELECT * FROM forecasts WHERE `query` = :query") - fun getLiveForecastData(query: String): Flow + fun getLiveForecastData(query: String): Flow @Query("SELECT COUNT(*) FROM forecasts GROUP BY `query`") suspend fun getForecastDataCountGroupedByQuery(): Int diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/GoogleWeatherIconsProvider.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/GoogleWeatherIconsProvider.kt index 3969073a8..f4fa61650 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/GoogleWeatherIconsProvider.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/GoogleWeatherIconsProvider.kt @@ -181,6 +181,9 @@ class GoogleWeatherIconsProvider : WeatherIconProvider() { WeatherIcons.DIRECTION_UP -> R.drawable.material_arrow_upward WeatherIcons.DIRECTION_DOWN -> R.drawable.material_arrow_downward + WeatherIcons.VISIBILITY -> R.drawable.material_visibility + WeatherIcons.AIR_QUALITY -> R.drawable.material_aq + WeatherIcons.WIND_BEAUFORT_0 -> R.drawable.wi_wind_beaufort_0 WeatherIcons.WIND_BEAUFORT_1 -> R.drawable.wi_wind_beaufort_1 WeatherIcons.WIND_BEAUFORT_2 -> R.drawable.wi_wind_beaufort_2 diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/JDWIIconsProvider.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/JDWIIconsProvider.kt index cd04990c7..9586601ca 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/JDWIIconsProvider.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/JDWIIconsProvider.kt @@ -159,6 +159,9 @@ class JDWIIconsProvider : WeatherIconProvider() { WeatherIcons.DIRECTION_UP -> R.drawable.material_arrow_upward WeatherIcons.DIRECTION_DOWN -> R.drawable.material_arrow_downward + WeatherIcons.VISIBILITY -> R.drawable.jdwi_visibility + WeatherIcons.AIR_QUALITY -> R.drawable.material_aq + WeatherIcons.WIND_BEAUFORT_0 -> R.drawable.wi_wind_beaufort_0 WeatherIcons.WIND_BEAUFORT_1 -> R.drawable.wi_wind_beaufort_1 WeatherIcons.WIND_BEAUFORT_2 -> R.drawable.wi_wind_beaufort_2 diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WUndergroundIconsProvider.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WUndergroundIconsProvider.kt deleted file mode 100644 index 95bd73a46..000000000 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WUndergroundIconsProvider.kt +++ /dev/null @@ -1,217 +0,0 @@ -package com.thewizrd.shared_resources.icons - -import androidx.annotation.DrawableRes -import com.thewizrd.shared_resources.R - -class WUndergroundIconsProvider : WeatherIconProvider() { - override fun getKey(): String { - return "wui-ashley-jager" - } - - override fun getDisplayName(): String { - return "WeatherUnderground Icons" - } - - override fun getAuthorName(): String { - return "Ashley Jager" - } - - override fun getAttributionLink(): String { - return "https://github.com/manifestinteractive/weather-underground-icons" - } - - override fun isFontIcon(): Boolean { - return false - } - - @DrawableRes - override fun getWeatherIconResource(icon: String): Int { - var weatherIcon = when (icon) { - WeatherIcons.DAY_SUNNY, - WeatherIcons.DAY_HOT, - WeatherIcons.DAY_LIGHT_WIND -> R.drawable.wui_day_sunny - - WeatherIcons.DAY_CLOUDY, - WeatherIcons.DAY_CLOUDY_GUSTS, - WeatherIcons.DAY_CLOUDY_WINDY, - WeatherIcons.DAY_CLOUDY_HIGH -> R.drawable.wui_day_mostlycloudy - - WeatherIcons.DAY_PARTLY_CLOUDY, - WeatherIcons.DAY_SUNNY_OVERCAST -> R.drawable.wui_day_partlycloudy - - // Night - WeatherIcons.NIGHT_CLEAR, - WeatherIcons.NIGHT_HOT, - WeatherIcons.NIGHT_LIGHT_WIND -> R.drawable.wui_nt_clear - - WeatherIcons.NIGHT_ALT_CLOUDY, - WeatherIcons.NIGHT_ALT_CLOUDY_GUSTS, - WeatherIcons.NIGHT_ALT_CLOUDY_WINDY -> R.drawable.wui_nt_mostlycloudy - - WeatherIcons.NIGHT_ALT_PARTLY_CLOUDY, - WeatherIcons.NIGHT_OVERCAST -> R.drawable.wui_nt_partlycloudy - - WeatherIcons.NIGHT_ALT_CLOUDY_HIGH -> R.drawable.wui_nt_mostlycloudy - - // Neutral - WeatherIcons.DAY_FOG, - WeatherIcons.DAY_HAZE, - WeatherIcons.NIGHT_FOG, - WeatherIcons.NIGHT_HAZE, - WeatherIcons.FOG, - WeatherIcons.HAZE -> R.drawable.wui_fog - - WeatherIcons.DAY_LIGHTNING, - WeatherIcons.NIGHT_ALT_LIGHTNING, - WeatherIcons.LIGHTNING -> R.drawable.wui_chancetstorms - - WeatherIcons.DAY_HAIL, - WeatherIcons.DAY_SLEET, - WeatherIcons.DAY_SLEET_STORM, - WeatherIcons.NIGHT_ALT_HAIL, - WeatherIcons.NIGHT_ALT_SLEET, - WeatherIcons.NIGHT_ALT_SLEET_STORM, - WeatherIcons.SLEET, - WeatherIcons.SLEET_STORM -> R.drawable.wui_sleet - - WeatherIcons.DAY_RAIN_MIX, - WeatherIcons.NIGHT_ALT_RAIN_MIX, - WeatherIcons.RAIN_MIX, - WeatherIcons.HAIL -> R.drawable.wui_chancesleet - - WeatherIcons.DAY_RAIN, - WeatherIcons.DAY_RAIN_WIND, - WeatherIcons.DAY_SHOWERS, - WeatherIcons.NIGHT_ALT_RAIN, - WeatherIcons.NIGHT_ALT_RAIN_WIND, - WeatherIcons.NIGHT_ALT_SHOWERS, - WeatherIcons.RAIN, - WeatherIcons.RAIN_WIND, - WeatherIcons.SHOWERS -> R.drawable.wui_rain - - WeatherIcons.DAY_SNOW, - WeatherIcons.DAY_SNOW_THUNDERSTORM, - WeatherIcons.DAY_SNOW_WIND, - WeatherIcons.NIGHT_ALT_SNOW, - WeatherIcons.NIGHT_ALT_SNOW_THUNDERSTORM, - WeatherIcons.NIGHT_ALT_SNOW_WIND, - WeatherIcons.SNOW, - WeatherIcons.SNOW_THUNDERSTORM, - WeatherIcons.SNOW_WIND, - WeatherIcons.SNOWFLAKE_COLD -> R.drawable.wui_snow - - WeatherIcons.DAY_SPRINKLE, - WeatherIcons.NIGHT_ALT_SPRINKLE, - WeatherIcons.SPRINKLE -> R.drawable.wui_chancerain - - WeatherIcons.DAY_STORM_SHOWERS, - WeatherIcons.DAY_THUNDERSTORM, - WeatherIcons.NIGHT_ALT_STORM_SHOWERS, - WeatherIcons.NIGHT_ALT_THUNDERSTORM, - WeatherIcons.STORM_SHOWERS, - WeatherIcons.THUNDERSTORM -> R.drawable.wui_tstorms - - WeatherIcons.DAY_WINDY, - WeatherIcons.NIGHT_WINDY -> R.drawable.wi_windy - - WeatherIcons.CLOUD, - WeatherIcons.CLOUDY, - WeatherIcons.CLOUDY_GUSTS, - WeatherIcons.CLOUDY_WINDY, - WeatherIcons.OVERCAST -> R.drawable.wui_cloudy - - WeatherIcons.HOT -> R.drawable.wi_thermometer_up - WeatherIcons.SMOG -> R.drawable.wi_smog - WeatherIcons.SMOKE -> R.drawable.wi_smoke - WeatherIcons.DUST -> R.drawable.wi_dust - WeatherIcons.WINDY, - WeatherIcons.LIGHT_WIND -> R.drawable.wi_windy - WeatherIcons.STRONG_WIND -> R.drawable.wi_strong_wind - WeatherIcons.SANDSTORM -> R.drawable.wi_sandstorm - WeatherIcons.HURRICANE -> R.drawable.wi_hurricane - WeatherIcons.TORNADO -> R.drawable.wi_tornado - - // Misc icons - WeatherIcons.FIRE -> R.drawable.wi_fire - WeatherIcons.FLOOD -> R.drawable.wi_flood - WeatherIcons.VOLCANO -> R.drawable.wi_volcano - WeatherIcons.BAROMETER -> R.drawable.wi_barometer - WeatherIcons.HUMIDITY -> R.drawable.wi_humidity - WeatherIcons.MOONRISE -> R.drawable.wi_moonrise - WeatherIcons.MOONSET -> R.drawable.wi_moonset - WeatherIcons.RAINDROP -> R.drawable.wi_raindrop - WeatherIcons.RAINDROPS -> R.drawable.wi_raindrops - WeatherIcons.SUNRISE -> R.drawable.wi_sunrise - WeatherIcons.SUNSET -> R.drawable.wi_sunset - WeatherIcons.THERMOMETER -> R.drawable.wi_thermometer - WeatherIcons.UMBRELLA -> R.drawable.wi_umbrella - WeatherIcons.WIND_DIRECTION -> R.drawable.wi_wind_direction - WeatherIcons.DIRECTION_UP -> R.drawable.wi_direction_up - WeatherIcons.DIRECTION_DOWN -> R.drawable.wi_direction_down - - // Beaufort - WeatherIcons.WIND_BEAUFORT_0 -> R.drawable.wi_wind_beaufort_0 - WeatherIcons.WIND_BEAUFORT_1 -> R.drawable.wi_wind_beaufort_1 - WeatherIcons.WIND_BEAUFORT_2 -> R.drawable.wi_wind_beaufort_2 - WeatherIcons.WIND_BEAUFORT_3 -> R.drawable.wi_wind_beaufort_3 - WeatherIcons.WIND_BEAUFORT_4 -> R.drawable.wi_wind_beaufort_4 - WeatherIcons.WIND_BEAUFORT_5 -> R.drawable.wi_wind_beaufort_5 - WeatherIcons.WIND_BEAUFORT_6 -> R.drawable.wi_wind_beaufort_6 - WeatherIcons.WIND_BEAUFORT_7 -> R.drawable.wi_wind_beaufort_7 - WeatherIcons.WIND_BEAUFORT_8 -> R.drawable.wi_wind_beaufort_8 - WeatherIcons.WIND_BEAUFORT_9 -> R.drawable.wi_wind_beaufort_9 - WeatherIcons.WIND_BEAUFORT_10 -> R.drawable.wi_wind_beaufort_10 - WeatherIcons.WIND_BEAUFORT_11 -> R.drawable.wi_wind_beaufort_11 - WeatherIcons.WIND_BEAUFORT_12 -> R.drawable.wi_wind_beaufort_12 - - // Moon phase - WeatherIcons.MOON_NEW -> R.drawable.wi_moon_new - WeatherIcons.MOON_WAXING_CRESCENT_3 -> R.drawable.wi_moon_waxing_crescent_3 - WeatherIcons.MOON_FIRST_QUARTER -> R.drawable.wi_moon_first_quarter - WeatherIcons.MOON_WAXING_GIBBOUS_3 -> R.drawable.wi_moon_waxing_gibbous_3 - WeatherIcons.MOON_FULL -> R.drawable.wi_moon_full - WeatherIcons.MOON_WANING_GIBBOUS_3 -> R.drawable.wi_moon_waning_gibbous_3 - WeatherIcons.MOON_THIRD_QUARTER -> R.drawable.wi_moon_third_quarter - WeatherIcons.MOON_WANING_CRESCENT_3 -> R.drawable.wi_moon_waning_crescent_3 - WeatherIcons.MOON_ALT_NEW -> R.drawable.wi_moon_alt_new - WeatherIcons.MOON_ALT_WAXING_CRESCENT_3 -> R.drawable.wi_moon_alt_waxing_crescent_3 - WeatherIcons.MOON_ALT_FIRST_QUARTER -> R.drawable.wi_moon_alt_first_quarter - WeatherIcons.MOON_ALT_WAXING_GIBBOUS_3 -> R.drawable.wi_moon_alt_waxing_gibbous_3 - WeatherIcons.MOON_ALT_FULL -> R.drawable.wi_moon_alt_full - WeatherIcons.MOON_ALT_WANING_GIBBOUS_3 -> R.drawable.wi_moon_alt_waning_gibbous_3 - WeatherIcons.MOON_ALT_THIRD_QUARTER -> R.drawable.wi_moon_alt_third_quarter - WeatherIcons.MOON_ALT_WANING_CRESCENT_3 -> R.drawable.wi_moon_alt_waning_crescent_3 - - WeatherIcons.UV_INDEX, - WeatherIcons.UV_INDEX_1, - WeatherIcons.UV_INDEX_2, - WeatherIcons.UV_INDEX_3, - WeatherIcons.UV_INDEX_4, - WeatherIcons.UV_INDEX_5, - WeatherIcons.UV_INDEX_6, - WeatherIcons.UV_INDEX_7, - WeatherIcons.UV_INDEX_8, - WeatherIcons.UV_INDEX_9, - WeatherIcons.UV_INDEX_10, - WeatherIcons.UV_INDEX_11 -> R.drawable.wui_day_sunny - - WeatherIcons.TREE_POLLEN -> R.drawable.ic_outline_tree - WeatherIcons.GRASS_POLLEN -> R.drawable.ic_baseline_grass - WeatherIcons.RAGWEED_POLLEN -> R.drawable.ic_ragweed_pollen - - WeatherIcons.FAHRENHEIT -> R.drawable.wi_fahrenheit - WeatherIcons.CELSIUS -> R.drawable.wi_celsius - - WeatherIcons.NA -> R.drawable.wui_unknown - - else -> -1 - } - - if (weatherIcon == -1) { - // Not Available - weatherIcon = R.drawable.wui_unknown - } - - return weatherIcon - } -} \ No newline at end of file diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconicProvider.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconicProvider.kt index db0ca050c..874cc6884 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconicProvider.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconicProvider.kt @@ -3,133 +3,136 @@ package com.thewizrd.shared_resources.icons import androidx.annotation.DrawableRes import com.thewizrd.shared_resources.R -class WeatherIconicProvider : WeatherIconProvider() { +class WeatherIconicProvider(private val isColored: Boolean = false) : WeatherIconProvider() { override fun getKey(): String { - return "w-iconic-jackd248" + return "w-iconic-jackd248" + if (isColored) "-multicolor" else "" } override fun getDisplayName(): String { - return "Weather Iconic" + return "Weather Iconic" + if (isColored) " (Multi-Color)" else "" } override fun getAuthorName(): String { - return "jackd248" + return "konradmichalik" } override fun getAttributionLink(): String { - return "https://github.com/jackd248/weather-iconic" + return "https://konradmichalik.github.io/weather-iconic/" } override fun isFontIcon(): Boolean { - return true + return !isColored } @DrawableRes override fun getWeatherIconResource(icon: String): Int { var weatherIcon = when (icon) { - WeatherIcons.DAY_SUNNY -> R.drawable.wic_sun - WeatherIcons.DAY_CLOUDY -> R.drawable.wic_sun_cloud - WeatherIcons.DAY_CLOUDY_GUSTS -> R.drawable.wic_sun_cloud_wind - WeatherIcons.DAY_CLOUDY_WINDY -> R.drawable.wic_sun_cloud_wind - WeatherIcons.DAY_FOG -> R.drawable.wic_sun_fog - WeatherIcons.DAY_HAIL -> R.drawable.wic_hail - WeatherIcons.DAY_HAZE -> R.drawable.wic_sun_fog - WeatherIcons.DAY_LIGHTNING -> R.drawable.wic_sun_cloud_lightning - WeatherIcons.DAY_PARTLY_CLOUDY -> R.drawable.wic_sun_cloud - WeatherIcons.DAY_RAIN -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_RAIN_MIX -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_RAIN_WIND -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_SHOWERS -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_SLEET -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_SLEET_STORM -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_SNOW -> R.drawable.wic_sun_cloud_snow - WeatherIcons.DAY_SNOW_THUNDERSTORM -> R.drawable.wic_sun_cloud_snow - WeatherIcons.DAY_SNOW_WIND -> R.drawable.wic_sun_cloud_snow - WeatherIcons.DAY_SPRINKLE -> R.drawable.wic_sun_cloud_rain - WeatherIcons.DAY_STORM_SHOWERS -> R.drawable.wic_sun_cloud_lightning - WeatherIcons.DAY_SUNNY_OVERCAST -> R.drawable.wic_sun_cloud - WeatherIcons.DAY_THUNDERSTORM -> R.drawable.wic_sun_cloud_lightning - WeatherIcons.DAY_WINDY -> R.drawable.wic_wind - WeatherIcons.DAY_HOT -> R.drawable.wic_sun - WeatherIcons.DAY_CLOUDY_HIGH -> R.drawable.wic_sun_cloud - WeatherIcons.DAY_LIGHT_WIND -> R.drawable.wic_wind - - WeatherIcons.NIGHT_CLEAR -> R.drawable.wic_moon - WeatherIcons.NIGHT_ALT_CLOUDY -> R.drawable.wic_moon_cloud - WeatherIcons.NIGHT_ALT_CLOUDY_GUSTS -> R.drawable.wic_moon_cloud_wind - WeatherIcons.NIGHT_ALT_CLOUDY_WINDY -> R.drawable.wic_moon_cloud_wind - WeatherIcons.NIGHT_ALT_HAIL -> R.drawable.wic_hail - WeatherIcons.NIGHT_ALT_LIGHTNING -> R.drawable.wic_moon_cloud_lightning - WeatherIcons.NIGHT_ALT_RAIN -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_RAIN_MIX -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_RAIN_WIND -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_SHOWERS -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_SLEET -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_SLEET_STORM -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_SNOW -> R.drawable.wic_moon_cloud_snow - WeatherIcons.NIGHT_ALT_SNOW_THUNDERSTORM -> R.drawable.wic_moon_cloud_snow - WeatherIcons.NIGHT_ALT_SNOW_WIND -> R.drawable.wic_moon_cloud_snow - WeatherIcons.NIGHT_ALT_SPRINKLE -> R.drawable.wic_moon_cloud_rain - WeatherIcons.NIGHT_ALT_STORM_SHOWERS -> R.drawable.wic_moon_cloud_lightning - WeatherIcons.NIGHT_ALT_THUNDERSTORM -> R.drawable.wic_moon_cloud_lightning - WeatherIcons.NIGHT_ALT_PARTLY_CLOUDY -> R.drawable.wic_moon_cloud - WeatherIcons.NIGHT_ALT_CLOUDY_HIGH -> R.drawable.wic_moon_cloud - WeatherIcons.NIGHT_FOG -> R.drawable.wic_moon_fog - WeatherIcons.NIGHT_OVERCAST -> R.drawable.wic_moon_cloud - WeatherIcons.NIGHT_HAZE -> R.drawable.wic_moon_fog - WeatherIcons.NIGHT_WINDY -> R.drawable.wic_wind - WeatherIcons.NIGHT_HOT -> R.drawable.wic_moon - WeatherIcons.NIGHT_LIGHT_WIND -> R.drawable.wic_wind - - WeatherIcons.CLOUD -> R.drawable.wic_cloud - WeatherIcons.CLOUDY -> R.drawable.wic_clouds - WeatherIcons.CLOUDY_GUSTS -> R.drawable.wic_cloud_wind - WeatherIcons.CLOUDY_WINDY -> R.drawable.wic_cloud_wind - WeatherIcons.FOG -> R.drawable.wic_fog - WeatherIcons.HAIL -> R.drawable.wic_hail - WeatherIcons.HAZE -> R.drawable.wic_fog - WeatherIcons.HOT -> R.drawable.wic_thermometer_hot - WeatherIcons.LIGHT_WIND -> R.drawable.wic_wind - WeatherIcons.RAIN -> R.drawable.wic_cloud_rain - WeatherIcons.RAIN_MIX -> R.drawable.wic_cloud_rain - WeatherIcons.RAIN_WIND -> R.drawable.wic_cloud_rain - WeatherIcons.OVERCAST -> R.drawable.wic_clouds - WeatherIcons.SHOWERS -> R.drawable.wic_cloud_rain - WeatherIcons.SLEET -> R.drawable.wic_cloud_rain - WeatherIcons.SLEET_STORM -> R.drawable.wic_cloud_rain - WeatherIcons.SNOW -> R.drawable.wic_cloud_snow - WeatherIcons.SNOW_THUNDERSTORM -> R.drawable.wic_cloud_snow - WeatherIcons.SPRINKLE -> R.drawable.wic_cloud_rain_single - WeatherIcons.STORM_SHOWERS -> R.drawable.wic_lightning - WeatherIcons.THUNDERSTORM -> R.drawable.wic_lightning - WeatherIcons.SNOW_WIND -> R.drawable.wic_cloud_snow - WeatherIcons.SMOG -> R.drawable.wi_smog + WeatherIcons.DAY_SUNNY -> if (isColored) R.drawable.wic_color_sun else R.drawable.wic_sun + WeatherIcons.DAY_CLOUDY -> if (isColored) R.drawable.wic_color_sun_cloud else R.drawable.wic_sun_cloud + WeatherIcons.DAY_CLOUDY_GUSTS -> if (isColored) R.drawable.wic_color_sun_cloud_wind else R.drawable.wic_sun_cloud_wind + WeatherIcons.DAY_CLOUDY_WINDY -> if (isColored) R.drawable.wic_color_sun_cloud_wind else R.drawable.wic_sun_cloud_wind + WeatherIcons.DAY_FOG -> if (isColored) R.drawable.wic_color_sun_fog else R.drawable.wic_sun_fog + WeatherIcons.DAY_HAIL -> if (isColored) R.drawable.wic_color_sun_cloud_hail else R.drawable.wic_sun_cloud_hail + WeatherIcons.DAY_HAZE -> if (isColored) R.drawable.wic_color_sun_cloud_haze else R.drawable.wic_sun_cloud_haze + WeatherIcons.DAY_LIGHTNING -> if (isColored) R.drawable.wic_color_sun_cloud_lightning else R.drawable.wic_sun_cloud_lightning + WeatherIcons.DAY_PARTLY_CLOUDY -> if (isColored) R.drawable.wic_color_sun_cloud else R.drawable.wic_sun_cloud + WeatherIcons.DAY_RAIN -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_RAIN_MIX -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_RAIN_WIND -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_SHOWERS -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_SLEET -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_SLEET_STORM -> if (isColored) R.drawable.wic_color_sun_cloud_rain else R.drawable.wic_sun_cloud_rain + WeatherIcons.DAY_SNOW -> if (isColored) R.drawable.wic_color_sun_cloud_snow_alt else R.drawable.wic_sun_cloud_snow_alt + WeatherIcons.DAY_SNOW_THUNDERSTORM -> if (isColored) R.drawable.wic_color_sun_cloud_snow else R.drawable.wic_sun_cloud_snow + WeatherIcons.DAY_SNOW_WIND -> if (isColored) R.drawable.wic_color_sun_cloud_snow else R.drawable.wic_sun_cloud_snow + WeatherIcons.DAY_SPRINKLE -> if (isColored) R.drawable.wic_color_sun_cloud_rain_alt else R.drawable.wic_sun_cloud_rain_alt + WeatherIcons.DAY_STORM_SHOWERS -> if (isColored) R.drawable.wic_color_sun_cloud_lightning else R.drawable.wic_sun_cloud_lightning + WeatherIcons.DAY_SUNNY_OVERCAST -> if (isColored) R.drawable.wic_color_sun_cloud else R.drawable.wic_sun_cloud + WeatherIcons.DAY_THUNDERSTORM -> if (isColored) R.drawable.wic_color_sun_cloud_lightning else R.drawable.wic_sun_cloud_lightning + WeatherIcons.DAY_WINDY -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + WeatherIcons.DAY_HOT -> if (isColored) R.drawable.wic_color_sun else R.drawable.wic_sun + WeatherIcons.DAY_CLOUDY_HIGH -> if (isColored) R.drawable.wic_color_sun_cloud else R.drawable.wic_sun_cloud + WeatherIcons.DAY_LIGHT_WIND -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + + WeatherIcons.NIGHT_CLEAR -> if (isColored) R.drawable.wic_color_moon else R.drawable.wic_moon + WeatherIcons.NIGHT_ALT_CLOUDY -> if (isColored) R.drawable.wic_color_moon_cloud else R.drawable.wic_moon_cloud + WeatherIcons.NIGHT_ALT_CLOUDY_GUSTS -> if (isColored) R.drawable.wic_color_moon_cloud_wind else R.drawable.wic_moon_cloud_wind + WeatherIcons.NIGHT_ALT_CLOUDY_WINDY -> if (isColored) R.drawable.wic_color_moon_cloud_wind else R.drawable.wic_moon_cloud_wind + WeatherIcons.NIGHT_ALT_HAIL -> if (isColored) R.drawable.wic_color_moon_cloud_hail else R.drawable.wic_moon_cloud_hail + WeatherIcons.NIGHT_ALT_LIGHTNING -> if (isColored) R.drawable.wic_color_moon_cloud_lightning else R.drawable.wic_moon_cloud_lightning + WeatherIcons.NIGHT_ALT_RAIN -> if (isColored) R.drawable.wic_color_moon_cloud_rain else R.drawable.wic_moon_cloud_rain + WeatherIcons.NIGHT_ALT_RAIN_MIX -> if (isColored) R.drawable.wic_color_moon_cloud_rain else R.drawable.wic_moon_cloud_rain + WeatherIcons.NIGHT_ALT_RAIN_WIND -> if (isColored) R.drawable.wic_color_moon_cloud_rain else R.drawable.wic_moon_cloud_rain + WeatherIcons.NIGHT_ALT_SHOWERS -> if (isColored) R.drawable.wic_color_moon_cloud_rain else R.drawable.wic_moon_cloud_rain + WeatherIcons.NIGHT_ALT_SLEET -> if (isColored) R.drawable.wic_color_moon_cloud_sleet else R.drawable.wic_moon_cloud_sleet + WeatherIcons.NIGHT_ALT_SLEET_STORM -> if (isColored) R.drawable.wic_color_moon_cloud_sleet else R.drawable.wic_moon_cloud_sleet + WeatherIcons.NIGHT_ALT_SNOW -> if (isColored) R.drawable.wic_color_moon_cloud_snow_alt else R.drawable.wic_moon_cloud_snow_alt + WeatherIcons.NIGHT_ALT_SNOW_THUNDERSTORM -> if (isColored) R.drawable.wic_color_moon_cloud_snow else R.drawable.wic_moon_cloud_snow + WeatherIcons.NIGHT_ALT_SNOW_WIND -> if (isColored) R.drawable.wic_color_moon_cloud_snow else R.drawable.wic_moon_cloud_snow + WeatherIcons.NIGHT_ALT_SPRINKLE -> if (isColored) R.drawable.wic_color_moon_cloud_rain_alt else R.drawable.wic_moon_cloud_rain_alt + WeatherIcons.NIGHT_ALT_STORM_SHOWERS -> if (isColored) R.drawable.wic_color_moon_cloud_lightning else R.drawable.wic_moon_cloud_lightning + WeatherIcons.NIGHT_ALT_THUNDERSTORM -> if (isColored) R.drawable.wic_color_moon_cloud_lightning else R.drawable.wic_moon_cloud_lightning + WeatherIcons.NIGHT_ALT_PARTLY_CLOUDY -> if (isColored) R.drawable.wic_color_moon_cloud else R.drawable.wic_moon_cloud + WeatherIcons.NIGHT_ALT_CLOUDY_HIGH -> if (isColored) R.drawable.wic_color_moon_cloud else R.drawable.wic_moon_cloud + WeatherIcons.NIGHT_FOG -> if (isColored) R.drawable.wic_color_moon_fog else R.drawable.wic_moon_fog + WeatherIcons.NIGHT_OVERCAST -> if (isColored) R.drawable.wic_color_moon_cloud else R.drawable.wic_moon_cloud + WeatherIcons.NIGHT_HAZE -> if (isColored) R.drawable.wic_color_moon_cloud_haze else R.drawable.wic_moon_cloud_haze + WeatherIcons.NIGHT_WINDY -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + WeatherIcons.NIGHT_HOT -> if (isColored) R.drawable.wic_color_moon else R.drawable.wic_moon + WeatherIcons.NIGHT_LIGHT_WIND -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + + WeatherIcons.CLOUD -> if (isColored) R.drawable.wic_color_cloud else R.drawable.wic_cloud + WeatherIcons.CLOUDY -> if (isColored) R.drawable.wic_color_clouds else R.drawable.wic_clouds + WeatherIcons.CLOUDY_GUSTS -> if (isColored) R.drawable.wic_color_cloud_wind else R.drawable.wic_cloud_wind + WeatherIcons.CLOUDY_WINDY -> if (isColored) R.drawable.wic_color_cloud_wind else R.drawable.wic_cloud_wind + WeatherIcons.FOG -> if (isColored) R.drawable.wic_color_fog else R.drawable.wic_fog + WeatherIcons.HAIL -> if (isColored) R.drawable.wic_color_cloud_hail else R.drawable.wic_cloud_hail + WeatherIcons.HAZE -> if (isColored) R.drawable.wic_color_cloud_haze else R.drawable.wic_cloud_haze + WeatherIcons.HOT -> if (isColored) R.drawable.wic_color_thermometer_heat else R.drawable.wic_thermometer_heat + WeatherIcons.LIGHT_WIND -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + WeatherIcons.RAIN -> if (isColored) R.drawable.wic_color_cloud_rain else R.drawable.wic_cloud_rain + WeatherIcons.RAIN_MIX -> if (isColored) R.drawable.wic_color_cloud_sleet else R.drawable.wic_cloud_sleet + WeatherIcons.RAIN_WIND -> if (isColored) R.drawable.wic_color_cloud_rain else R.drawable.wic_cloud_rain + WeatherIcons.OVERCAST -> if (isColored) R.drawable.wic_color_clouds_alt else R.drawable.wic_clouds_alt + WeatherIcons.SHOWERS -> if (isColored) R.drawable.wic_color_cloud_rain else R.drawable.wic_cloud_rain + WeatherIcons.SLEET -> if (isColored) R.drawable.wic_color_cloud_sleet else R.drawable.wic_cloud_sleet + WeatherIcons.SLEET_STORM -> if (isColored) R.drawable.wic_color_cloud_sleet else R.drawable.wic_cloud_sleet + WeatherIcons.SNOW -> if (isColored) R.drawable.wic_color_cloud_snow_alt else R.drawable.wic_cloud_snow_alt + WeatherIcons.SNOW_THUNDERSTORM -> if (isColored) R.drawable.wic_color_cloud_snow else R.drawable.wic_cloud_snow + WeatherIcons.SPRINKLE -> if (isColored) R.drawable.wic_color_cloud_rain_alt else R.drawable.wic_cloud_rain_alt + WeatherIcons.STORM_SHOWERS -> if (isColored) R.drawable.wic_color_lightning else R.drawable.wic_lightning + WeatherIcons.THUNDERSTORM -> if (isColored) R.drawable.wic_color_lightning else R.drawable.wic_lightning + WeatherIcons.SNOW_WIND -> if (isColored) R.drawable.wic_color_cloud_snow else R.drawable.wic_cloud_snow + WeatherIcons.SMOG -> if (isColored) R.drawable.wic_color_cloud_smog else R.drawable.wic_cloud_smog WeatherIcons.SMOKE -> R.drawable.wi_smoke - WeatherIcons.LIGHTNING -> R.drawable.wic_lightning + WeatherIcons.LIGHTNING -> if (isColored) R.drawable.wic_color_lightning else R.drawable.wic_lightning WeatherIcons.DUST -> R.drawable.wi_dust - WeatherIcons.SNOWFLAKE_COLD -> R.drawable.wic_snowflake - WeatherIcons.WINDY -> R.drawable.wic_wind - WeatherIcons.STRONG_WIND -> R.drawable.wic_wind_high - WeatherIcons.SANDSTORM -> R.drawable.wi_sandstorm - WeatherIcons.HURRICANE -> R.drawable.wi_hurricane - WeatherIcons.TORNADO -> R.drawable.wic_tornado - WeatherIcons.FIRE -> R.drawable.wi_fire - WeatherIcons.FLOOD -> R.drawable.wi_flood + WeatherIcons.SNOWFLAKE_COLD -> if (isColored) R.drawable.wic_color_snowflake else R.drawable.wic_snowflake + WeatherIcons.WINDY -> if (isColored) R.drawable.wic_color_wind else R.drawable.wic_wind + WeatherIcons.STRONG_WIND -> if (isColored) R.drawable.wic_color_wind_high else R.drawable.wic_wind_high + WeatherIcons.SANDSTORM -> if (isColored) R.drawable.wic_color_sandstorm else R.drawable.wic_sandstorm + WeatherIcons.HURRICANE -> if (isColored) R.drawable.wic_color_hurricane else R.drawable.wic_hurricane + WeatherIcons.TORNADO -> if (isColored) R.drawable.wic_color_tornado else R.drawable.wic_tornado + WeatherIcons.FIRE -> if (isColored) R.drawable.wic_color_fire else R.drawable.wic_fire + WeatherIcons.FLOOD -> if (isColored) R.drawable.wic_color_flood else R.drawable.wic_flood WeatherIcons.VOLCANO -> R.drawable.wi_volcano - WeatherIcons.BAROMETER -> R.drawable.wic_barometer - WeatherIcons.HUMIDITY -> R.drawable.wic_raindrop - WeatherIcons.MOONRISE -> R.drawable.wi_moonrise - WeatherIcons.MOONSET -> R.drawable.wi_moonset - WeatherIcons.RAINDROP -> R.drawable.wi_raindrop + WeatherIcons.BAROMETER -> if (isColored) R.drawable.wic_color_barometer else R.drawable.wic_barometer + WeatherIcons.HUMIDITY -> if (isColored) R.drawable.wic_color_humidity else R.drawable.wic_humidity + WeatherIcons.MOONRISE -> if (isColored) R.drawable.wic_color_moonrise else R.drawable.wic_moonrise + WeatherIcons.MOONSET -> if (isColored) R.drawable.wic_color_moonset else R.drawable.wic_moonset + WeatherIcons.RAINDROP -> if (isColored) R.drawable.wic_color_raindrop else R.drawable.wic_raindrop WeatherIcons.RAINDROPS -> R.drawable.wi_raindrops - WeatherIcons.SUNRISE -> R.drawable.wic_sunrise - WeatherIcons.SUNSET -> R.drawable.wic_sunset - WeatherIcons.THERMOMETER -> R.drawable.wic_thermometer_medium - WeatherIcons.UMBRELLA -> R.drawable.wic_umbrella - WeatherIcons.WIND_DIRECTION -> R.drawable.wic_compass + WeatherIcons.SUNRISE -> if (isColored) R.drawable.wic_color_sunrise else R.drawable.wic_sunrise + WeatherIcons.SUNSET -> if (isColored) R.drawable.wic_color_sunset else R.drawable.wic_sunset + WeatherIcons.THERMOMETER -> if (isColored) R.drawable.wic_color_thermometer_medium else R.drawable.wic_thermometer_medium + WeatherIcons.UMBRELLA -> if (isColored) R.drawable.wic_color_umbrella else R.drawable.wic_umbrella + WeatherIcons.WIND_DIRECTION -> if (isColored) R.drawable.wic_color_compass else R.drawable.wic_compass WeatherIcons.DIRECTION_UP -> R.drawable.wi_direction_up WeatherIcons.DIRECTION_DOWN -> R.drawable.wi_direction_down + WeatherIcons.VISIBILITY -> R.drawable.material_visibility + WeatherIcons.AIR_QUALITY -> if (isColored) R.drawable.wic_color_fog else R.drawable.wic_fog + WeatherIcons.WIND_BEAUFORT_0 -> R.drawable.wi_wind_beaufort_0 WeatherIcons.WIND_BEAUFORT_1 -> R.drawable.wi_wind_beaufort_1 WeatherIcons.WIND_BEAUFORT_2 -> R.drawable.wi_wind_beaufort_2 @@ -144,26 +147,26 @@ class WeatherIconicProvider : WeatherIconProvider() { WeatherIcons.WIND_BEAUFORT_11 -> R.drawable.wi_wind_beaufort_11 WeatherIcons.WIND_BEAUFORT_12 -> R.drawable.wi_wind_beaufort_12 - WeatherIcons.MOON_NEW -> R.drawable.wic_moon_fullmoon - WeatherIcons.MOON_WAXING_CRESCENT_3 -> R.drawable.wic_moon_waxing_crescent - WeatherIcons.MOON_FIRST_QUARTER -> R.drawable.wic_moon_first_quarter - WeatherIcons.MOON_WAXING_GIBBOUS_3 -> R.drawable.wic_moon_waxing_gibbous - WeatherIcons.MOON_FULL -> R.drawable.wic_moon_newmoon - WeatherIcons.MOON_WANING_GIBBOUS_3 -> R.drawable.wic_moon_waning_gibbous - WeatherIcons.MOON_THIRD_QUARTER -> R.drawable.wic_moon_last_quarter - WeatherIcons.MOON_WANING_CRESCENT_3 -> R.drawable.wic_moon_waning_crescent - - WeatherIcons.MOON_ALT_NEW -> R.drawable.wic_moon_fullmoon - WeatherIcons.MOON_ALT_WAXING_CRESCENT_3 -> R.drawable.wic_moon_waxing_crescent - WeatherIcons.MOON_ALT_FIRST_QUARTER -> R.drawable.wic_moon_first_quarter - WeatherIcons.MOON_ALT_WAXING_GIBBOUS_3 -> R.drawable.wic_moon_waxing_gibbous - WeatherIcons.MOON_ALT_FULL -> R.drawable.wic_moon_newmoon - WeatherIcons.MOON_ALT_WANING_GIBBOUS_3 -> R.drawable.wic_moon_waning_gibbous - WeatherIcons.MOON_ALT_THIRD_QUARTER -> R.drawable.wic_moon_last_quarter - WeatherIcons.MOON_ALT_WANING_CRESCENT_3 -> R.drawable.wic_moon_waning_crescent - - WeatherIcons.FAHRENHEIT -> R.drawable.wic_fahrenheit - WeatherIcons.CELSIUS -> R.drawable.wic_celsius + WeatherIcons.MOON_NEW -> if (isColored) R.drawable.wic_color_moon_fullmoon else R.drawable.wic_moon_fullmoon + WeatherIcons.MOON_WAXING_CRESCENT_3 -> if (isColored) R.drawable.wic_color_moon_waxing_crescent else R.drawable.wic_moon_waxing_crescent + WeatherIcons.MOON_FIRST_QUARTER -> if (isColored) R.drawable.wic_color_moon_first_quarter else R.drawable.wic_moon_first_quarter + WeatherIcons.MOON_WAXING_GIBBOUS_3 -> if (isColored) R.drawable.wic_color_moon_waxing_gibbous else R.drawable.wic_moon_waxing_gibbous + WeatherIcons.MOON_FULL -> if (isColored) R.drawable.wic_color_moon_newmoon else R.drawable.wic_moon_newmoon + WeatherIcons.MOON_WANING_GIBBOUS_3 -> if (isColored) R.drawable.wic_color_moon_waning_gibbous else R.drawable.wic_moon_waning_gibbous + WeatherIcons.MOON_THIRD_QUARTER -> if (isColored) R.drawable.wic_color_moon_last_quarter else R.drawable.wic_moon_last_quarter + WeatherIcons.MOON_WANING_CRESCENT_3 -> if (isColored) R.drawable.wic_color_moon_waning_crescent else R.drawable.wic_moon_waning_crescent + + WeatherIcons.MOON_ALT_NEW -> if (isColored) R.drawable.wic_color_moon_fullmoon else R.drawable.wic_moon_fullmoon + WeatherIcons.MOON_ALT_WAXING_CRESCENT_3 -> if (isColored) R.drawable.wic_color_moon_waxing_crescent else R.drawable.wic_moon_waxing_crescent + WeatherIcons.MOON_ALT_FIRST_QUARTER -> if (isColored) R.drawable.wic_color_moon_first_quarter else R.drawable.wic_moon_first_quarter + WeatherIcons.MOON_ALT_WAXING_GIBBOUS_3 -> if (isColored) R.drawable.wic_color_moon_waxing_gibbous else R.drawable.wic_moon_waxing_gibbous + WeatherIcons.MOON_ALT_FULL -> if (isColored) R.drawable.wic_color_moon_newmoon else R.drawable.wic_moon_newmoon + WeatherIcons.MOON_ALT_WANING_GIBBOUS_3 -> if (isColored) R.drawable.wic_color_moon_waning_gibbous else R.drawable.wic_moon_waning_gibbous + WeatherIcons.MOON_ALT_THIRD_QUARTER -> if (isColored) R.drawable.wic_color_moon_last_quarter else R.drawable.wic_moon_last_quarter + WeatherIcons.MOON_ALT_WANING_CRESCENT_3 -> if (isColored) R.drawable.wic_color_moon_waning_crescent else R.drawable.wic_moon_waning_crescent + + WeatherIcons.FAHRENHEIT -> if (isColored) R.drawable.wic_color_fahrenheit else R.drawable.wic_fahrenheit + WeatherIcons.CELSIUS -> if (isColored) R.drawable.wic_color_celsius else R.drawable.wic_celsius WeatherIcons.UV_INDEX, WeatherIcons.UV_INDEX_1, @@ -176,20 +179,20 @@ class WeatherIconicProvider : WeatherIconProvider() { WeatherIcons.UV_INDEX_8, WeatherIcons.UV_INDEX_9, WeatherIcons.UV_INDEX_10, - WeatherIcons.UV_INDEX_11 -> R.drawable.wic_sun + WeatherIcons.UV_INDEX_11 -> if (isColored) R.drawable.wic_color_sun else R.drawable.wic_sun WeatherIcons.TREE_POLLEN -> R.drawable.ic_outline_tree WeatherIcons.GRASS_POLLEN -> R.drawable.ic_baseline_grass - WeatherIcons.RAGWEED_POLLEN -> R.drawable.ic_ragweed_pollen + WeatherIcons.RAGWEED_POLLEN -> if (isColored) R.drawable.wic_color_pollen else R.drawable.wic_pollen - WeatherIcons.NA -> R.drawable.wui_unknown + WeatherIcons.NA -> if (isColored) R.drawable.wic_color_na else R.drawable.wic_na - else -> -1 + else -> 0 } - if (weatherIcon == -1) { + if (weatherIcon == 0) { // Not Available - weatherIcon = R.drawable.wui_unknown + weatherIcon = if (isColored) R.drawable.wic_color_na else R.drawable.wic_na } return weatherIcon diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIcons.java b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIcons.java index 99bf2cc47..bfb88d914 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIcons.java +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIcons.java @@ -113,6 +113,9 @@ private WeatherIcons() { public static final String DIRECTION_UP = "\uf058"; public static final String DIRECTION_DOWN = "\uf044"; + public static final String VISIBILITY = "\uf014-vis"; + public static final String AIR_QUALITY = "\uf011-aqi"; + // Beaufort public static final String WIND_BEAUFORT_0 = "\uf0b7"; public static final String WIND_BEAUFORT_1 = "\uf0b8"; diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsEFProvider.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsEFProvider.kt index 1a34d5848..69507a171 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsEFProvider.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsEFProvider.kt @@ -134,6 +134,9 @@ class WeatherIconsEFProvider : WeatherIconProvider() { WeatherIcons.DIRECTION_UP -> R.drawable.wi_direction_up WeatherIcons.DIRECTION_DOWN -> R.drawable.wi_direction_down + WeatherIcons.VISIBILITY -> R.drawable.material_visibility + WeatherIcons.AIR_QUALITY -> R.drawable.wi_windy + WeatherIcons.WIND_BEAUFORT_0 -> R.drawable.wi_wind_beaufort_0 WeatherIcons.WIND_BEAUFORT_1 -> R.drawable.wi_wind_beaufort_1 WeatherIcons.WIND_BEAUFORT_2 -> R.drawable.wi_wind_beaufort_2 diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsManager.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsManager.kt index a0d2c15f7..d3bb9175a 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsManager.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/icons/WeatherIconsManager.kt @@ -11,8 +11,8 @@ class WeatherIconsManager internal constructor() : WeatherIconsProvider { init { val defaultIconMap = mutableMapOf() defaultIconMap.addIconProvider(WeatherIconsEFProvider()) - defaultIconMap.addIconProvider(WUndergroundIconsProvider()) defaultIconMap.addIconProvider(WeatherIconicProvider()) + defaultIconMap.addIconProvider(WeatherIconicProvider(isColored = true)) defaultIconMap.addIconProvider(JDWIIconsProvider()) defaultIconMap.addIconProvider(GoogleWeatherIconsProvider()) defaultIconProviders = Collections.unmodifiableMap(defaultIconMap) @@ -96,7 +96,9 @@ class WeatherIconsManager internal constructor() : WeatherIconsProvider { "pixeden-icons_set-weather" -> true "meteocons-basmilius", - "wci_sliu_iconfinder" -> false + "meteocons-basmilius-line", + "wci_sliu_iconfinder", + "w-iconic-jackd248-multicolor" -> false else -> true } diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/json/NaNToNullAdapter.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/json/NaNToNullAdapter.kt new file mode 100644 index 000000000..98576bfb3 --- /dev/null +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/json/NaNToNullAdapter.kt @@ -0,0 +1,35 @@ +package com.thewizrd.shared_resources.json + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter + +val doubleNaNToNullAdapter = object : JsonAdapter() { + override fun fromJson(reader: JsonReader): Double? { + val value = reader.readJsonValue() + return (value as? Number)?.toDouble() + } + + override fun toJson(writer: JsonWriter, value: Double?) { + if (value == null || value.isNaN() || value.isInfinite()) { + writer.nullValue() // Replaces invalid values with null + } else { + writer.value(value) + } + } +} + +val floatNaNToNullAdapter = object : JsonAdapter() { + override fun fromJson(reader: JsonReader): Float? { + val value = reader.readJsonValue() + return (value as? Number)?.toFloat() + } + + override fun toJson(writer: JsonWriter, value: Float?) { + if (value == null || value.isNaN() || value.isInfinite()) { + writer.nullValue() // Replaces invalid values with null + } else { + writer.value(value) + } + } +} \ No newline at end of file diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/locationdata/LocationQuery.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/locationdata/LocationQuery.kt index b92bb2009..801959351 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/locationdata/LocationQuery.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/locationdata/LocationQuery.kt @@ -91,6 +91,14 @@ class LocationQuery { df.format(locationLong) ) } + WeatherAPI.OPENMETEO -> { + String.format( + Locale.ROOT, + "latitude=%s&longitude=%s", + df.format(locationLat), + df.format(locationLong) + ) + } else -> { String.format( Locale.ROOT, diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/AnalyticsProps.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/AnalyticsProps.kt index 5e4475aee..20b8e72ee 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/AnalyticsProps.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/AnalyticsProps.kt @@ -2,6 +2,7 @@ package com.thewizrd.shared_resources.utils object AnalyticsProps { const val WEATHER_PROVIDER = "weather_provider" + const val ICON_PROVIDER = "icon_provider" const val USING_PERSONAL_KEY = "using_personal_key" const val USER_LOCALE = "user_locale" const val DEVICE_TYPE = "device_type" diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/JSONParser.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/JSONParser.kt index e7a5333ee..d54c7afec 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/JSONParser.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/JSONParser.kt @@ -11,6 +11,8 @@ import com.thewizrd.shared_resources.json.CustomJsonConverter import com.thewizrd.shared_resources.json.DateConverter import com.thewizrd.shared_resources.json.LocalDateTimeConverter import com.thewizrd.shared_resources.json.ZonedDateTimeConverter +import com.thewizrd.shared_resources.json.doubleNaNToNullAdapter +import com.thewizrd.shared_resources.json.floatNaNToNullAdapter import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.weatherdata.model.AirQuality import com.thewizrd.shared_resources.weatherdata.model.Astronomy @@ -68,6 +70,8 @@ object JSONParser { .add(Pollen::class.java, CustomJsonConverter(Pollen::class.java)) .add(WeatherAlert::class.java, CustomJsonConverter(WeatherAlert::class.java)) .add(KotlinJsonAdapterFactory()) + .add(Double::class.java, doubleNaNToNullAdapter) + .add(Float::class.java, floatNaNToNullAdapter) .build() } diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/LocationUtils.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/LocationUtils.kt index 63d85e86f..c82c1795b 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/LocationUtils.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/LocationUtils.kt @@ -6,7 +6,8 @@ import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.locationdata.LocationQuery object LocationUtils { - // Source: https://gist.github.com/graydon/11198540 + // xMin -> lon_min, xMax -> lon_max; yMin -> lat_min, yMax -> lat_max + // xMax -> East, xMin -> West, yMax -> North, yMin -> South private val US_BOUNDING_BOX = BoundingBox(24.9493, 49.5904, -125.0011, -66.9326) // Canada @@ -35,6 +36,53 @@ object LocationUtils { private val DE_BOUNDING_BOX = BoundingBox(47.2701114, 55.099161, 5.8663153, 15.0419319) + private val CAMS_OPENMETEO_EUROPE_BBOX = + BoundingBox(30.0, 72.0, -25.0, 45.0) + + // United Kingdom and Ireland + private val UK_IE_BOUNDING_BOX = + BoundingBox(49.674, 61.061, -14.015517, 2.0919117) + + // Korea + private val KOREA_BOUNDING_BOX = + BoundingBox(32.9104556, 43.0078553939, 124.3017732603, 131.0789644224) + + // Japan + private val JP_BOUNDING_BOX = + BoundingBox(20.2145811, 45.7563343, 122.7141754, 154.205541) + + // Switzerland + private val CH_BOUNDING_BOX = + BoundingBox(45.8179579, 47.8084544, 5.9558318, 10.4922941) + + // Met Norway Area + private val METNO_BOUNDING_BOX = + BoundingBox(54.4504920972, 81.0280176, -9.6846279, 34.6889114) + + // Australia + private val AU_BOUNDING_BOX = + BoundingBox(-55.3228175, -9.0880125, 72.2461932, 168.2261259) + + // China + private val CN_BOUNDING_BOX = + BoundingBox(17.917694912, 53.5608154, 73.4997347, 134.7751959) + + // Netherlands + private val NL_BOUNDING_BOX = + BoundingBox(50.7218810189, 53.7801536938, 3.3388847969, 7.590283575) + + // Denmark + private val DK_BOUNDING_BOX = + BoundingBox(54.4516667, 57.9524297, 7.7153255, 15.5530641) + + // Italy + private val IT_BOUNDING_BOX = + BoundingBox(35.2889616, 47.0921485, 6.6272658, 18.7844746) + + // Austria + private val AT_BOUNDING_BOX = + BoundingBox(46.3722987, 49.0205239, 9.5307487, 17.1607728) + private val NWS_SUPPORTED_COUNTRIES = setOf("US", "AS", "UM", "GU", "MP", "PR", "VI") private val NWS_SUPPORTED_LOCATIONS = listOf( US_BOUNDING_BOX, @@ -44,6 +92,57 @@ object LocationUtils { AS_BOUNDING_BOX ) + private val OPENMETEO_SUPPORTED_COUNTRIES = setOf( + "US", "AS", "UM", "GU", "MP", "PR", "VI", // NWS + "UK", "IE", // UK and Ireland - UK Met Office + "FR", // France - MeteoFrance + "KR", "KP", // Korea - KMA Korea + "JP", // JMA Japan + "CH", // Switzerland - MeteoSwiss + "NO", "DK", "SE", "FI", // Norway, Denmark, Sweden, Finland - Met Norway + "CA", // Canada - GEM Canada + "AU", // Australia - BOM Australia + "CN", // China - CMA China + "NL", // Netherlands - KNMI Netherlands + "DK", // Denmark - DMI Denmark + "IT", // Italy - ItaliaMeteo + "AT", // Austria - GeoSphere Austria + ) + private val OPENMETEO_SUPPORTED_LOCATIONS = listOf( + // NWS + US_BOUNDING_BOX, + PR_BOUNDING_BOX, + VI_BOUNDING_BOX, + GU_MP_BOUNDING_BOX, + AS_BOUNDING_BOX, + // UK and Ireland + UK_IE_BOUNDING_BOX, + // France + FR_BOUNDING_BOX, + // Korea + KOREA_BOUNDING_BOX, + // Japan + JP_BOUNDING_BOX, + // Switzerland + CH_BOUNDING_BOX, + // MetNo + METNO_BOUNDING_BOX, + // Canada + CA_BOUNDING_BOX, + // Australia + AU_BOUNDING_BOX, + // China + CN_BOUNDING_BOX, + // Netherlands + NL_BOUNDING_BOX, + // Denmark + DK_BOUNDING_BOX, + // Italy + IT_BOUNDING_BOX, + // Austria, + AT_BOUNDING_BOX, + ) + fun isUS(countryCode: String?): Boolean { return if (countryCode.isNullOrBlank()) { false @@ -233,6 +332,40 @@ object LocationUtils { } } + fun isCAMSEuroCovered(location: LocationData): Boolean { + return CAMS_OPENMETEO_EUROPE_BBOX.intersects(location.latitude, location.longitude) + } + + fun isOpenMeteoSupported(countryCode: String?): Boolean { + return OPENMETEO_SUPPORTED_COUNTRIES.contains(countryCode?.uppercase()) + } + + fun isOpenMeteoSupported(location: LocationData): Boolean { + return if (!location.countryCode.isNullOrBlank()) { + isOpenMeteoSupported(location.countryCode) + } else { + OPENMETEO_SUPPORTED_LOCATIONS.any { + it.intersects( + location.latitude, + location.longitude + ) + } + } + } + + fun isOpenMeteoSupported(location: LocationQuery): Boolean { + return if (!location.locationCountry.isNullOrBlank()) { + isOpenMeteoSupported(location.locationCountry) + } else { + OPENMETEO_SUPPORTED_LOCATIONS.any { + it.intersects( + location.locationLat, + location.locationLong + ) + } + } + } + private data class BoundingBox( val lat_min: Double, val lat_max: Double, diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/WeatherUtils.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/WeatherUtils.kt index 4170b54da..c3deaf558 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/WeatherUtils.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/utils/WeatherUtils.kt @@ -1,5 +1,5 @@ -@file:kotlin.jvm.JvmMultifileClass -@file:kotlin.jvm.JvmName("WeatherUtils") +@file:JvmMultifileClass +@file:JvmName("WeatherUtils") package com.thewizrd.shared_resources.utils @@ -9,8 +9,13 @@ import androidx.annotation.ColorInt import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.sharedDeps +import com.thewizrd.shared_resources.weatherdata.model.BaseForecast import com.thewizrd.shared_resources.weatherdata.model.Weather import java.time.ZonedDateTime +import kotlin.math.abs +import kotlin.math.ln +import kotlin.math.pow +import kotlin.math.sqrt fun getLastBuildDate(weather: Weather): String { val context = sharedDeps.context @@ -71,7 +76,9 @@ fun getFeelsLikeTemp(temp_f: Float, wind_mph: Float, humidity_percent: Int): Flo fun calculateWindChill(temp_f: Float, wind_mph: Float): Float { return if (temp_f < 50) { - (35.74f + 0.6215f * temp_f - 35.75f * Math.pow(wind_mph.toDouble(), 0.16) + 0.4275f * temp_f * Math.pow(wind_mph.toDouble(), 0.16)).toFloat() + (35.74f + 0.6215f * temp_f - 35.75f * wind_mph.pow(0.16f) + 0.4275f * temp_f * wind_mph.pow( + 0.16f + )) } else { temp_f } @@ -83,17 +90,17 @@ fun calculateHeatIndex(temp_f: Float, humidity: Int): Float { + (2.04901523 * temp_f) + (10.14333127 * humidity) - (0.22475541 * temp_f * humidity) - - (0.00683783 * Math.pow(temp_f.toDouble(), 2.0)) - - (0.05481717 * Math.pow(humidity.toDouble(), 2.0)) - + (0.00122874 * Math.pow(temp_f.toDouble(), 2.0) * humidity) - + (0.00085282 * temp_f * Math.pow(humidity.toDouble(), 2.0)) - - (0.00000199 * Math.pow(temp_f.toDouble(), 2.0) * Math.pow(humidity.toDouble(), 2.0))) + - (0.00683783 * temp_f.pow(2.0f)) + - (0.05481717 * humidity.toFloat().pow(2.0f)) + + (0.00122874 * temp_f.pow(2.0f) * humidity) + + (0.00085282 * temp_f * humidity.toFloat().pow(2.0f)) + - (0.00000199 * temp_f.pow(2.0f) * humidity.toFloat().pow(2.0f))) if (humidity < 13 && temp_f > 80 && temp_f < 112) { - val adj = (13 - humidity) / 4f * Math.sqrt(((17 - Math.abs(temp_f - 95)) / 17).toDouble()) + val adj = (13 - humidity) / 4f * sqrt(((17 - abs(temp_f - 95)) / 17)) HI -= adj } else if (humidity > 85 && temp_f > 80 && temp_f < 87) { - val adj = ((humidity - 85) / 10f * ((87 - temp_f) / 5)).toDouble() + val adj = ((humidity - 85) / 10f * ((87 - temp_f) / 5)) HI += adj } @@ -107,12 +114,75 @@ fun calculateHeatIndex(temp_f: Float, humidity: Int): Float { } } +fun Weather.calculateFeelsLikeTemp() { + if (this.condition == null) return + if (this.atmosphere == null) return + + val currentTempF = this.condition?.tempF ?: return + val currentHumidity = this.atmosphere?.humidity ?: return + val currentWindMph = this.condition?.windMph ?: return + val currentFeelsLikeF = this.condition?.feelslikeF + + if (currentFeelsLikeF == null) { + val feelsLikeF = getFeelsLikeTemp(currentTempF, currentWindMph, currentHumidity) + this.condition?.feelslikeF = feelsLikeF + this.condition?.feelslikeC = ConversionMethods.FtoC(feelsLikeF) + } +} + +fun BaseForecast.calculateFeelsLikeTemp() { + if (this.extras == null) return + + val tempF = this.highF ?: return + val humidity = this.extras?.humidity ?: return + val windMph = this.extras?.windMph ?: return + val currentFeelsLikeF = this.extras?.feelslikeF + + if (currentFeelsLikeF == null) { + val feelsLikeF = getFeelsLikeTemp(tempF, windMph, humidity) + this.extras?.feelslikeF = feelsLikeF + this.extras?.feelslikeC = ConversionMethods.FtoC(feelsLikeF) + } +} + fun calculateDewpointF(temp_f: Float, humidity: Int): Float { return ConversionMethods.CtoF(calculateDewpointC(ConversionMethods.FtoC(temp_f), humidity)) } fun calculateDewpointC(temp_c: Float, humidity: Int): Float { - return (243.04f * (Math.log((humidity / 100f).toDouble()) + ((17.625f * temp_c) / (243.04f + temp_c))) / (17.625f - Math.log((humidity / 100f).toDouble()) - ((17.625f * temp_c) / (243.04f + temp_c)))).toFloat() + return (243.04f * (ln((humidity / 100f)) + ((17.625f * temp_c) / (243.04f + temp_c))) / (17.625f - ln( + (humidity / 100f) + ) - ((17.625f * temp_c) / (243.04f + temp_c)))) +} + +fun Weather.calculateDewpoint() { + if (this.atmosphere == null) return + + val currentTempC = this.condition?.tempC ?: return + val currentTempF = this.condition?.tempF ?: return + val currentHumidity = this.atmosphere?.humidity ?: return + val currentDewPointC = this.atmosphere?.dewpointC + val currentDewPointF = this.atmosphere?.dewpointF + + if (currentDewPointC == null || currentDewPointF == null) { + this.atmosphere?.dewpointC = calculateDewpointC(currentTempC, currentHumidity) + this.atmosphere?.dewpointF = calculateDewpointF(currentTempF, currentHumidity) + } +} + +fun BaseForecast.calculateDewpoint() { + if (this.extras == null) return + + val tempC = this.highC ?: return + val tempF = this.highF ?: return + val humidity = this.extras?.humidity ?: return + val dewPointC = this.extras?.dewpointC + val dewPointF = this.extras?.dewpointF + + if (dewPointC == null || dewPointF == null) { + this.extras?.dewpointC = calculateDewpointC(tempC, humidity) + this.extras?.dewpointF = calculateDewpointF(tempF, humidity) + } } @ColorInt diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/WeatherAPI.kt b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/WeatherAPI.kt index bbfd5c271..1ee33e695 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/WeatherAPI.kt +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/WeatherAPI.kt @@ -25,6 +25,7 @@ object WeatherAPI { const val APPLE = "apple" const val DWD = "dwd" const val ECCC = "eccc" + const val OPENMETEO = "open_meteo" // Location APIs const val ANDROID = "android" @@ -44,7 +45,7 @@ object WeatherAPI { * 2) Add constructor for [Weather] data objects * 3) Update [LocationQuery] (if needed) * 4) Add API to provider list below - * 5) Add API to WeatherProviderManager / [com.thewizrd.weather_api.weatherdata.WeatherProviderFactoryImpl] + * 5) Add API to [com.thewizrd.weather_api.weatherdata.WeatherProviderFactoryImpl] * 6) Add to remote_config_defaults.xml */ @StringDef( @@ -63,7 +64,8 @@ object WeatherAPI { APPLE, DWD, ECCC, - GOOGLE + GOOGLE, + OPENMETEO ) @Retention(AnnotationRetention.SOURCE) annotation class WeatherProviders @@ -104,23 +106,15 @@ object WeatherAPI { private val GMSFullAPIs by lazy { listOf( - ProviderEntry( - "HERE Weather", HERE, - "https://www.here.com/en", - "https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account" - ), ProviderEntry( "Apple Weather", APPLE, "https://developer.apple.com/weatherkit/", "https://developer.apple.com/weatherkit/" ), ProviderEntry( - "OpenWeatherMap", OPENWEATHERMAP, - "http://www.openweathermap.org", "https://home.openweathermap.org/users/sign_up" - ), - ProviderEntry( - "WeatherAPI.com", WEATHERAPI, - "https://weatherapi.com", "https://weatherapi.com/api" + "Open-Meteo", OPENMETEO, + "https://open-meteo.com/", + "https://open-meteo.com/en/features" ), ProviderEntry( "National Weather Service (United States)", NWS, @@ -143,21 +137,25 @@ object WeatherAPI { "https://www.met.no/en", "https://www.met.no/en" ), ProviderEntry( - "Tomorrow.io", TOMORROWIO, - "https://www.tomorrow.io/weather-api/", "https://www.tomorrow.io/weather-api/" + "HERE Weather", HERE, + "https://www.here.com/en", + "https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account" ), ProviderEntry( - "Weatherbit.io", WEATHERBITIO, - "https://www.weatherbit.io/", "https://www.weatherbit.io/pricing" + "OpenWeatherMap", OPENWEATHERMAP, + "http://www.openweathermap.org", "https://home.openweathermap.org/users/sign_up" ), ProviderEntry( - "WeatherUnlocked", WEATHERUNLOCKED, - "https://developer.weatherunlocked.com/", "https://developer.weatherunlocked.com/" + "WeatherAPI.com", WEATHERAPI, + "https://weatherapi.com", "https://weatherapi.com/api" ), ProviderEntry( - "Meteomatics", METEOMATICS, - "https://www.meteomatics.com/", - "https://www.meteomatics.com/en/sign-up-weather-api-free-basic-account/" + "Tomorrow.io", TOMORROWIO, + "https://www.tomorrow.io/weather-api/", "https://www.tomorrow.io/weather-api/" + ), + ProviderEntry( + "Weatherbit.io", WEATHERBITIO, + "https://www.weatherbit.io/", "https://www.weatherbit.io/pricing" ) ) } @@ -168,6 +166,10 @@ object WeatherAPI { "MET Norway", METNO, "https://www.met.no/en", "https://www.met.no/en" ), + ProviderEntry( + "Open-Meteo", OPENMETEO, + "https://open-meteo.com/", "https://open-meteo.com/en/features" + ), ProviderEntry( "National Weather Service (United States)", NWS, "https://www.weather.gov", "https://www.weather.gov" @@ -180,6 +182,11 @@ object WeatherAPI { "Environment and Climate Change Canada (ECCC)", ECCC, "https://www.weather.gc.ca/", "https://www.weather.gc.ca/canada_e.html" ), + ProviderEntry( + "HERE Weather", HERE, + "https://www.here.com/en", + "https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account" + ), ProviderEntry( "OpenWeatherMap", OPENWEATHERMAP, "http://www.openweathermap.org", "https://home.openweathermap.org/users/sign_up" @@ -195,11 +202,6 @@ object WeatherAPI { ProviderEntry( "Weatherbit.io", WEATHERBITIO, "https://www.weatherbit.io/", "https://www.weatherbit.io/pricing" - ), - ProviderEntry( - "Meteomatics", METEOMATICS, - "https://www.meteomatics.com/", - "https://www.meteomatics.com/en/sign-up-weather-api-free-basic-account/" ) ) } diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/HourlyForecast.java b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/HourlyForecast.java index 0cca633b1..e342f46cd 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/HourlyForecast.java +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/HourlyForecast.java @@ -19,15 +19,6 @@ public class HourlyForecast extends BaseForecast { - @Json(name = "wind_degrees") - private Integer windDegrees; - - @Json(name = "wind_mph") - private Float windMph; - - @Json(name = "wind_kph") - private Float windKph; - @Json(name = "date") private String _date; @@ -62,30 +53,6 @@ public void setDate(ZonedDateTime date) { _date = date.format(DateTimeUtils.getZonedDateTimeFormatter()); } - public Integer getWindDegrees() { - return windDegrees; - } - - public void setWindDegrees(Integer windDegrees) { - this.windDegrees = windDegrees; - } - - public Float getWindMph() { - return windMph; - } - - public void setWindMph(Float windMph) { - this.windMph = windMph; - } - - public Float getWindKph() { - return windKph; - } - - public void setWindKph(Float windKph) { - this.windKph = windKph; - } - @Override public void fromJson(@NonNull JsonReader extReader) { try { @@ -132,15 +99,6 @@ public void fromJson(@NonNull JsonReader extReader) { case "icon": this.icon = reader.nextString(); break; - case "wind_degrees": - this.windDegrees = NumberUtils.tryParseInt(reader.nextString()); - break; - case "wind_mph": - this.windMph = NumberUtils.tryParseFloat(reader.nextString()); - break; - case "wind_kph": - this.windKph = NumberUtils.tryParseFloat(reader.nextString()); - break; case "extras": this.extras = new ForecastExtras(); this.extras.fromJson(reader); @@ -184,18 +142,6 @@ public void toJson(@NonNull JsonWriter writer) { writer.name("icon"); writer.value(icon); - // "wind_degrees" : "" - writer.name("wind_degrees"); - writer.value(windDegrees); - - // "wind_mph" : "" - writer.name("wind_mph"); - writer.value(windMph); - - // "wind_kph" : "" - writer.name("wind_kph"); - writer.value(windKph); - // "extras" : "" if (extras != null) { writer.name("extras"); diff --git a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/MinutelyForecast.java b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/MinutelyForecast.java index 9d6b6fa95..f60c5ebd0 100644 --- a/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/MinutelyForecast.java +++ b/shared_resources/src/main/java/com/thewizrd/shared_resources/weatherdata/model/MinutelyForecast.java @@ -24,6 +24,9 @@ public class MinutelyForecast extends CustomJsonObject { @Json(name = "rain_mm") private Float rainMm; + @Json(name = "snow_mm") + private Float snowMm; + public ZonedDateTime getDate() { return date; } @@ -40,6 +43,14 @@ public void setRainMm(Float rainMm) { this.rainMm = rainMm; } + public Float getSnowMm() { + return snowMm; + } + + public void setSnowMm(Float snowMm) { + this.snowMm = snowMm; + } + @Override public void fromJson(@NonNull JsonReader extReader) { try { @@ -77,6 +88,9 @@ public void fromJson(@NonNull JsonReader extReader) { case "rain_mm": this.rainMm = NumberUtils.tryParseFloat(reader.nextString()); break; + case "snow_mm": + this.snowMm = NumberUtils.tryParseFloat(reader.nextString()); + break; default: reader.skipValue(); break; @@ -104,6 +118,10 @@ public void toJson(@NonNull JsonWriter writer) { writer.name("rain_mm"); writer.value(rainMm); + // "snow_mm" : "" + writer.name("snow_mm"); + writer.value(snowMm); + // } writer.endObject(); } catch (IOException e) { diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_blowing_snow.xml b/shared_resources/src/main/res/drawable-night-v24/goog_blowing_snow.xml new file mode 100644 index 000000000..ce20d718c --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_blowing_snow.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_clear_day.xml b/shared_resources/src/main/res/drawable-night-v24/goog_clear_day.xml new file mode 100644 index 000000000..d9442652a --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_clear_day.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_clear_night.xml b/shared_resources/src/main/res/drawable-night-v24/goog_clear_night.xml new file mode 100644 index 000000000..38a2d7b9c --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_clear_night.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_cloudy.xml b/shared_resources/src/main/res/drawable-night-v24/goog_cloudy.xml new file mode 100644 index 000000000..d3866416b --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_cloudy.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_hail.xml b/shared_resources/src/main/res/drawable-night-v24/goog_hail.xml new file mode 100644 index 000000000..1d841d24e --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_hail.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_heavy_rain.xml b/shared_resources/src/main/res/drawable-night-v24/goog_heavy_rain.xml new file mode 100644 index 000000000..a84ee71de --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_heavy_rain.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_heavy_snow.xml b/shared_resources/src/main/res/drawable-night-v24/goog_heavy_snow.xml new file mode 100644 index 000000000..dade37c4d --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_heavy_snow.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_light_rain.xml b/shared_resources/src/main/res/drawable-night-v24/goog_light_rain.xml new file mode 100644 index 000000000..7b1246780 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_light_rain.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_light_snow.xml b/shared_resources/src/main/res/drawable-night-v24/goog_light_snow.xml new file mode 100644 index 000000000..654bdd388 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_light_snow.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_day.xml b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_day.xml new file mode 100644 index 000000000..050c54668 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_day.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_night.xml b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_night.xml new file mode 100644 index 000000000..d60859ab3 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_clear_night.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_day.xml b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_day.xml new file mode 100644 index 000000000..a33f3307d --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_day.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_night.xml b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_night.xml new file mode 100644 index 000000000..5c76018cf --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_mostly_cloudy_night.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_day.xml b/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_day.xml new file mode 100644 index 000000000..07804422e --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_day.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_night.xml b/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_night.xml new file mode 100644 index 000000000..58a8bb84b --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_partly_cloudy_night.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_rain_mix.xml b/shared_resources/src/main/res/drawable-night-v24/goog_rain_mix.xml new file mode 100644 index 000000000..3f7c061fe --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_rain_mix.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_scattered_showers.xml b/shared_resources/src/main/res/drawable-night-v24/goog_scattered_showers.xml new file mode 100644 index 000000000..e70dee6c0 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_scattered_showers.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_scattered_tstorms.xml b/shared_resources/src/main/res/drawable-night-v24/goog_scattered_tstorms.xml new file mode 100644 index 000000000..224eb07ae --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_scattered_tstorms.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_snow.xml b/shared_resources/src/main/res/drawable-night-v24/goog_snow.xml new file mode 100644 index 000000000..17fb1d589 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_snow.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_snow_showers.xml b/shared_resources/src/main/res/drawable-night-v24/goog_snow_showers.xml new file mode 100644 index 000000000..568a54324 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_snow_showers.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_tstorm.xml b/shared_resources/src/main/res/drawable-night-v24/goog_tstorm.xml new file mode 100644 index 000000000..dc7c41be4 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_tstorm.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_wind_rain.xml b/shared_resources/src/main/res/drawable-night-v24/goog_wind_rain.xml new file mode 100644 index 000000000..e29389c31 --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_wind_rain.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night-v24/goog_windy.xml b/shared_resources/src/main/res/drawable-night-v24/goog_windy.xml new file mode 100644 index 000000000..de5cb2aef --- /dev/null +++ b/shared_resources/src/main/res/drawable-night-v24/goog_windy.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-night/goog_blowing_snow.xml b/shared_resources/src/main/res/drawable-night/goog_blowing_snow.xml index ce20d718c..d2ac7140e 100644 --- a/shared_resources/src/main/res/drawable-night/goog_blowing_snow.xml +++ b/shared_resources/src/main/res/drawable-night/goog_blowing_snow.xml @@ -1,5 +1,4 @@ - - - - - - - - + - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> diff --git a/shared_resources/src/main/res/drawable-night/goog_cloudy.xml b/shared_resources/src/main/res/drawable-night/goog_cloudy.xml index d3866416b..7d1f1f9d6 100644 --- a/shared_resources/src/main/res/drawable-night/goog_cloudy.xml +++ b/shared_resources/src/main/res/drawable-night/goog_cloudy.xml @@ -1,5 +1,4 @@ - - - - - - - - + - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - - + - - - - - - - - - - - - - - - - + + - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - - - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> + - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - - - - - - - - - - + + - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - - - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> + - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> diff --git a/shared_resources/src/main/res/drawable-night/goog_partly_cloudy_day.xml b/shared_resources/src/main/res/drawable-night/goog_partly_cloudy_day.xml index 07804422e..19ef6433c 100644 --- a/shared_resources/src/main/res/drawable-night/goog_partly_cloudy_day.xml +++ b/shared_resources/src/main/res/drawable-night/goog_partly_cloudy_day.xml @@ -1,5 +1,4 @@ - - - - - - - - - - - - - - - - + + - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - - - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFCD35C" /> - - - - - - - - + - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - - + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_blowing_snow.xml b/shared_resources/src/main/res/drawable-v24/goog_blowing_snow.xml new file mode 100644 index 000000000..ec9d42385 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_blowing_snow.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_clear_day.xml b/shared_resources/src/main/res/drawable-v24/goog_clear_day.xml new file mode 100644 index 000000000..89dece89b --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_clear_day.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_clear_night.xml b/shared_resources/src/main/res/drawable-v24/goog_clear_night.xml new file mode 100644 index 000000000..a00bb1ffd --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_clear_night.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_cloudy.xml b/shared_resources/src/main/res/drawable-v24/goog_cloudy.xml new file mode 100644 index 000000000..aaf8d1390 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_cloudy.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_hail.xml b/shared_resources/src/main/res/drawable-v24/goog_hail.xml new file mode 100644 index 000000000..5b39139af --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_hail.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_heavy_rain.xml b/shared_resources/src/main/res/drawable-v24/goog_heavy_rain.xml new file mode 100644 index 000000000..96a868980 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_heavy_rain.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_heavy_snow.xml b/shared_resources/src/main/res/drawable-v24/goog_heavy_snow.xml new file mode 100644 index 000000000..f1358486e --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_heavy_snow.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_light_rain.xml b/shared_resources/src/main/res/drawable-v24/goog_light_rain.xml new file mode 100644 index 000000000..dfda62ace --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_light_rain.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_light_snow.xml b/shared_resources/src/main/res/drawable-v24/goog_light_snow.xml new file mode 100644 index 000000000..a7f4e9ec7 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_light_snow.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_day.xml b/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_day.xml new file mode 100644 index 000000000..9af6744f7 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_day.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_night.xml b/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_night.xml new file mode 100644 index 000000000..b385be484 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_mostly_clear_night.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_day.xml b/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_day.xml new file mode 100644 index 000000000..8d699d751 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_day.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_night.xml b/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_night.xml new file mode 100644 index 000000000..7aeb2e663 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_mostly_cloudy_night.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_day.xml b/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_day.xml new file mode 100644 index 000000000..36abed8ce --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_day.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_night.xml b/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_night.xml new file mode 100644 index 000000000..51f1450a5 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_partly_cloudy_night.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_rain_mix.xml b/shared_resources/src/main/res/drawable-v24/goog_rain_mix.xml new file mode 100644 index 000000000..63681f1bb --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_rain_mix.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_scattered_showers.xml b/shared_resources/src/main/res/drawable-v24/goog_scattered_showers.xml new file mode 100644 index 000000000..6996321f5 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_scattered_showers.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_scattered_tstorms.xml b/shared_resources/src/main/res/drawable-v24/goog_scattered_tstorms.xml new file mode 100644 index 000000000..ab67134aa --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_scattered_tstorms.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_snow.xml b/shared_resources/src/main/res/drawable-v24/goog_snow.xml new file mode 100644 index 000000000..e781a3253 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_snow.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_snow_showers.xml b/shared_resources/src/main/res/drawable-v24/goog_snow_showers.xml new file mode 100644 index 000000000..52eaceb55 --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_snow_showers.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_tstorm.xml b/shared_resources/src/main/res/drawable-v24/goog_tstorm.xml new file mode 100644 index 000000000..233c2aaca --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_tstorm.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_wind_rain.xml b/shared_resources/src/main/res/drawable-v24/goog_wind_rain.xml new file mode 100644 index 000000000..453299feb --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_wind_rain.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable-v24/goog_windy.xml b/shared_resources/src/main/res/drawable-v24/goog_windy.xml new file mode 100644 index 000000000..8cd19ddaf --- /dev/null +++ b/shared_resources/src/main/res/drawable-v24/goog_windy.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/goog_blowing_snow.xml b/shared_resources/src/main/res/drawable/goog_blowing_snow.xml index ec9d42385..f109b696c 100644 --- a/shared_resources/src/main/res/drawable/goog_blowing_snow.xml +++ b/shared_resources/src/main/res/drawable/goog_blowing_snow.xml @@ -1,5 +1,4 @@ - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> diff --git a/shared_resources/src/main/res/drawable/goog_cloudy.xml b/shared_resources/src/main/res/drawable/goog_cloudy.xml index aaf8d1390..52e0b0a4c 100644 --- a/shared_resources/src/main/res/drawable/goog_cloudy.xml +++ b/shared_resources/src/main/res/drawable/goog_cloudy.xml @@ -1,5 +1,4 @@ - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> diff --git a/shared_resources/src/main/res/drawable/goog_partly_cloudy_day.xml b/shared_resources/src/main/res/drawable/goog_partly_cloudy_day.xml index 36abed8ce..ff7c26bf5 100644 --- a/shared_resources/src/main/res/drawable/goog_partly_cloudy_day.xml +++ b/shared_resources/src/main/res/drawable/goog_partly_cloudy_day.xml @@ -1,5 +1,4 @@ - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFFBBC04" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillAlpha="0.5" + android:fillColor="#FFFCD35C" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDEDFDF" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFF1F3F4" /> - - - - - - - + android:fillType="evenOdd" + android:fillColor="#FFDADCE0" /> + + diff --git a/shared_resources/src/main/res/drawable/material_visibility.xml b/shared_resources/src/main/res/drawable/material_visibility.xml new file mode 100644 index 000000000..f96b8ea2d --- /dev/null +++ b/shared_resources/src/main/res/drawable/material_visibility.xml @@ -0,0 +1,9 @@ + + + diff --git a/shared_resources/src/main/res/drawable/wic_barometer.xml b/shared_resources/src/main/res/drawable/wic_barometer.xml index 557db641b..e99c343dd 100644 --- a/shared_resources/src/main/res/drawable/wic_barometer.xml +++ b/shared_resources/src/main/res/drawable/wic_barometer.xml @@ -1,15 +1,29 @@ + + + + diff --git a/shared_resources/src/main/res/drawable/wic_celsius.xml b/shared_resources/src/main/res/drawable/wic_celsius.xml index 79a2e4cfa..42532df83 100644 --- a/shared_resources/src/main/res/drawable/wic_celsius.xml +++ b/shared_resources/src/main/res/drawable/wic_celsius.xml @@ -1,18 +1,29 @@ + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud.xml b/shared_resources/src/main/res/drawable/wic_cloud.xml index 45eaa2511..bfabbba01 100644 --- a/shared_resources/src/main/res/drawable/wic_cloud.xml +++ b/shared_resources/src/main/res/drawable/wic_cloud.xml @@ -1,15 +1,18 @@ + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_cloud_fog.xml index 34e83a24e..c5f95ef38 100644 --- a/shared_resources/src/main/res/drawable/wic_cloud_fog.xml +++ b/shared_resources/src/main/res/drawable/wic_cloud_fog.xml @@ -1,24 +1,29 @@ + - - + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_cloud_hail.xml new file mode 100644 index 000000000..23d138294 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_cloud_haze.xml new file mode 100644 index 000000000..da8db9f71 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_haze.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_cloud_rain.xml index d14e88603..30c53c065 100644 --- a/shared_resources/src/main/res/drawable/wic_cloud_rain.xml +++ b/shared_resources/src/main/res/drawable/wic_cloud_rain.xml @@ -1,25 +1,29 @@ + + android:scaleY="1.5"> - - + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_cloud_rain_alt.xml new file mode 100644 index 000000000..6bc33dd8b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_rain_single.xml b/shared_resources/src/main/res/drawable/wic_cloud_rain_single.xml deleted file mode 100644 index 912bbbf32..000000000 --- a/shared_resources/src/main/res/drawable/wic_cloud_rain_single.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wic_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_cloud_sleet.xml new file mode 100644 index 000000000..8e7d706a2 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_smog.xml b/shared_resources/src/main/res/drawable/wic_cloud_smog.xml new file mode 100644 index 000000000..124cba82c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_smog.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_cloud_snow.xml index ec7af9ca1..8c2d316b4 100644 --- a/shared_resources/src/main/res/drawable/wic_cloud_snow.xml +++ b/shared_resources/src/main/res/drawable/wic_cloud_snow.xml @@ -1,37 +1,29 @@ + + android:scaleY="1.5"> - - - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_cloud_snow_alt.xml new file mode 100644 index 000000000..93468f361 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_cloud_wind.xml index d8983e2a2..c23fa2955 100644 --- a/shared_resources/src/main/res/drawable/wic_cloud_wind.xml +++ b/shared_resources/src/main/res/drawable/wic_cloud_wind.xml @@ -1,23 +1,29 @@ + + android:scaleY="1.25"> - + + diff --git a/shared_resources/src/main/res/drawable/wic_clouds.xml b/shared_resources/src/main/res/drawable/wic_clouds.xml index 4954e8297..60aca659f 100644 --- a/shared_resources/src/main/res/drawable/wic_clouds.xml +++ b/shared_resources/src/main/res/drawable/wic_clouds.xml @@ -1,16 +1,29 @@ + + android:scaleY="1.25"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_clouds_alt.xml b/shared_resources/src/main/res/drawable/wic_clouds_alt.xml new file mode 100644 index 000000000..5884c23f6 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_clouds_alt.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_barometer.xml b/shared_resources/src/main/res/drawable/wic_color_barometer.xml new file mode 100644 index 000000000..daa799df6 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_barometer.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_celsius.xml b/shared_resources/src/main/res/drawable/wic_color_celsius.xml new file mode 100644 index 000000000..247c9f1bd --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_celsius.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud.xml b/shared_resources/src/main/res/drawable/wic_color_cloud.xml new file mode 100644 index 000000000..bfabbba01 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_fog.xml new file mode 100644 index 000000000..708699aea --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_hail.xml new file mode 100644 index 000000000..4164edbee --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_haze.xml new file mode 100644 index 000000000..638a150f7 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_haze.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_rain.xml new file mode 100644 index 000000000..065dfd852 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_rain.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_rain_alt.xml new file mode 100644 index 000000000..be9852bbc --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_sleet.xml new file mode 100644 index 000000000..8a663fff9 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_smog.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_smog.xml new file mode 100644 index 000000000..d05801a33 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_smog.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_snow.xml new file mode 100644 index 000000000..0f7389c06 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_snow.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_snow_alt.xml new file mode 100644 index 000000000..4961acfb5 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_color_cloud_wind.xml new file mode 100644 index 000000000..6aa9cdac5 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_cloud_wind.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_clouds.xml b/shared_resources/src/main/res/drawable/wic_color_clouds.xml new file mode 100644 index 000000000..6af5ec32b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_clouds.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_clouds_alt.xml b/shared_resources/src/main/res/drawable/wic_color_clouds_alt.xml new file mode 100644 index 000000000..5884c23f6 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_clouds_alt.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_compass.xml b/shared_resources/src/main/res/drawable/wic_color_compass.xml new file mode 100644 index 000000000..fc779ba40 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_compass.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_fahrenheit.xml b/shared_resources/src/main/res/drawable/wic_color_fahrenheit.xml new file mode 100644 index 000000000..a6b730b83 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_fahrenheit.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_fire.xml b/shared_resources/src/main/res/drawable/wic_color_fire.xml new file mode 100644 index 000000000..8e159a70c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_fire.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_flood.xml b/shared_resources/src/main/res/drawable/wic_color_flood.xml new file mode 100644 index 000000000..4b2685b62 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_flood.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_fog.xml b/shared_resources/src/main/res/drawable/wic_color_fog.xml new file mode 100644 index 000000000..c83aa55b1 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_humidity.xml b/shared_resources/src/main/res/drawable/wic_color_humidity.xml new file mode 100644 index 000000000..9d4dea9dd --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_humidity.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_hurricane.xml b/shared_resources/src/main/res/drawable/wic_color_hurricane.xml new file mode 100644 index 000000000..6a2be557e --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_hurricane.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_info.xml b/shared_resources/src/main/res/drawable/wic_color_info.xml new file mode 100644 index 000000000..40def6480 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_info.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_lightning.xml b/shared_resources/src/main/res/drawable/wic_color_lightning.xml new file mode 100644 index 000000000..0ba575213 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_lightning.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon.xml b/shared_resources/src/main/res/drawable/wic_color_moon.xml new file mode 100644 index 000000000..a92613f00 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud.xml new file mode 100644 index 000000000..3d1db01fd --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_fog.xml new file mode 100644 index 000000000..7caf0baba --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_hail.xml new file mode 100644 index 000000000..ff0ce367f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_haze.xml new file mode 100644 index 000000000..507266cc3 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_haze.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_lightning.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_lightning.xml new file mode 100644 index 000000000..4dc76a6eb --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_lightning.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain.xml new file mode 100644 index 000000000..f0c3f172d --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain_alt.xml new file mode 100644 index 000000000..0c28192a0 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_sleet.xml new file mode 100644 index 000000000..3f2334fcf --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow.xml new file mode 100644 index 000000000..524985b41 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow_alt.xml new file mode 100644 index 000000000..808bbf75a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_wind.xml new file mode 100644 index 000000000..e7ea870c7 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_cloud_wind.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_first_quarter.xml b/shared_resources/src/main/res/drawable/wic_color_moon_first_quarter.xml new file mode 100644 index 000000000..721bb5ddb --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_first_quarter.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_fog.xml b/shared_resources/src/main/res/drawable/wic_color_moon_fog.xml new file mode 100644 index 000000000..58db6f8b4 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_fullmoon.xml b/shared_resources/src/main/res/drawable/wic_color_moon_fullmoon.xml new file mode 100644 index 000000000..d51ac69b4 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_fullmoon.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_last_quarter.xml b/shared_resources/src/main/res/drawable/wic_color_moon_last_quarter.xml new file mode 100644 index 000000000..0d14d3228 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_last_quarter.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_newmoon.xml b/shared_resources/src/main/res/drawable/wic_color_moon_newmoon.xml new file mode 100644 index 000000000..01b51814c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_newmoon.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_waning_crescent.xml b/shared_resources/src/main/res/drawable/wic_color_moon_waning_crescent.xml new file mode 100644 index 000000000..911b7461f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_waning_crescent.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_waning_gibbous.xml b/shared_resources/src/main/res/drawable/wic_color_moon_waning_gibbous.xml new file mode 100644 index 000000000..ac8f6a11f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_waning_gibbous.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_waxing_crescent.xml b/shared_resources/src/main/res/drawable/wic_color_moon_waxing_crescent.xml new file mode 100644 index 000000000..4753d342f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_waxing_crescent.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moon_waxing_gibbous.xml b/shared_resources/src/main/res/drawable/wic_color_moon_waxing_gibbous.xml new file mode 100644 index 000000000..a22141b1a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moon_waxing_gibbous.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moonrise.xml b/shared_resources/src/main/res/drawable/wic_color_moonrise.xml new file mode 100644 index 000000000..5c78f30b6 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moonrise.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_moonset.xml b/shared_resources/src/main/res/drawable/wic_color_moonset.xml new file mode 100644 index 000000000..876b2b033 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_moonset.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_na.xml b/shared_resources/src/main/res/drawable/wic_color_na.xml new file mode 100644 index 000000000..a6aa69f8c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_na.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_pollen.xml b/shared_resources/src/main/res/drawable/wic_color_pollen.xml new file mode 100644 index 000000000..5b518290d --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_pollen.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_raindrop.xml b/shared_resources/src/main/res/drawable/wic_color_raindrop.xml new file mode 100644 index 000000000..85d37b541 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_raindrop.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sandstorm.xml b/shared_resources/src/main/res/drawable/wic_color_sandstorm.xml new file mode 100644 index 000000000..8920e60a2 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sandstorm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_snowflake.xml b/shared_resources/src/main/res/drawable/wic_color_snowflake.xml new file mode 100644 index 000000000..24714bc99 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_snowflake.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun.xml b/shared_resources/src/main/res/drawable/wic_color_sun.xml new file mode 100644 index 000000000..023e3c820 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud.xml new file mode 100644 index 000000000..bc9c9a92b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_fog.xml new file mode 100644 index 000000000..d08075652 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_hail.xml new file mode 100644 index 000000000..4d360e7c9 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_haze.xml new file mode 100644 index 000000000..52db66a02 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_haze.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_lightning.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_lightning.xml new file mode 100644 index 000000000..1f5212a4a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_lightning.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain.xml new file mode 100644 index 000000000..0da59b15f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain_alt.xml new file mode 100644 index 000000000..d3e681f19 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_sleet.xml new file mode 100644 index 000000000..485ac5c13 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow.xml new file mode 100644 index 000000000..9a3f6b1a7 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow_alt.xml new file mode 100644 index 000000000..54c019e79 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_wind.xml new file mode 100644 index 000000000..61ce5e849 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_cloud_wind.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sun_fog.xml b/shared_resources/src/main/res/drawable/wic_color_sun_fog.xml new file mode 100644 index 000000000..39348b19f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sun_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sunrise.xml b/shared_resources/src/main/res/drawable/wic_color_sunrise.xml new file mode 100644 index 000000000..8f88ed90c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sunrise.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_sunset.xml b/shared_resources/src/main/res/drawable/wic_color_sunset.xml new file mode 100644 index 000000000..acebe7ca4 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_sunset.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_thermometer_cold.xml b/shared_resources/src/main/res/drawable/wic_color_thermometer_cold.xml new file mode 100644 index 000000000..1df709116 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_thermometer_cold.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_thermometer_freeze.xml b/shared_resources/src/main/res/drawable/wic_color_thermometer_freeze.xml new file mode 100644 index 000000000..67677eb99 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_thermometer_freeze.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_thermometer_heat.xml b/shared_resources/src/main/res/drawable/wic_color_thermometer_heat.xml new file mode 100644 index 000000000..01fc5a9d8 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_thermometer_heat.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_thermometer_hot.xml b/shared_resources/src/main/res/drawable/wic_color_thermometer_hot.xml new file mode 100644 index 000000000..c9bb701a6 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_thermometer_hot.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_thermometer_medium.xml b/shared_resources/src/main/res/drawable/wic_color_thermometer_medium.xml new file mode 100644 index 000000000..f3e9074ed --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_thermometer_medium.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_tornado.xml b/shared_resources/src/main/res/drawable/wic_color_tornado.xml new file mode 100644 index 000000000..68501b9af --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_tornado.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_umbrella.xml b/shared_resources/src/main/res/drawable/wic_color_umbrella.xml new file mode 100644 index 000000000..92de210b2 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_umbrella.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_wind.xml b/shared_resources/src/main/res/drawable/wic_color_wind.xml new file mode 100644 index 000000000..91e80fed9 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_wind.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_color_wind_high.xml b/shared_resources/src/main/res/drawable/wic_color_wind_high.xml new file mode 100644 index 000000000..19c417138 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_color_wind_high.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_compass.xml b/shared_resources/src/main/res/drawable/wic_compass.xml index b757db6c2..d57bd14b7 100644 --- a/shared_resources/src/main/res/drawable/wic_compass.xml +++ b/shared_resources/src/main/res/drawable/wic_compass.xml @@ -1,19 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_fahrenheit.xml b/shared_resources/src/main/res/drawable/wic_fahrenheit.xml index b89484580..511abc76a 100644 --- a/shared_resources/src/main/res/drawable/wic_fahrenheit.xml +++ b/shared_resources/src/main/res/drawable/wic_fahrenheit.xml @@ -1,19 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_fire.xml b/shared_resources/src/main/res/drawable/wic_fire.xml new file mode 100644 index 000000000..c5ee581d1 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_fire.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_flood.xml b/shared_resources/src/main/res/drawable/wic_flood.xml new file mode 100644 index 000000000..784bb59ab --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_flood.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_fog.xml b/shared_resources/src/main/res/drawable/wic_fog.xml index 32db1d8a5..050c49ca5 100644 --- a/shared_resources/src/main/res/drawable/wic_fog.xml +++ b/shared_resources/src/main/res/drawable/wic_fog.xml @@ -1,28 +1,29 @@ + + android:scaleY="1.5"> - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_hail.xml b/shared_resources/src/main/res/drawable/wic_hail.xml deleted file mode 100644 index 5df922df3..000000000 --- a/shared_resources/src/main/res/drawable/wic_hail.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wic_humidity.xml b/shared_resources/src/main/res/drawable/wic_humidity.xml new file mode 100644 index 000000000..88e28a7ed --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_humidity.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_hurricane.xml b/shared_resources/src/main/res/drawable/wic_hurricane.xml new file mode 100644 index 000000000..471660ae7 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_hurricane.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_info.xml b/shared_resources/src/main/res/drawable/wic_info.xml new file mode 100644 index 000000000..1b3ac07d8 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_info.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_lightning.xml b/shared_resources/src/main/res/drawable/wic_lightning.xml index 7d9dee989..8865e0e4b 100644 --- a/shared_resources/src/main/res/drawable/wic_lightning.xml +++ b/shared_resources/src/main/res/drawable/wic_lightning.xml @@ -1,19 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_moon.xml b/shared_resources/src/main/res/drawable/wic_moon.xml index 67b321e44..a92613f00 100644 --- a/shared_resources/src/main/res/drawable/wic_moon.xml +++ b/shared_resources/src/main/res/drawable/wic_moon.xml @@ -1,16 +1,18 @@ + + android:scaleY="1.75"> diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud.xml index b3c3f6cfe..1dfc1ecc6 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_cloud.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud.xml @@ -1,16 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_fog.xml new file mode 100644 index 000000000..f7819b94a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_hail.xml new file mode 100644 index 000000000..bf929e51c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_haze.xml new file mode 100644 index 000000000..c8a35a73d --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_haze.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_lightning.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_lightning.xml index c2b52528b..839309a8e 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_cloud_lightning.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_lightning.xml @@ -1,19 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_rain.xml index 136a7201a..1d4767221 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_cloud_rain.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_rain.xml @@ -1,26 +1,29 @@ + + android:scaleY="1.5"> - - + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_rain_alt.xml new file mode 100644 index 000000000..2eaa69229 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_sleet.xml new file mode 100644 index 000000000..3223928e9 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_snow.xml index 96f9731df..5bba76d28 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_cloud_snow.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_snow.xml @@ -1,37 +1,29 @@ + + android:scaleY="1.5"> - - - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_snow_alt.xml new file mode 100644 index 000000000..eb6d6654a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_moon_cloud_wind.xml index ddd3c7518..ff1443274 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_cloud_wind.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_cloud_wind.xml @@ -1,22 +1,29 @@ + + android:scaleY="1.25"> - + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_first_quarter.xml b/shared_resources/src/main/res/drawable/wic_moon_first_quarter.xml index 00e688e00..01c5a2b86 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_first_quarter.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_first_quarter.xml @@ -1,16 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_fog.xml b/shared_resources/src/main/res/drawable/wic_moon_fog.xml index a017e8345..9da390478 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_fog.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_fog.xml @@ -1,17 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_fullmoon.xml b/shared_resources/src/main/res/drawable/wic_moon_fullmoon.xml index 71576d70b..d51ac69b4 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_fullmoon.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_fullmoon.xml @@ -1,16 +1,18 @@ + + android:scaleY="1.5"> diff --git a/shared_resources/src/main/res/drawable/wic_moon_last_quarter.xml b/shared_resources/src/main/res/drawable/wic_moon_last_quarter.xml index d00265ae0..4717c68b8 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_last_quarter.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_last_quarter.xml @@ -1,17 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_newmoon.xml b/shared_resources/src/main/res/drawable/wic_moon_newmoon.xml index 98cd3501b..01b51814c 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_newmoon.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_newmoon.xml @@ -1,17 +1,18 @@ + + android:scaleY="1.5"> diff --git a/shared_resources/src/main/res/drawable/wic_moon_waning_crescent.xml b/shared_resources/src/main/res/drawable/wic_moon_waning_crescent.xml index 162179bdb..3a1baa296 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_waning_crescent.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_waning_crescent.xml @@ -1,16 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_waning_gibbous.xml b/shared_resources/src/main/res/drawable/wic_moon_waning_gibbous.xml index 5dd274e73..ab8fc2edb 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_waning_gibbous.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_waning_gibbous.xml @@ -1,16 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_waxing_crescent.xml b/shared_resources/src/main/res/drawable/wic_moon_waxing_crescent.xml index 16bb9f322..e69701024 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_waxing_crescent.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_waxing_crescent.xml @@ -1,17 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moon_waxing_gibbous.xml b/shared_resources/src/main/res/drawable/wic_moon_waxing_gibbous.xml index 077ca7cce..9fc4b836a 100644 --- a/shared_resources/src/main/res/drawable/wic_moon_waxing_gibbous.xml +++ b/shared_resources/src/main/res/drawable/wic_moon_waxing_gibbous.xml @@ -1,17 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_moonrise.xml b/shared_resources/src/main/res/drawable/wic_moonrise.xml new file mode 100644 index 000000000..0df7a4d6b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moonrise.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_moonset.xml b/shared_resources/src/main/res/drawable/wic_moonset.xml new file mode 100644 index 000000000..cd19a9127 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_moonset.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_na.xml b/shared_resources/src/main/res/drawable/wic_na.xml new file mode 100644 index 000000000..f2326a93b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_na.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_pollen.xml b/shared_resources/src/main/res/drawable/wic_pollen.xml new file mode 100644 index 000000000..e49ac491f --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_pollen.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_raindrop.xml b/shared_resources/src/main/res/drawable/wic_raindrop.xml index 57ffaa44d..6871f931a 100644 --- a/shared_resources/src/main/res/drawable/wic_raindrop.xml +++ b/shared_resources/src/main/res/drawable/wic_raindrop.xml @@ -1,19 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_sandstorm.xml b/shared_resources/src/main/res/drawable/wic_sandstorm.xml new file mode 100644 index 000000000..9f8d023db --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sandstorm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_snowflake.xml b/shared_resources/src/main/res/drawable/wic_snowflake.xml index 24172f7e1..24714bc99 100644 --- a/shared_resources/src/main/res/drawable/wic_snowflake.xml +++ b/shared_resources/src/main/res/drawable/wic_snowflake.xml @@ -1,17 +1,18 @@ + + android:scaleY="1.5"> diff --git a/shared_resources/src/main/res/drawable/wic_sun.xml b/shared_resources/src/main/res/drawable/wic_sun.xml index 22e2f6c4b..023e3c820 100644 --- a/shared_resources/src/main/res/drawable/wic_sun.xml +++ b/shared_resources/src/main/res/drawable/wic_sun.xml @@ -1,40 +1,18 @@ + + android:scaleY="1.5"> - - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud.xml index a9b0dc7e8..e12e69e88 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_cloud.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud.xml @@ -1,29 +1,29 @@ + + android:scaleY="1.4"> - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_fog.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_fog.xml new file mode 100644 index 000000000..288288682 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_fog.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_hail.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_hail.xml new file mode 100644 index 000000000..2f8875848 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_hail.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_haze.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_haze.xml new file mode 100644 index 000000000..58dcb401a --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_haze.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_lightning.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_lightning.xml index f88f1090a..56cfbffba 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_cloud_lightning.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_lightning.xml @@ -1,32 +1,29 @@ + + android:scaleY="1.25"> - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_rain.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_rain.xml index e282a897f..39c9d3e74 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_cloud_rain.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_rain.xml @@ -1,38 +1,29 @@ + + android:scaleY="1.25"> - - - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_rain_alt.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_rain_alt.xml new file mode 100644 index 000000000..30cd95861 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_rain_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_sleet.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_sleet.xml new file mode 100644 index 000000000..a8715e89b --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_sleet.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_snow.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_snow.xml index a608dd18c..bce98b144 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_cloud_snow.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_snow.xml @@ -1,50 +1,29 @@ + + android:scaleY="1.25"> - - - - - - - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_snow_alt.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_snow_alt.xml new file mode 100644 index 000000000..72991f640 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_snow_alt.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_cloud_wind.xml b/shared_resources/src/main/res/drawable/wic_sun_cloud_wind.xml index 102408036..a8608f69d 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_cloud_wind.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_cloud_wind.xml @@ -1,35 +1,29 @@ + + android:scaleY="1.25"> - - - - - + + diff --git a/shared_resources/src/main/res/drawable/wic_sun_fog.xml b/shared_resources/src/main/res/drawable/wic_sun_fog.xml index 51610e1d6..b215bec05 100644 --- a/shared_resources/src/main/res/drawable/wic_sun_fog.xml +++ b/shared_resources/src/main/res/drawable/wic_sun_fog.xml @@ -1,17 +1,29 @@ + - + android:scaleY="1.5"> + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sunrise.xml b/shared_resources/src/main/res/drawable/wic_sunrise.xml index a707697e7..7d8d7da26 100644 --- a/shared_resources/src/main/res/drawable/wic_sunrise.xml +++ b/shared_resources/src/main/res/drawable/wic_sunrise.xml @@ -1,29 +1,27 @@ + - - - - - + android:scaleX="1.5" + android:scaleY="1.5"> + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_sunset.xml b/shared_resources/src/main/res/drawable/wic_sunset.xml index 9df669095..5380fad1e 100644 --- a/shared_resources/src/main/res/drawable/wic_sunset.xml +++ b/shared_resources/src/main/res/drawable/wic_sunset.xml @@ -1,29 +1,27 @@ + - - - - - + android:scaleX="1.5" + android:scaleY="1.5"> + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_thermometer_cold.xml b/shared_resources/src/main/res/drawable/wic_thermometer_cold.xml new file mode 100644 index 000000000..08b5daa49 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_thermometer_cold.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_thermometer_freeze.xml b/shared_resources/src/main/res/drawable/wic_thermometer_freeze.xml new file mode 100644 index 000000000..77cd60010 --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_thermometer_freeze.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_thermometer_heat.xml b/shared_resources/src/main/res/drawable/wic_thermometer_heat.xml new file mode 100644 index 000000000..1f1a7789c --- /dev/null +++ b/shared_resources/src/main/res/drawable/wic_thermometer_heat.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_thermometer_hot.xml b/shared_resources/src/main/res/drawable/wic_thermometer_hot.xml index b8c97b3bf..8f6a4addc 100644 --- a/shared_resources/src/main/res/drawable/wic_thermometer_hot.xml +++ b/shared_resources/src/main/res/drawable/wic_thermometer_hot.xml @@ -1,20 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_thermometer_medium.xml b/shared_resources/src/main/res/drawable/wic_thermometer_medium.xml index 939e495c7..05329f618 100644 --- a/shared_resources/src/main/res/drawable/wic_thermometer_medium.xml +++ b/shared_resources/src/main/res/drawable/wic_thermometer_medium.xml @@ -1,20 +1,29 @@ + + android:scaleY="1.5"> + + diff --git a/shared_resources/src/main/res/drawable/wic_tornado.xml b/shared_resources/src/main/res/drawable/wic_tornado.xml index 74472f5f8..a43a9beca 100644 --- a/shared_resources/src/main/res/drawable/wic_tornado.xml +++ b/shared_resources/src/main/res/drawable/wic_tornado.xml @@ -1,17 +1,27 @@ + - + android:scaleY="1.5"> + + + + + + diff --git a/shared_resources/src/main/res/drawable/wic_umbrella.xml b/shared_resources/src/main/res/drawable/wic_umbrella.xml index 996973eae..9f557abea 100644 --- a/shared_resources/src/main/res/drawable/wic_umbrella.xml +++ b/shared_resources/src/main/res/drawable/wic_umbrella.xml @@ -1,17 +1,29 @@ + + android:scaleY="1.5"> + + + diff --git a/shared_resources/src/main/res/drawable/wic_wind.xml b/shared_resources/src/main/res/drawable/wic_wind.xml index cb1db0a57..83d2f81fe 100644 --- a/shared_resources/src/main/res/drawable/wic_wind.xml +++ b/shared_resources/src/main/res/drawable/wic_wind.xml @@ -1,23 +1,29 @@ + + android:scaleY="1.25"> - + + diff --git a/shared_resources/src/main/res/drawable/wic_wind_high.xml b/shared_resources/src/main/res/drawable/wic_wind_high.xml index 7e63464fd..d1d29f1ba 100644 --- a/shared_resources/src/main/res/drawable/wic_wind_high.xml +++ b/shared_resources/src/main/res/drawable/wic_wind_high.xml @@ -1,26 +1,29 @@ + + android:scaleY="1.25"> - - + + diff --git a/shared_resources/src/main/res/drawable/wui_chanceflurries.xml b/shared_resources/src/main/res/drawable/wui_chanceflurries.xml deleted file mode 100644 index c62acc9b5..000000000 --- a/shared_resources/src/main/res/drawable/wui_chanceflurries.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_chancerain.xml b/shared_resources/src/main/res/drawable/wui_chancerain.xml deleted file mode 100644 index c35c4aa74..000000000 --- a/shared_resources/src/main/res/drawable/wui_chancerain.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_chancesleet.xml b/shared_resources/src/main/res/drawable/wui_chancesleet.xml deleted file mode 100644 index 3b2162ab1..000000000 --- a/shared_resources/src/main/res/drawable/wui_chancesleet.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_chancesnow.xml b/shared_resources/src/main/res/drawable/wui_chancesnow.xml deleted file mode 100644 index 3fd1ced8e..000000000 --- a/shared_resources/src/main/res/drawable/wui_chancesnow.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_chancetstorms.xml b/shared_resources/src/main/res/drawable/wui_chancetstorms.xml deleted file mode 100644 index 68befc805..000000000 --- a/shared_resources/src/main/res/drawable/wui_chancetstorms.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_cloudy.xml b/shared_resources/src/main/res/drawable/wui_cloudy.xml deleted file mode 100644 index 25e0fdd0c..000000000 --- a/shared_resources/src/main/res/drawable/wui_cloudy.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_day_mostlycloudy.xml b/shared_resources/src/main/res/drawable/wui_day_mostlycloudy.xml deleted file mode 100644 index 584576d00..000000000 --- a/shared_resources/src/main/res/drawable/wui_day_mostlycloudy.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_day_partlycloudy.xml b/shared_resources/src/main/res/drawable/wui_day_partlycloudy.xml deleted file mode 100644 index 8760ddb06..000000000 --- a/shared_resources/src/main/res/drawable/wui_day_partlycloudy.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_day_sunny.xml b/shared_resources/src/main/res/drawable/wui_day_sunny.xml deleted file mode 100644 index cde455094..000000000 --- a/shared_resources/src/main/res/drawable/wui_day_sunny.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_flurries.xml b/shared_resources/src/main/res/drawable/wui_flurries.xml deleted file mode 100644 index b1a5e319c..000000000 --- a/shared_resources/src/main/res/drawable/wui_flurries.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_fog.xml b/shared_resources/src/main/res/drawable/wui_fog.xml deleted file mode 100644 index 927fbc993..000000000 --- a/shared_resources/src/main/res/drawable/wui_fog.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_nt_clear.xml b/shared_resources/src/main/res/drawable/wui_nt_clear.xml deleted file mode 100644 index 656dd241a..000000000 --- a/shared_resources/src/main/res/drawable/wui_nt_clear.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_nt_mostlycloudy.xml b/shared_resources/src/main/res/drawable/wui_nt_mostlycloudy.xml deleted file mode 100644 index ba86bd2e0..000000000 --- a/shared_resources/src/main/res/drawable/wui_nt_mostlycloudy.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_nt_partlycloudy.xml b/shared_resources/src/main/res/drawable/wui_nt_partlycloudy.xml deleted file mode 100644 index 9c457ce72..000000000 --- a/shared_resources/src/main/res/drawable/wui_nt_partlycloudy.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_rain.xml b/shared_resources/src/main/res/drawable/wui_rain.xml deleted file mode 100644 index e9c72bf48..000000000 --- a/shared_resources/src/main/res/drawable/wui_rain.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_sleet.xml b/shared_resources/src/main/res/drawable/wui_sleet.xml deleted file mode 100644 index da3f3382d..000000000 --- a/shared_resources/src/main/res/drawable/wui_sleet.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/shared_resources/src/main/res/drawable/wui_tstorms.xml b/shared_resources/src/main/res/drawable/wui_tstorms.xml deleted file mode 100644 index 9385d6cb3..000000000 --- a/shared_resources/src/main/res/drawable/wui_tstorms.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - diff --git a/shared_resources/src/main/res/values/strings.xml b/shared_resources/src/main/res/values/strings.xml index 51ae180c1..9eaaf8c52 100644 --- a/shared_resources/src/main/res/values/strings.xml +++ b/shared_resources/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ Google Bright Sky (DWD) Environment and Climate Change Canada (ECCC) + Open-Meteo RainViewer Current Location Get Started diff --git a/shared_resources/src/nongms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt b/shared_resources/src/nongms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt index f56a47d32..dd248bc83 100644 --- a/shared_resources/src/nongms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt +++ b/shared_resources/src/nongms/java/com/thewizrd/shared_resources/remoteconfig/RemoteConfigServiceImpl.kt @@ -40,6 +40,18 @@ class RemoteConfigServiceImpl : RemoteConfigService { WeatherAPI.METEOFRANCE } + LocationUtils.isGermany(location) && isProviderEnabled(WeatherAPI.DWD) -> { + WeatherAPI.DWD + } + + LocationUtils.isCanada(location) && isProviderEnabled(WeatherAPI.ECCC) -> { + WeatherAPI.ECCC + } + + LocationUtils.isOpenMeteoSupported(location) && isProviderEnabled(WeatherAPI.OPENMETEO) -> { + WeatherAPI.OPENMETEO + } + else -> { getDefaultWeatherProvider() } @@ -57,6 +69,18 @@ class RemoteConfigServiceImpl : RemoteConfigService { WeatherAPI.METEOFRANCE } + LocationUtils.isGermany(location) && isProviderEnabled(WeatherAPI.DWD) -> { + WeatherAPI.DWD + } + + LocationUtils.isCanada(location) && isProviderEnabled(WeatherAPI.ECCC) -> { + WeatherAPI.ECCC + } + + LocationUtils.isOpenMeteoSupported(location) && isProviderEnabled(WeatherAPI.OPENMETEO) -> { + WeatherAPI.OPENMETEO + } + else -> { getDefaultWeatherProvider() } diff --git a/wearapp/build.gradle b/wearapp/build.gradle index 553325a59..afa13ba8b 100644 --- a/wearapp/build.gradle +++ b/wearapp/build.gradle @@ -1,7 +1,5 @@ plugins { id 'com.android.application' - id 'kotlin-android' - id 'kotlin-kapt' id 'com.google.devtools.ksp' id 'org.jetbrains.kotlin.plugin.compose' } @@ -15,11 +13,11 @@ android { // Specifies the fully-qualified class name of the test instrumentation runner. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" minSdkVersion 26 - targetSdkVersion libs.versions.targetSdkVersion.get() + targetSdkVersion libs.versions.wearTargetSdkVersion.get() // NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code [Android: 0, WearOS: 1]) // ex) 345100131 = (34, 5.10, 013, 1) - versionCode 365130141 - versionName "5.13.0" + versionCode 365140111 + versionName "5.14.0" vectorDrawables { useSupportLibrary true @@ -64,8 +62,8 @@ android { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true // Sets Java compatibility to Java 8 - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } composeOptions { @@ -73,7 +71,7 @@ android { } kotlin { - jvmToolchain(17) + jvmToolchain(21) } sourceSets { diff --git a/wearapp/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt b/wearapp/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt index bfc8a7456..be295f671 100644 --- a/wearapp/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt +++ b/wearapp/src/fullgms/java/com/thewizrd/simpleweather/FirebaseConfigurator.kt @@ -8,6 +8,7 @@ import com.google.firebase.remoteconfig.ConfigUpdate import com.google.firebase.remoteconfig.ConfigUpdateListener import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfigException +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.utils.AnalyticsProps import com.thewizrd.shared_resources.utils.CrashlyticsLoggingTree diff --git a/wearapp/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt b/wearapp/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt index 0cc23674b..6f95af55e 100644 --- a/wearapp/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt +++ b/wearapp/src/fullgms/java/com/thewizrd/simpleweather/extras/Extras.kt @@ -6,10 +6,10 @@ package com.thewizrd.simpleweather.extras import android.content.Context import android.content.Intent import android.widget.Toast +import com.thewizrd.extras.R import com.thewizrd.extras.extrasModule import com.thewizrd.shared_resources.di.localBroadcastManager import com.thewizrd.simpleweather.FirebaseConfigurator -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.preferences.SettingsActivity import com.thewizrd.simpleweather.wearable.WearableListenerActions diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt index 22d7372cf..a14903f76 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/main/MainActivity.kt @@ -16,6 +16,7 @@ import com.thewizrd.common.helpers.locationPermissionEnabled import com.thewizrd.common.location.LocationResult import com.thewizrd.common.utils.ActivityUtils.showToast import com.thewizrd.common.utils.ErrorMessage +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.preferences.SettingsManager @@ -79,7 +80,7 @@ class MainActivity : UserLocaleActivity() { // permission denied, boo! Disable the // functionality that depends on this permission. settingsManager.setFollowGPS(false) - showToast(R.string.error_location_denied, Toast.LENGTH_SHORT) + showToast(sharedRes.string.error_location_denied, Toast.LENGTH_SHORT) } } ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/KeyEntryPreferenceDialogFragment.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/KeyEntryPreferenceDialogFragment.kt index 56675b0e0..ba9b6ea71 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/KeyEntryPreferenceDialogFragment.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/KeyEntryPreferenceDialogFragment.kt @@ -7,6 +7,8 @@ import android.view.View import android.widget.TextView import androidx.core.widget.doAfterTextChanged import com.google.android.material.textfield.TextInputLayout +import com.thewizrd.common.R as commonRes +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.weatherdata.auth.* import com.thewizrd.simpleweather.R @@ -107,10 +109,10 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { when (authType) { AuthType.APPID_APPCODE, AuthType.BASIC -> { - inflate(R.layout.layout_keyentry2_dialog, null) + inflate(commonRes.layout.layout_keyentry2_dialog, null) } else -> { - inflate(R.layout.layout_keyentry_dialog, null) + inflate(commonRes.layout.layout_keyentry_dialog, null) } } } @@ -125,8 +127,8 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { AuthType.APPID_APPCODE -> { val credentials = providerKey as? ProviderAppKey - view.findViewById(R.id.keyentry1_layout)?.apply { - this.setHint(R.string.hint_appid) + view.findViewById(commonRes.id.keyentry1_layout)?.apply { + this.setHint(sharedRes.string.hint_appid) editText?.let { editText -> editText.requestFocus() editText.setText(credentials?.appId ?: "") @@ -137,8 +139,8 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { } } } - view.findViewById(R.id.keyentry2_layout)?.apply { - this.setHint(R.string.hint_appcode) + view.findViewById(commonRes.id.keyentry2_layout)?.apply { + this.setHint(sharedRes.string.hint_appcode) editText?.let { editText -> editText.setText(credentials?.appCode ?: "") @@ -151,8 +153,8 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { AuthType.BASIC -> { val credentials = providerKey as? BasicAuthProviderKey - view.findViewById(R.id.keyentry1_layout)?.apply { - this.setHint(R.string.hint_username) + view.findViewById(commonRes.id.keyentry1_layout)?.apply { + this.setHint(sharedRes.string.hint_username) editText?.let { editText -> editText.requestFocus() editText.setText(credentials?.username ?: "") @@ -163,8 +165,8 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { } } } - view.findViewById(R.id.keyentry2_layout)?.apply { - this.setHint(R.string.hint_password) + view.findViewById(commonRes.id.keyentry2_layout)?.apply { + this.setHint(sharedRes.string.hint_password) endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE passwordVisibilityToggleRequested(true) @@ -178,8 +180,8 @@ class KeyEntryPreferenceDialogFragment : WearPreferenceDialogFragment() { } } else -> { - view.findViewById(R.id.keyentry1_layout)?.apply { - this.setHint(R.string.key_hint) + view.findViewById(commonRes.id.keyentry1_layout)?.apply { + this.setHint(sharedRes.string.key_hint) editText?.let { editText -> editText.requestFocus() editText.setText(key ?: "") diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/SettingsActivity.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/SettingsActivity.kt index 8f8009891..e125a9d45 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/SettingsActivity.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/preferences/SettingsActivity.kt @@ -89,6 +89,7 @@ import com.thewizrd.simpleweather.wearable.tiles.WeatherTileHelper import com.thewizrd.weather_api.weatherModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import com.thewizrd.shared_resources.R as sharedRes class SettingsActivity : UserLocaleActivity() { companion object { @@ -178,7 +179,7 @@ class SettingsActivity : UserLocaleActivity() { private lateinit var onBackPressedCallback: OnBackPressedCallback override val titleResId: Int - get() = R.string.title_activity_settings + get() = sharedRes.string.title_activity_settings override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -196,7 +197,7 @@ class SettingsActivity : UserLocaleActivity() { // functionality that depends on this permission. followGps.isChecked = false settingsManager.setFollowGPS(false) - showToast(R.string.error_location_denied, Toast.LENGTH_SHORT) + showToast(sharedRes.string.error_location_denied, Toast.LENGTH_SHORT) } } ) @@ -205,7 +206,7 @@ class SettingsActivity : UserLocaleActivity() { override fun handleOnBackPressed() { if (isProviderAndKeyInvalid()) { // Set keyentrypref color to red - showToast(R.string.message_enter_apikey, Toast.LENGTH_SHORT) + showToast(sharedRes.string.message_enter_apikey, Toast.LENGTH_SHORT) } } } @@ -427,7 +428,7 @@ class SettingsActivity : UserLocaleActivity() { ) ) { showToast( - R.string.error_enable_location_services, + sharedRes.string.error_enable_location_services, Toast.LENGTH_SHORT ) settingsManager.setFollowGPS(false) @@ -457,11 +458,11 @@ class SettingsActivity : UserLocaleActivity() { } intervalPref = findPreference(SettingsManager.KEY_REFRESHINTERVAL)!! if (enableAdditionalRefreshIntervals()) { - intervalPref.setEntries(R.array.premium_refreshinterval_entries) - intervalPref.setEntryValues(R.array.premium_refreshinterval_values) + intervalPref.setEntries(sharedRes.array.premium_refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.premium_refreshinterval_values) } else { - intervalPref.setEntries(R.array.refreshinterval_entries) - intervalPref.setEntryValues(R.array.refreshinterval_values) + intervalPref.setEntries(sharedRes.array.refreshinterval_entries) + intervalPref.setEntryValues(sharedRes.array.refreshinterval_values) } bgLocationPref = findPreference(KEY_BGLOCATIONACCESS)!! @@ -497,7 +498,7 @@ class SettingsActivity : UserLocaleActivity() { for (i in langCodes.indices) { val code = langCodes[i] if (TextUtils.isEmpty(code)) { - langEntries[i] = getString(R.string.summary_default) + langEntries[i] = getString(sharedRes.string.summary_default) } else { val localeCode = code.toString() val locale = LocaleUtils.getLocaleForTag(localeCode) @@ -765,7 +766,7 @@ class SettingsActivity : UserLocaleActivity() { dialog.dismiss() } else { - showToast(R.string.message_keyinvalid, Toast.LENGTH_SHORT) + showToast(sharedRes.string.message_keyinvalid, Toast.LENGTH_SHORT) } } catch (e: WeatherException) { Logger.writeLine(Log.ERROR, e) @@ -790,7 +791,7 @@ class SettingsActivity : UserLocaleActivity() { private val localeSummaryFunc: Function = Function { input -> if (input.isNullOrBlank()) { - getString(R.string.summary_default) + getString(sharedRes.string.summary_default) } else { LocaleUtils.getLocaleDisplayName() } @@ -833,13 +834,18 @@ class SettingsActivity : UserLocaleActivity() { val colorSpan = ForegroundColorSpan(if (keyVerified) Color.GREEN else Color.RED) val summary: Spannable = SpannableString( - if (keyVerified) getString(R.string.message_keyverified) else getString(R.string.message_keyinvalid) + if (keyVerified) getString(sharedRes.string.message_keyverified) else getString( + sharedRes.string.message_keyinvalid + ) ) summary.setSpan(colorSpan, 0, summary.length, 0) keyEntry.summary = summary } else { keyEntry.summary = - getString(R.string.pref_summary_apikey, providerAPI ?: WeatherIcons.EM_DASH) + getString( + sharedRes.string.pref_summary_apikey, + providerAPI ?: WeatherIcons.EM_DASH + ) } } @@ -914,12 +920,12 @@ class SettingsActivity : UserLocaleActivity() { private lateinit var pressureUnitPref: ListPreference override val titleResId: Int - get() = R.string.pref_title_units + get() = sharedRes.string.pref_title_units override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_units, rootKey) - preferenceScreen.setTitle(R.string.pref_title_units) + preferenceScreen.setTitle(sharedRes.string.pref_title_units) tempUnitPref = findPreference(SettingsManager.KEY_TEMPUNIT)!! speedUnitPref = findPreference(SettingsManager.KEY_SPEEDUNIT)!! @@ -931,8 +937,8 @@ class SettingsActivity : UserLocaleActivity() { Preference.OnPreferenceClickListener { activity?.let { val params = WearDialogParams.Builder(it) - .setTitle(R.string.pref_title_units) - .setItems(R.array.default_units) { dialog, which -> + .setTitle(sharedRes.string.pref_title_units) + .setItems(sharedRes.array.default_units) { dialog, which -> val isFahrenheit = which == 0 tempUnitPref.value = if (isFahrenheit) Units.FAHRENHEIT else Units.CELSIUS @@ -960,7 +966,7 @@ class SettingsActivity : UserLocaleActivity() { class IconsFragment : WearIconProviderPickerFragment() { override val titleResId: Int - get() = R.string.pref_title_icons + get() = sharedRes.string.pref_title_icons override fun getDefaultKey(): String { return settingsManager.getIconsProvider() @@ -1000,6 +1006,10 @@ class SettingsActivity : UserLocaleActivity() { return } super.onRadioButtonConfirmed(selectedKey) + AnalyticsLogger.logEvent("W_Icon_Selected", Bundle().apply { + putString("iconProvider", selectedKey) + }) + AnalyticsLogger.setUserProperty(AnalyticsProps.ICON_PROVIDER, selectedKey) } } @@ -1012,7 +1022,7 @@ class SettingsActivity : UserLocaleActivity() { } override val titleResId: Int - get() = R.string.pref_title_about + get() = sharedRes.string.pref_title_about override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_aboutapp, rootKey) @@ -1049,7 +1059,7 @@ class SettingsActivity : UserLocaleActivity() { private val confirmationViewModel: ConfirmationViewModel by viewModels() override val titleResId: Int - get() = R.string.pref_title_credits + get() = sharedRes.string.pref_title_credits override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -1118,7 +1128,7 @@ class SettingsActivity : UserLocaleActivity() { class OSSCreditsFragment : SwipeDismissPreferenceFragment() { override val titleResId: Int - get() = R.string.pref_title_oslibs + get() = sharedRes.string.pref_title_oslibs override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.pref_oslibs, rootKey) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt index b0bf359f6..8be96454a 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/services/ServiceNotificationHelper.kt @@ -8,6 +8,7 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.simpleweather.R internal object ServiceNotificationHelper { @@ -19,7 +20,7 @@ internal object ServiceNotificationHelper { // Gets an instance of the NotificationManager service val mNotifyMgr = context.getSystemService(NotificationManager::class.java) var mChannel = mNotifyMgr.getNotificationChannel(NOT_CHANNEL_ID) - val notchannel_name = context.resources.getString(R.string.not_channel_name_general) + val notchannel_name = context.resources.getString(sharedRes.string.not_channel_name_general) if (mChannel == null) { mChannel = NotificationChannel( NOT_CHANNEL_ID, @@ -39,9 +40,9 @@ internal object ServiceNotificationHelper { @RequiresApi(Build.VERSION_CODES.O) internal fun getForegroundNotification(context: Context): Notification { return NotificationCompat.Builder(context, NOT_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_launcher_monochrome) - .setContentTitle(context.getString(R.string.not_title_weather_update)) - .setColor(ContextCompat.getColor(context, R.color.colorPrimary)) + .setSmallIcon(sharedRes.drawable.ic_launcher_monochrome) + .setContentTitle(context.getString(sharedRes.string.not_title_weather_update)) + .setColor(ContextCompat.getColor(context, sharedRes.color.colorPrimary)) .setOnlyAlertOnce(true) .setNotificationSilent() .setPriority(NotificationCompat.PRIORITY_LOW) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt index 7c2ce0682..3925e7a1b 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/services/WeatherUpdaterWorker.kt @@ -13,6 +13,7 @@ import com.thewizrd.common.utils.LiveDataUtils.awaitWithTimeout import com.thewizrd.common.weatherdata.WeatherDataLoader import com.thewizrd.common.weatherdata.WeatherRequest import com.thewizrd.common.weatherdata.WeatherResult +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.appLib import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.preferences.SettingsManager @@ -235,7 +236,7 @@ class WeatherUpdaterWorker(context: Context, workerParams: WorkerParameters) : C val locMan = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager? if (locMan == null || !LocationManagerCompat.isLocationEnabled(locMan)) { - return LocationResult.Error(errorMessage = ErrorMessage.Resource(R.string.error_retrieve_location)) + return LocationResult.Error(errorMessage = ErrorMessage.Resource(sharedRes.string.error_retrieve_location)) } return locationProvider.getLatestLocationData(settingsManager.getLastGPSLocData()) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/ConfirmationOverlay.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/ConfirmationOverlay.kt index 6ef2c659f..6357a8173 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/ConfirmationOverlay.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/ConfirmationOverlay.kt @@ -22,6 +22,7 @@ import androidx.wear.compose.material3.Text import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.viewmodels.ConfirmationData import com.thewizrd.simpleweather.viewmodels.ConfirmationType +import androidx.wear.R as wearRes @Composable fun ConfirmationOverlay( @@ -90,7 +91,7 @@ fun ConfirmationOverlay( }, content = { val image = - AnimatedImageVector.animatedVectorResource(R.drawable.open_on_phone_animation) + AnimatedImageVector.animatedVectorResource(wearRes.drawable.open_on_phone_animation) var atEnd by remember { mutableStateOf(false) } Icon( @@ -102,7 +103,7 @@ fun ConfirmationOverlay( } ), painter = rememberAnimatedVectorPainter(image, atEnd), - contentDescription = stringResource(R.string.common_open_on_phone) + contentDescription = stringResource(R.string.action_openonphone) ) LaunchedEffect(Unit) { diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/IconControl.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/IconControl.kt index d34af60ce..1d95fcb85 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/IconControl.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/IconControl.kt @@ -30,7 +30,6 @@ fun WeatherIcon( factory = { IconControl(it).apply { this.scaleType = alignment.scaleType - this.showAsMonochrome = showAsMonochrome this.shouldAnimate = shouldAnimate this.forceDarkMode = forceDarkMode this.iconProvider = iconProvider @@ -40,8 +39,8 @@ fun WeatherIcon( if (useDefaultIconProvider) { useDefaultIconProvider() } - this.contentDescription = contentDescription + this.showAsMonochrome = showAsMonochrome } }, update = { @@ -51,6 +50,9 @@ fun WeatherIcon( if (it.weatherIcon != weatherIcon) { it.weatherIcon = weatherIcon } + if (it.showAsMonochrome != showAsMonochrome) { + it.showAsMonochrome = showAsMonochrome + } } ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WearDivider.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WearDivider.kt index 2f4f73a76..5887671e0 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WearDivider.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WearDivider.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.PathEffect +import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -27,19 +28,21 @@ fun WearDivider() { .height(24.dp), contentAlignment = Alignment.Center ) { - val pathEffect = PathEffect.dashPathEffect(floatArrayOf(ctx.dpToPx(2f), ctx.dpToPx(4f))) + val strokeWidth = ctx.dpToPx(3f) + val pathEffect = PathEffect.dashPathEffect(floatArrayOf(0f, strokeWidth * 2)) Canvas( modifier = Modifier .width(48.dp) - .height(1.dp) + .height(4.dp) ) { drawLine( color = Color.White, - strokeWidth = ctx.dpToPx(2f), - start = Offset(0f, 0f), - end = Offset(size.width, 0f), - pathEffect = pathEffect + strokeWidth = strokeWidth, + start = Offset(0f, size.height / 2f), + end = Offset(size.width, size.height / 2f), + cap = StrokeCap.Round, + pathEffect = pathEffect, ) } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherAlertPanel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherAlertPanel.kt index 34ec863b9..e26eefd4c 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherAlertPanel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherAlertPanel.kt @@ -34,6 +34,7 @@ import androidx.wear.compose.material3.Text import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales import com.google.android.horologist.annotations.ExperimentalHorologistApi import com.thewizrd.common.controls.WeatherAlertViewModel +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.utils.getColorFromAlertSeverity import com.thewizrd.shared_resources.utils.getDrawableFromAlertType import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertSeverity @@ -59,7 +60,7 @@ private fun WeatherAlertPanel( title: String, alertBodyMessage: CharSequence, @ColorInt alertSeverityColor: Int, - @DrawableRes alertDrawable: Int = R.drawable.ic_error + @DrawableRes alertDrawable: Int = sharedRes.drawable.ic_error ) { var showDialog by remember { mutableStateOf(false) } val severityColor = remember(alertSeverityColor) { Color(alertSeverityColor) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherDetailItem.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherDetailItem.kt index 72da1d018..27ec61ee4 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherDetailItem.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherDetailItem.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -19,15 +20,42 @@ import androidx.wear.compose.material3.LocalContentColor import androidx.wear.compose.material3.Text import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales import com.thewizrd.common.controls.DetailItemViewModel -import com.thewizrd.common.controls.WeatherDetailsType -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.simpleweather.ui.compose.tools.WearPreviewDevices import com.thewizrd.simpleweather.ui.text.spannableStringToAnnotatedString import org.jetbrains.annotations.TestOnly +import com.thewizrd.shared_resources.R as sharedRes @Composable fun WeatherDetailItem( - model: DetailItemViewModel + model: DetailItemViewModel, + iconProvider: String? = null +) { + val wim = remember { + sharedDeps.weatherIconsManager + } + + WeatherDetailItem( + label = model.label, + value = model.value, + icon = model.icon, + iconRotation = model.iconRotation, + iconProvider = iconProvider, + showAsMonochrome = wim.shouldUseMonochrome(), + shouldAnimate = true + ) +} + +@Composable +private fun WeatherDetailItem( + label: CharSequence, + value: CharSequence, + icon: String, + iconProvider: String? = null, + iconRotation: Int = 0, + showAsMonochrome: Boolean = false, + shouldAnimate: Boolean = true, ) { val isPreview = LocalInspectionMode.current @@ -37,12 +65,12 @@ fun WeatherDetailItem( .height(60.dp), label = { Text( - text = spannableStringToAnnotatedString(model.label) + text = spannableStringToAnnotatedString(label) ) }, secondaryLabel = { Text( - text = spannableStringToAnnotatedString(model.value) + text = spannableStringToAnnotatedString(value) ) }, onClick = {}, @@ -53,7 +81,7 @@ fun WeatherDetailItem( modifier = Modifier .size(ButtonDefaults.IconSize) .wrapContentSize(align = Alignment.Center), - painter = painterResource(id = R.drawable.ic_error), + painter = painterResource(id = sharedRes.drawable.ic_error), contentDescription = "", colorFilter = ColorFilter.tint(LocalContentColor.current) ) @@ -62,9 +90,12 @@ fun WeatherDetailItem( modifier = Modifier .size(ButtonDefaults.IconSize) .wrapContentSize(align = Alignment.Center) - .rotate(model.iconRotation.toFloat()), - weatherIcon = model.icon, - tint = LocalContentColor.current + .rotate(iconRotation.toFloat()), + weatherIcon = icon, + iconProvider = iconProvider, + tint = LocalContentColor.current, + shouldAnimate = shouldAnimate, + showAsMonochrome = showAsMonochrome ) } } @@ -77,9 +108,8 @@ fun WeatherDetailItem( @TestOnly fun PreviewWeatherDetailItem() { WeatherDetailItem( - model = DetailItemViewModel(WeatherDetailsType.FEELSLIKE).apply { - value = "70°" - label = "Feels like" - } + label = "Feels like", + value = "70°", + icon = WeatherIcons.THERMOMETER ) } \ No newline at end of file diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherForecastPanel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherForecastPanel.kt index fba50b82a..ebfe032bc 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherForecastPanel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherForecastPanel.kt @@ -37,10 +37,12 @@ import com.thewizrd.shared_resources.designer.initializeDependencies import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.ui.text.spannableStringToAnnotatedString +import com.thewizrd.shared_resources.R as sharedRes @Composable fun WeatherForecastPanel( - model: ForecastItemViewModel + model: ForecastItemViewModel, + iconProvider: String? = null ) { val context = LocalContext.current val isLargeHeight = LocalConfiguration.current.screenHeightDp >= 225 @@ -81,6 +83,7 @@ fun WeatherForecastPanel( width = 32.dp, height = 36.dp ), weatherIcon = model.weatherIcon, + iconProvider = iconProvider, shouldAnimate = true ) Column( @@ -100,7 +103,7 @@ fun WeatherForecastPanel( ) Icon( modifier = Modifier.size(28.dp), - painter = painterResource(id = R.drawable.wi_direction_up), + painter = painterResource(id = sharedRes.drawable.wi_direction_up), tint = Color(0xFFFF4500), contentDescription = null ) @@ -118,7 +121,7 @@ fun WeatherForecastPanel( ) Icon( modifier = Modifier.size(28.dp), - painter = painterResource(id = R.drawable.wi_direction_down), + painter = painterResource(id = sharedRes.drawable.wi_direction_down), tint = Color(0xFF87CEFA), contentDescription = null ) @@ -132,20 +135,22 @@ fun WeatherForecastPanel( ) { if (popData != null) { Row(verticalAlignment = Alignment.CenterVertically) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 2.dp), - painter = painterResource(R.drawable.wi_umbrella), - tint = colorResource(R.color.colorPrimaryLight), - contentDescription = null + weatherIcon = WeatherIcons.UMBRELLA, + iconProvider = iconProvider, + tint = colorResource(sharedRes.color.colorPrimaryLight), + showAsMonochrome = true, + contentDescription = popData.label?.toString() ) Text( text = spannableStringToAnnotatedString(popData.value), style = MaterialTheme.typography.bodyLarge.copy(fontSize = 14.sp), textAlign = TextAlign.End, maxLines = 1, - color = colorResource(R.color.colorPrimaryLight) + color = colorResource(sharedRes.color.colorPrimaryLight) ) } } @@ -162,15 +167,17 @@ fun WeatherForecastPanel( } Row(verticalAlignment = Alignment.CenterVertically) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 2.dp) .rotate(windData.iconRotation.toFloat()) .align(Alignment.CenterVertically), - painter = painterResource(R.drawable.wi_wind_direction), + weatherIcon = WeatherIcons.WIND_DIRECTION, + useDefaultIconProvider = true, tint = Color(0xFF20B2AA), - contentDescription = null + showAsMonochrome = true, + contentDescription = windData.label?.toString() ) Text( modifier = Modifier.align(Alignment.CenterVertically), diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherHourlyForecastPanel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherHourlyForecastPanel.kt index ace487be2..066099e96 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherHourlyForecastPanel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherHourlyForecastPanel.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextAlign @@ -34,7 +33,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp -import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text import androidx.wear.tooling.preview.devices.WearDevices @@ -49,10 +47,12 @@ import com.thewizrd.shared_resources.utils.StringUtils import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.ui.text.spannableStringToAnnotatedString import java.time.ZonedDateTime +import com.thewizrd.shared_resources.R as sharedRes @Composable fun WeatherHourlyForecastPanel( - model: HourlyForecastItemViewModel + model: HourlyForecastItemViewModel, + iconProvider: String? = null ) { val ctx = LocalContext.current val isLargeHeight = LocalConfiguration.current.screenHeightDp >= 225 @@ -129,6 +129,7 @@ fun WeatherHourlyForecastPanel( width = 32.dp, height = 36.dp ), weatherIcon = model.weatherIcon, + iconProvider = iconProvider, shouldAnimate = true ) Text( @@ -146,14 +147,16 @@ fun WeatherHourlyForecastPanel( ) { if (popData != null) { Row(verticalAlignment = Alignment.CenterVertically) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 2.dp) .align(Alignment.CenterVertically), - painter = painterResource(R.drawable.wi_umbrella), - tint = colorResource(R.color.colorPrimaryLight), - contentDescription = null + weatherIcon = WeatherIcons.UMBRELLA, + iconProvider = iconProvider, + tint = colorResource(sharedRes.color.colorPrimaryLight), + showAsMonochrome = true, + contentDescription = popData.label?.toString() ) Text( modifier = Modifier.align(Alignment.CenterVertically), @@ -161,7 +164,7 @@ fun WeatherHourlyForecastPanel( style = MaterialTheme.typography.bodyLarge.copy(fontSize = 14.sp), textAlign = TextAlign.End, maxLines = 1, - color = colorResource(R.color.colorPrimaryLight) + color = colorResource(sharedRes.color.colorPrimaryLight) ) } } @@ -178,15 +181,17 @@ fun WeatherHourlyForecastPanel( } Row(verticalAlignment = Alignment.CenterVertically) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 2.dp) .rotate(windData.iconRotation.toFloat()) .align(Alignment.CenterVertically), - painter = painterResource(R.drawable.wi_wind_direction), + weatherIcon = WeatherIcons.WIND_DIRECTION, + useDefaultIconProvider = true, tint = Color(0xFF20B2AA), - contentDescription = null + showAsMonochrome = true, + contentDescription = windData.label?.toString() ) Text( modifier = Modifier.align(Alignment.CenterVertically), diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherMinutelyForecastPanel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherMinutelyForecastPanel.kt index 8ea9373d6..bec5d59e5 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherMinutelyForecastPanel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/WeatherMinutelyForecastPanel.kt @@ -16,11 +16,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text import androidx.wear.tooling.preview.devices.WearDevices @@ -29,21 +28,27 @@ import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.viewmodels.MinutelyForecastViewModel import java.time.ZonedDateTime import java.time.format.DateTimeFormatter +import com.thewizrd.shared_resources.R as sharedRes @Composable fun WeatherMinutelyForecastPanel( - model: MinutelyForecastViewModel + model: MinutelyForecastViewModel, + iconProvider: String? = null ) { WeatherMinutelyForecastPanel( date = model.date, - rainAmount = model.rainAmount + precipAmount = model.precipAmount, + isSnow = model.isSnow, + iconProvider = iconProvider ) } @Composable private fun WeatherMinutelyForecastPanel( date: String? = null, - rainAmount: String? = null + precipAmount: String? = null, + isSnow: Boolean = false, + iconProvider: String? = null ) { Row( modifier = Modifier @@ -55,13 +60,19 @@ private fun WeatherMinutelyForecastPanel( ), verticalAlignment = Alignment.CenterVertically ) { - Text( + Column( modifier = Modifier .weight(1f), - textAlign = TextAlign.Center, - text = date ?: WeatherIcons.EM_DASH, - style = MaterialTheme.typography.bodyLarge - ) + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + text = date ?: WeatherIcons.EM_DASH, + style = MaterialTheme.typography.bodyLarge + ) + } Column( modifier = Modifier .weight(1f), @@ -70,18 +81,31 @@ private fun WeatherMinutelyForecastPanel( ) { Text( modifier = Modifier - .weight(1f, false), + .fillMaxWidth() + .defaultMinSize(minHeight = 20.dp), textAlign = TextAlign.Center, - text = rainAmount ?: WeatherIcons.PLACEHOLDER, + text = precipAmount ?: WeatherIcons.PLACEHOLDER, style = MaterialTheme.typography.bodyLarge ) - Icon( - modifier = Modifier - .weight(1f, false) - .size(20.dp), - painter = painterResource(R.drawable.wi_raindrop), - contentDescription = null, - tint = colorResource(id = R.color.colorSecondaryDark) + WeatherIcon( + modifier = Modifier.size(20.dp), + weatherIcon = if (isSnow) { + WeatherIcons.SNOWFLAKE_COLD + } else { + WeatherIcons.RAINDROP + }, + iconProvider = iconProvider, + tint = if (isSnow) { + colorResource(id = sharedRes.color.colorSecondaryLight) + } else { + colorResource(id = sharedRes.color.colorSecondaryDark) + }, + showAsMonochrome = true, + contentDescription = if (isSnow) { + stringResource(id = sharedRes.string.label_qpf_snow) + } else { + stringResource(id = sharedRes.string.label_qpf_rain) + } ) } } @@ -131,7 +155,7 @@ fun PreviewWeatherMinutelyForecastPanel() { WeatherMinutelyForecastPanel( date = ZonedDateTime.now().format(fmt), - rainAmount = "1.00 mm" + precipAmount = "1.00 mm" ) } } \ No newline at end of file diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearEditTextPreference.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearEditTextPreference.kt index e6f828226..2dc2474eb 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearEditTextPreference.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearEditTextPreference.kt @@ -39,6 +39,7 @@ import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.helpers.SimpleActionModeCallback @@ -123,7 +124,7 @@ fun WearEditTextPreference( modifier = Modifier .size(24.dp) .wrapContentSize(align = Alignment.Center), - painter = painterResource(id = R.drawable.ic_close_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_close_white_24dp), contentDescription = stringResource(id = android.R.string.cancel) ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearListPreference.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearListPreference.kt index 972da0863..f0cecb913 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearListPreference.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/components/preferences/WearListPreference.kt @@ -28,6 +28,7 @@ import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.RadioButton import androidx.wear.compose.material3.Text +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.ui.compose.tools.WearPreviewDevices @@ -100,7 +101,7 @@ fun WearListPreference( modifier = Modifier .size(24.dp) .wrapContentSize(align = Alignment.Center), - painter = painterResource(id = R.drawable.ic_close_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_close_white_24dp), contentDescription = stringResource(id = android.R.string.cancel) ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/preferences/DetailsWeatherTileConfigScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/preferences/DetailsWeatherTileConfigScreen.kt index dab0b2aae..d9afb96c8 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/preferences/DetailsWeatherTileConfigScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/preferences/DetailsWeatherTileConfigScreen.kt @@ -97,6 +97,7 @@ import sh.calvin.reorderable.ReorderableItem import sh.calvin.reorderable.rememberReorderableLazyGridState import java.util.Collections import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes @Composable fun DetailsWeatherTileConfigScreen( @@ -315,7 +316,7 @@ private fun DetailsWeatherTileConfigScreen( ) { Icon( modifier = Modifier.size(ButtonDefaults.IconSize), - painter = painterResource(id = R.drawable.ic_close_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_close_white_24dp), contentDescription = null, ) } @@ -396,7 +397,7 @@ private fun DetailsWeatherTileConfigScreen( Icon( modifier = Modifier.size(ButtonDefaults.IconSize), painter = painterResource(id = R.drawable.ic_restart_alt_24dp), - contentDescription = stringResource(R.string.action_reset), + contentDescription = stringResource(sharedRes.string.action_reset), ) } IconButton( @@ -458,14 +459,14 @@ private fun DetailsWeatherTileConfigScreen( modifier = Modifier.fillMaxSize(), visible = showAddTileDialog, onDismissRequest = { showAddTileDialog = false }, - title = { Text(text = stringResource(id = R.string.label_details)) }, + title = { Text(text = stringResource(id = sharedRes.string.label_details)) }, edgeButton = { EdgeButton( onClick = { showAddTileDialog = false } ) { Icon( modifier = Modifier.size(ButtonDefaults.IconSize), - painter = painterResource(id = R.drawable.ic_close_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_close_white_24dp), contentDescription = stringResource(android.R.string.cancel) ) } @@ -540,7 +541,7 @@ private fun WeatherDetailsType.toWeatherIcon(): String = when (this) { WeatherDetailsType.WINDGUST -> WeatherIcons.CLOUDY_GUSTS WeatherDetailsType.HUMIDITY -> WeatherIcons.HUMIDITY WeatherDetailsType.PRESSURE -> WeatherIcons.BAROMETER - WeatherDetailsType.VISIBILITY -> WeatherIcons.FOG + WeatherDetailsType.VISIBILITY -> WeatherIcons.VISIBILITY WeatherDetailsType.POPCLOUDINESS -> WeatherIcons.CLOUDY WeatherDetailsType.POPCHANCE -> WeatherIcons.UMBRELLA WeatherDetailsType.POPRAIN -> WeatherIcons.RAINDROPS @@ -551,33 +552,33 @@ private fun WeatherDetailsType.toWeatherIcon(): String = when (this) { WeatherDetailsType.MOONPHASE -> WeatherIcons.MOON_NEW WeatherDetailsType.BEAUFORT -> WeatherIcons.WIND_BEAUFORT_0 WeatherDetailsType.UV -> WeatherIcons.UV_INDEX - WeatherDetailsType.AIRQUALITY -> WeatherIcons.CLOUDY_GUSTS + WeatherDetailsType.AIRQUALITY -> WeatherIcons.AIR_QUALITY WeatherDetailsType.TREEPOLLEN -> WeatherIcons.TREE_POLLEN WeatherDetailsType.GRASSPOLLEN -> WeatherIcons.GRASS_POLLEN WeatherDetailsType.RAGWEEDPOLLEN -> WeatherIcons.RAGWEED_POLLEN } private fun WeatherDetailsType.toLabelStringResId(): Int = when (this) { - WeatherDetailsType.SUNRISE -> R.string.label_sunrise - WeatherDetailsType.SUNSET -> R.string.label_sunset - WeatherDetailsType.FEELSLIKE -> R.string.label_feelslike - WeatherDetailsType.WINDSPEED -> R.string.label_wind - WeatherDetailsType.WINDGUST -> R.string.label_windgust - WeatherDetailsType.HUMIDITY -> R.string.label_humidity - WeatherDetailsType.PRESSURE -> R.string.label_pressure - WeatherDetailsType.VISIBILITY -> R.string.label_visibility - WeatherDetailsType.POPCHANCE -> R.string.label_chance - WeatherDetailsType.POPCLOUDINESS -> R.string.label_cloudiness - WeatherDetailsType.POPRAIN -> R.string.label_qpf_rain - WeatherDetailsType.POPSNOW -> R.string.label_qpf_snow - WeatherDetailsType.DEWPOINT -> R.string.label_dewpoint - WeatherDetailsType.MOONRISE -> R.string.label_moonrise - WeatherDetailsType.MOONSET -> R.string.label_moonset - WeatherDetailsType.MOONPHASE -> R.string.label_moonphase - WeatherDetailsType.BEAUFORT -> R.string.label_beaufort - WeatherDetailsType.UV -> R.string.label_uv - WeatherDetailsType.AIRQUALITY -> R.string.label_airquality - WeatherDetailsType.TREEPOLLEN -> R.string.label_tree_pollen - WeatherDetailsType.GRASSPOLLEN -> R.string.label_grass_pollen - WeatherDetailsType.RAGWEEDPOLLEN -> R.string.label_ragweed_pollen + WeatherDetailsType.SUNRISE -> sharedRes.string.label_sunrise + WeatherDetailsType.SUNSET -> sharedRes.string.label_sunset + WeatherDetailsType.FEELSLIKE -> sharedRes.string.label_feelslike + WeatherDetailsType.WINDSPEED -> sharedRes.string.label_wind + WeatherDetailsType.WINDGUST -> sharedRes.string.label_windgust + WeatherDetailsType.HUMIDITY -> sharedRes.string.label_humidity + WeatherDetailsType.PRESSURE -> sharedRes.string.label_pressure + WeatherDetailsType.VISIBILITY -> sharedRes.string.label_visibility + WeatherDetailsType.POPCHANCE -> sharedRes.string.label_chance + WeatherDetailsType.POPCLOUDINESS -> sharedRes.string.label_cloudiness + WeatherDetailsType.POPRAIN -> sharedRes.string.label_qpf_rain + WeatherDetailsType.POPSNOW -> sharedRes.string.label_qpf_snow + WeatherDetailsType.DEWPOINT -> sharedRes.string.label_dewpoint + WeatherDetailsType.MOONRISE -> sharedRes.string.label_moonrise + WeatherDetailsType.MOONSET -> sharedRes.string.label_moonset + WeatherDetailsType.MOONPHASE -> sharedRes.string.label_moonphase + WeatherDetailsType.BEAUFORT -> sharedRes.string.label_beaufort + WeatherDetailsType.UV -> sharedRes.string.label_uv + WeatherDetailsType.AIRQUALITY -> sharedRes.string.label_airquality + WeatherDetailsType.TREEPOLLEN -> sharedRes.string.label_tree_pollen + WeatherDetailsType.GRASSPOLLEN -> sharedRes.string.label_grass_pollen + WeatherDetailsType.RAGWEEDPOLLEN -> sharedRes.string.label_ragweed_pollen } \ No newline at end of file diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationListScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationListScreen.kt index 92756c4c6..6adbac279 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationListScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationListScreen.kt @@ -38,6 +38,7 @@ import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight import com.thewizrd.common.viewmodels.LocationSearchViewModel +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.locationdata.LocationQuery @@ -129,7 +130,7 @@ private fun SetupLocationListScreen( .animateItem(), transformation = SurfaceTransformation(transformationSpec), ) { - Text(text = stringResource(id = R.string.label_nav_locations)) + Text(text = stringResource(id = sharedRes.string.label_nav_locations)) } } @@ -157,7 +158,7 @@ private fun SetupLocationListScreen( } else { { Icon( - painter = painterResource(id = R.drawable.ic_place_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_place_white_24dp), contentDescription = null ) } @@ -172,9 +173,10 @@ private fun SetupLocationListScreen( .animateItem(), transformation = SurfaceTransformation(transformationSpec), ) { + val creditPrefix = stringResource(sharedRes.string.credit_prefix) Text(text = remember(context, locationSource) { buildString { - append(context.getString(R.string.credit_prefix)) + append(creditPrefix) append(" ") append(locationSource) } @@ -192,7 +194,7 @@ private fun SetupLocationListScreen( verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically) ) { Text( - text = stringResource(id = R.string.werror_querynotfound), + text = stringResource(id = sharedRes.string.werror_querynotfound), textAlign = TextAlign.Center ) CompactButton( diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationSearchScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationSearchScreen.kt index 7dc8df96b..f4e3c50de 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationSearchScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupLocationSearchScreen.kt @@ -42,6 +42,7 @@ import androidx.wear.compose.material3.IconButtonDefaults import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.Constants import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.simpleweather.R @@ -71,6 +72,8 @@ fun SetupLocationSearchScreen(navController: NavController) { } } + val searchHintPrompt = stringResource(sharedRes.string.location_search_hint) + SetupLocationSearchScreen( onVoiceSearch = { val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply { @@ -80,7 +83,7 @@ fun SetupLocationSearchScreen(navController: NavController) { ) putExtra( RecognizerIntent.EXTRA_PROMPT, - context.getString(R.string.location_search_hint) + searchHintPrompt ) } @@ -148,7 +151,7 @@ private fun SetupLocationSearchScreen( top = 26.dp, bottom = 16.dp ) ) { - Text(text = stringResource(id = R.string.location_search_hint)) + Text(text = stringResource(id = sharedRes.string.location_search_hint)) } Box( @@ -171,7 +174,7 @@ private fun SetupLocationSearchScreen( ) { Icon( painter = painterResource(R.drawable.ic_keyboard_voice_black_24dp), - contentDescription = stringResource(R.string.abc_searchview_description_voice) + contentDescription = stringResource(androidx.appcompat.R.string.abc_searchview_description_voice) ) } @@ -189,7 +192,7 @@ private fun SetupLocationSearchScreen( ) { Icon( painter = painterResource(R.drawable.ic_keyboard_black_24dp), - contentDescription = stringResource(R.string.abc_searchview_description_search) + contentDescription = stringResource(androidx.appcompat.R.string.abc_searchview_description_search) ) } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupScreen.kt index cbf5552ba..bf385fa5c 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupScreen.kt @@ -53,6 +53,7 @@ import com.thewizrd.simpleweather.ui.helpers.rememberLocationPermissionLauncher import com.thewizrd.simpleweather.ui.navigation.Screen import com.thewizrd.simpleweather.ui.theme.activityViewModel import com.thewizrd.simpleweather.ui.utils.rememberFocusRequester +import com.thewizrd.shared_resources.R as sharedRes @Composable fun SetupScreen( @@ -146,7 +147,7 @@ private fun SetupScreen( ) { item { ListHeader { - Text(text = stringResource(id = R.string.app_name)) + Text(text = stringResource(id = sharedRes.string.app_name)) } } item { @@ -161,7 +162,7 @@ private fun SetupScreen( }, label = { Text( - text = stringResource(id = R.string.location_search_hint), + text = stringResource(id = sharedRes.string.location_search_hint), color = LocalContentColor.current ) }, @@ -184,12 +185,12 @@ private fun SetupScreen( fetchGeoLocation() }, label = { - Text(text = stringResource(id = R.string.label_gpsfollow)) + Text(text = stringResource(id = sharedRes.string.label_gpsfollow)) }, icon = { Icon( - painter = painterResource(id = R.drawable.ic_my_location_white_24dp), - contentDescription = stringResource(id = R.string.label_gpsfollow) + painter = painterResource(id = sharedRes.drawable.ic_my_location_white_24dp), + contentDescription = stringResource(id = sharedRes.string.label_gpsfollow) ) } ) @@ -211,7 +212,7 @@ private fun SetupScreen( icon = { Icon( modifier = Modifier.size(ButtonDefaults.IconSize), - painter = painterResource(id = R.drawable.common_full_open_on_phone), + painter = painterResource(id = R.drawable.ic_mobile_arrow_right), contentDescription = stringResource(id = R.string.action_setupfromphone) ) } @@ -230,7 +231,7 @@ private fun SetupScreen( }, text = { Text( - text = stringResource(id = R.string.error_location_denied), + text = stringResource(id = sharedRes.string.error_location_denied), overflow = TextOverflow.Ellipsis, ) }, @@ -238,7 +239,7 @@ private fun SetupScreen( content = { Icon( modifier = Modifier.size(ConfirmationDialogDefaults.SmallIconSize), - painter = painterResource(id = R.drawable.ic_location_off_24dp), + painter = painterResource(id = sharedRes.drawable.ic_location_off_24dp), contentDescription = null ) } @@ -264,7 +265,7 @@ private fun SetupScreen( errorMessage.exception.message } - else -> stringResource(R.string.werror_unknown) + else -> stringResource(sharedRes.string.werror_unknown) }, overflow = TextOverflow.Ellipsis, ) @@ -273,7 +274,7 @@ private fun SetupScreen( content = { Icon( modifier = Modifier.size(ConfirmationDialogDefaults.SmallIconSize), - painter = painterResource(id = R.drawable.ic_error_white), + painter = painterResource(id = sharedRes.drawable.ic_error_white), contentDescription = null ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupSyncScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupSyncScreen.kt index 4bc702b13..9b844be27 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupSyncScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/setup/SetupSyncScreen.kt @@ -1,5 +1,6 @@ package com.thewizrd.simpleweather.ui.setup +import android.annotation.SuppressLint import android.content.Intent import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloat @@ -43,6 +44,7 @@ import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.touchTargetAwareSize import androidx.wear.compose.navigation.rememberSwipeDismissableNavController import com.thewizrd.common.utils.ErrorMessage +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.utils.ContextUtils.isLargeWatch import com.thewizrd.shared_resources.wearable.WearableDataSync @@ -61,6 +63,7 @@ import com.thewizrd.simpleweather.wearable.WearableListenerActions.EXTRA_SUCCESS import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +@SuppressLint("LocalContextGetResourceValueCall") @Composable fun SetupSyncScreen( navController: NavController, @@ -196,7 +199,7 @@ private fun SetupSyncScreen( }, ) { Icon( - painter = painterResource(R.drawable.ic_close_white_24dp), + painter = painterResource(sharedRes.drawable.ic_close_white_24dp), contentDescription = stringResource(android.R.string.cancel) ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/theme/ViewModelExtras.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/theme/ViewModelExtras.kt index 17ee40936..ec85d5345 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/theme/ViewModelExtras.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/theme/ViewModelExtras.kt @@ -10,21 +10,23 @@ import androidx.lifecycle.viewmodel.compose.viewModel /** Try to fetch a viewModel in [store] */ @Composable -inline fun viewModelInStore(store: S): Result = - runCatching { - var result: Result? = null - CompositionLocalProvider(LocalViewModelStoreOwner provides store) { - result = runCatching { viewModel(T::class.java) } - } - result!!.getOrThrow() +inline fun viewModelInStore(store: S): T { + var result: T? = null + CompositionLocalProvider(LocalViewModelStoreOwner provides store) { + result = viewModel(T::class.java) } + return result!! +} /** Try to fetch a viewModel with current context (i.e. activity) */ @Composable -inline fun safeActivityViewModel(): Result = runCatching { - val activity = LocalContext.current as? ViewModelStoreOwner - ?: throw IllegalStateException("Current context is not a viewModelStoreOwner.") - return viewModelInStore(activity) +inline fun safeActivityViewModel(): Result { + val context = LocalContext.current + return if (context is ViewModelStoreOwner) { + Result.success(viewModelInStore(context)) + } else { + Result.failure(IllegalStateException("Current context is not a viewModelStoreOwner.")) + } } /** Force fetch a viewModel inside context's viewModelStore */ diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherDetailsScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherDetailsScreen.kt index 9462a8b33..1a48c5d68 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherDetailsScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherDetailsScreen.kt @@ -38,7 +38,8 @@ import com.thewizrd.simpleweather.ui.utils.rememberFocusRequester fun WeatherDetailsScreen( backStackEntry: NavBackStackEntry, focusRequester: FocusRequester, - weatherDetails: Collection + weatherDetails: Collection, + iconProvider: String? = null ) { val lifecycleOwner = LocalLifecycleOwner.current val scrollStateViewModel: ScalingLazyListStateViewModel = viewModel(backStackEntry) @@ -57,7 +58,7 @@ fun WeatherDetailsScreen( ) { weatherDetails.forEach { item(key = it.detailsType) { - WeatherDetailItem(model = it) + WeatherDetailItem(model = it, iconProvider = iconProvider) } } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherForecastScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherForecastScreen.kt index 086fe1b5e..01cb87fbf 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherForecastScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherForecastScreen.kt @@ -29,7 +29,8 @@ import com.thewizrd.simpleweather.ui.theme.activityViewModel @Composable fun WeatherForecastScreen( backStackEntry: NavBackStackEntry, - focusRequester: FocusRequester + focusRequester: FocusRequester, + iconProvider: String? = null ) { val lifecycleOwner = LocalLifecycleOwner.current @@ -55,7 +56,7 @@ fun WeatherForecastScreen( ) { items(forecasts) { it?.let { - WeatherForecastPanel(model = it) + WeatherForecastPanel(model = it, iconProvider = iconProvider) } } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherHourlyForecastScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherHourlyForecastScreen.kt index d74a27319..644bd6c32 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherHourlyForecastScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherHourlyForecastScreen.kt @@ -29,7 +29,8 @@ import com.thewizrd.simpleweather.ui.theme.activityViewModel @Composable fun WeatherHourlyForecastScreen( backStackEntry: NavBackStackEntry, - focusRequester: FocusRequester + focusRequester: FocusRequester, + iconProvider: String? = null ) { val lifecycleOwner = LocalLifecycleOwner.current @@ -55,7 +56,7 @@ fun WeatherHourlyForecastScreen( ) { items(hourlyForecasts) { it?.let { - WeatherHourlyForecastPanel(model = it) + WeatherHourlyForecastPanel(model = it, iconProvider = iconProvider) } } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherMinutelyForecastScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherMinutelyForecastScreen.kt index d6677b329..a3ab89cf4 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherMinutelyForecastScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherMinutelyForecastScreen.kt @@ -29,7 +29,8 @@ import com.thewizrd.simpleweather.viewmodels.ForecastPanelsViewModel @Composable fun WeatherMinutelyForecastScreen( backStackEntry: NavBackStackEntry, - focusRequester: FocusRequester + focusRequester: FocusRequester, + iconProvider: String? = null ) { val lifecycleOwner = LocalLifecycleOwner.current @@ -51,7 +52,7 @@ fun WeatherMinutelyForecastScreen( contentPadding = PaddingValues(top = 48.dp) ) { items(minutelyForecasts) { - WeatherMinutelyForecastPanel(model = it) + WeatherMinutelyForecastPanel(model = it, iconProvider = iconProvider) } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNow.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNow.kt index eb1b563e3..687b05e29 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNow.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNow.kt @@ -128,7 +128,12 @@ fun WeatherNow( weather.weatherDetailsMap.values } - WeatherDetailsScreen(backStackEntry, swipeFocusRequester, detailItems) + WeatherDetailsScreen( + backStackEntry, + swipeFocusRequester, + detailItems, + iconProvider = weather.iconProvider + ) } composable( @@ -140,7 +145,11 @@ fun WeatherNow( }, ) ) { backStackEntry -> - WeatherForecastScreen(backStackEntry, swipeFocusRequester) + WeatherForecastScreen( + backStackEntry, + swipeFocusRequester, + iconProvider = weather.iconProvider + ) } composable( @@ -152,13 +161,21 @@ fun WeatherNow( }, ) ) { backStackEntry -> - WeatherHourlyForecastScreen(backStackEntry, swipeFocusRequester) + WeatherHourlyForecastScreen( + backStackEntry, + swipeFocusRequester, + iconProvider = weather.iconProvider + ) } composable( route = Screen.Precipitation.route, ) { backStackEntry -> - WeatherMinutelyForecastScreen(backStackEntry, swipeFocusRequester) + WeatherMinutelyForecastScreen( + backStackEntry, + swipeFocusRequester, + iconProvider = weather.iconProvider + ) } composable( diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNowScreen.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNowScreen.kt index 01bfdb8ad..b35f93f04 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNowScreen.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/ui/weather/WeatherNowScreen.kt @@ -1,5 +1,6 @@ package com.thewizrd.simpleweather.ui.weather +import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.content.res.Configuration @@ -76,6 +77,7 @@ import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.Text import androidx.wear.compose.navigation.rememberSwipeDismissableNavController import com.google.android.horologist.compose.layout.fillMaxRectangle +import com.thewizrd.common.controls.DetailItemViewModel import com.thewizrd.common.controls.ForecastItemViewModel import com.thewizrd.common.controls.HourlyForecastItemViewModel import com.thewizrd.common.controls.WeatherAlertViewModel @@ -95,6 +97,7 @@ import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.utils.getColorFromTempF import com.thewizrd.shared_resources.weatherdata.model.Condition import com.thewizrd.shared_resources.weatherdata.model.Location +import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.simpleweather.BuildConfig import com.thewizrd.simpleweather.R @@ -122,7 +125,9 @@ import com.thewizrd.simpleweather.viewmodels.WeatherNowStateModel import com.thewizrd.simpleweather.viewmodels.WeatherNowViewModel import com.thewizrd.simpleweather.wearable.WearableListenerActions import kotlinx.coroutines.launch +import com.thewizrd.shared_resources.R as sharedRes +@SuppressLint("LocalContextGetResourceValueCall") @Composable fun WeatherNowScreen( navController: NavHostController, @@ -203,6 +208,10 @@ fun WeatherNowScreen( curTemp = weather.curTemp, tempUnit = weather.tempUnit ) + // FeelsLike + weather.weatherDetailsMap[WeatherDetailsType.FEELSLIKE]?.let { + FeelsLikeText(it) + } // Condition weather.curCondition?.let { condition -> ConditionText(condition) @@ -376,12 +385,12 @@ private fun NoLocationsPrompt( ) { Spacer(modifier = Modifier.height(8.dp)) Icon( - painter = painterResource(R.drawable.ic_location_off_24dp), + painter = painterResource(sharedRes.drawable.ic_location_off_24dp), contentDescription = null, ) Spacer(modifier = Modifier.height(8.dp)) Text( - text = stringResource(id = R.string.prompt_location_not_set), + text = stringResource(id = sharedRes.string.prompt_location_not_set), textAlign = TextAlign.Center, style = MaterialTheme.typography.bodyLarge ) @@ -431,7 +440,7 @@ private fun AlertsBox(navController: NavHostController) { ) { Icon( modifier = Modifier.size(IconButtonDefaults.SmallIconSize), - painter = painterResource(id = R.drawable.ic_error_white), + painter = painterResource(id = sharedRes.drawable.ic_error_white), tint = MaterialTheme.colorScheme.onErrorContainer, contentDescription = null ) @@ -463,7 +472,7 @@ private fun ColumnScope.WeatherLocation( modifier = Modifier .size(18.dp) .align(Alignment.CenterVertically), - painter = painterResource(id = R.drawable.ic_place_white_24dp), + painter = painterResource(id = sharedRes.drawable.ic_place_white_24dp), contentDescription = null ) } @@ -519,6 +528,31 @@ private fun IconTempRow( } } +@Composable +private fun FeelsLikeText( + detail: DetailItemViewModel +) { + Text( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = dimensionResource(id = R.dimen.wnow_horizontal_padding), + vertical = 4.dp + ), + text = buildString { + append(detail.label) + append(": ") + append(detail.value) + }, + color = LocalContentColor.current.copy(alpha = 0.75f), + textAlign = TextAlign.Center, + overflow = TextOverflow.Ellipsis, + letterSpacing = 0.sp, + maxLines = 1, + style = MaterialTheme.typography.bodySmall + ) +} + @Composable private fun ConditionText( curCondition: String @@ -568,7 +602,7 @@ private fun HiLoLayout( modifier = Modifier .size(30.dp) .offset(x = (-4).dp), - painter = painterResource(id = R.drawable.wi_direction_up), + painter = painterResource(id = sharedRes.drawable.wi_direction_up), tint = Color(0xFFFF4500), contentDescription = null ) @@ -594,7 +628,7 @@ private fun HiLoLayout( modifier = Modifier .size(30.dp) .offset(x = (-4).dp), - painter = painterResource(id = R.drawable.wi_direction_down), + painter = painterResource(id = sharedRes.drawable.wi_direction_down), tint = Color(0xFF87CEFA), contentDescription = null ) @@ -633,14 +667,16 @@ private fun ConditionDetails( Row( modifier = Modifier.padding(4.dp) ) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 4.dp) .align(Alignment.CenterVertically), - painter = painterResource(id = R.drawable.wi_umbrella), - tint = colorResource(R.color.colorPrimaryLight), - contentDescription = null + weatherIcon = WeatherIcons.UMBRELLA, + iconProvider = weather.iconProvider, + tint = colorResource(sharedRes.color.colorPrimaryLight), + showAsMonochrome = true, + contentDescription = popData.label?.toString() ) Text( modifier = Modifier.align(Alignment.CenterVertically), @@ -648,7 +684,7 @@ private fun ConditionDetails( style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.End, maxLines = 1, - color = colorResource(R.color.colorPrimaryLight) + color = colorResource(sharedRes.color.colorPrimaryLight) ) } } @@ -659,15 +695,17 @@ private fun ConditionDetails( Row( modifier = Modifier.padding(4.dp) ) { - Icon( + WeatherIcon( modifier = Modifier .size(20.dp) .padding(end = 4.dp) .rotate(windData.iconRotation.toFloat()) .align(Alignment.CenterVertically), - painter = painterResource(id = R.drawable.wi_wind_direction), + weatherIcon = WeatherIcons.WIND_DIRECTION, + useDefaultIconProvider = true, tint = Color(0xFF20B2AA), - contentDescription = null + showAsMonochrome = true, + contentDescription = windData.label?.toString() ) Text( modifier = Modifier.align(Alignment.CenterVertically), @@ -825,7 +863,7 @@ private fun ForecastsButton( navController: NavHostController ) { NavigationButton( - label = stringResource(id = R.string.label_forecast), + label = stringResource(id = sharedRes.string.label_forecast), iconDrawableId = R.drawable.ic_date_range_black_24dp ) { navController.navigate(Screen.Forecast.route) @@ -837,7 +875,7 @@ private fun HourlyForecastsButton( navController: NavHostController ) { NavigationButton( - label = stringResource(id = R.string.label_hourlyforecast), + label = stringResource(id = sharedRes.string.label_hourlyforecast), iconDrawableId = R.drawable.ic_access_time_black_24dp ) { navController.navigate(Screen.HourlyForecast.route) @@ -849,8 +887,8 @@ private fun MinutelyForecastsButton( navController: NavHostController ) { NavigationButton( - label = stringResource(id = R.string.label_precipitation), - iconDrawableId = R.drawable.wi_raindrops + label = stringResource(id = sharedRes.string.label_precipitation), + iconDrawableId = sharedRes.drawable.wi_raindrops ) { navController.navigate(Screen.Precipitation.route) } @@ -861,7 +899,7 @@ private fun DetailsButton( navController: NavHostController ) { NavigationButton( - label = stringResource(id = R.string.label_details), + label = stringResource(id = sharedRes.string.label_details), iconDrawableId = R.drawable.ic_list_black_24dp ) { navController.navigate(Screen.Details.route) @@ -874,7 +912,7 @@ private fun DetailsTileEditorButton( ) { NavigationButton( label = stringResource(id = R.string.pref_title_detailstileeditor), - iconDrawableId = R.drawable.ic_mode_edit_white_24dp + iconDrawableId = sharedRes.drawable.ic_mode_edit_white_24dp ) { navController.navigate(Screen.DetailsTileEditor.route) } @@ -897,8 +935,8 @@ private fun SettingsButton( activity: Activity ) { NavigationButton( - label = stringResource(id = R.string.action_settings), - iconDrawableId = R.drawable.ic_settings_black_24dp + label = stringResource(id = sharedRes.string.action_settings), + iconDrawableId = sharedRes.drawable.ic_settings_black_24dp ) { activity.startActivity(Intent(activity, SettingsActivity::class.java)) } @@ -910,7 +948,7 @@ private fun OpenOnPhoneButton( ) { NavigationButton( label = stringResource(id = R.string.action_openonphone), - iconDrawableId = R.drawable.common_full_open_on_phone, + iconDrawableId = R.drawable.ic_mobile_arrow_right, onClick = onOpenOnPhone ) } @@ -984,18 +1022,29 @@ private fun PreviewWeatherNowScreen() { } val weather = remember { Weather().apply { + location = Location().apply { + name = "New York" + } condition = Condition().apply { icon = WeatherIcons.DAY_SUNNY tempF = 70f weather = "Sunny" highF = 75f lowF = 60f + windMph = 4f + windKph = 6.43f + windGustKph = 9f + windGustKph = 14.5f + windDegrees = 0 } - location = Location().apply { - name = "New York" + precipitation = Precipitation().apply { + pop = 5 } }.toUiModel() } + val feelsLikeDetail = remember { + DetailItemViewModel(WeatherDetailsType.FEELSLIKE, "71°") + } CompositionLocalProvider( LocalContentColor provides Color.White, @@ -1034,6 +1083,8 @@ private fun PreviewWeatherNowScreen() { tempUnit = "F" ) } + // FeelsLike + FeelsLikeText(feelsLikeDetail) // Condition ConditionText("Sunny") diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ConfirmationViewModel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ConfirmationViewModel.kt index 13671e886..2428d3ba9 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ConfirmationViewModel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ConfirmationViewModel.kt @@ -4,12 +4,13 @@ import androidx.annotation.DrawableRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.wear.compose.material3.ConfirmationDialogDefaults -import com.thewizrd.simpleweather.R +import com.squareup.moshi.JsonClass import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import androidx.wear.R as wearRes class ConfirmationViewModel : ViewModel() { private val _confirmationEventsFlow = MutableStateFlow(null) @@ -29,7 +30,7 @@ class ConfirmationViewModel : ViewModel() { fun showSuccess(message: String? = null) { _confirmationEventsFlow.update { ConfirmationData( - animatedVectorResId = R.drawable.confirmation_animation, + animatedVectorResId = wearRes.drawable.confirmation_animation, confirmationType = ConfirmationType.Success, message = message ) @@ -39,7 +40,7 @@ class ConfirmationViewModel : ViewModel() { fun showFailure(message: String? = null) { _confirmationEventsFlow.update { ConfirmationData( - animatedVectorResId = R.drawable.failure_animation, + animatedVectorResId = wearRes.drawable.failure_animation, confirmationType = ConfirmationType.Failure, message = message ) @@ -49,7 +50,7 @@ class ConfirmationViewModel : ViewModel() { fun showOpenOnPhone(message: String? = null) { _confirmationEventsFlow.update { ConfirmationData( - animatedVectorResId = R.drawable.open_on_phone_animation, + animatedVectorResId = wearRes.drawable.open_on_phone_animation, confirmationType = ConfirmationType.OpenOnPhone, message = message ) @@ -61,6 +62,7 @@ class ConfirmationViewModel : ViewModel() { } } +@JsonClass(generateAdapter = true) data class ConfirmationData( val message: String? = null, @DrawableRes val iconResId: Int? = null, diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ForecastPanelsViewModel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ForecastPanelsViewModel.kt index d043add33..3b0adba66 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ForecastPanelsViewModel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/ForecastPanelsViewModel.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.lastOrNull import kotlinx.coroutines.launch import java.time.ZoneOffset @@ -75,7 +76,8 @@ class ForecastPanelsViewModel(app: Application) : AndroidViewModel(app) { flowScope?.cancel() currentForecastsData = - weatherDAO.getLiveForecastData(location.query).distinctUntilChanged() + weatherDAO.getLiveForecastData(location.query).filterNotNull() + .distinctUntilChanged() val hrInterval = weatherModule.weatherManager.getHourlyForecastInterval() currentHrForecastsData = @@ -89,6 +91,7 @@ class ForecastPanelsViewModel(app: Application) : AndroidViewModel(app) { flowScope?.launch { currentForecastsData.collect { forecasts.emit(forecastMapper.apply(it)) + minutelyForecasts.emit(minForecastMapper.apply(it)) } } flowScope?.launch { diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/MinutelyForecastViewModel.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/MinutelyForecastViewModel.kt index 5beee1279..0ffead670 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/MinutelyForecastViewModel.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/viewmodels/MinutelyForecastViewModel.kt @@ -4,7 +4,6 @@ import android.text.format.DateFormat import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.appLib -import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.ConversionMethods import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.utils.LocaleUtils @@ -14,7 +13,8 @@ import java.text.DecimalFormat class MinutelyForecastViewModel(minutely: MinutelyForecast) { val date: String - val rainAmount: String + val precipAmount: String + val isSnow: Boolean init { val context = appLib.context @@ -33,35 +33,38 @@ class MinutelyForecastViewModel(minutely: MinutelyForecast) { } date = minutely.date.format(fmt) - if (minutely.rainMm != null) { - val unit = settingsMgr.getPrecipitationUnit() - val precipValue: Float - val precipUnit: String + val raimMm = minutely.rainMm ?: 0f + val snowMm = minutely.snowMm ?: 0f + isSnow = snowMm > raimMm + val precipValueMm = if (isSnow) snowMm else raimMm - when (unit) { - Units.INCHES -> { - precipValue = ConversionMethods.mmToIn(minutely.rainMm) - precipUnit = context.getString(R.string.unit_in) - } - Units.MILLIMETERS -> { - precipValue = minutely.rainMm - precipUnit = context.getString(R.string.unit_mm) - } - else -> { - precipValue = ConversionMethods.mmToIn(minutely.rainMm) - precipUnit = context.getString(R.string.unit_in) - } + val unit = settingsMgr.getPrecipitationUnit() + val precipValue: Float + val precipUnit: String + + when (unit) { + Units.INCHES -> { + precipValue = ConversionMethods.mmToIn(precipValueMm) + precipUnit = context.getString(R.string.unit_in) } - rainAmount = String.format( - LocaleUtils.getLocale(), - "%s %s", - df.format(precipValue.toDouble()), - precipUnit - ) - } else { - rainAmount = WeatherIcons.EM_DASH + Units.MILLIMETERS -> { + precipValue = precipValueMm + precipUnit = context.getString(R.string.unit_mm) + } + + else -> { + precipValue = ConversionMethods.mmToIn(precipValueMm) + precipUnit = context.getString(R.string.unit_in) + } } + + precipAmount = String.format( + LocaleUtils.getLocale(), + "%s %s", + df.format(precipValue.toDouble()), + precipUnit + ) } override fun equals(other: Any?): Boolean { @@ -71,14 +74,16 @@ class MinutelyForecastViewModel(minutely: MinutelyForecast) { other as MinutelyForecastViewModel if (date != other.date) return false - if (rainAmount != other.rainAmount) return false + if (precipAmount != other.precipAmount) return false + if (isSnow != other.isSnow) return false return true } override fun hashCode(): Int { var result = date.hashCode() - result = 31 * result + rainAmount.hashCode() + result = 31 * result + precipAmount.hashCode() + result = 31 * result + isSnow.hashCode() return result } } \ No newline at end of file diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/AQIComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/AQIComplicationService.kt index c79d90117..ff4c58926 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/AQIComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/AQIComplicationService.kt @@ -9,22 +9,27 @@ import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.RangedValueComplicationData import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType import androidx.wear.watchface.complications.datasource.ComplicationRequest import com.thewizrd.common.controls.AirQualityViewModel +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.common.weatherdata.WeatherDataLoader import com.thewizrd.common.weatherdata.WeatherRequest import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.AirQualityUtils.getIndexFromData import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.weatherdata.model.AirQuality -import com.thewizrd.simpleweather.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.withContext import timber.log.Timber import java.time.LocalDate import kotlin.math.max +import com.thewizrd.shared_resources.R as sharedRes class AQIComplicationService : BaseWeatherComplicationService() { companion object { @@ -37,7 +42,8 @@ class AQIComplicationService : BaseWeatherComplicationService() { ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT ) - private val complicationIconResId = R.drawable.wi_cloud + + private val complicationIcon = WeatherIcons.AIR_QUALITY override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData { if (!supportedComplicationTypes.contains(request.complicationType)) { @@ -95,17 +101,33 @@ class AQIComplicationService : BaseWeatherComplicationService() { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 57f, 0f, 301f, PlainComplicationText.Builder("Air Quality: 57, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("57").build() ).setValueType( RangedValueComplicationData.TYPE_RATING @@ -116,11 +138,16 @@ class AQIComplicationService : BaseWeatherComplicationService() { PlainComplicationText.Builder("57").build(), PlainComplicationText.Builder("Air Quality: 57, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -129,11 +156,16 @@ class AQIComplicationService : BaseWeatherComplicationService() { ).setTitle( PlainComplicationText.Builder("57, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -146,6 +178,8 @@ class AQIComplicationService : BaseWeatherComplicationService() { return null } + val wim = sharedDeps.weatherIconsManager + val aqiModel = aqi?.apply { if (index == null) index = getIndexFromData() } ?.takeIf { it.index != null }?.let { AirQualityViewModel(it) } val aqiStr = aqiModel?.let { "${it.index}, ${it.level}" } ?: WeatherIcons.EM_DASH @@ -153,19 +187,34 @@ class AQIComplicationService : BaseWeatherComplicationService() { val aqiProgress = aqiModel?.progress?.toFloat() ?: 0f val aqiProgressMax = aqiModel?.let { max(it.progressMax, it.progress).toFloat() } ?: 301f + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( aqiProgress, 0f, aqiProgressMax, PlainComplicationText.Builder( - "${getString(R.string.label_airquality_short)}: $aqiStr" + "${getString(sharedRes.string.label_airquality_short)}: $aqiStr" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder(aqiShortStr).build() ).setTapAction( getTapIntent(this) @@ -177,32 +226,42 @@ class AQIComplicationService : BaseWeatherComplicationService() { ShortTextComplicationData.Builder( PlainComplicationText.Builder(aqiShortStr).build(), PlainComplicationText.Builder( - "${getString(R.string.label_airquality_short)}: $aqiStr" + "${getString(sharedRes.string.label_airquality_short)}: $aqiStr" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_airquality_short)) + PlainComplicationText.Builder(getString(sharedRes.string.label_airquality_short)) .build(), PlainComplicationText.Builder( - "${getString(R.string.label_airquality_short)}: $aqiStr" + "${getString(sharedRes.string.label_airquality_short)}: $aqiStr" ).build() ).setTitle( PlainComplicationText.Builder(aqiStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/BeaufortComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/BeaufortComplicationService.kt index 886391d57..a718e4c61 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/BeaufortComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/BeaufortComplicationService.kt @@ -16,7 +16,6 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.controls.BeaufortViewModel import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride @@ -24,7 +23,9 @@ import com.thewizrd.shared_resources.utils.getBeaufortScale import com.thewizrd.shared_resources.weatherdata.model.Beaufort import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R +import kotlin.math.max +import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -39,24 +40,41 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_strong_wind override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.WIND_BEAUFORT_3 + + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 3f, 0f, 12f, PlainComplicationText.Builder("Beaufort: 3, Gentle Breeze").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("3").build() ).setValueType( RangedValueComplicationData.TYPE_RATING @@ -67,11 +85,16 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { PlainComplicationText.Builder("3").build(), PlainComplicationText.Builder("Beaufort: 3, Gentle Breeze").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -80,35 +103,28 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { ).setTitle( PlainComplicationText.Builder("3, Gentle Breeze").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource(this, R.drawable.wi_wind_beaufort_3) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), PlainComplicationText.Builder("Beaufort: 3, Gentle Breeze").build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_beaufort_3 - ) - ), - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithResource(this, R.drawable.wi_wind_beaufort_3) - .setTint(Colors.WHITESMOKE) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder("Beaufort: 3, Gentle Breeze").build() ).build() } @@ -127,37 +143,52 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { return null } - val beaufort = weather.condition!!.beaufort ?: hourlyForecast?.extras?.windMph?.let { - Beaufort(getBeaufortScale(it)) + val beaufort = weather.condition?.beaufort ?: hourlyForecast?.extras?.windMph?.let { + Beaufort(getBeaufortScale(it.roundToInt())) } val beaufortModel = beaufort?.let { BeaufortViewModel(it) } val wim = sharedDeps.weatherIconsManager - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) val contentDescription = PlainComplicationText.Builder( beaufortModel?.let { "${beaufortModel.beaufort.label}: ${beaufortModel.progress}, ${beaufortModel.beaufort.value}" } - ?: "${getString(R.string.label_beaufort)}: ${getString(R.string.weather_notavailable)}" + ?: "${getString(sharedRes.string.label_beaufort)}: ${getString(sharedRes.string.weather_notavailable)}" ).build() val progressShortStr = beaufortModel?.progress?.toString() ?: WeatherIcons.EM_DASH val progressStr = beaufortModel?.let { "${it.progress}, ${it.beaufort.value}" } ?: WeatherIcons.EM_DASH + val beaufortProgress = beaufortModel?.progress?.toFloat() ?: 0f + val beaufortProgressMax = + beaufortModel?.let { max(it.progressMax, it.progress).toFloat() } ?: 12f val beaufortIcon = beaufortModel?.beaufort?.icon ?: WeatherIcons.WIND_BEAUFORT_0 + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(beaufortIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(beaufortIcon) + ) + ) + return when (dataType) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( - beaufortModel?.progress?.toFloat() ?: 0f, - 0f, - beaufortModel?.progressMax?.toFloat() ?: 1f, + beaufortProgress, 0f, beaufortProgressMax, contentDescription ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setText( PlainComplicationText.Builder(progressShortStr).build() ).setTapAction( getTapIntent(this) @@ -170,40 +201,45 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { PlainComplicationText.Builder(progressShortStr).build(), contentDescription ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_beaufort)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_beaufort)) + .build(), contentDescription ).setTitle( PlainComplicationText.Builder( progressStr ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource( - this, - wip.getWeatherIconResource(beaufortIcon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), contentDescription ).setTapAction( getTapIntent(this) @@ -211,21 +247,9 @@ class BeaufortComplicationService : WeatherHourlyForecastComplicationService() { } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - wim.getWeatherIconResource(beaufortIcon) - ) - ), - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithResource( - this, - wip.getWeatherIconResource(beaufortIcon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), contentDescription ).setTapAction( getTapIntent(this) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationFeelsLikeWeatherComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationFeelsLikeWeatherComplicationService.kt index 4937d55e8..2b36bcf17 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationFeelsLikeWeatherComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationFeelsLikeWeatherComplicationService.kt @@ -15,7 +15,6 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride @@ -23,8 +22,9 @@ import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.Forecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import com.thewizrd.weather_api.weatherModule +import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastComplicationService() { companion object { @@ -38,24 +38,39 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_day_sunny override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.DAY_SUNNY + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("70°").build(), PlainComplicationText.Builder("70° - Sunny").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } ComplicationType.LONG_TEXT -> { @@ -65,30 +80,30 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli ).setTitle( PlainComplicationText.Builder("70°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE), - SmallImageType.ICON - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } @@ -122,14 +137,12 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli val feelsLike = if (weather.condition?.feelslikeF != null && weather.condition!!.feelslikeF != weather.condition!!.feelslikeC) { val temp = - if (isFahrenheit) Math.round(weather.condition!!.feelslikeF) else Math.round( - weather.condition!!.feelslikeC - ) + if (isFahrenheit) weather.condition!!.feelslikeF.roundToInt() else weather.condition!!.feelslikeC.roundToInt() String.format(LocaleUtils.getLocale(), "%d°", temp) } else { WeatherIcons.EM_DASH } - val feelsLikeLabel = getString(R.string.label_feelslike) + val feelsLikeLabel = getString(sharedRes.string.label_feelslike) val tempUnit = if (isFahrenheit) Units.FAHRENHEIT else Units.CELSIUS @@ -145,6 +158,8 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli val wim = sharedDeps.weatherIconsManager val weatherIcon = wim.getWeatherIconResource(weather.condition!!.icon) + val monochromaticIcon = Icon.createWithResource(this, weatherIcon) + .setTint(Colors.WHITESMOKE) val icon = Icon.createWithBitmap( ImageUtils.bitmapFromDrawable( getThemeContextOverride(false), @@ -167,21 +182,20 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli MonochromaticImage.Builder(icon).apply { // Weather Icon if (!wim.isFontIcon) { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this@CurrentLocationFeelsLikeWeatherComplicationService, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + setAmbientImage(monochromaticIcon) } } .build() ) + if (!wim.isFontIcon) { + builder.setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + builder.setTapAction(getTapIntent(this)) return builder.build() } @@ -200,18 +214,9 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli MonochromaticImage.Builder(icon).build() ) } else { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) builder.setSmallImage( SmallImage.Builder(icon, SmallImageType.ICON) - .setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + .setAmbientImage(monochromaticIcon) .build() ) } @@ -221,16 +226,8 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli } ComplicationType.MONOCHROMATIC_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource( - this, - wip.getWeatherIconResource(weather.condition!!.icon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), contentDescription ).setTapAction( getTapIntent(this) @@ -238,21 +235,10 @@ class CurrentLocationFeelsLikeWeatherComplicationService : WeatherForecastCompli } ComplicationType.SMALL_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return SmallImageComplicationData.Builder( - SmallImage.Builder( - icon, - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), contentDescription ).setTapAction( getTapIntent(this) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationWeatherComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationWeatherComplicationService.kt index 3c6a63bef..f300262c9 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationWeatherComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/CurrentLocationWeatherComplicationService.kt @@ -15,7 +15,6 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride @@ -23,7 +22,6 @@ import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.Forecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import com.thewizrd.weather_api.weatherModule class CurrentLocationWeatherComplicationService : WeatherForecastComplicationService() { @@ -38,24 +36,39 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_day_sunny override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.DAY_SUNNY + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("70°").build(), PlainComplicationText.Builder("70° - Sunny").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } ComplicationType.LONG_TEXT -> { @@ -65,30 +78,30 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer ).setTitle( PlainComplicationText.Builder("70°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE), - SmallImageType.ICON - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } @@ -134,6 +147,8 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer val wim = sharedDeps.weatherIconsManager val weatherIcon = wim.getWeatherIconResource(weather.condition!!.icon) + val monochromaticIcon = Icon.createWithResource(this, weatherIcon) + .setTint(Colors.WHITESMOKE) val icon = Icon.createWithBitmap( ImageUtils.bitmapFromDrawable( getThemeContextOverride(false), @@ -154,21 +169,20 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer MonochromaticImage.Builder(icon).apply { // Weather Icon if (!wim.isFontIcon) { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this@CurrentLocationWeatherComplicationService, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + setAmbientImage(monochromaticIcon) } } .build() ) + if (!wim.isFontIcon) { + builder.setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + builder.setTapAction(getTapIntent(this)) return builder.build() } @@ -189,18 +203,9 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer MonochromaticImage.Builder(icon).build() ) } else { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) builder.setSmallImage( SmallImage.Builder(icon, SmallImageType.ICON) - .setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + .setAmbientImage(monochromaticIcon) .build() ) } @@ -210,16 +215,8 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer } ComplicationType.MONOCHROMATIC_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource( - this, - wip.getWeatherIconResource(weather.condition!!.icon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), contentDescription ).setTapAction( getTapIntent(this) @@ -227,21 +224,10 @@ class CurrentLocationWeatherComplicationService : WeatherForecastComplicationSer } ComplicationType.SMALL_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return SmallImageComplicationData.Builder( - SmallImage.Builder( - icon, - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), contentDescription ).setTapAction( getTapIntent(this) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/DewPointComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/DewPointComplicationService.kt index afcbcee33..6365496e7 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/DewPointComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/DewPointComplicationService.kt @@ -8,14 +8,19 @@ import androidx.wear.watchface.complications.data.MonochromaticImage import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes class DewPointComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -24,37 +29,60 @@ class DewPointComplicationService : WeatherHourlyForecastComplicationService() { override val supportedComplicationTypes = setOf(ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT) - private val complicationIconResId = R.drawable.wi_thermometer + + private val complicationIcon = WeatherIcons.THERMOMETER override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("38°").build(), PlainComplicationText.Builder("Dew Point: 38°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_dewpoint)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_dewpoint)) + .build(), PlainComplicationText.Builder("Dew Point: 38°").build() ).setTitle( PlainComplicationText.Builder("38°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -71,6 +99,8 @@ class DewPointComplicationService : WeatherHourlyForecastComplicationService() { return null } + val wim = sharedDeps.weatherIconsManager + val dewPointF = weather.atmosphere?.dewpointF ?: hourlyForecast?.extras?.dewpointF val dewPointC = weather.atmosphere?.dewpointC ?: hourlyForecast?.extras?.dewpointC @@ -83,36 +113,57 @@ class DewPointComplicationService : WeatherHourlyForecastComplicationService() { String.format("$tempVal°$tempUnit") } + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder(tempStr).build(), PlainComplicationText.Builder( - String.format("%s: %s", getString(R.string.label_dewpoint), tempStr) + String.format("%s: %s", getString(sharedRes.string.label_dewpoint), tempStr) ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_dewpoint)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_dewpoint)) + .build(), PlainComplicationText.Builder( - String.format("%s: %s", getString(R.string.label_dewpoint), tempStr) + String.format("%s: %s", getString(sharedRes.string.label_dewpoint), tempStr) ).build() ).setTitle( PlainComplicationText.Builder(tempStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/FeelsLikeComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/FeelsLikeComplicationService.kt index f1c241f1f..5039bebfa 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/FeelsLikeComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/FeelsLikeComplicationService.kt @@ -8,14 +8,19 @@ import androidx.wear.watchface.complications.data.MonochromaticImage import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes class FeelsLikeComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -24,37 +29,60 @@ class FeelsLikeComplicationService : WeatherHourlyForecastComplicationService() override val supportedComplicationTypes = setOf(ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT) - private val complicationIconResId = R.drawable.wi_thermometer + + private val complicationIcon = WeatherIcons.THERMOMETER override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("75°").build(), PlainComplicationText.Builder("Feels like: 75°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_feelslike)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_feelslike)) + .build(), PlainComplicationText.Builder("Feels like: 75°").build() ).setTitle( PlainComplicationText.Builder("75°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -71,6 +99,8 @@ class FeelsLikeComplicationService : WeatherHourlyForecastComplicationService() return null } + val wim = sharedDeps.weatherIconsManager + val feelsLikeF = weather.condition?.feelslikeF ?: hourlyForecast?.extras?.feelslikeF val feelsLikeC = weather.condition?.feelslikeC ?: hourlyForecast?.extras?.feelslikeC @@ -83,36 +113,65 @@ class FeelsLikeComplicationService : WeatherHourlyForecastComplicationService() String.format("$tempVal°$tempUnit") } + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder(tempStr).build(), PlainComplicationText.Builder( - String.format("%s: %s", getString(R.string.label_feelslike), tempStr) + String.format( + "%s: %s", + getString(sharedRes.string.label_feelslike), + tempStr + ) ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_feelslike)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_feelslike)) + .build(), PlainComplicationText.Builder( - String.format("%s: %s", getString(R.string.label_feelslike), tempStr) + String.format( + "%s: %s", + getString(sharedRes.string.label_feelslike), + tempStr + ) ).build() ).setTitle( PlainComplicationText.Builder(tempStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/HumidityComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/HumidityComplicationService.kt index 31a1db92c..4ecbc0fa5 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/HumidityComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/HumidityComplicationService.kt @@ -9,11 +9,16 @@ import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.RangedValueComplicationData import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R as sharedRes class HumidityComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -26,25 +31,42 @@ class HumidityComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT ) - private val complicationIconResId = R.drawable.wi_humidity + + private val complicationIcon = WeatherIcons.HUMIDITY override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 75f, 0f, 100f, - PlainComplicationText.Builder("${getString(R.string.label_humidity)}: 75%") + PlainComplicationText.Builder("${getString(sharedRes.string.label_humidity)}: 75%") .build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("75%").build() ).setValueType( RangedValueComplicationData.TYPE_PERCENTAGE @@ -53,28 +75,39 @@ class HumidityComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("75%").build(), - PlainComplicationText.Builder("${getString(R.string.label_humidity)}: 75%") + PlainComplicationText.Builder("${getString(sharedRes.string.label_humidity)}: 75%") .build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_humidity)).build(), - PlainComplicationText.Builder("${getString(R.string.label_humidity)}: 75%") + PlainComplicationText.Builder(getString(sharedRes.string.label_humidity)) + .build(), + PlainComplicationText.Builder("${getString(sharedRes.string.label_humidity)}: 75%") .build() ).setTitle( PlainComplicationText.Builder("75%").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -91,22 +124,39 @@ class HumidityComplicationService : WeatherHourlyForecastComplicationService() { return null } + val wim = sharedDeps.weatherIconsManager + val humidityPct = weather.atmosphere?.humidity ?: hourlyForecast?.extras?.humidity val humidityStr = humidityPct?.let { "${it}%" } ?: WeatherIcons.EM_DASH + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( humidityPct?.toFloat() ?: 0f, 0f, 100f, PlainComplicationText.Builder( - "${getString(R.string.label_humidity)}: $humidityStr" + "${getString(sharedRes.string.label_humidity)}: $humidityStr" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder(humidityStr).build() ).setValueType( RangedValueComplicationData.TYPE_PERCENTAGE @@ -118,31 +168,42 @@ class HumidityComplicationService : WeatherHourlyForecastComplicationService() { ShortTextComplicationData.Builder( PlainComplicationText.Builder(humidityStr).build(), PlainComplicationText.Builder( - "${getString(R.string.label_humidity)}: $humidityStr" + "${getString(sharedRes.string.label_humidity)}: $humidityStr" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_humidity)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_humidity)) + .build(), PlainComplicationText.Builder( - "${getString(R.string.label_humidity)}: $humidityStr" + "${getString(sharedRes.string.label_humidity)}: $humidityStr" ).build() ).setTitle( PlainComplicationText.Builder(humidityStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PrecipitationComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PrecipitationComplicationService.kt index 823127465..50ea1b5d7 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PrecipitationComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PrecipitationComplicationService.kt @@ -9,11 +9,16 @@ import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.RangedValueComplicationData import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R +import com.thewizrd.shared_resources.R as sharedRes class PrecipitationComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -26,24 +31,41 @@ class PrecipitationComplicationService : WeatherHourlyForecastComplicationServic ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT ) - private val complicationIconResId = R.drawable.wi_umbrella + + private val complicationIcon = WeatherIcons.UMBRELLA override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 50f, 0f, 100f, PlainComplicationText.Builder("Chance: 50%").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("50%").build() ).setValueType( RangedValueComplicationData.TYPE_PERCENTAGE @@ -54,11 +76,16 @@ class PrecipitationComplicationService : WeatherHourlyForecastComplicationServic PlainComplicationText.Builder("50%").build(), PlainComplicationText.Builder("Chance: 50%").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -67,11 +94,16 @@ class PrecipitationComplicationService : WeatherHourlyForecastComplicationServic ).setTitle( PlainComplicationText.Builder("50%").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -88,20 +120,37 @@ class PrecipitationComplicationService : WeatherHourlyForecastComplicationServic return null } + val wim = sharedDeps.weatherIconsManager + val popChance = weather.precipitation?.pop ?: hourlyForecast?.extras?.pop val popChanceStr = popChance?.let { "${it}%" } ?: WeatherIcons.EM_DASH + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( popChance?.toFloat() ?: 0f, 0f, 100f, - PlainComplicationText.Builder(getString(R.string.label_chance)).build() + PlainComplicationText.Builder(getString(sharedRes.string.label_chance)).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder(popChanceStr).build() ).setValueType( RangedValueComplicationData.TYPE_PERCENTAGE @@ -113,31 +162,41 @@ class PrecipitationComplicationService : WeatherHourlyForecastComplicationServic ShortTextComplicationData.Builder( PlainComplicationText.Builder(popChanceStr).build(), PlainComplicationText.Builder( - "${getString(R.string.label_chance)}: $popChanceStr" + "${getString(sharedRes.string.label_chance)}: $popChanceStr" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_chance)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_chance)).build(), PlainComplicationText.Builder( - "${getString(R.string.label_chance)}: $popChanceStr" + "${getString(sharedRes.string.label_chance)}: $popChanceStr" ).build() ).setTitle( PlainComplicationText.Builder(popChanceStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PressureComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PressureComplicationService.kt index a9fd2d525..cf9e46e3f 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PressureComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/PressureComplicationService.kt @@ -9,16 +9,23 @@ import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.RangedValueComplicationData import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.utils.ConversionMethods import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import java.text.DecimalFormat +import kotlin.math.max +import kotlin.math.min +import com.thewizrd.shared_resources.R as sharedRes class PressureComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -31,24 +38,41 @@ class PressureComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT ) - private val complicationIconResId = R.drawable.wi_barometer + + private val complicationIcon = WeatherIcons.BAROMETER override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 30.3f, 26f, 32f, PlainComplicationText.Builder("Pressure: 30.3 inHg").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("30.3 in").build() ).build() } @@ -58,25 +82,36 @@ class PressureComplicationService : WeatherHourlyForecastComplicationService() { PlainComplicationText.Builder("30.3 in").build(), PlainComplicationText.Builder("Pressure: 30.3 inHg").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_pressure)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_pressure)) + .build(), PlainComplicationText.Builder("Pressure: 30.3 inHg").build() ).setTitle( PlainComplicationText.Builder("30.3 inHg").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { @@ -114,25 +149,25 @@ class PressureComplicationService : WeatherHourlyForecastComplicationService() { when (unit) { Units.INHG -> { pressureVal = df.format(pressureIn) - pressureUnit = getString(R.string.unit_inHg) - pressureUnitShort = getString(R.string.unit_in) + pressureUnit = getString(sharedRes.string.unit_inHg) + pressureUnitShort = getString(sharedRes.string.unit_in) } Units.MILLIBAR -> { pressureVal = df.format(pressureMb) - pressureUnit = getString(R.string.unit_mBar).also { pressureUnitShort = it } + pressureUnit = getString(sharedRes.string.unit_mBar).also { pressureUnitShort = it } } Units.MMHG -> { pressureVal = df.format(ConversionMethods.inHgToMmHg(pressureIn)) - pressureUnit = getString(R.string.unit_mmHg) - pressureUnitShort = getString(R.string.unit_mm) + pressureUnit = getString(sharedRes.string.unit_mmHg) + pressureUnitShort = getString(sharedRes.string.unit_mm) } else -> { pressureVal = df.format(pressureIn) - pressureUnit = getString(R.string.unit_inHg) - pressureUnitShort = getString(R.string.unit_in) + pressureUnit = getString(sharedRes.string.unit_inHg) + pressureUnitShort = getString(sharedRes.string.unit_in) } } @@ -145,25 +180,46 @@ class PressureComplicationService : WeatherHourlyForecastComplicationService() { private fun buildUpdate( dataType: ComplicationType, - pressureStr: String? = null, pressureStrShort: String? = null, pressureVal: Float? = null + pressureStr: String? = null, pressureStrShort: String? = null, pressureInVal: Float? = null ): ComplicationData? { + val wim = sharedDeps.weatherIconsManager + + val pressureProgress = pressureInVal ?: 26f + val pressureMin = min(pressureProgress, 26f) + val pressureMax = max(pressureProgress, 32f) + + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( - pressureVal ?: 26f, 26f, 32f, + pressureProgress, pressureMin, pressureMax, PlainComplicationText.Builder( String.format( "%s: %s", - getString(R.string.label_pressure), - pressureStr ?: getString(R.string.weather_notavailable) + getString(sharedRes.string.label_pressure), + pressureStr ?: getString(sharedRes.string.weather_notavailable) ) ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder(pressureStrShort ?: WeatherIcons.EM_DASH) .build() ).setTapAction( @@ -178,38 +234,49 @@ class PressureComplicationService : WeatherHourlyForecastComplicationService() { PlainComplicationText.Builder( String.format( "%s: %s", - getString(R.string.label_pressure), - pressureStr ?: getString(R.string.weather_notavailable) + getString(sharedRes.string.label_pressure), + pressureStr ?: getString(sharedRes.string.weather_notavailable) ) ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_pressure)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_pressure)) + .build(), PlainComplicationText.Builder( String.format( "%s: %s", - getString(R.string.label_pressure), - pressureStr ?: getString(R.string.weather_notavailable) + getString(sharedRes.string.label_pressure), + pressureStr ?: getString(sharedRes.string.weather_notavailable) ) ).build() ).setTitle( PlainComplicationText.Builder(pressureStr ?: WeatherIcons.EM_DASH).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/SunriseSunsetComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/SunriseSunsetComplicationService.kt index 3ccd69486..d1a7c6cea 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/SunriseSunsetComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/SunriseSunsetComplicationService.kt @@ -9,15 +9,20 @@ import androidx.wear.watchface.complications.data.MonochromaticImage import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import java.time.LocalDateTime import java.time.ZonedDateTime +import com.thewizrd.shared_resources.R as sharedRes class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -32,17 +37,34 @@ class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationServic return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.SUNSET + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("6:05 PM").build(), PlainComplicationText.Builder("Sunset: 6:05 PM").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, R.drawable.wi_sunset) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { @@ -52,11 +74,16 @@ class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationServic ).setTitle( PlainComplicationText.Builder("6:05 PM").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, R.drawable.wi_sunset) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { @@ -74,6 +101,8 @@ class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationServic return null } + val wim = sharedDeps.weatherIconsManager + val sunrise = weather.astronomy?.sunrise val sunset = weather.astronomy?.sunset @@ -91,40 +120,55 @@ class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationServic } val text: String - val complicationIconResId: Int + val complicationIcon: String val desc: String if (sunset != null && sunrise != null) { if (now.toLocalTime() > sunrise.toLocalTime()) { text = sunset.format(fmt) - complicationIconResId = R.drawable.wi_sunset - desc = getString(R.string.label_sunset) + complicationIcon = WeatherIcons.SUNSET + desc = getString(sharedRes.string.label_sunset) } else { text = sunrise.format(fmt) - complicationIconResId = R.drawable.wi_sunrise - desc = getString(R.string.label_sunrise) + complicationIcon = WeatherIcons.SUNRISE + desc = getString(sharedRes.string.label_sunrise) } } else if (sunset != null) { text = sunset.format(fmt) - complicationIconResId = R.drawable.wi_sunset - desc = getString(R.string.label_sunset) + complicationIcon = WeatherIcons.SUNSET + desc = getString(sharedRes.string.label_sunset) } else { text = sunrise?.format(fmt) ?: WeatherIcons.EM_DASH - complicationIconResId = R.drawable.wi_sunrise - desc = getString(R.string.label_sunrise) + complicationIcon = WeatherIcons.SUNRISE + desc = getString(sharedRes.string.label_sunrise) } + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (dataType) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder(text).build(), PlainComplicationText.Builder("$desc: $text").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } @@ -136,11 +180,16 @@ class SunriseSunsetComplicationService : WeatherHourlyForecastComplicationServic ).setTitle( PlainComplicationText.Builder(text).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/UVComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/UVComplicationService.kt index 8286fdbdb..335f7db1f 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/UVComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/UVComplicationService.kt @@ -9,14 +9,19 @@ import androidx.wear.watchface.complications.data.NoDataComplicationData import androidx.wear.watchface.complications.data.PlainComplicationText import androidx.wear.watchface.complications.data.RangedValueComplicationData import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.data.SmallImage +import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.controls.UVIndexViewModel +import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors +import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.UV import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import kotlin.math.max +import com.thewizrd.shared_resources.R as sharedRes class UVComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -29,24 +34,41 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT ) - private val complicationIconResId = R.drawable.wi_day_sunny override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.UV_INDEX_3 + + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.RANGED_VALUE -> { RangedValueComplicationData.Builder( 3f, 0f, 11f, PlainComplicationText.Builder("UV Index: 3, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.setText( PlainComplicationText.Builder("3").build() ).setTitle( PlainComplicationText.Builder("UV").build() @@ -59,24 +81,34 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { PlainComplicationText.Builder("3").build(), PlainComplicationText.Builder("UV Index: 3, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_uv)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_uv)).build(), PlainComplicationText.Builder("UV Index: 3, Moderate").build() ).setTitle( PlainComplicationText.Builder("3, Moderate").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } else -> { null @@ -93,6 +125,8 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { return null } + val wim = sharedDeps.weatherIconsManager + val uvIndex = weather.condition?.uv?.index ?: hourlyForecast?.extras?.uvIndex val uvModel = uvIndex?.let { UVIndexViewModel(UV(it)) } val uvStr = @@ -100,7 +134,17 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { val uvIdxStr = uvModel?.index?.toString() ?: WeatherIcons.EM_DASH val uvProgress = uvModel?.progress?.toFloat() ?: 0f val uvProgressMax = uvModel?.let { max(it.progressMax, it.progress).toFloat() } ?: 11f - val contentDescription = "${getString(R.string.label_uv)}: $uvStr" + val contentDescription = "${getString(sharedRes.string.label_uv)}: $uvStr" + val uvIcon = uvModel?.icon ?: WeatherIcons.UV_INDEX + + val monochromaticIcon = Icon.createWithResource(this, wim.getWeatherIconResource(uvIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(uvIcon) + ) + ) return when (dataType) { ComplicationType.RANGED_VALUE -> { @@ -110,11 +154,16 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { contentDescription ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setText( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setText( PlainComplicationText.Builder(uvIdxStr).build() ).setTitle( PlainComplicationText.Builder("UV").build() @@ -131,28 +180,38 @@ class UVComplicationService : WeatherHourlyForecastComplicationService() { contentDescription ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_uv)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_uv)).build(), PlainComplicationText.Builder( contentDescription ).build() ).setTitle( PlainComplicationText.Builder(uvStr).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setTapAction( getTapIntent(this) ).build() } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherComplicationService.kt index d8d615217..3e3f7aa00 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherComplicationService.kt @@ -15,7 +15,6 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride @@ -23,8 +22,8 @@ import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.Forecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import com.thewizrd.weather_api.weatherModule +import com.thewizrd.shared_resources.R as sharedRes class WeatherComplicationService : WeatherForecastComplicationService() { companion object { @@ -38,24 +37,39 @@ class WeatherComplicationService : WeatherForecastComplicationService() { ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_day_sunny override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.DAY_SUNNY + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("70°").build(), PlainComplicationText.Builder("70° - Sunny").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -64,28 +78,27 @@ class WeatherComplicationService : WeatherForecastComplicationService() { ).setTitle( PlainComplicationText.Builder("70°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE), - SmallImageType.ICON - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder("70° - Sunny").build() ).build() } @@ -126,10 +139,12 @@ class WeatherComplicationService : WeatherForecastComplicationService() { weather.condition!!.weather } else { provider.getWeatherCondition(weather.condition!!.icon) - } ?: getString(R.string.weather_notavailable) + } ?: getString(sharedRes.string.weather_notavailable) val wim = sharedDeps.weatherIconsManager val weatherIcon = wim.getWeatherIconResource(weather.condition!!.icon) + val monochromaticIcon = Icon.createWithResource(this, weatherIcon) + .setTint(Colors.WHITESMOKE) val icon = Icon.createWithBitmap( ImageUtils.bitmapFromDrawable( getThemeContextOverride(false), @@ -150,21 +165,20 @@ class WeatherComplicationService : WeatherForecastComplicationService() { MonochromaticImage.Builder(icon).apply { // Weather Icon if (!wim.isFontIcon) { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this@WeatherComplicationService, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + setAmbientImage(monochromaticIcon) } } .build() ) + if (!wim.isFontIcon) { + builder.setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + builder.setTapAction(getTapIntent(this)) return builder.build() } @@ -182,18 +196,9 @@ class WeatherComplicationService : WeatherForecastComplicationService() { MonochromaticImage.Builder(icon).build() ) } else { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) builder.setSmallImage( SmallImage.Builder(icon, SmallImageType.ICON) - .setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + .setAmbientImage(monochromaticIcon) .build() ) } @@ -202,37 +207,18 @@ class WeatherComplicationService : WeatherForecastComplicationService() { return builder.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource( - this, - wip.getWeatherIconResource(weather.condition!!.icon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), contentDescription ).setTapAction( getTapIntent(this) ).build() } ComplicationType.SMALL_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return SmallImageComplicationData.Builder( - SmallImage.Builder( - icon, - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), contentDescription ).setTapAction( getTapIntent(this) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherHiLoComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherHiLoComplicationService.kt index e11d400b4..9eb607e11 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherHiLoComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WeatherHiLoComplicationService.kt @@ -15,7 +15,6 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons -import com.thewizrd.shared_resources.icons.WeatherIconsEFProvider import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride @@ -23,8 +22,8 @@ import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.weatherdata.model.Forecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import com.thewizrd.weather_api.weatherModule +import com.thewizrd.shared_resources.R as sharedRes class WeatherHiLoComplicationService : WeatherForecastComplicationService() { companion object { @@ -38,24 +37,39 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_day_sunny override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val complicationIcon = WeatherIcons.DAY_SUNNY + val monochromaticIcon = + Icon.createWithResource(this, wim.getWeatherIconResource(complicationIcon)) + .setTint(Colors.WHITESMOKE) + val icon = Icon.createWithBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ) + ) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("75°/65°").build(), PlainComplicationText.Builder("70° - Sunny").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -64,11 +78,15 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { ).setTitle( PlainComplicationText.Builder("75° | 65°").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon).build(), + ) + } + }.build() } else -> { null @@ -144,6 +162,8 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { val wim = sharedDeps.weatherIconsManager val weatherIcon = wim.getWeatherIconResource(weather.condition!!.icon) + val monochromaticIcon = Icon.createWithResource(this, weatherIcon) + .setTint(Colors.WHITESMOKE) val icon = Icon.createWithBitmap( ImageUtils.bitmapFromDrawable( getThemeContextOverride(false), @@ -152,7 +172,11 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { ) val contentDescription = PlainComplicationText.Builder( - "$temp - $condition; ${getString(R.string.label_high)}: $hiTemp, ${getString(R.string.label_low)}: $loTemp" + "$temp - $condition; ${getString(sharedRes.string.label_high)}: $hiTemp, ${ + getString( + sharedRes.string.label_low + ) + }: $loTemp" ).build() when (dataType) { @@ -172,21 +196,20 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { MonochromaticImage.Builder(icon).apply { // Weather Icon if (!wim.isFontIcon) { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this@WeatherHiLoComplicationService, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + setAmbientImage(monochromaticIcon) } } .build() ) + if (!wim.isFontIcon) { + builder.setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + builder.setTapAction(getTapIntent(this)) return builder.build() } @@ -204,18 +227,9 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { MonochromaticImage.Builder(icon).build() ) } else { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) builder.setSmallImage( SmallImage.Builder(icon, SmallImageType.ICON) - .setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ) + .setAmbientImage(monochromaticIcon) .build() ) } @@ -224,37 +238,18 @@ class WeatherHiLoComplicationService : WeatherForecastComplicationService() { return builder.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithResource( - this, - wip.getWeatherIconResource(weather.condition!!.icon) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), contentDescription ).setTapAction( getTapIntent(this) ).build() } ComplicationType.SMALL_IMAGE -> { - val wip = wim.getIconProvider(WeatherIconsEFProvider.KEY) - return SmallImageComplicationData.Builder( - SmallImage.Builder( - icon, - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.tintedBitmapFromDrawable( - this, - wip.getWeatherIconResource(weather.condition!!.icon), - Colors.WHITE - ) - ) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), contentDescription ).setTapAction( getTapIntent(this) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WindComplicationService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WindComplicationService.kt index 584ca5a06..ac2d7615b 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WindComplicationService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/complications/WindComplicationService.kt @@ -15,6 +15,7 @@ import androidx.wear.watchface.complications.data.SmallImageType import com.thewizrd.common.utils.ImageUtils import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ContextUtils.getThemeContextOverride import com.thewizrd.shared_resources.utils.ConversionMethods @@ -23,8 +24,8 @@ import com.thewizrd.shared_resources.utils.Units import com.thewizrd.shared_resources.utils.getWindDirection import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.simpleweather.R import kotlin.math.roundToInt +import com.thewizrd.shared_resources.R as sharedRes class WindComplicationService : WeatherHourlyForecastComplicationService() { companion object { @@ -38,30 +39,49 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { ComplicationType.MONOCHROMATIC_IMAGE, ComplicationType.SMALL_IMAGE ) - private val complicationIconResId = R.drawable.wi_strong_wind + + private val complicationIcon = WeatherIcons.WIND_DIRECTION override fun getPreviewData(type: ComplicationType): ComplicationData? { if (!supportedComplicationTypes.contains(type)) { return NoDataComplicationData() } + val wim = sharedDeps.weatherIconsManager + val icon = Icon.createWithBitmap( + ImageUtils.rotateBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ), 330.0f // 150° + 180 + ) + ) + val monochromaticIcon = Icon.createWithBitmap( + ImageUtils.rotateBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ), 330.0f // 150° + 180 + ) + ) + .setTint(Colors.WHITESMOKE) + return when (type) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( PlainComplicationText.Builder("5 mph").build(), PlainComplicationText.Builder("Wind: 5 mph, SSE").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), 330.0f // 150° + 180 - ) + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() ) - ).build() - ).build() + } + }.build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( @@ -70,51 +90,30 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { ).setTitle( PlainComplicationText.Builder("5 mph, SSE").build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).build() + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build() + ) + } + }.build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), 330.0f // 150° + 180 - ) - ) - ).build(), + MonochromaticImage.Builder(monochromaticIcon).build(), PlainComplicationText.Builder("Wind: 5 mph, SSE").build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), 330.0f // 150° + 180 - ) - ), - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), 330.0f // 150° + 180 - ) - ) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder("Wind: 5 mph, SSE").build() ).build() } @@ -134,9 +133,9 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { return null } - val windMph = weather.condition?.windMph ?: hourlyForecast?.windMph - val windKph = weather.condition?.windKph ?: hourlyForecast?.windKph - val windDirection = weather.condition?.windDegrees ?: hourlyForecast?.windDegrees + val windMph = weather.condition?.windMph ?: hourlyForecast?.extras?.windMph + val windKph = weather.condition?.windKph ?: hourlyForecast?.extras?.windKph + val windDirection = weather.condition?.windDegrees ?: hourlyForecast?.extras?.windDegrees if (windMph == null || windKph == null || windDirection == null || windMph < 0 || windKph < 0 || windDirection < 0) { return buildUpdate(dataType) @@ -150,26 +149,26 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { when (unit) { Units.MILES_PER_HOUR -> { speedVal = windMph.roundToInt() - speedUnit = getString(R.string.unit_mph).also { speedUnitShort = it } + speedUnit = getString(sharedRes.string.unit_mph).also { speedUnitShort = it } } Units.KILOMETERS_PER_HOUR -> { speedVal = windKph.roundToInt() - speedUnit = getString(R.string.unit_kph).also { speedUnitShort = it } + speedUnit = getString(sharedRes.string.unit_kph).also { speedUnitShort = it } } Units.METERS_PER_SECOND -> { speedVal = ConversionMethods.kphToMsec(windKph).roundToInt() - speedUnit = getString(R.string.unit_msec).also { speedUnitShort = it } + speedUnit = getString(sharedRes.string.unit_msec).also { speedUnitShort = it } } Units.KNOTS -> { speedVal = ConversionMethods.mphToKts(windMph).roundToInt() - speedUnit = getString(R.string.unit_knots) + speedUnit = getString(sharedRes.string.unit_knots) speedUnitShort = "kn" } else -> { speedVal = windMph.roundToInt() - speedUnit = getString(R.string.unit_mph).also { speedUnitShort = it } + speedUnit = getString(sharedRes.string.unit_mph).also { speedUnitShort = it } } } @@ -190,6 +189,24 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { dataType: ComplicationType, windSpeedShort: String? = null, windSpeedLong: String? = null, windDirection: Int = 0 ): ComplicationData? { + val wim = sharedDeps.weatherIconsManager + val icon = Icon.createWithBitmap( + ImageUtils.rotateBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ), windDirection.toFloat() + 180 + ) + ) + val monochromaticIcon = Icon.createWithBitmap( + ImageUtils.rotateBitmap( + ImageUtils.bitmapFromDrawable( + getThemeContextOverride(false), + wim.getWeatherIconResource(complicationIcon) + ), windDirection.toFloat() + 180 + ) + ).setTint(Colors.WHITESMOKE) + return when (dataType) { ComplicationType.SHORT_TEXT -> { ShortTextComplicationData.Builder( @@ -197,87 +214,63 @@ class WindComplicationService : WeatherHourlyForecastComplicationService() { .build(), PlainComplicationText.Builder( windSpeedLong - ?: "${getString(R.string.label_wind)}: ${getString(R.string.weather_notavailable)}" + ?: "${getString(sharedRes.string.label_wind)}: ${getString(sharedRes.string.weather_notavailable)}" ).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), windDirection.toFloat() + 180 - ) + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), ) - ).build() - ).setTapAction( + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.LONG_TEXT -> { LongTextComplicationData.Builder( - PlainComplicationText.Builder(getString(R.string.label_wind)).build(), + PlainComplicationText.Builder(getString(sharedRes.string.label_wind)).build(), PlainComplicationText.Builder( windSpeedLong - ?: "${getString(R.string.label_wind)}: ${getString(R.string.weather_notavailable)}" + ?: "${getString(sharedRes.string.label_wind)}: ${getString(sharedRes.string.weather_notavailable)}" ).build() ).setTitle( PlainComplicationText.Builder(windSpeedLong ?: WeatherIcons.EM_DASH).build() ).setMonochromaticImage( - MonochromaticImage.Builder( - Icon.createWithResource(this, complicationIconResId) - .setTint(Colors.WHITESMOKE) - ).build() - ).setTapAction( + MonochromaticImage.Builder(monochromaticIcon).build() + ).apply { + if (!wim.isFontIcon) { + setSmallImage( + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), + ) + } + }.setTapAction( getTapIntent(this) ).build() } ComplicationType.MONOCHROMATIC_IMAGE -> { MonochromaticImageComplicationData.Builder( - MonochromaticImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), windDirection.toFloat() + 180 - ) - ) - .setTint(Colors.WHITESMOKE) - ).build(), - PlainComplicationText.Builder("${getString(R.string.label_wind)}: $windSpeedLong") + MonochromaticImage.Builder(monochromaticIcon).build(), + PlainComplicationText.Builder("${getString(sharedRes.string.label_wind)}: $windSpeedLong") .build() ).build() } ComplicationType.SMALL_IMAGE -> { SmallImageComplicationData.Builder( - SmallImage.Builder( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), windDirection.toFloat() + 180 - ) - ), - SmallImageType.ICON - ).setAmbientImage( - Icon.createWithBitmap( - ImageUtils.rotateBitmap( - ImageUtils.bitmapFromDrawable( - getThemeContextOverride(false), - R.drawable.wi_wind_direction_white - ), windDirection.toFloat() + 180 - ) - ) - .setTint(Colors.WHITESMOKE) - ).build(), + SmallImage.Builder(icon, SmallImageType.ICON) + .setAmbientImage(monochromaticIcon) + .build(), PlainComplicationText.Builder( - "${getString(R.string.label_wind)}: ${ + "${getString(sharedRes.string.label_wind)}: ${ windSpeedLong ?: getString( - R.string.weather_notavailable + sharedRes.string.weather_notavailable ) }" ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/DetailsWeatherTileProviderService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/DetailsWeatherTileProviderService.kt index 46de9b109..c51b0dc31 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/DetailsWeatherTileProviderService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/DetailsWeatherTileProviderService.kt @@ -111,7 +111,7 @@ class DetailsWeatherTileProviderService : WeatherCoroutinesTileService() { WeatherDetailsType.VISIBILITY.name -> { this.addIdToImageMapping( id, - createImageResourceFromWeatherIcon(WeatherIcons.FOG, rotation) + createImageResourceFromWeatherIcon(WeatherIcons.VISIBILITY, rotation) ) } @@ -181,14 +181,14 @@ class DetailsWeatherTileProviderService : WeatherCoroutinesTileService() { WeatherDetailsType.UV.name -> { this.addIdToImageMapping( id, - createImageResourceFromWeatherIcon(WeatherIcons.DAY_SUNNY, rotation) + createImageResourceFromWeatherIcon(WeatherIcons.UV_INDEX, rotation) ) } WeatherDetailsType.AIRQUALITY.name -> { this.addIdToImageMapping( id, - createImageResourceFromWeatherIcon(WeatherIcons.CLOUDY_GUSTS, rotation) + createImageResourceFromWeatherIcon(WeatherIcons.AIR_QUALITY, rotation) ) } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/ForecastWeatherTileProviderService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/ForecastWeatherTileProviderService.kt index 268031575..420f11f6e 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/ForecastWeatherTileProviderService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/ForecastWeatherTileProviderService.kt @@ -5,6 +5,7 @@ import androidx.wear.protolayout.LayoutElementBuilders import androidx.wear.protolayout.ResourceBuilders import androidx.wear.tiles.RequestBuilders import com.google.android.horologist.tiles.images.drawableResToImageResource +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.weatherdata.model.Weather @@ -46,21 +47,21 @@ class ForecastWeatherTileProviderService : WeatherCoroutinesTileService() { ID_WEATHER_CHANCE_ICON -> { addIdToImageMapping( ID_WEATHER_CHANCE_ICON, - drawableResToImageResource(R.drawable.wi_umbrella) + drawableResToImageResource(sharedRes.drawable.wi_umbrella) ) } ID_WEATHER_CLOUDINESS_ICON -> { addIdToImageMapping( ID_WEATHER_CLOUDINESS_ICON, - drawableResToImageResource(R.drawable.wi_cloudy) + drawableResToImageResource(sharedRes.drawable.wi_cloudy) ) } ID_WEATHER_WINDSPEED_ICON -> { addIdToImageMapping( ID_WEATHER_WINDSPEED_ICON, - drawableResToImageResource(R.drawable.wi_strong_wind) + drawableResToImageResource(sharedRes.drawable.wi_strong_wind) ) } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/HourlyForecastWeatherTileProviderService.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/HourlyForecastWeatherTileProviderService.kt index 40b03bacc..c7d0d577b 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/HourlyForecastWeatherTileProviderService.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/HourlyForecastWeatherTileProviderService.kt @@ -5,6 +5,7 @@ import androidx.wear.protolayout.LayoutElementBuilders import androidx.wear.protolayout.ResourceBuilders import androidx.wear.tiles.RequestBuilders import com.google.android.horologist.tiles.images.drawableResToImageResource +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.di.settingsManager import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.weatherdata.model.Weather @@ -49,21 +50,21 @@ class HourlyForecastWeatherTileProviderService : WeatherCoroutinesTileService() ID_WEATHER_CHANCE_ICON -> { addIdToImageMapping( ID_WEATHER_CHANCE_ICON, - drawableResToImageResource(R.drawable.wi_umbrella) + drawableResToImageResource(sharedRes.drawable.wi_umbrella) ) } ID_WEATHER_CLOUDINESS_ICON -> { addIdToImageMapping( ID_WEATHER_CLOUDINESS_ICON, - drawableResToImageResource(R.drawable.wi_cloudy) + drawableResToImageResource(sharedRes.drawable.wi_cloudy) ) } ID_WEATHER_WINDSPEED_ICON -> { addIdToImageMapping( ID_WEATHER_WINDSPEED_ICON, - drawableResToImageResource(R.drawable.wi_strong_wind) + drawableResToImageResource(sharedRes.drawable.wi_strong_wind) ) } } diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherGoogleTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherGoogleTileLayout.kt index dc8614018..8a28ccf38 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherGoogleTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherGoogleTileLayout.kt @@ -32,6 +32,7 @@ import com.google.android.horologist.tiles.images.drawableResToImageResource import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.getColorFromTempF @@ -217,7 +218,7 @@ private fun currentWeatherGoogleTilePreview(context: Context) = TilePreviewData( "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -225,7 +226,7 @@ private fun currentWeatherGoogleTilePreview(context: Context) = TilePreviewData( "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherTileLayout.kt index 9f2971f46..51e249dcd 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/CurrentWeatherTileLayout.kt @@ -28,6 +28,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewHelper import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.getColorFromTempF @@ -170,7 +171,7 @@ private fun currentWeatherTilePreview(context: Context) = TilePreviewData( "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -178,7 +179,7 @@ private fun currentWeatherTilePreview(context: Context) = TilePreviewData( "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/DetailsWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/DetailsWeatherTileLayout.kt index 623da33d1..3855d5c8c 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/DetailsWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/DetailsWeatherTileLayout.kt @@ -85,7 +85,6 @@ import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.UV import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.simpleweather.LaunchActivity -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.preferences.DetailsWeatherTileUtils import com.thewizrd.simpleweather.ui.theme.wearTileColorScheme import com.thewizrd.simpleweather.ui.tiles.tools.WearPreviewDevices @@ -96,6 +95,7 @@ import java.time.LocalTime import java.time.ZonedDateTime import java.time.temporal.ChronoUnit import kotlin.random.Random +import com.thewizrd.shared_resources.R as sharedRes internal const val ID_DETAIL_ICON_PREFIX = "detail_icon:" internal const val ID_ROTATION_PREFIX = "rotation:" @@ -152,7 +152,7 @@ internal fun detailsWeatherTileLayout( when (detailItems.size) { 0 -> { text( - text = context.getString(R.string.label_nodata).layoutString, + text = context.getString(sharedRes.string.label_nodata).layoutString, typography = androidx.wear.protolayout.material3.Typography.LABEL_LARGE ) } @@ -192,14 +192,14 @@ internal fun detailsWeatherTileLayout( textEdgeButton( onClick = clickable(getLaunchAction(context)), labelContent = { - text(context.getString(R.string.label_nav_weathernow).layoutString) + text(context.getString(sharedRes.string.label_nav_weathernow).layoutString) } ) } else { compactButton( onClick = clickable(getLaunchAction(context)), labelContent = { - text(context.getString(R.string.label_nav_weathernow).layoutString) + text(context.getString(sharedRes.string.label_nav_weathernow).layoutString) } ) } @@ -805,8 +805,6 @@ private fun buildMockWeatherData(): Weather { highC = 23f + index / 2f condition = "Sunny" icon = WeatherIcons.DAY_SUNNY - windMph = 5f - windKph = 8f extras = ForecastExtras().apply { feelslikeF = 80f feelslikeC = 26f diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/ForecastWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/ForecastWeatherTileLayout.kt index 635a9c7c4..54c43adee 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/ForecastWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/ForecastWeatherTileLayout.kt @@ -30,6 +30,7 @@ import com.google.android.horologist.tiles.images.drawableResToImageResource import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.preferences.SettingsManager @@ -275,7 +276,7 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -283,21 +284,21 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) .addIdToImageMapping( ID_WEATHER_CHANCE_ICON, - drawableResToImageResource(R.drawable.wi_umbrella_white) + drawableResToImageResource(sharedRes.drawable.wi_umbrella_white) ) .addIdToImageMapping( ID_WEATHER_CLOUDINESS_ICON, - drawableResToImageResource(R.drawable.wi_cloudy) + drawableResToImageResource(sharedRes.drawable.wi_cloudy) ) .addIdToImageMapping( ID_WEATHER_WINDSPEED_ICON, - drawableResToImageResource(R.drawable.wi_strong_wind) + drawableResToImageResource(sharedRes.drawable.wi_strong_wind) ) .apply { forecasts.forEach { item -> @@ -305,7 +306,7 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastCardTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastCardTileLayout.kt index d25c52a69..7f6ad6bfd 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastCardTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastCardTileLayout.kt @@ -39,6 +39,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewHelper import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ConversionMethods @@ -106,7 +107,7 @@ internal fun hourlyForecastCardTileLayout( mainSlot = { if (forecasts.isNullOrEmpty()) { text( - text = context.getString(R.string.label_nodata).layoutString, + text = context.getString(sharedRes.string.label_nodata).layoutString, alignment = TEXT_ALIGN_CENTER ) } else { @@ -306,7 +307,7 @@ private fun hourlyForecastCardTileLayout(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -314,7 +315,7 @@ private fun hourlyForecastCardTileLayout(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) @@ -324,7 +325,7 @@ private fun hourlyForecastCardTileLayout(context: Context): TilePreviewData { "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastPillsTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastPillsTileLayout.kt index 4f6198f91..67c66ca08 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastPillsTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastPillsTileLayout.kt @@ -31,6 +31,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewHelper import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ConversionMethods @@ -92,7 +93,7 @@ internal fun hourlyForecastPillsTileLayout( mainSlot = { if (forecasts.isNullOrEmpty()) { text( - text = context.getString(R.string.label_nodata).layoutString, + text = context.getString(sharedRes.string.label_nodata).layoutString, alignment = TEXT_ALIGN_CENTER ) } else { @@ -195,7 +196,7 @@ private fun hourlyForecastPillsTileLayout(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -203,7 +204,7 @@ private fun hourlyForecastPillsTileLayout(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) @@ -213,7 +214,7 @@ private fun hourlyForecastPillsTileLayout(context: Context): TilePreviewData { "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastWeatherTileLayout.kt index 2d6323757..6a6f27d3c 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/HourlyForecastWeatherTileLayout.kt @@ -28,6 +28,7 @@ import com.google.android.horologist.tiles.images.drawableResToImageResource import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.DateTimeConstants import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.preferences.SettingsManager @@ -198,7 +199,7 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -206,21 +207,21 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) .addIdToImageMapping( ID_WEATHER_CHANCE_ICON, - drawableResToImageResource(R.drawable.wi_umbrella_white) + drawableResToImageResource(sharedRes.drawable.wi_umbrella_white) ) .addIdToImageMapping( ID_WEATHER_CLOUDINESS_ICON, - drawableResToImageResource(R.drawable.wi_cloudy) + drawableResToImageResource(sharedRes.drawable.wi_cloudy) ) .addIdToImageMapping( ID_WEATHER_WINDSPEED_ICON, - drawableResToImageResource(R.drawable.wi_strong_wind) + drawableResToImageResource(sharedRes.drawable.wi_strong_wind) ) .apply { forecasts.forEach { item -> @@ -228,7 +229,7 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3ForecastWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3ForecastWeatherTileLayout.kt index ccfea18e6..15c4e1b90 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3ForecastWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3ForecastWeatherTileLayout.kt @@ -39,6 +39,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewHelper import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ConversionMethods @@ -169,7 +170,7 @@ private fun m3ForecastWeatherTileLayout( if (forecasts.isNullOrEmpty()) { addContent( text( - text = context.getString(R.string.label_nodata).layoutString, + text = context.getString(sharedRes.string.label_nodata).layoutString, alignment = TEXT_ALIGN_CENTER ) ) @@ -398,7 +399,7 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -406,7 +407,7 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) @@ -416,7 +417,7 @@ private fun forecastWeatherTilePreview(context: Context): TilePreviewData { "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3HourlyForecastWeatherTileLayout.kt b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3HourlyForecastWeatherTileLayout.kt index f378b427e..44d9a01ee 100644 --- a/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3HourlyForecastWeatherTileLayout.kt +++ b/wearapp/src/main/java/com/thewizrd/simpleweather/wearable/tiles/layouts/M3HourlyForecastWeatherTileLayout.kt @@ -39,6 +39,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewHelper import com.google.android.horologist.tiles.images.toImageResource import com.thewizrd.common.controls.toUiModel import com.thewizrd.common.utils.ImageUtils +import com.thewizrd.shared_resources.R as sharedRes import com.thewizrd.shared_resources.icons.WeatherIcons import com.thewizrd.shared_resources.utils.Colors import com.thewizrd.shared_resources.utils.ConversionMethods @@ -169,7 +170,7 @@ private fun m3HourlyForecastWeatherTileLayout( if (forecasts.isNullOrEmpty()) { addContent( text( - text = context.getString(R.string.label_nodata).layoutString, + text = context.getString(sharedRes.string.label_nodata).layoutString, alignment = TEXT_ALIGN_CENTER ) ) @@ -390,7 +391,7 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "$ID_WEATHER_ICON_PREFIX${WeatherIcons.DAY_SUNNY}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_day_sunny, + sharedRes.drawable.wi_day_sunny, Colors.WHITE ).toImageResource() ) @@ -398,7 +399,7 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "$ID_WEATHER_ICON_PREFIX${WeatherIcons.NA}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_na, + sharedRes.drawable.wi_na, Colors.WHITE ).toImageResource() ) @@ -408,7 +409,7 @@ private fun hourlyForecastWeatherTilePreview(context: Context): TilePreviewData "${ID_WEATHER_ICON_PREFIX}${item.icon}", ImageUtils.tintedBitmapFromDrawable( context, - R.drawable.wi_cloudy, + sharedRes.drawable.wi_cloudy, Colors.WHITE ).toImageResource() ) diff --git a/wearapp/src/main/res/drawable/ic_mobile_arrow_right.xml b/wearapp/src/main/res/drawable/ic_mobile_arrow_right.xml new file mode 100644 index 000000000..60769569a --- /dev/null +++ b/wearapp/src/main/res/drawable/ic_mobile_arrow_right.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/wearapp/src/main/res/layout-sw180dp-notround/tile_layout_currentweather_icontemp.xml b/wearapp/src/main/res/layout-sw180dp-notround/tile_layout_currentweather_icontemp.xml index eee1f27fe..ba1b16a08 100644 --- a/wearapp/src/main/res/layout-sw180dp-notround/tile_layout_currentweather_icontemp.xml +++ b/wearapp/src/main/res/layout-sw180dp-notround/tile_layout_currentweather_icontemp.xml @@ -16,7 +16,7 @@ android:layout_height="48dp" android:scaleType="fitCenter" android:layout_gravity="center" - tools:srcCompat="@drawable/wui_day_mostlycloudy" /> + tools:srcCompat="@drawable/goog_mostly_cloudy_day" /> + tools:srcCompat="@drawable/goog_mostly_cloudy_day" /> + tools:srcCompat="@drawable/goog_mostly_cloudy_day" /> \ No newline at end of file diff --git a/wearapp/src/main/res/values/wear.xml b/wearapp/src/main/res/values/wear.xml index 5ab1ffd69..f9e36dcf7 100644 --- a/wearapp/src/main/res/values/wear.xml +++ b/wearapp/src/main/res/values/wear.xml @@ -1,5 +1,5 @@ - + com.thewizrd.simpleweather_wear_app diff --git a/wearapp/src/main/res/xml/pref_credits.xml b/wearapp/src/main/res/xml/pref_credits.xml index 8d5c7a479..c4802601f 100644 --- a/wearapp/src/main/res/xml/pref_credits.xml +++ b/wearapp/src/main/res/xml/pref_credits.xml @@ -41,11 +41,6 @@ android:widgetLayout="@layout/credit_waqi"> - - - @@ -70,6 +65,13 @@ android:action="android.intent.action.VIEW" android:data="https://www.weather.gc.ca/" /> + + + diff --git a/wearapp/src/nongms/java/com/thewizrd/simpleweather/extras/Extras.kt b/wearapp/src/nongms/java/com/thewizrd/simpleweather/extras/Extras.kt index 8816efeec..cd45e05ca 100644 --- a/wearapp/src/nongms/java/com/thewizrd/simpleweather/extras/Extras.kt +++ b/wearapp/src/nongms/java/com/thewizrd/simpleweather/extras/Extras.kt @@ -39,7 +39,7 @@ fun SettingsActivity.IconsFragment.navigateUnsupportedIconPack() { } fun enableAdditionalRefreshIntervals(): Boolean { - return false + return true } fun checkPremiumStatus() { diff --git a/weather-api/build.gradle b/weather-api/build.gradle index 95143e798..933248cf9 100644 --- a/weather-api/build.gradle +++ b/weather-api/build.gradle @@ -1,7 +1,6 @@ plugins { id 'com.android.library' - id 'kotlin-android' - id 'kotlin-kapt' + id 'com.android.legacy-kapt' id 'com.google.devtools.ksp' id 'androidx.room' } @@ -11,7 +10,6 @@ android { defaultConfig { minSdk libs.versions.minSdkVersion.get().toInteger() - targetSdk libs.versions.targetSdkVersion.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -40,12 +38,12 @@ android { compileOptions { // Flag to enable support for the new language APIs coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } kotlin { - jvmToolchain(17) + jvmToolchain(21) } room { @@ -63,13 +61,26 @@ android { productFlavors { nongms { dimension 'gms' + buildConfigField "boolean", "IS_NONGMS", "true" } fullgms { dimension 'gms' + buildConfigField "boolean", "IS_NONGMS", "false" + externalNativeBuild { + ndkBuild { + arguments "FULL_GMS_VERSION=true" + } + } } } namespace 'com.thewizrd.weather_api' + lint { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } + testOptions { + targetSdk libs.versions.targetSdkVersion.get().toInteger() + } } dependencies { @@ -120,4 +131,4 @@ dependencies { fullgmsImplementation libs.places fullgmsImplementation libs.volley // Required by Places API ^^^ fullgmsImplementation libs.kotlinx.coroutines.play.services -} +} \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt index 8c9aea4b2..a7d271fac 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt @@ -329,7 +329,7 @@ class AccuWeatherProvider : WeatherProviderImpl(), PollenProvider { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { - // no-op + super.updateWeatherData(location, weather) } override suspend fun updateLocationQuery(weather: Weather): String { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/WeatherData.kt index f12aa03c2..c15644f1a 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/WeatherData.kt @@ -204,10 +204,7 @@ fun createHourlyForecast(hourly: HourlyResponseItem): HourlyForecast { hourly.wind?.speed?.value?.let { extras.windKph = it - windKph = it - extras.windMph = ConversionMethods.kphTomph(it) - windMph = extras.windMph } extras.windDegrees = hourly.wind?.direction?.degrees?.roundToInt() diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/AQICNData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/AQICNData.kt index dcfb71958..39e9d52a9 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/AQICNData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/AQICNData.kt @@ -19,7 +19,7 @@ class AQICNData internal constructor(root: Rootobject) : AirQualityData() { pm10 = root.data?.iaqi?.pm10?.v?.roundToInt() co = root.data?.iaqi?.co?.v?.roundToInt() - index = root.data?.aqi ?: getIndexFromData() + index = root.data?.aqi?.toIntOrNull() ?: getIndexFromData() } aqiForecast = root.createAQIForecasts() } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/Data.kt b/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/Data.kt index 79ac2ceb2..6fb6db46f 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/Data.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/aqicn/Data.kt @@ -15,7 +15,7 @@ data class Data( var city: City? = null, @Json(name = "aqi") - var aqi: Int? = null, + var aqi: String? = null, @Json(name = "forecast") var forecast: Forecast? = null, diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt index a663491cf..7f08826f9 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt @@ -11,7 +11,11 @@ import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocationUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.ZoneIdCompat +import com.thewizrd.shared_resources.utils.createUnsupportedLocationException import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid @@ -36,7 +40,7 @@ import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class BrightSkyProvider : WeatherProviderImpl() { @@ -228,6 +232,8 @@ class BrightSkyProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // DWD reports datetime in UTC; add location tz_offset val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) @@ -256,7 +262,7 @@ class BrightSkyProvider : WeatherProviderImpl() { for (forecast in weather.forecast!!) { forecast.icon.let { forecast.icon = getWeatherIcon(it) - forecast.condition = getWeatherCondition(it) + forecast.condition = getWeatherCondition(forecast.icon) } } @@ -271,7 +277,7 @@ class BrightSkyProvider : WeatherProviderImpl() { hrfLocalTime.isBefore(sunrise) || hrfLocalTime.isAfter(sunset), it ) - hr_forecast.condition = getWeatherCondition(it) + hr_forecast.condition = getWeatherCondition(hr_forecast.icon) } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/WeatherData.kt index b30e4fb5a..b44747ecf 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/WeatherData.kt @@ -232,22 +232,12 @@ fun createHourlyForecast(hr_forecast: WeatherItem): HourlyForecast { highF = ConversionMethods.CtoF(it) highC = it } - windDegrees = hr_forecast.windDirection?.roundToInt() - hr_forecast.windSpeed?.let { - windMph = ConversionMethods.kphTomph(it) - windKph = it - } icon = hr_forecast.icon // Extras val humidity = hr_forecast.relativeHumidity?.roundToInt() extras = ForecastExtras() - if (highF != null && windMph != null && humidity != null) { - val feelsLikeF = getFeelsLikeTemp(highF, windMph, humidity) - extras.feelslikeF = feelsLikeF - extras.feelslikeC = ConversionMethods.FtoC(feelsLikeF) - } extras.humidity = humidity hr_forecast.dewPoint?.let { extras.dewpointF = ConversionMethods.CtoF(it) @@ -260,9 +250,11 @@ fun createHourlyForecast(hr_forecast: WeatherItem): HourlyForecast { extras.pressureIn = ConversionMethods.mbToInHg(it) extras.pressureMb = it } - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = hr_forecast.windDirection?.roundToInt() + hr_forecast.windSpeed?.let { + extras.windMph = ConversionMethods.kphTomph(it) + extras.windKph = it + } hr_forecast.windGustSpeed?.let { extras.windGustMph = ConversionMethods.kphTomph(it) extras.windGustKph = it @@ -271,6 +263,11 @@ fun createHourlyForecast(hr_forecast: WeatherItem): HourlyForecast { extras.visibilityMi = ConversionMethods.kmToMi(it / 1000f) extras.visibilityKm = it / 1000f } + if (highF != null && extras.windMph != null && humidity != null) { + val feelsLikeF = getFeelsLikeTemp(highF, extras.windMph, humidity) + extras.feelslikeF = feelsLikeF + extras.feelslikeC = ConversionMethods.FtoC(feelsLikeF) + } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt index e20b55e79..fad1de8c2 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt @@ -2,6 +2,7 @@ package com.thewizrd.weather_api.eccc import android.util.Log import com.ibm.icu.util.ULocale +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.icons.WeatherIcons @@ -12,11 +13,15 @@ import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.LocationUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.ZoneIdCompat +import com.thewizrd.shared_resources.utils.createUnsupportedLocationException import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.extras.cacheRequestIfNeeded import com.thewizrd.weather_api.locationiq.LocationIQProvider import com.thewizrd.weather_api.nws.SolCalcAstroProvider @@ -37,7 +42,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class ECCCWeatherProvider : WeatherProviderImpl() { @@ -175,6 +180,8 @@ class ECCCWeatherProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) weather.condition!!.observationTime = diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/WeatherData.kt index 66deb9a68..95107519e 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/WeatherData.kt @@ -188,12 +188,6 @@ fun createHourlyForecast(item: HourlyItem): HourlyForecast { highF = item.temperature?.imperial?.toFloatOrNull() highC = item.temperature?.metric?.toFloatOrNull() - windDegrees = item.windDir?.let { - getWindDirection(it) - } - windMph = item.windSpeed?.imperial?.toFloatOrNull() - windKph = item.windSpeed?.metric?.toFloatOrNull() - icon = item.iconCode condition = item.condition @@ -202,9 +196,11 @@ fun createHourlyForecast(item: HourlyItem): HourlyForecast { extras.feelslikeF = item.feelsLike?.imperial?.toFloatOrNull() extras.feelslikeC = item.feelsLike?.metric?.toFloatOrNull() extras.pop = item.precip?.toIntOrNull() - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = item.windDir?.let { + getWindDirection(it) + } + extras.windMph = item.windSpeed?.imperial?.toFloatOrNull() + extras.windKph = item.windSpeed?.metric?.toFloatOrNull() extras.windGustMph = item.windGust?.imperial?.toFloatOrNull() extras.windGustKph = item.windGust?.metric?.toFloatOrNull() extras.uvIndex = item.uv?.index?.toFloatOrNull() diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/AlertsResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/AlertsResponse.kt new file mode 100644 index 000000000..1d36533e7 --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/AlertsResponse.kt @@ -0,0 +1,99 @@ +package com.thewizrd.weather_api.google.weather + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class AlertsResponse( + + @Json(name = "regionCode") + var regionCode: String? = null, + + @Json(name = "weatherAlerts") + var weatherAlerts: List? = null, + + @Json(name = "nextPageToken") + var nextPageToken: String? = null +) + +@JsonClass(generateAdapter = true) +data class AlertTitle( + + @Json(name = "text") + var text: String? = null, + + @Json(name = "languageCode") + var languageCode: String? = null +) + +@JsonClass(generateAdapter = true) +data class PublicAlerts( + + @Json(name = "alertId") + var alertId: String? = null, + + @Json(name = "alertTitle") + var alertTitle: AlertTitle? = null, + + @Json(name = "eventType") + var eventType: String? = null, + + @Json(name = "areaName") + var areaName: String? = null, + + @Json(name = "instruction") + var instruction: List? = null, + + @Json(name = "safetyRecommendations") + var safetyRecommendations: List? = null, + + @Json(name = "timezoneOffset") + var timezoneOffset: String? = null, + + @Json(name = "startTime") + var startTime: String? = null, + + @Json(name = "expirationTime") + var expirationTime: String? = null, + + @Json(name = "dataSource") + var dataSource: DataSource? = null, + + @Json(name = "polygon") + var polygon: String? = null, + + @Json(name = "description") + var description: String? = null, + + @Json(name = "severity") + var severity: String? = null, + + @Json(name = "certainty") + var certainty: String? = null, + + @Json(name = "urgency") + var urgency: String? = null +) + +@JsonClass(generateAdapter = true) +data class DataSource( + + @Json(name = "authorityUri") + var authorityUri: String? = null, + + @Json(name = "name") + var name: String? = null, + + @Json(name = "publisher") + var publisher: String? = null +) + +@JsonClass(generateAdapter = true) +data class SafetyRecommendationsItem( + + @Json(name = "directive") + var directive: String? = null, + + @Json(name = "subtext") + var subtext: String? = null +) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/GoogleWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/GoogleWeatherProvider.kt index 4f50def14..ce44ace51 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/GoogleWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/GoogleWeatherProvider.kt @@ -49,6 +49,8 @@ class GoogleWeatherProvider : WeatherProviderImpl() { private const val CONDITIONS_PATH = "currentConditions:lookup" private const val FORECAST_PATH = "forecast/days:lookup" private const val HOURLY_FORECAST_PATH = "forecast/hours:lookup" + private const val MINUTELY_FORECAST_PATH = "forecast/minutes:lookup" + private const val PUBLIC_ALERTS_PATH = "publicAlerts:lookup" } init { @@ -87,6 +89,10 @@ class GoogleWeatherProvider : WeatherProviderImpl() { return AuthType.APIKEY } + override fun needsExternalAlertData(): Boolean { + return false + } + @Throws(WeatherException::class) override suspend fun isKeyValid(key: String?): Boolean = withContext(Dispatchers.IO) { if (key.isNullOrBlank()) { @@ -226,6 +232,36 @@ class GoogleWeatherProvider : WeatherProviderImpl() { .addGoogleAuth(context) .build() + val minutelyRequestUri = BASE_URL.toUri().buildUpon() + .appendEncodedPath(MINUTELY_FORECAST_PATH) + .appendQueryParameter("location.latitude", df.format(location.latitude)) + .appendQueryParameter("location.longitude", df.format(location.longitude)) + .appendQueryParameter("units_system", "METRIC") + .appendQueryParameter("key", key) + .build() + + val minutelyRequest = Request.Builder() + .cacheRequestIfNeeded(isKeyRequired(), 1, TimeUnit.HOURS) + .url(minutelyRequestUri.toString()) + .addUserAgent(context) + .addGoogleAuth(context) + .build() + + val alertRequestUri = BASE_URL.toUri().buildUpon() + .appendEncodedPath(PUBLIC_ALERTS_PATH) + .appendQueryParameter("location.latitude", df.format(location.latitude)) + .appendQueryParameter("location.longitude", df.format(location.longitude)) + .appendQueryParameter("languageCode", locale) + .appendQueryParameter("key", key) + .build() + + val alertRequest = Request.Builder() + .cacheRequestIfNeeded(isKeyRequired(), 1, TimeUnit.HOURS) + .url(alertRequestUri.toString()) + .addUserAgent(context) + .addGoogleAuth(context) + .build() + // Connect to webstream conditionResponse = client.newCall(conditionRequest).await() checkForErrors(conditionResponse) @@ -238,8 +274,16 @@ class GoogleWeatherProvider : WeatherProviderImpl() { val dailyData = getDailyForecasts(client, dailyRequest) val hourlyData = getHourlyForecasts(client, hourlyRequest) - - weather = createWeatherData(conditionData, dailyData, hourlyData) + val minutelyData = getMinutelyForecasts(client, minutelyRequest) + val alertData = getPublicAlerts(client, alertRequest) + + weather = createWeatherData( + conditionData, + dailyData, + hourlyData, + minutely = minutelyData, + alerts = alertData + ) } catch (ex: Exception) { weather = null if (ex is IOException) { @@ -343,7 +387,89 @@ class GoogleWeatherProvider : WeatherProviderImpl() { return hourlyData } + private suspend fun getMinutelyForecasts( + client: OkHttpClient, + minutelyRequest: Request + ): MinutelyResponse { + val minutelyData = MinutelyResponse() + val minutelySegments = mutableListOf() + + do { + val request = if (minutelyData.nextPageToken != null) { + val newUrl = minutelyRequest.url.newBuilder() + .setQueryParameter("pageToken", minutelyData.nextPageToken) + .build() + + minutelyRequest.newBuilder() + .url(newUrl) + .build() + } else { + minutelyRequest + } + + val minutelyResponse = client.newCall(request).await() + checkForErrors(minutelyResponse) + val minutelyResponseData = minutelyResponse.use { r -> + r.getStream().use { s -> + JSONParser.deserializer(s, MinutelyResponse::class.java) + } + } + + minutelyData.overallPredictionTimeframe = minutelyData.overallPredictionTimeframe + ?: minutelyResponseData?.overallPredictionTimeframe + minutelyData.timeZone = minutelyData.timeZone ?: minutelyResponseData?.timeZone + minutelyData.nextPageToken = minutelyResponseData?.nextPageToken + + minutelyResponseData?.segments?.run { minutelySegments.addAll(this) } + } while (!minutelyData.nextPageToken.isNullOrEmpty()) + + minutelyData.segments = minutelySegments + + return minutelyData + } + + private suspend fun getPublicAlerts( + client: OkHttpClient, + alertsRequest: Request + ): AlertsResponse { + val alertsData = AlertsResponse() + val weatherAlerts = mutableListOf() + + do { + val request = if (alertsData.nextPageToken != null) { + val newUrl = alertsRequest.url.newBuilder() + .setQueryParameter("pageToken", alertsData.nextPageToken) + .build() + + alertsRequest.newBuilder() + .url(newUrl) + .build() + } else { + alertsRequest + } + + val alertsResponse = client.newCall(request).await() + checkForErrors(alertsResponse) + val alertsResponseData = alertsResponse.use { r -> + r.getStream().use { s -> + JSONParser.deserializer(s, AlertsResponse::class.java) + } + } + + alertsData.regionCode = alertsData.regionCode ?: alertsResponseData?.regionCode + alertsData.nextPageToken = alertsResponseData?.nextPageToken + + alertsResponseData?.weatherAlerts?.run { weatherAlerts.addAll(this) } + } while (!alertsData.nextPageToken.isNullOrEmpty()) + + alertsData.weatherAlerts = weatherAlerts + + return alertsData + } + override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // Update forecast, hourly, sunrise/sunset, moonrise/moonset val offset = location.tzOffset @@ -357,6 +483,13 @@ class GoogleWeatherProvider : WeatherProviderImpl() { weather.hrForecast?.forEach { hr_forecast -> hr_forecast.date = hr_forecast.date.withZoneSameInstant(offset) } + weather.minForecast?.forEach { min_forecast -> + min_forecast.date = min_forecast.date.withZoneSameInstant(offset) + } + weather.weatherAlerts?.forEach { alert -> + alert.date = alert.date.withZoneSameInstant(offset) + alert.expiresDate = alert.expiresDate.withZoneSameInstant(offset) + } if (weather.astronomy != null) { // The time of day is set to max if the sun never sets/rises and diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/MinutelyResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/MinutelyResponse.kt new file mode 100644 index 000000000..9d28d1c9c --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/MinutelyResponse.kt @@ -0,0 +1,72 @@ +package com.thewizrd.weather_api.google.weather + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class MinutelyResponse( + + @Json(name = "timeZone") + var timeZone: TimeZone? = null, + + @Json(name = "overallPredictionTimeframe") + var overallPredictionTimeframe: OverallPredictionTimeframe? = null, + + @Json(name = "segments") + var segments: List? = null, + + @Json(name = "nextPageToken") + var nextPageToken: String? = null +) + +@JsonClass(generateAdapter = true) +data class OverallPredictionTimeframe( + + @Json(name = "startTime") + var startTime: String? = null, + + @Json(name = "endTime") + var endTime: String? = null +) + +@JsonClass(generateAdapter = true) +data class SnowfallAmount( + + @Json(name = "unit") + var unit: String? = null, + + @Json(name = "quantity") + var quantity: Float? = null +) + +@JsonClass(generateAdapter = true) +data class TimeFrame( + + @Json(name = "startTime") + var startTime: String? = null, + + @Json(name = "endTime") + var endTime: String? = null +) + +@JsonClass(generateAdapter = true) +data class SegmentsItem( + + @Json(name = "intensity") + var intensity: String? = null, + + @Json(name = "snowfallAmount") + var snowfallAmount: SnowfallAmount? = null, + + @Json(name = "probability") + var probability: Int? = null, + + @Json(name = "qpf") + var qpf: Qpf? = null, + + @Json(name = "type") + var type: String? = null, + + @Json(name = "timeFrame") + var timeFrame: TimeFrame? = null +) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherAlerts.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherAlerts.kt new file mode 100644 index 000000000..b3de4d100 --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherAlerts.kt @@ -0,0 +1,56 @@ +package com.thewizrd.weather_api.google.weather + +import com.thewizrd.shared_resources.weatherdata.model.WeatherAlert +import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertSeverity +import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertType +import java.time.ZonedDateTime + +fun createWeatherAlerts(response: AlertsResponse?): Collection? { + return response?.weatherAlerts?.map { + createWeatherAlert(it) + } +} + +fun createWeatherAlert(alert: PublicAlerts): WeatherAlert { + return WeatherAlert().apply { + title = alert.alertTitle?.text + message = alert.description + attribution = alert.dataSource?.name + date = ZonedDateTime.parse(alert.startTime) + expiresDate = ZonedDateTime.parse(alert.expirationTime) + severity = when (alert.severity) { + "EXTREME" -> WeatherAlertSeverity.EXTREME + "SEVERE" -> WeatherAlertSeverity.SEVERE + "MODERATE" -> WeatherAlertSeverity.MODERATE + "MINOR" -> WeatherAlertSeverity.MINOR + else -> WeatherAlertSeverity.UNKNOWN + } + type = when (alert.eventType) { + "ACID_RAIN", "AVALANCHE", "DROUGHT", + "HUMIDITY", "LANDSLIDE", "MONSOON", "OUTFLOW", "RADIATION", "RAIN_EVENT" -> WeatherAlertType.SPECIALWEATHERALERT + + "BLIZZARD", "BLOWING_SNOW", "COLD", "FREEZING", "FREEZING_AIR_TEMPERATURE", + "FREEZING_DRIZZLE", "FREEZING_RAIN_EVENT", "FROST", "GLAZE", "ICE_STORM", + "LAKE_EFFECT_SNOW", "SNOWSQUALL", "SNOW_EVENT", "WIND_CHILL", "WINTER_STORM" -> WeatherAlertType.WINTERWEATHER + + "BUSHFIRE", "FIRE", "FIRE_WEATHER", "INDUSTRIAL_FIRE", "WILDFIRE" -> WeatherAlertType.FIRE + "COASTAL_FLOOD", "COASTAL_HAZARD", "FLASH_FLOOD", "FLOOD", "MUDDY_FLOOD", "RIVER_FLOODING" -> WeatherAlertType.FLOODWARNING + "DUST_STORM" -> WeatherAlertType.DUSTADVISORY + "AFTERSHOCK", "EARTHQUAKE" -> WeatherAlertType.EARTHQUAKEWARNING + "FOG" -> WeatherAlertType.DENSEFOG + "GALE" -> WeatherAlertType.GALEWARNING + "HEAT" -> WeatherAlertType.HEAT + "HURRICANE", "CYCLONE", "EXTRATROPICAL_CYCLONE", "TROPICAL_CYCLONE", + "TROPICAL_CYCLONE_WARNINGS_AND_WATCHES", "TROPICAL_DISTURBANCE", "TROPICAL_STORM", "TYPHOON" -> WeatherAlertType.HURRICANEWINDWARNING + + "SEVERE_THUNDERSTORM_WARNING", "THUNDER", "THUNDERSTORM", "HAIL" -> WeatherAlertType.SEVERETHUNDERSTORMWARNING + "STORM", "STORM_SURGE" -> WeatherAlertType.STORMWARNING + "TORNADO", "TORNADO_WARNING" -> WeatherAlertType.TORNADOWARNING + "TSUNAMI" -> WeatherAlertType.TSUNAMIWARNING + "VOLCANIC_ASH", "VOLCANIC_ERUPTION" -> WeatherAlertType.VOLCANO + "WIND" -> WeatherAlertType.HIGHWIND + "HAZARDOUS_SEAS", "WIND_WAVE" -> WeatherAlertType.SMALLCRAFT + else -> WeatherAlertType.SPECIALWEATHERALERT + } + } +} \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherData.kt index b3b114266..719a1468f 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/weather/WeatherData.kt @@ -1,5 +1,6 @@ package com.thewizrd.weather_api.google.weather +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.ConversionMethods import com.thewizrd.shared_resources.utils.DateTimeUtils @@ -13,20 +14,23 @@ import com.thewizrd.shared_resources.weatherdata.model.Forecast import com.thewizrd.shared_resources.weatherdata.model.ForecastExtras import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Location +import com.thewizrd.shared_resources.weatherdata.model.MinutelyForecast import com.thewizrd.shared_resources.weatherdata.model.MoonPhase import com.thewizrd.shared_resources.weatherdata.model.MoonPhase.MoonPhaseType import com.thewizrd.shared_resources.weatherdata.model.TextForecast import com.thewizrd.shared_resources.weatherdata.model.UV import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.weatherModule import java.time.LocalDateTime +import java.time.ZoneOffset import java.time.ZonedDateTime fun createWeatherData( current: CurrentResponse, daily: DailyResponse, - hourly: HourlyResponse + hourly: HourlyResponse, + minutely: MinutelyResponse? = null, + alerts: AlertsResponse? = null ): Weather { return Weather().apply { @@ -69,13 +73,18 @@ fun createWeatherData( createHourlyForecast(it) } + minForecast = minutely?.segments?.map { + createMinutelyForecast(it) + } + condition = createCondition(current, todaysForecast?.second, todaysTxtForecast) atmosphere = createAtmosphere(current) astronomy = createAstronomy(todaysForecast?.first) precipitation = createPrecipitation(current) + weatherAlerts = createWeatherAlerts(alerts) ttl = 60 // TODO: TBD - if ((condition!!.highF == null || condition!!.highC == null) && forecast!!.size > 0) { + if ((condition!!.highF == null || condition!!.highC == null) && forecast!!.isNotEmpty()) { condition!!.highF = forecast!![0].highF condition!!.highC = forecast!![0].highC condition!!.lowF = forecast!![0].lowF @@ -249,12 +258,6 @@ fun createHourlyForecast(hour: ForecastHoursItem): HourlyForecast { icon = wm.getWeatherIcon(hour.isDaytime?.not() ?: false, hour.weatherCondition?.type) condition = hour.weatherCondition?.description?.text - windDegrees = hour.wind?.direction?.degrees - hour.wind?.speed?.value?.let { - windKph = it - windMph = ConversionMethods.kphTomph(it) - } - extras = ForecastExtras() hour.feelsLikeTemperature?.degrees?.let { extras.feelslikeC = it @@ -275,9 +278,11 @@ fun createHourlyForecast(hour: ForecastHoursItem): HourlyForecast { extras.pressureMb = it extras.pressureIn = ConversionMethods.mbToInHg(it) } - extras.windDegrees = windDegrees - extras.windKph = windKph - extras.windMph = windMph + extras.windDegrees = hour.wind?.direction?.degrees + hour.wind?.speed?.value?.let { + extras.windKph = it + extras.windMph = ConversionMethods.kphTomph(it) + } hour.wind?.gust?.value?.let { extras.windGustKph = it extras.windGustMph = ConversionMethods.kphTomph(it) @@ -290,6 +295,14 @@ fun createHourlyForecast(hour: ForecastHoursItem): HourlyForecast { } } +fun createMinutelyForecast(minute: SegmentsItem): MinutelyForecast { + return MinutelyForecast().apply { + date = ZonedDateTime.parse(minute.timeFrame?.startTime).withZoneSameInstant(ZoneOffset.UTC) + rainMm = minute.qpf?.quantity + snowMm = minute.snowfallAmount?.quantity + } +} + fun createAtmosphere(current: CurrentResponse): Atmosphere { return Atmosphere().apply { current.dewPoint?.degrees?.let { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt index 90c347164..74c17cf46 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt @@ -214,16 +214,13 @@ class HEREWeatherProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset weather.weatherAlerts?.forEach { alert -> - if (alert.date.offset != offset) { - alert.date = alert.date.withZoneSameLocal(offset) - } - - if (alert.expiresDate.offset != offset) { - alert.expiresDate = alert.expiresDate.withZoneSameLocal(offset) - } + alert.date = alert.date.withZoneSameInstant(offset) + alert.expiresDate = alert.expiresDate.withZoneSameInstant(offset) } // Update tz for weather properties diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/WeatherData.kt index 68f6b40e9..a76580b89 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/WeatherData.kt @@ -201,12 +201,6 @@ fun createHourlyForecast(hr_forecast: ForecastsItem): HourlyForecast { hr_forecast.iconName ) - windDegrees = hr_forecast.windDirection?.toIntOrNull() - hr_forecast.windSpeed?.toFloatOrNull()?.let { - windMph = it - windKph = ConversionMethods.mphTokph(it) - } - // Extras extras = ForecastExtras() hr_forecast.comfort?.toFloatOrNull()?.let { @@ -237,9 +231,11 @@ fun createHourlyForecast(hr_forecast: ForecastsItem): HourlyForecast { extras.pressureIn = it extras.pressureMb = ConversionMethods.inHgToMB(it) } - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = hr_forecast.windDirection?.toIntOrNull() + hr_forecast.windSpeed?.toFloatOrNull()?.let { + extras.windMph = it + extras.windKph = ConversionMethods.mphTokph(it) + } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/Common.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/Common.kt new file mode 100644 index 000000000..bc6ea1164 --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/Common.kt @@ -0,0 +1,14 @@ +package com.thewizrd.weather_api.meteofrance.weather + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class Geometry( + + @Json(name = "coordinates") + val coordinates: List? = null, + + @Json(name = "type") + val type: String? = null +) \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/CurrentsResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/CurrentsResponse.kt index 1bbedda8e..bfee7c5fe 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/CurrentsResponse.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/CurrentsResponse.kt @@ -6,61 +6,53 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class CurrentsResponse( - @field:Json(name = "updated_on") - var updatedOn: Long? = null, + @Json(name = "update_time") + val updateTime: String? = null, - @field:Json(name = "observation") - var observation: Observation? = null, + @Json(name = "geometry") + val geometry: Geometry? = null, - @field:Json(name = "position") - var position: CurrentsPosition? = null + @Json(name = "type") + val type: String? = null, + + @Json(name = "properties") + val properties: CurrentProperties? = null ) @JsonClass(generateAdapter = true) -data class CurrentsPosition( - - @field:Json(name = "timezone") - var timezone: String? = null, +data class CurrentProperties( - @field:Json(name = "lon") - var lon: Float? = null, + @Json(name = "timezone") + val timezone: String? = null, - @field:Json(name = "lat") - var lat: Float? = null + @Json(name = "gridded") + val gridded: Gridded? = null ) @JsonClass(generateAdapter = true) -data class Observation( +data class Gridded( - @field:Json(name = "T") - var T: Float? = null, + @Json(name = "T") + val t: Float? = null, - @field:Json(name = "weather") - var weather: Weather? = null, + @Json(name = "weather_description") + val weatherDescription: String? = null, - @field:Json(name = "wind") - var wind: Wind? = null -) -/* -@JsonClass(generateAdapter = true) -data class Weather( + @Json(name = "wind_icon") + val windIcon: String? = null, - @field:Json(name = "icon") - var icon: String? = null, + @Json(name = "wind_speed") + val windSpeed: Float? = null, - @field:Json(name = "desc") - var desc: String? = null -) -@JsonClass(generateAdapter = true) -data class Wind( + @Json(name = "wind_direction") + val windDirection: Int? = null, - @field:Json(name = "icon") - var icon: String? = null, + @Json(name = "time") + val time: String? = null, - @field:Json(name = "speed") - var speed: Int? = null, + @Json(name = "weather_icon") + val weatherIcon: String? = null, - @field:Json(name = "direction") - var direction: Int? = null -) -*/ \ No newline at end of file + @Json(name = "wind_speed_gust") + val windSpeedGust: Float? = null +) \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/ForecastResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/ForecastResponse.kt index 9eca47dfd..581371a5e 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/ForecastResponse.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/ForecastResponse.kt @@ -6,242 +6,196 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class ForecastResponse( - @field:Json(name = "updated_on") - var updatedOn: Long? = null, + @Json(name = "update_time") + val updateTime: String? = null, - @field:Json(name = "probability_forecast") - var probabilityForecast: List? = null, + @Json(name = "geometry") + val geometry: Geometry? = null, - @field:Json(name = "forecast") - var forecast: List? = null, + @Json(name = "type") + val type: String? = null, - @field:Json(name = "position") - var position: ForecastPosition? = null, - - @field:Json(name = "daily_forecast") - var dailyForecast: List? = null -) - -@JsonClass(generateAdapter = true) -data class Rain( - - @field:Json(name = "6h") - var jsonMember6h: Float? = null, - - @field:Json(name = "3h") - var jsonMember3h: Float? = null, - - @field:Json(name = "1h") - var jsonMember1h: Float? = null + @Json(name = "properties") + val properties: ForecastProperties? = null ) @JsonClass(generateAdapter = true) -data class Weather12H( - - @field:Json(name = "icon") - var icon: String? = null, - - @field:Json(name = "desc") - var desc: String? = null -) +data class DailyForecastItem( -@JsonClass(generateAdapter = true) -data class ForecastItem( + @Json(name = "daily_weather_icon") + val dailyWeatherIcon: String? = null, - @field:Json(name = "dt") - var dt: Long? = null, + @Json(name = "sunset_time") + val sunsetTime: String? = null, - @field:Json(name = "rain") - var rain: Rain? = null, + @Json(name = "daily_weather_description") + val dailyWeatherDescription: String? = null, - @field:Json(name = "T") - var T: ForecastTemp? = null, + @Json(name = "uv_index") + val uvIndex: Float? = null, - @field:Json(name = "snow") - var snow: Snow? = null, + @Json(name = "T_max") + val tMax: Float? = null, - @field:Json(name = "weather") - var weather: Weather? = null, + @Json(name = "total_precipitation_24h") + val totalPrecipitation24h: Float? = null, - @field:Json(name = "humidity") - var humidity: Int? = null, + @Json(name = "relative_humidity_min") + val relativeHumidityMin: Int? = null, - @field:Json(name = "rain snow limit") - var rainSnowLimit: String? = null, + @Json(name = "relative_humidity_max") + val relativeHumidityMax: Int? = null, - @field:Json(name = "iso0") - var iso0: Int? = null, + @Json(name = "sunrise_time") + val sunriseTime: String? = null, - @field:Json(name = "sea_level") - var seaLevel: Float? = null, + @Json(name = "time") + val time: String? = null, - @field:Json(name = "clouds") - var clouds: Int? = null, + @Json(name = "T_min") + val tMin: Float? = null, - @field:Json(name = "wind") - var wind: Wind? = null + @Json(name = "T_sea") + val tSea: Float? = null ) @JsonClass(generateAdapter = true) -data class ForecastPosition( - - @field:Json(name = "bulletin_cote") - var bulletinCote: Int? = null, - - @field:Json(name = "country") - var country: String? = null, - - @field:Json(name = "insee") - var insee: String? = null, +data class ProbabilityForecastItem( - @field:Json(name = "timezone") - var timezone: String? = null, + @Json(name = "freezing_hazard") + val freezingHazard: Int? = null, - @field:Json(name = "name") - var name: String? = null, + @Json(name = "snow_hazard_3h") + val snowHazard3h: Float? = null, - @field:Json(name = "lon") - var lon: Float? = null, + @Json(name = "snow_hazard_6h") + val snowHazard6h: Float? = null, - @field:Json(name = "dept") - var dept: String? = null, + @Json(name = "rain_hazard_3h") + val rainHazard3h: Float? = null, - @field:Json(name = "alti") - var alti: Int? = null, + @Json(name = "rain_hazard_6h") + val rainHazard6h: Float? = null, - @field:Json(name = "lat") - var lat: Float? = null, + @Json(name = "time") + val time: String? = null, - @field:Json(name = "rain_product_available") - var rainProductAvailable: Int? = null + @Json(name = "storm_hazard") + val stormHazard: Int? = null ) @JsonClass(generateAdapter = true) -data class Weather( - - @field:Json(name = "icon") - var icon: String? = null, +data class ForecastItem( - @field:Json(name = "desc") - var desc: String? = null -) + @Json(name = "weather_icon") + val weatherIcon: String? = null, -@JsonClass(generateAdapter = true) -data class Precipitation( + @Json(name = "rain_24h") + val rain24h: Float? = null, - @field:Json(name = "24h") - var jsonMember24h: Float? = null -) + @Json(name = "T") + val t: Float? = null, -@JsonClass(generateAdapter = true) -data class DailyForecastTemp( + @Json(name = "rain_12h") + val rain12h: Float? = null, - @field:Json(name = "min") - var min: Float? = null, + @Json(name = "weather_confidence_index") + val weatherConfidenceIndex: Int? = null, - @field:Json(name = "max") - var max: Float? = null, + @Json(name = "wind_speed") + val windSpeed: Float? = null, - @field:Json(name = "sea") - var sea: Float? = null -) + @Json(name = "snow_6h") + val snow6h: Float? = null, -@JsonClass(generateAdapter = true) -data class ForecastTemp( + @Json(name = "snow_12h") + val snow12h: Float? = null, - @field:Json(name = "value") - var value: Float? = null, + @Json(name = "T_windchill") + val tWindchill: Float? = null, - @field:Json(name = "windchill") - var windchill: Float? = null -) + @Json(name = "snow_24h") + val snow24h: Float? = null, -@JsonClass(generateAdapter = true) -data class Sun( + @Json(name = "snow_3h") + val snow3h: Float? = null, - @field:Json(name = "set") - var set: Long? = null, + @Json(name = "weather_description") + val weatherDescription: String? = null, - @field:Json(name = "rise") - var rise: Long? = null -) + @Json(name = "rain_1h") + val rain1h: Float? = null, -@JsonClass(generateAdapter = true) -data class DailyForecastItem( + @Json(name = "snow_1h") + val snow1h: Float? = null, - @field:Json(name = "dt") - var dt: Long? = null, + @Json(name = "rain_3h") + val rain3h: Float? = null, - @field:Json(name = "precipitation") - var precipitation: Precipitation? = null, + @Json(name = "total_cloud_cover") + val totalCloudCover: Int? = null, - @field:Json(name = "uv") - var uv: Float? = null, + @Json(name = "wind_direction") + val windDirection: Int? = null, - @field:Json(name = "T") - var T: DailyForecastTemp? = null, + @Json(name = "wind_speed_gust") + val windSpeedGust: Float? = null, - @field:Json(name = "weather12H") - var weather12H: Weather12H? = null, + @Json(name = "P_sea") + val pSea: Float? = null, - @field:Json(name = "humidity") - var humidity: Humidity? = null, + @Json(name = "rain_snow_limit") + val rainSnowLimit: String? = null, - @field:Json(name = "sun") - var sun: Sun? = null -) + @Json(name = "wind_icon") + val windIcon: String? = null, -@JsonClass(generateAdapter = true) -data class Snow( + @Json(name = "rain_6h") + val rain6h: Float? = null, - @field:Json(name = "6h") - var jsonMember6h: Float? = null, + @Json(name = "iso0") + val iso0: Int? = null, - @field:Json(name = "3h") - var jsonMember3h: Float? = null, + @Json(name = "time") + val time: String? = null, - @field:Json(name = "1h") - var jsonMember1h: Float? = null + @Json(name = "relative_humidity") + val relativeHumidity: Int? = null ) @JsonClass(generateAdapter = true) -data class Humidity( +data class ForecastProperties( - @field:Json(name = "min") - var min: Int? = null, + @Json(name = "bulletin_cote") + val bulletinCote: Int? = null, - @field:Json(name = "max") - var max: Int? = null -) + @Json(name = "altitude") + val altitude: Int? = null, -@JsonClass(generateAdapter = true) -data class ProbabilityForecastItem( - - @field:Json(name = "dt") - var dt: Long? = null, + @Json(name = "country") + val country: String? = null, - @field:Json(name = "rain") - var rain: Rain? = null, + @Json(name = "french_department") + val frenchDepartment: String? = null, - @field:Json(name = "freezing") - var freezing: Int? = null, + @Json(name = "insee") + val insee: String? = null, - @field:Json(name = "snow") - var snow: Snow? = null -) + @Json(name = "timezone") + val timezone: String? = null, -@JsonClass(generateAdapter = true) -data class Wind( + @Json(name = "probability_forecast") + val probabilityForecast: List? = null, - @field:Json(name = "icon") - var icon: String? = null, + @Json(name = "name") + val name: String? = null, - @field:Json(name = "speed") - var speed: Float? = null, + @Json(name = "forecast") + val forecast: List? = null, - @field:Json(name = "gust") - var gust: Float? = null, + @Json(name = "daily_forecast") + val dailyForecast: List? = null, - @field:Json(name = "direction") - var direction: Int? = null + @Json(name = "rain_product_available") + val rainProductAvailable: Int? = null ) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt index b82630063..feb742419 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt @@ -1,6 +1,7 @@ package com.thewizrd.weather_api.meteofrance.weather import android.util.Log +import androidx.core.net.toUri import com.ibm.icu.util.ULocale import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException @@ -11,7 +12,12 @@ import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.LocationUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.ZoneIdCompat +import com.thewizrd.shared_resources.utils.createUnsupportedLocationException import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.auth.AuthType import com.thewizrd.shared_resources.weatherdata.model.Weather @@ -38,15 +44,12 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class MeteoFranceProvider : WeatherProviderImpl() { companion object { private const val BASE_URL = "https://webservice.meteofrance.com/" - private const val CURRENT_QUERY_URL = BASE_URL + "observation/gridded?%s&lang=%s&token=%s" - private const val FORECAST_QUERY_URL = BASE_URL + "forecast?%s&lang=%s&token=%s" - private const val ALERTS_QUERY_URL = BASE_URL + "warning/full?domain=%s&token=%s" } init { @@ -140,13 +143,33 @@ class MeteoFranceProvider : WeatherProviderImpl() { throw WeatherException(ErrorStatus.INVALIDAPIKEY) } + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") + + val currentRequestUri = BASE_URL.toUri().buildUpon() + .appendPath("v2/observation") + .appendQueryParameter("lat", df.format(location.latitude)) + .appendQueryParameter("lon", df.format(location.longitude)) + .appendQueryParameter("lang", locale) + .appendQueryParameter("token", key) + .build() + val currentRequest = Request.Builder() .cacheRequestIfNeeded(isKeyRequired(), 15, TimeUnit.MINUTES) - .url(String.format(CURRENT_QUERY_URL, query, locale, key)) + .url(currentRequestUri.toString()) .build() + + val forecastRequestUri = BASE_URL.toUri().buildUpon() + .appendPath("v2/forecast") + .appendQueryParameter("lat", df.format(location.latitude)) + .appendQueryParameter("lon", df.format(location.longitude)) + .appendQueryParameter("lang", locale) + .appendQueryParameter("token", key) + .build() + val forecastRequest = Request.Builder() .cacheRequestIfNeeded(isKeyRequired(), 1, TimeUnit.HOURS) - .url(String.format(FORECAST_QUERY_URL, query, locale, key)) + .url(forecastRequestUri.toString()) .build() // Connect to webstream @@ -171,18 +194,28 @@ class MeteoFranceProvider : WeatherProviderImpl() { ) var alertsRoot: AlertsResponse? = null - if (foreRoot?.position?.dept != null) { + foreRoot?.properties?.frenchDepartment.let { dept -> + val alertsRequestUri = BASE_URL.toUri().buildUpon() + .appendPath("v3/warning/full") + .appendQueryParameter("domain", dept) + .appendQueryParameter("token", key) + .build() + val alertsRequest = Request.Builder() .cacheRequestIfNeeded(isKeyRequired(), 1, TimeUnit.HOURS) - .url(String.format(ALERTS_QUERY_URL, foreRoot.position!!.dept, key)) + .url(alertsRequestUri.toString()) .build() - alertsResponse = client.newCall(alertsRequest).await() - alertStream = alertsResponse.getStream() - alertsRoot = JSONParser.deserializer( - alertStream, - AlertsResponse::class.java - ) + runCatching { + alertsResponse = client.newCall(alertsRequest).await() + alertStream = alertsResponse.getStream() + alertsRoot = JSONParser.deserializer( + alertStream, + AlertsResponse::class.java + ) + }.getOrElse { + Logger.warn("MeteoFranceProvider", it, "Error fetching alerts") + } } // End Stream @@ -227,6 +260,8 @@ class MeteoFranceProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // MeteoFrance reports datetime in UTC; add location tz_offset val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) @@ -242,36 +277,23 @@ class MeteoFranceProvider : WeatherProviderImpl() { } // Update icons - val now = ZonedDateTime.now(ZoneOffset.UTC).withZoneSameInstant(offset).toLocalTime() - val sunrise = weather.astronomy!!.sunrise.toLocalTime() - val sunset = weather.astronomy!!.sunset.toLocalTime() - - weather.condition!!.icon = - getWeatherIcon(now.isBefore(sunrise) || now.isAfter(sunset), weather.condition!!.icon) + weather.condition!!.icon = getWeatherIcon(weather.condition!!.icon) for (forecast in weather.forecast!!) { forecast.date = forecast.date.plusSeconds(offset.totalSeconds.toLong()) + forecast.icon = getWeatherIcon(false, forecast.icon) } for (hr_forecast in weather.hrForecast!!) { val hrf_date = hr_forecast.date.withZoneSameInstant(offset) hr_forecast.date = hrf_date - val hrf_localTime = hrf_date.toLocalTime() - hr_forecast.icon = getWeatherIcon( - hrf_localTime.isBefore(sunrise) || hrf_localTime.isAfter(sunset), - hr_forecast.icon - ) + hr_forecast.icon = getWeatherIcon(hr_forecast.icon) } if (!weather.weatherAlerts.isNullOrEmpty()) { for (alert in weather.weatherAlerts) { - if (alert.date.offset != offset) { - alert.date = alert.date.withZoneSameLocal(offset) - } - - if (alert.expiresDate.offset != offset) { - alert.expiresDate = alert.expiresDate.withZoneSameLocal(offset) - } + alert.date = alert.date.withZoneSameInstant(offset) + alert.expiresDate = alert.expiresDate.withZoneSameInstant(offset) } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt index 4c4b5d4c1..458923277 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt @@ -16,12 +16,10 @@ import com.thewizrd.shared_resources.weatherdata.model.Location import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.weather_api.weatherModule -import java.time.Instant -import java.time.LocalDateTime import java.time.ZoneOffset import java.time.ZonedDateTime +import java.time.temporal.ChronoUnit import java.util.Locale -import java.util.concurrent.TimeUnit import kotlin.math.roundToInt @SuppressLint("VisibleForTests") @@ -31,41 +29,40 @@ fun createWeatherData(currRoot: CurrentsResponse, foreRoot: ForecastResponse, location = createLocation(foreRoot) updateTime = ZonedDateTime.now(ZoneOffset.UTC) - forecast = ArrayList(foreRoot.dailyForecast!!.size) - hrForecast = ArrayList(foreRoot.forecast!!.size) - // Forecast - for (daily in foreRoot.dailyForecast!!) { - forecast!!.add(createForecast(daily!!)) + forecast = foreRoot.properties?.dailyForecast?.map { daily -> + createForecast(daily) } - - for (hourly in foreRoot.forecast!!) { - hrForecast!!.add(createHourlyForecast(hourly!!, foreRoot.probabilityForecast)) + hrForecast = foreRoot.properties?.forecast?.map { hourly -> + createHourlyForecast(hourly, foreRoot.properties.probabilityForecast) } condition = createCondition(currRoot) atmosphere = createAtmosphere(currRoot) + precipitation = createPrecipitation(currRoot) ttl = 180 // Observation only gives temp & wind if (!hrForecast.isNullOrEmpty()) { val firstHr = hrForecast!![0] - atmosphere!!.humidity = firstHr.extras.humidity - atmosphere!!.pressureMb = firstHr.extras.pressureMb - atmosphere!!.pressureIn = firstHr.extras.pressureIn - atmosphere!!.dewpointC = firstHr.extras.dewpointC - atmosphere!!.dewpointF = firstHr.extras.dewpointF - atmosphere!!.visibilityKm = firstHr.extras.visibilityKm - atmosphere!!.visibilityMi = firstHr.extras.visibilityMi - - precipitation = Precipitation().apply { - cloudiness = firstHr.extras.cloudiness - pop = firstHr.extras.pop - qpfRainIn = firstHr.extras.qpfRainIn - qpfRainMm = firstHr.extras.qpfRainMm - qpfSnowIn = firstHr.extras.qpfSnowIn - qpfSnowCm = firstHr.extras.qpfSnowCm + atmosphere?.run { + humidity = firstHr.extras?.humidity + pressureMb = firstHr.extras?.pressureMb + pressureIn = firstHr.extras?.pressureIn + dewpointC = firstHr.extras?.dewpointC + dewpointF = firstHr.extras?.dewpointF + visibilityKm = firstHr.extras?.visibilityKm + visibilityMi = firstHr.extras?.visibilityMi + } + + precipitation?.run { + cloudiness = firstHr.extras?.cloudiness + pop = firstHr.extras?.pop + qpfRainIn = firstHr.extras?.qpfRainIn + qpfRainMm = firstHr.extras?.qpfRainMm + qpfSnowIn = firstHr.extras?.qpfSnowIn + qpfSnowCm = firstHr.extras?.qpfSnowCm } } @@ -76,7 +73,7 @@ fun createWeatherData(currRoot: CurrentsResponse, foreRoot: ForecastResponse, condition!!.feelslikeC = ConversionMethods.FtoC(condition!!.feelslikeF) } - if ((condition?.highF == null || condition?.highC == null) && forecast!!.size > 0) { + if ((condition?.highF == null || condition?.highC == null) && forecast!!.isNotEmpty()) { condition!!.highF = forecast!![0].highF condition!!.highC = forecast!![0].highC condition!!.lowF = forecast!![0].lowF @@ -93,9 +90,9 @@ fun createLocation(foreRoot: ForecastResponse): Location { return Location().apply { // Use location name from location provider name = null - latitude = foreRoot.position?.lat - longitude = foreRoot.position?.lon - tzLong = foreRoot.position?.timezone + latitude = foreRoot.geometry?.coordinates?.getOrNull(1) + longitude = foreRoot.geometry?.coordinates?.getOrNull(0) + tzLong = foreRoot.properties?.timezone } } @@ -104,130 +101,122 @@ fun createForecast(day: DailyForecastItem): Forecast { val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.METEOFRANCE) val locale = LocaleUtils.getLocale() - date = LocalDateTime.ofEpochSecond(day.dt!!, 0, ZoneOffset.UTC) + date = ZonedDateTime.parse(day.time).toLocalDateTime() - day.T?.max?.let { + day.tMax?.let { highC = it highF = ConversionMethods.CtoF(it) } - day.T?.min?.let { + day.tMin?.let { lowC = it lowF = ConversionMethods.CtoF(it) } condition = - if (!day.weather12H?.desc.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!day.dailyWeatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() .startsWith("en_") || locale.toString() == "fr" || locale.toString().startsWith("fr_") || locale == Locale.ROOT ) { - day.weather12H?.desc + day.dailyWeatherDescription } else { - provider.getWeatherCondition(day.weather12H?.icon) + provider.getWeatherCondition(provider.getWeatherIcon(false, day.dailyWeatherIcon)) } - icon = provider.getWeatherIcon(false, day.weather12H?.icon) + icon = day.dailyWeatherIcon // Extras extras = ForecastExtras() - if (day.humidity?.max != null && day.humidity?.min != null) { - extras.humidity = ((day.humidity!!.min!! + day.humidity!!.max!!) / 2f).roundToInt() + if (day.relativeHumidityMax != null && day.relativeHumidityMin != null) { + extras.humidity = + ((day.relativeHumidityMin + day.relativeHumidityMax) / 2f).roundToInt() } - day.T?.sea?.let { + day.tSea?.let { extras.pressureMb = it extras.pressureIn = ConversionMethods.mbToInHg(it) } - day.precipitation?.jsonMember24h?.let { + day.totalPrecipitation24h?.let { extras.qpfRainMm = it extras.qpfRainIn = ConversionMethods.mmToIn(it) } - extras.uvIndex = day.uv + extras.uvIndex = day.uvIndex } } fun createHourlyForecast(forecast: ForecastItem, - probabilityForecasts: List?): HourlyForecast { + probabilityForecasts: List? +): HourlyForecast { return HourlyForecast().apply { val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.METEOFRANCE) val locale = LocaleUtils.getLocale() - val date = Instant.ofEpochSecond(forecast.dt!!).atZone(ZoneOffset.UTC) - setDate(date) + date = ZonedDateTime.parse(forecast.time) - forecast.T?.value?.let { + forecast.t?.let { highC = it highF = ConversionMethods.CtoF(it) } condition = - if (!forecast.weather?.desc.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!forecast.weatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() .startsWith("en_") || locale.toString() == "fr" || locale.toString().startsWith("fr_") || locale == Locale.ROOT ) { - forecast.weather?.desc + forecast.weatherDescription } else { - provider.getWeatherCondition(forecast.weather?.icon) + provider.getWeatherCondition(provider.getWeatherIcon(forecast.weatherIcon)) } - icon = forecast.weather?.icon + icon = forecast.weatherIcon // Extras extras = ForecastExtras() - forecast.T?.windchill?.let { + forecast.tWindchill?.let { extras.feelslikeC = it extras.feelslikeF = ConversionMethods.CtoF(it) } - extras.humidity = forecast.humidity + extras.humidity = forecast.relativeHumidity - forecast.seaLevel?.let { + forecast.pSea?.let { extras.pressureMb = it extras.pressureIn = ConversionMethods.mbToInHg(it) } - if (forecast.wind != null) { - if (forecast.wind!!.speed != null && forecast.wind!!.direction != null) { - windDegrees = forecast.wind!!.direction - windKph = ConversionMethods.msecToKph(forecast.wind!!.speed!!.toFloat()) - windMph = ConversionMethods.msecToMph(forecast.wind!!.speed!!.toFloat()) - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph - } - if (forecast.wind!!.gust != null) { - extras.windGustKph = ConversionMethods.msecToKph(forecast.wind!!.gust!!.toFloat()) - extras.windGustMph = ConversionMethods.msecToMph(forecast.wind!!.gust!!.toFloat()) - } + forecast.windSpeed?.let { + extras.windMph = ConversionMethods.msecToMph(it) + extras.windKph = ConversionMethods.msecToKph(it) + extras.windDegrees = forecast.windDirection + } + forecast.windSpeedGust?.let { + extras.windGustKph = ConversionMethods.msecToKph(it) + extras.windGustMph = ConversionMethods.msecToMph(it) } - if (forecast.rain != null) { - if (forecast.rain!!.jsonMember1h != null) { - extras.qpfRainMm = forecast.rain!!.jsonMember1h - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain!!.jsonMember1h!!) - } else if (forecast.rain!!.jsonMember3h != null) { - extras.qpfRainMm = forecast.rain!!.jsonMember3h - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain!!.jsonMember3h!!) - } else if (forecast.rain!!.jsonMember6h != null) { - extras.qpfRainMm = forecast.rain!!.jsonMember6h - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain!!.jsonMember6h!!) - } + if (forecast.rain1h != null) { + extras.qpfRainMm = forecast.rain1h + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain1h) + } else if (forecast.rain3h != null) { + extras.qpfRainMm = forecast.rain3h + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain3h) + } else if (forecast.rain6h != null) { + extras.qpfRainMm = forecast.rain6h + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.rain6h) } - if (forecast.snow != null) { - if (forecast.snow!!.jsonMember1h != null) { - extras.qpfSnowCm = forecast.snow!!.jsonMember1h!! / 10 - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow!!.jsonMember1h!!) - } else if (forecast.snow!!.jsonMember3h != null) { - extras.qpfSnowCm = forecast.snow!!.jsonMember3h!! / 10 - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow!!.jsonMember3h!!) - } else if (forecast.snow!!.jsonMember6h != null) { - extras.qpfSnowCm = forecast.snow!!.jsonMember6h!! / 10 - extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow!!.jsonMember6h!!) - } + if (forecast.snow1h != null) { + extras.qpfSnowCm = forecast.snow1h / 10 + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow1h) + } else if (forecast.snow3h != null) { + extras.qpfSnowCm = forecast.snow3h / 10 + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow3h) + } else if (forecast.snow6h != null) { + extras.qpfSnowCm = forecast.snow6h / 10 + extras.qpfRainIn = ConversionMethods.mmToIn(forecast.snow6h) } - extras.cloudiness = forecast.clouds + extras.cloudiness = forecast.totalCloudCover if (highC != null && extras.humidity != null) { extras.dewpointC = calculateDewpointC(highC, extras.humidity) @@ -239,48 +228,59 @@ fun createHourlyForecast(forecast: ForecastItem, if (!probabilityForecasts.isNullOrEmpty()) { // Note: probability forecasts are given either every 3 or 6 hours // Rain/Snow object can contain forecast for either next 3 or 6 hrs, or both - val dt = forecast.dt!! // Unix time in seconds - val hrsInSec = TimeUnit.HOURS.toSeconds(1) + val dt = date.truncatedTo(ChronoUnit.HOURS) var found3hrForecast = false var _3hrForecastNA = false for (prob in probabilityForecasts) { + val probDt = ZonedDateTime.parse(prob.time).truncatedTo(ChronoUnit.HOURS) + // Check if timestamp is within 3-hr forecast - if (dt == prob!!.dt!! || dt == (prob.dt!! + hrsInSec) || dt == (prob.dt!! + hrsInSec * 2)) { - if (prob.rain?.jsonMember3h != null) { - extras.pop = prob.rain!!.jsonMember3h!!.toInt() + if (dt.isEqual(probDt) || dt.isEqual(probDt.plusHours(1)) || dt.isEqual( + probDt.plusHours( + 2 + ) + ) + ) { + if (prob.rainHazard3h != null) { + extras.pop = prob.rainHazard3h.toInt() found3hrForecast = true _3hrForecastNA = false } else { found3hrForecast = false _3hrForecastNA = true } - if (extras.pop == null && prob.rain?.jsonMember6h != null) { - extras.pop = prob.rain!!.jsonMember6h!!.toInt() + if (extras.pop == null && prob.rainHazard3h != null) { + extras.pop = prob.rainHazard3h.toInt() _3hrForecastNA = true found3hrForecast = false } if (extras.pop == null) { - if (prob.snow?.jsonMember3h != null) { - extras.pop = prob.snow!!.jsonMember3h!!.toInt() + if (prob.snowHazard3h != null) { + extras.pop = prob.snowHazard3h.toInt() } - if (prob.snow?.jsonMember6h != null) { - extras.pop = prob.snow!!.jsonMember6h!!.toInt() + if (prob.snowHazard6h != null) { + extras.pop = prob.snowHazard6h.toInt() } } } // Timestamp is not within 3-hr forecast; check 6-hr timeframe // Check if timestamp is within 6-hr forecast - if (extras.pop == null && (dt == (prob.dt!! + hrsInSec * 3) || dt == (prob.dt!! + hrsInSec * 4) || dt == (prob.dt!! + hrsInSec * 5))) { - if (prob.rain!!.jsonMember6h != null) { - extras.pop = prob.rain!!.jsonMember6h!!.toInt() + if (extras.pop == null && (dt.isEqual(probDt.plusHours(3)) || dt.isEqual( + probDt.plusHours( + 4 + ) + ) || dt.isEqual(probDt.plusHours(5))) + ) { + if (prob.rainHazard6h != null) { + extras.pop = prob.rainHazard6h.toInt() _3hrForecastNA = true found3hrForecast = false } if (extras.pop == null) { - if (prob.snow!!.jsonMember6h != null) { - extras.pop = prob.snow!!.jsonMember6h!!.toInt() + if (prob.snowHazard6h != null) { + extras.pop = prob.snowHazard6h.toInt() } } } @@ -296,34 +296,35 @@ fun createCondition(currRoot: CurrentsResponse): Condition { val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.METEOFRANCE) val locale = LocaleUtils.getLocale() - currRoot.observation?.T?.let { + currRoot.properties?.gridded?.t?.let { tempC = it tempF = ConversionMethods.CtoF(it) } weather = - if (!currRoot.observation?.weather?.desc.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!currRoot.properties?.gridded?.weatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() .startsWith("en_") || locale.toString() == "fr" || locale.toString().startsWith("fr_") || locale == Locale.ROOT ) { - currRoot.observation?.weather?.desc + currRoot.properties?.gridded?.weatherDescription } else { - provider.getWeatherCondition(currRoot.observation?.weather?.icon) - } - icon = currRoot.observation?.weather?.icon - - if (currRoot.observation!!.wind != null) { - windDegrees = currRoot.observation!!.wind!!.direction - if (currRoot.observation!!.wind!!.speed != null) { - windKph = - ConversionMethods.msecToKph(currRoot.observation!!.wind!!.speed!!.toFloat()) - windMph = - ConversionMethods.msecToMph(currRoot.observation!!.wind!!.speed!!.toFloat()) + provider.getWeatherCondition(provider.getWeatherIcon(currRoot.properties?.gridded?.weatherIcon)) } + icon = currRoot.properties?.gridded?.weatherIcon + + windDegrees = currRoot.properties?.gridded?.windDirection + currRoot.properties?.gridded?.windSpeed?.let { + windKph = ConversionMethods.msecToKph(it) + windMph = ConversionMethods.msecToMph(it) + } + currRoot.properties?.gridded?.windSpeedGust?.let { + windGustKph = ConversionMethods.msecToKph(it) + windGustMph = ConversionMethods.msecToMph(it) } - observationTime = ZonedDateTime.ofInstant(Instant.ofEpochSecond(currRoot.updatedOn!!), ZoneOffset.UTC) + observationTime = + ZonedDateTime.parse(currRoot.properties?.gridded?.time ?: currRoot.updateTime) } } @@ -331,4 +332,10 @@ fun createAtmosphere(currRoot: CurrentsResponse): Atmosphere { return Atmosphere().apply { // no-op } +} + +fun createPrecipitation(currRoot: CurrentsResponse): Precipitation { + return Precipitation().apply { + // no-op + } } \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt index ddb4add47..9b0f41c13 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt @@ -3,6 +3,7 @@ package com.thewizrd.weather_api.meteomatics.weather import android.net.Uri import android.util.Log import androidx.core.net.toUri +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.icons.WeatherIcons @@ -20,7 +21,6 @@ import com.thewizrd.shared_resources.weatherdata.auth.AuthType import com.thewizrd.shared_resources.weatherdata.auth.BasicAuthProviderKey import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.extras.cacheRequestIfNeeded import com.thewizrd.weather_api.locationiq.LocationIQProvider import com.thewizrd.weather_api.smc.SunMoonCalcProvider @@ -309,6 +309,8 @@ class MeteomaticsWeatherProvider : WeatherProviderImpl() { } override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) weather.condition!!.observationTime = diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt index 565970c37..32ee584f2 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt @@ -30,10 +30,13 @@ import okhttp3.Request import okhttp3.internal.closeQuietly import java.io.IOException import java.text.DecimalFormat -import java.time.* import java.time.Instant +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.ZoneOffset +import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class MetnoWeatherProvider : WeatherProviderImpl() { @@ -187,6 +190,8 @@ class MetnoWeatherProvider : WeatherProviderImpl() { } override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // OWM reports datetime in UTC; add location tz_offset val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/metno/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/metno/WeatherData.kt index 4301e0bab..3128fdf9a 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/metno/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/metno/WeatherData.kt @@ -27,6 +27,7 @@ import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit import java.util.Locale +import kotlin.math.roundToInt fun createWeatherData( foreRoot: Response, @@ -254,9 +255,9 @@ fun createHourlyForecast(hr_forecast: TimeseriesItem): HourlyForecast { ) highF = ConversionMethods.CtoF(hr_forecast.data.instant.details.airTemperature) highC = hr_forecast.data.instant.details.airTemperature - windDegrees = Math.round(hr_forecast.data.instant.details.windFromDirection) - windMph = ConversionMethods.msecToMph(hr_forecast.data.instant.details.windSpeed) - windKph = ConversionMethods.msecToKph(hr_forecast.data.instant.details.windSpeed) + val windDegrees = hr_forecast.data.instant.details.windFromDirection.roundToInt() + val windMph = ConversionMethods.msecToMph(hr_forecast.data.instant.details.windSpeed) + val windKph = ConversionMethods.msecToKph(hr_forecast.data.instant.details.windSpeed) if (hr_forecast.data.next1Hours != null) { icon = hr_forecast.data.next1Hours.summary.symbolCode @@ -269,23 +270,25 @@ fun createHourlyForecast(hr_forecast: TimeseriesItem): HourlyForecast { val humidity = hr_forecast.data.instant.details.relativeHumidity // Extras extras = ForecastExtras() - extras.feelslikeF = getFeelsLikeTemp(highF, windMph, Math.round(humidity)) - extras.feelslikeC = ConversionMethods.FtoC(getFeelsLikeTemp(highF, windMph, Math.round(humidity))) - extras.humidity = Math.round(humidity) + extras.feelslikeF = getFeelsLikeTemp(highF, windMph, humidity.roundToInt()) + extras.feelslikeC = + ConversionMethods.FtoC(getFeelsLikeTemp(highF, windMph, humidity.roundToInt())) + extras.humidity = humidity.roundToInt() extras.dewpointF = ConversionMethods.CtoF(hr_forecast.data.instant.details.dewPointTemperature) extras.dewpointC = hr_forecast.data.instant.details.dewPointTemperature if (hr_forecast.data.instant.details.cloudAreaFraction != null) { - extras.cloudiness = Math.round(hr_forecast.data.instant.details.cloudAreaFraction) + extras.cloudiness = hr_forecast.data.instant.details.cloudAreaFraction.roundToInt() } // Precipitation if (hr_forecast.data.instant.details.probabilityOfPrecipitation != null) { - extras.pop = Math.round(hr_forecast.data.instant.details.probabilityOfPrecipitation) + extras.pop = hr_forecast.data.instant.details.probabilityOfPrecipitation.roundToInt() } else if (hr_forecast.data?.next1Hours?.details?.probabilityOfPrecipitation != null) { - extras.pop = Math.round(hr_forecast.data.next1Hours.details.probabilityOfPrecipitation) + extras.pop = hr_forecast.data.next1Hours.details.probabilityOfPrecipitation.roundToInt() } else if (hr_forecast.data?.next6Hours?.details?.probabilityOfPrecipitation != null) { - extras.pop = Math.round(hr_forecast.data.next6Hours.details.probabilityOfPrecipitation) + extras.pop = hr_forecast.data.next6Hours.details.probabilityOfPrecipitation.roundToInt() } else if (hr_forecast.data?.next12Hours?.details?.probabilityOfPrecipitation != null) { - extras.pop = Math.round(hr_forecast.data.next12Hours.details.probabilityOfPrecipitation) + extras.pop = + hr_forecast.data.next12Hours.details.probabilityOfPrecipitation.roundToInt() } extras.pressureIn = ConversionMethods.mbToInHg(hr_forecast.data.instant.details.airPressureAtSeaLevel) extras.pressureMb = hr_forecast.data.instant.details.airPressureAtSeaLevel diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/nws/NWSWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/nws/NWSWeatherProvider.kt index 5c7da4036..3280925c5 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/nws/NWSWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/nws/NWSWeatherProvider.kt @@ -56,7 +56,8 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Collections +import java.util.Locale import java.util.concurrent.TimeUnit class NWSWeatherProvider : WeatherProviderImpl() { @@ -417,6 +418,8 @@ class NWSWeatherProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt index 8151e2535..31699e5b5 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt @@ -288,13 +288,9 @@ fun createHourlyForecast(forecastItem: PeriodItem, adjustDate: Boolean = false): val windSpeed = forecastItem.windSpeed?.toFloatOrNull() val windDirection = forecastItem.windDirection?.toIntOrNull() if (windSpeed != null && windDirection != null) { - windDegrees = windDirection - windMph = windSpeed - windKph = ConversionMethods.mphTokph(windMph) - - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = windDirection + extras.windMph = windSpeed + extras.windKph = ConversionMethods.mphTokph(windSpeed) } forecastItem.windChill?.toFloatOrNull()?.let { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/oauth/OAuthRequest.java b/weather-api/src/main/java/com/thewizrd/weather_api/oauth/OAuthRequest.java index d9a7cb746..0f436a632 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/oauth/OAuthRequest.java +++ b/weather-api/src/main/java/com/thewizrd/weather_api/oauth/OAuthRequest.java @@ -7,7 +7,7 @@ import com.thewizrd.shared_resources.utils.StringUtils; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Set; @@ -69,7 +69,7 @@ private static String getTimeStamp() { } private static String getNonce() { - return Base64.encodeToString((System.nanoTime() + "").getBytes(Charset.forName("UTF-8")), Base64.NO_WRAP); + return Base64.encodeToString((System.nanoTime() + "").getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); } public String getAuthorizationHeader(String url) throws InvalidKeyException, NoSuchAlgorithmException { @@ -121,9 +121,9 @@ public String getAuthorizationHeader(String urlString, boolean addGrantType) thr lHasher = Mac.getInstance("HmacSHA1"); } - SecretKeySpec secret_key = new SecretKeySpec(lCKey.getBytes(Charset.forName("UTF-8")), lHasher.getAlgorithm()); + SecretKeySpec secret_key = new SecretKeySpec(lCKey.getBytes(StandardCharsets.UTF_8), lHasher.getAlgorithm()); lHasher.init(secret_key); - lSign = Base64.encodeToString(lHasher.doFinal(lSign.getBytes(Charset.forName("UTF-8"))), Base64.NO_WRAP); + lSign = Base64.encodeToString(lHasher.doFinal(lSign.getBytes(StandardCharsets.UTF_8)), Base64.NO_WRAP); return "OAuth " + "oauth_consumer_key=\"" + uriEncode(consumerKey) + "\", " + diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/AQIResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/AQIResponse.kt new file mode 100644 index 000000000..1cc72e7ea --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/AQIResponse.kt @@ -0,0 +1,121 @@ +package com.thewizrd.weather_api.openmeteo + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class AQIResponse( + + @Json(name = "elevation") + var elevation: Float? = null, + + @Json(name = "generationtime_ms") + var generationtimeMs: Double? = null, + + @Json(name = "current") + var current: CurrentAQI? = null, + + @Json(name = "timezone_abbreviation") + var timezoneAbbreviation: String? = null, + + @Json(name = "current_units") + var currentUnits: CurrentAQIUnits? = null, + + @Json(name = "timezone") + var timezone: String? = null, + + @Json(name = "latitude") + var latitude: Float? = null, + + @Json(name = "utc_offset_seconds") + var utcOffsetSeconds: Int? = null, + + @Json(name = "longitude") + var longitude: Float? = null +) + +@JsonClass(generateAdapter = true) +data class CurrentAQI( + + @Json(name = "birch_pollen") + var birchPollen: Float? = null, + + @Json(name = "us_aqi_nitrogen_dioxide") + var usAqiNitrogenDioxide: Int? = null, + + @Json(name = "us_aqi_pm2_5") + var usAqiPm25: Int? = null, + + @Json(name = "us_aqi") + var usAqi: Int? = null, + + @Json(name = "us_aqi_sulphur_dioxide") + var usAqiSulphurDioxide: Int? = null, + + @Json(name = "us_aqi_ozone") + var usAqiOzone: Int? = null, + + @Json(name = "us_aqi_pm10") + var usAqiPm10: Int? = null, + + @Json(name = "grass_pollen") + var grassPollen: Float? = null, + + @Json(name = "interval") + var interval: Int? = null, + + @Json(name = "time") + var time: Long? = null, + + @Json(name = "us_aqi_carbon_monoxide") + var usAqiCarbonMonoxide: Int? = null, + + @Json(name = "ragweed_pollen") + var ragweedPollen: Float? = null, + + @Json(name = "alder_pollen") + var alderPollen: Float? = null +) + +@JsonClass(generateAdapter = true) +data class CurrentAQIUnits( + + @Json(name = "birch_pollen") + var birchPollen: String? = null, + + @Json(name = "us_aqi_nitrogen_dioxide") + var usAqiNitrogenDioxide: String? = null, + + @Json(name = "us_aqi_pm2_5") + var usAqiPm25: String? = null, + + @Json(name = "us_aqi") + var usAqi: String? = null, + + @Json(name = "us_aqi_sulphur_dioxide") + var usAqiSulphurDioxide: String? = null, + + @Json(name = "us_aqi_ozone") + var usAqiOzone: String? = null, + + @Json(name = "us_aqi_pm10") + var usAqiPm10: String? = null, + + @Json(name = "grass_pollen") + var grassPollen: String? = null, + + @Json(name = "interval") + var interval: String? = null, + + @Json(name = "time") + var time: String? = null, + + @Json(name = "us_aqi_carbon_monoxide") + var usAqiCarbonMonoxide: String? = null, + + @Json(name = "ragweed_pollen") + var ragweedPollen: String? = null, + + @Json(name = "alder_pollen") + var alderPollen: String? = null +) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/ForecastResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/ForecastResponse.kt new file mode 100644 index 000000000..526d43a6a --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/ForecastResponse.kt @@ -0,0 +1,415 @@ +package com.thewizrd.weather_api.openmeteo + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ForecastResponse( + + @Json(name = "elevation") + var elevation: Float? = null, + + @Json(name = "minutely_15") + var minutely15: Minutely15? = null, + + @Json(name = "daily_units") + var dailyUnits: DailyUnits? = null, + + @Json(name = "timezone") + var timezone: String? = null, + + @Json(name = "latitude") + var latitude: Float? = null, + + @Json(name = "minutely_15_units") + var minutely15Units: Minutely15Units? = null, + + @Json(name = "hourly_units") + var hourlyUnits: HourlyUnits? = null, + + @Json(name = "generationtime_ms") + var generationtimeMs: Double? = null, + + @Json(name = "current") + var current: Current? = null, + + @Json(name = "timezone_abbreviation") + var timezoneAbbreviation: String? = null, + + @Json(name = "current_units") + var currentUnits: CurrentUnits? = null, + + @Json(name = "daily") + var daily: Daily? = null, + + @Json(name = "utc_offset_seconds") + var utcOffsetSeconds: Int? = null, + + @Json(name = "hourly") + var hourly: Hourly? = null, + + @Json(name = "longitude") + var longitude: Float? = null +) + +@JsonClass(generateAdapter = true) +data class Daily( + + @Json(name = "sunrise") + var sunrise: List? = null, + + @Json(name = "wind_speed_10m_max") + var windSpeed10mMax: List? = null, + + @Json(name = "cloud_cover_mean") + var cloudCoverMean: List? = null, + + @Json(name = "uv_index_max") + var uvIndexMax: List? = null, + + @Json(name = "visibility_mean") + var visibilityMean: List? = null, + + @Json(name = "apparent_temperature_mean") + var apparentTemperatureMean: List? = null, + + @Json(name = "temperature_2m_min") + var temperature2mMin: List? = null, + + @Json(name = "wind_gusts_10m_max") + var windGusts10mMax: List? = null, + + @Json(name = "dew_point_2m_mean") + var dewPoint2mMean: List? = null, + + @Json(name = "relative_humidity_2m_mean") + var relativeHumidity2mMean: List? = null, + + @Json(name = "sunset") + var sunset: List? = null, + + @Json(name = "precipitation_probability_max") + var precipitationProbabilityMax: List? = null, + + @Json(name = "temperature_2m_max") + var temperature2mMax: List? = null, + + @Json(name = "wind_direction_10m_dominant") + var windDirection10mDominant: List? = null, + + @Json(name = "pressure_msl_mean") + var pressureMslMean: List? = null, + + @Json(name = "time") + var time: List? = null, + + @Json(name = "weather_code") + var weatherCode: List? = null +) + +@JsonClass(generateAdapter = true) +data class DailyUnits( + + @Json(name = "sunrise") + var sunrise: String? = null, + + @Json(name = "wind_speed_10m_max") + var windSpeed10mMax: String? = null, + + @Json(name = "cloud_cover_mean") + var cloudCoverMean: String? = null, + + @Json(name = "uv_index_max") + var uvIndexMax: String? = null, + + @Json(name = "visibility_mean") + var visibilityMean: String? = null, + + @Json(name = "apparent_temperature_mean") + var apparentTemperatureMean: String? = null, + + @Json(name = "temperature_2m_min") + var temperature2mMin: String? = null, + + @Json(name = "wind_gusts_10m_max") + var windGusts10mMax: String? = null, + + @Json(name = "dew_point_2m_mean") + var dewPoint2mMean: String? = null, + + @Json(name = "relative_humidity_2m_mean") + var relativeHumidity2mMean: String? = null, + + @Json(name = "sunset") + var sunset: String? = null, + + @Json(name = "precipitation_probability_max") + var precipitationProbabilityMax: String? = null, + + @Json(name = "temperature_2m_max") + var temperature2mMax: String? = null, + + @Json(name = "wind_direction_10m_dominant") + var windDirection10mDominant: String? = null, + + @Json(name = "pressure_msl_mean") + var pressureMslMean: String? = null, + + @Json(name = "time") + var time: String? = null, + + @Json(name = "weather_code") + var weatherCode: String? = null +) + +@JsonClass(generateAdapter = true) +data class Hourly( + + @Json(name = "pressure_msl") + var pressureMsl: List? = null, + + @Json(name = "wind_speed_10m") + var windSpeed10m: List? = null, + + @Json(name = "rain") + var rain: List? = null, + + @Json(name = "dew_point_2m") + var dewPoint2m: List? = null, + + @Json(name = "visibility") + var visibility: List? = null, + + @Json(name = "relative_humidity_2m") + var relativeHumidity2m: List? = null, + + @Json(name = "snowfall") + var snowfall: List? = null, + + @Json(name = "is_day") + var isDay: List? = null, + + @Json(name = "wind_direction_10m") + var windDirection10m: List? = null, + + @Json(name = "wind_gusts_10m") + var windGusts10m: List? = null, + + @Json(name = "temperature_2m") + var temperature2m: List? = null, + + @Json(name = "uv_index") + var uvIndex: List? = null, + + @Json(name = "precipitation_probability") + var precipitationProbability: List? = null, + + @Json(name = "cloud_cover") + var cloudCover: List? = null, + + @Json(name = "apparent_temperature") + var apparentTemperature: List? = null, + + @Json(name = "time") + var time: List? = null, + + @Json(name = "weather_code") + var weatherCode: List? = null +) + +@JsonClass(generateAdapter = true) +data class Current( + + @Json(name = "pressure_msl") + var pressureMsl: Float? = null, + + @Json(name = "wind_speed_10m") + var windSpeed10m: Float? = null, + + @Json(name = "rain") + var rain: Float? = null, + + @Json(name = "dew_point_2m") + var dewPoint2m: Float? = null, + + @Json(name = "visibility") + var visibility: Float? = null, + + @Json(name = "relative_humidity_2m") + var relativeHumidity2m: Int? = null, + + @Json(name = "snowfall") + var snowfall: Float? = null, + + @Json(name = "is_day") + var isDay: Int? = null, + + @Json(name = "wind_direction_10m") + var windDirection10m: Int? = null, + + @Json(name = "wind_gusts_10m") + var windGusts10m: Float? = null, + + @Json(name = "temperature_2m") + var temperature2m: Float? = null, + + @Json(name = "uv_index") + var uvIndex: Float? = null, + + @Json(name = "precipitation_probability") + var precipitationProbability: Int? = null, + + @Json(name = "cloud_cover") + var cloudCover: Int? = null, + + @Json(name = "apparent_temperature") + var apparentTemperature: Float? = null, + + @Json(name = "interval") + var interval: Int? = null, + + @Json(name = "time") + var time: Long? = null, + + @Json(name = "weather_code") + var weatherCode: Int? = null +) + +@JsonClass(generateAdapter = true) +data class HourlyUnits( + + @Json(name = "pressure_msl") + var pressureMsl: String? = null, + + @Json(name = "wind_speed_10m") + var windSpeed10m: String? = null, + + @Json(name = "rain") + var rain: String? = null, + + @Json(name = "dew_point_2m") + var dewPoint2m: String? = null, + + @Json(name = "visibility") + var visibility: String? = null, + + @Json(name = "relative_humidity_2m") + var relativeHumidity2m: String? = null, + + @Json(name = "snowfall") + var snowfall: String? = null, + + @Json(name = "is_day") + var isDay: String? = null, + + @Json(name = "wind_direction_10m") + var windDirection10m: String? = null, + + @Json(name = "wind_gusts_10m") + var windGusts10m: String? = null, + + @Json(name = "temperature_2m") + var temperature2m: String? = null, + + @Json(name = "uv_index") + var uvIndex: String? = null, + + @Json(name = "precipitation_probability") + var precipitationProbability: String? = null, + + @Json(name = "cloud_cover") + var cloudCover: String? = null, + + @Json(name = "apparent_temperature") + var apparentTemperature: String? = null, + + @Json(name = "time") + var time: String? = null, + + @Json(name = "weather_code") + var weatherCode: String? = null +) + +@JsonClass(generateAdapter = true) +data class Minutely15( + + @Json(name = "rain") + var rain: List? = null, + + @Json(name = "snowfall") + var snowfall: List? = null, + + @Json(name = "time") + var time: List? = null +) + +@JsonClass(generateAdapter = true) +data class Minutely15Units( + + @Json(name = "rain") + var rain: String? = null, + + @Json(name = "snowfall") + var snowfall: String? = null, + + @Json(name = "time") + var time: String? = null +) + +@JsonClass(generateAdapter = true) +data class CurrentUnits( + + @Json(name = "pressure_msl") + var pressureMsl: String? = null, + + @Json(name = "wind_speed_10m") + var windSpeed10m: String? = null, + + @Json(name = "rain") + var rain: String? = null, + + @Json(name = "dew_point_2m") + var dewPoint2m: String? = null, + + @Json(name = "visibility") + var visibility: String? = null, + + @Json(name = "relative_humidity_2m") + var relativeHumidity2m: String? = null, + + @Json(name = "snowfall") + var snowfall: String? = null, + + @Json(name = "is_day") + var isDay: String? = null, + + @Json(name = "wind_direction_10m") + var windDirection10m: String? = null, + + @Json(name = "wind_gusts_10m") + var windGusts10m: String? = null, + + @Json(name = "temperature_2m") + var temperature2m: String? = null, + + @Json(name = "uv_index") + var uvIndex: String? = null, + + @Json(name = "precipitation_probability") + var precipitationProbability: String? = null, + + @Json(name = "cloud_cover") + var cloudCover: String? = null, + + @Json(name = "apparent_temperature") + var apparentTemperature: String? = null, + + @Json(name = "interval") + var interval: String? = null, + + @Json(name = "time") + var time: String? = null, + + @Json(name = "weather_code") + var weatherCode: String? = null +) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt new file mode 100644 index 000000000..fdc9851b7 --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt @@ -0,0 +1,703 @@ +package com.thewizrd.weather_api.openmeteo + +import android.util.Log +import androidx.core.net.toUri +import com.ibm.icu.util.ULocale +import com.thewizrd.shared_resources.R +import com.thewizrd.shared_resources.exceptions.ErrorStatus +import com.thewizrd.shared_resources.exceptions.WeatherException +import com.thewizrd.shared_resources.icons.WeatherIcons +import com.thewizrd.shared_resources.locationdata.LocationData +import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await +import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream +import com.thewizrd.shared_resources.remoteconfig.remoteConfigService +import com.thewizrd.shared_resources.sharedDeps +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.ZoneIdCompat +import com.thewizrd.shared_resources.weatherdata.PollenProvider +import com.thewizrd.shared_resources.weatherdata.WeatherAPI +import com.thewizrd.shared_resources.weatherdata.auth.AuthType +import com.thewizrd.shared_resources.weatherdata.model.Pollen +import com.thewizrd.shared_resources.weatherdata.model.Weather +import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid +import com.thewizrd.weather_api.BuildConfig +import com.thewizrd.weather_api.extras.cacheRequestIfNeeded +import com.thewizrd.weather_api.keys.Keys +import com.thewizrd.weather_api.nws.SolCalcAstroProvider +import com.thewizrd.weather_api.smc.SunMoonCalcProvider +import com.thewizrd.weather_api.utils.APIRequestUtils.checkForErrors +import com.thewizrd.weather_api.utils.APIRequestUtils.checkRateLimit +import com.thewizrd.weather_api.utils.APIRequestUtils.throwIfRateLimited +import com.thewizrd.weather_api.utils.logMissingIcon +import com.thewizrd.weather_api.weatherModule +import com.thewizrd.weather_api.weatherapi.location.WeatherApiLocationProvider +import com.thewizrd.weather_api.weatherdata.WeatherProviderImpl +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.CacheControl +import okhttp3.Request +import okhttp3.Response +import okhttp3.internal.closeQuietly +import java.io.IOException +import java.net.HttpURLConnection +import java.text.DecimalFormat +import java.time.Instant +import java.time.LocalTime +import java.time.ZoneOffset +import java.time.ZonedDateTime +import java.util.Locale +import java.util.concurrent.TimeUnit +import kotlin.math.max + +class OpenMeteoWeatherProvider : WeatherProviderImpl(), PollenProvider { + companion object { + private const val NON_COMMERCIAL_FORECAST_URL = "https://api.open-meteo.com/v1/forecast" + private const val COMMERCIAL_FORECAST_URL = + "https://customer-api.open-meteo.com/v1/forecast" + + private const val NON_COMMERCIAL_AQ_URL = + "https://air-quality-api.open-meteo.com/v1/air-quality" + private const val COMMERCIAL_AQ_URL = + "https://customer-air-quality-api.open-meteo.com/v1/air-quality" + private const val KEYCHECK_QUERY_URL = "$COMMERCIAL_FORECAST_URL?apikey=%s" + } + + init { + mLocationProvider = runCatching { + weatherModule.locationProviderFactory.getLocationProvider( + remoteConfigService.getLocationProvider( + getWeatherAPI() + ) + ) + }.getOrElse { + WeatherApiLocationProvider() + } + } + + override fun getWeatherAPI(): String { + return WeatherAPI.OPENMETEO + } + + override fun supportsWeatherLocale(): Boolean { + return false + } + + override fun isKeyRequired(): Boolean { + return BuildConfig.IS_NONGMS + } + + override fun getAuthType(): AuthType { + return if (BuildConfig.IS_NONGMS) AuthType.APIKEY else AuthType.INTERNAL + } + + @Throws(WeatherException::class) + override suspend fun isKeyValid(key: String?): Boolean = withContext(Dispatchers.IO) { + if (key.isNullOrBlank()) { + throw WeatherException(ErrorStatus.INVALIDAPIKEY) + } + + var isValid = false + var wEx: WeatherException? = null + + val client = sharedDeps.httpClient + var response: Response? = null + + try { + // If were under rate limit, deny request + checkRateLimit() + + val request = Request.Builder() + .cacheControl( + CacheControl.Builder() + .maxAge(1, TimeUnit.DAYS) + .build() + ) + .url(String.format(KEYCHECK_QUERY_URL, key)) + .build() + + // Connect to webstream + response = client.newCall(request).await() + throwIfRateLimited(response) + + when (response.code) { + HttpURLConnection.HTTP_BAD_REQUEST -> isValid = true + HttpURLConnection.HTTP_UNAUTHORIZED -> { + wEx = WeatherException(ErrorStatus.INVALIDAPIKEY) + isValid = false + } + } + } catch (ex: Exception) { + if (ex is IOException) { + wEx = WeatherException(ErrorStatus.NETWORKERROR, ex) + } else if (ex is WeatherException) { + wEx = ex + } + + isValid = false + } finally { + response?.closeQuietly() + } + + if (wEx != null && wEx.errorStatus != ErrorStatus.INVALIDAPIKEY) { + throw wEx + } + + return@withContext isValid + } + + override fun getAPIKey(): String? { + return Keys.getOpenMeteoKey() + } + + @Throws(WeatherException::class) + override suspend fun getWeatherData(location: LocationData): Weather = + withContext(Dispatchers.IO) { + var weather: Weather? + + val uLocale = ULocale.forLocale(LocaleUtils.getLocale()) + val locale = localeToLangCode(uLocale.language, uLocale.toLanguageTag()) + val query = updateLocationQuery(location) + + val key = getProviderKey() + + val client = sharedDeps.httpClient + var response: Response? = null + var aqiResponse: Response? = null + var wEx: WeatherException? = null + + try { + // If were under rate limit, deny request + checkRateLimit() + + if ((isKeyRequired() || getAuthType() == AuthType.INTERNAL) && key.isNullOrBlank()) { + throw WeatherException(ErrorStatus.INVALIDAPIKEY) + } + + val baseUrl = if (BuildConfig.IS_NONGMS) { + NON_COMMERCIAL_FORECAST_URL + } else { + COMMERCIAL_FORECAST_URL + } + + val aqiBaseUrl = if (BuildConfig.IS_NONGMS) { + NON_COMMERCIAL_AQ_URL + } else { + COMMERCIAL_AQ_URL + } + + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") + + val forecastRequestUri = baseUrl.toUri().buildUpon() + .appendQueryParameter("latitude", df.format(location.latitude)) + .appendQueryParameter("longitude", df.format(location.longitude)) + .appendQueryParameter( + "daily", + "weather_code,temperature_2m_max,temperature_2m_min,uv_index_max,precipitation_probability_max,wind_speed_10m_max,wind_gusts_10m_max,wind_direction_10m_dominant,cloud_cover_mean,apparent_temperature_mean,dew_point_2m_mean,pressure_msl_mean,relative_humidity_2m_mean,visibility_mean" + ) + .appendQueryParameter( + "hourly", + "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,weather_code,pressure_msl,cloud_cover,visibility,wind_speed_10m,wind_gusts_10m,wind_direction_10m,rain,snowfall,uv_index,is_day" + ) + .appendQueryParameter( + "current", + "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,weather_code,pressure_msl,cloud_cover,visibility,wind_speed_10m,wind_gusts_10m,wind_direction_10m,rain,snowfall,uv_index,is_day" + ) + .appendQueryParameter("minutely_15", "rain,snowfall") + .appendQueryParameter("models", "best_match") + .appendQueryParameter("timeformat", "unixtime") + .appendQueryParameter("timezone", "auto") + .apply { + if (isKeyRequired() || getAuthType() == AuthType.INTERNAL) { + this.appendQueryParameter("apikey", key) + } + } + .build() + + val forecastRequest = Request.Builder() + .cacheRequestIfNeeded( + (isKeyRequired() || getAuthType() == AuthType.INTERNAL), + 30, + TimeUnit.MINUTES + ) + .url(forecastRequestUri.toString()) + .header("Accept", "application/json") + .build() + + val aqiRequestUri = aqiBaseUrl.toUri().buildUpon() + .appendQueryParameter("latitude", df.format(location.latitude)) + .appendQueryParameter("longitude", df.format(location.longitude)) + .appendQueryParameter( + "current", + "us_aqi,ragweed_pollen,grass_pollen,birch_pollen,alder_pollen,pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone" + ) + .appendQueryParameter("timeformat", "unixtime") + .appendQueryParameter("timezone", "auto") + .apply { + if (isKeyRequired() || getAuthType() == AuthType.INTERNAL) { + this.appendQueryParameter("apikey", key) + } + } + .build() + + val aqiRequest = Request.Builder() + .cacheRequestIfNeeded( + (isKeyRequired() || getAuthType() == AuthType.INTERNAL), + 20, + TimeUnit.MINUTES + ) + .url(aqiRequestUri.toString()) + .header("Accept", "application/json") + .build() + + // Connect to webstream + response = client.newCall(forecastRequest).await() + checkForErrors(response) + // Load weather + val root = response.getStream().use { + JSONParser.deserializer(it, ForecastResponse::class.java) + } + + val aqiRoot = runCatching { + aqiResponse = client.newCall(aqiRequest).await() + checkForErrors(aqiResponse) + aqiResponse.getStream().use { + JSONParser.deserializer( + it, + AQIResponse::class.java + ) + } + }.getOrNull() + + requireNotNull(root) + requireNotNull(aqiRoot) + + weather = createWeatherData(root, aqiRoot) + } catch (ex: Exception) { + weather = null + if (ex is IOException) { + wEx = WeatherException(ErrorStatus.NETWORKERROR, ex) + } else if (ex is WeatherException) { + wEx = ex + } + Logger.writeLine( + Log.ERROR, + ex, + "OpenMeteoWeatherProvider: error getting weather data" + ) + } finally { + response?.closeQuietly() + aqiResponse?.closeQuietly() + } + + if (wEx == null && weather.isNullOrInvalid()) { + wEx = WeatherException(ErrorStatus.NOWEATHER) + } else if (weather != null) { + if (supportsWeatherLocale()) weather.locale = locale + + weather.query = query + } + + if (wEx != null) throw wEx + + return@withContext weather!! + } + + override suspend fun getPollenData(location: LocationData): Pollen? = + withContext(Dispatchers.IO) { + var pollenData: Pollen? = null + + val key = getProviderKey() + + val client = sharedDeps.httpClient + var response: Response? = null + + try { + // If were under rate limit, deny request + checkRateLimit() + + if ((isKeyRequired() || getAuthType() == AuthType.INTERNAL) && key.isNullOrBlank()) { + throw WeatherException(ErrorStatus.INVALIDAPIKEY) + } + + val baseUrl = if (BuildConfig.IS_NONGMS) { + NON_COMMERCIAL_AQ_URL + } else { + COMMERCIAL_AQ_URL + } + + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") + + val requestUri = baseUrl.toUri().buildUpon() + .appendQueryParameter("latitude", df.format(location.latitude)) + .appendQueryParameter("longitude", df.format(location.longitude)) + .appendQueryParameter( + "current", + "ragweed_pollen,grass_pollen,birch_pollen,alder_pollen" + ) + .appendQueryParameter("timeformat", "unixtime") + .appendQueryParameter("timezone", "auto") + .apply { + if (isKeyRequired() || getAuthType() == AuthType.INTERNAL) { + this.appendQueryParameter("apikey", key) + } + } + .build() + + val request = Request.Builder() + .cacheRequestIfNeeded( + isKeyRequired() || getAuthType() == AuthType.INTERNAL, + 20, + TimeUnit.MINUTES + ) + .url(requestUri.toString()) + .header("Accept", "application/json") + .build() + + // Connect to webstream + response = client.newCall(request).await() + checkForErrors(response) + // Load weather + val root = response.getStream().use { + JSONParser.deserializer(it, AQIResponse::class.java) + } + + requireNotNull(root) + + root.current?.let { current -> + val treePollenMeasure = + if (current.birchPollen != null && current.alderPollen != null) { + max(current.birchPollen!!, current.alderPollen!!) + } else { + current.birchPollen ?: current.alderPollen + } + val grassPollenMeasure = current.grassPollen + val ragweedPollenMeasure = current.ragweedPollen + + pollenData = Pollen().apply { + treePollenCount = when { + treePollenMeasure == null -> Pollen.PollenCount.UNKNOWN + treePollenMeasure < 15 -> Pollen.PollenCount.LOW + treePollenMeasure < 90 -> Pollen.PollenCount.MODERATE + treePollenMeasure < 1500 -> Pollen.PollenCount.HIGH + treePollenMeasure >= 1500 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + + grassPollenCount = when { + grassPollenMeasure == null -> Pollen.PollenCount.UNKNOWN + grassPollenMeasure < 5 -> Pollen.PollenCount.LOW + grassPollenMeasure < 20 -> Pollen.PollenCount.MODERATE + grassPollenMeasure < 200 -> Pollen.PollenCount.HIGH + grassPollenMeasure >= 200 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + + ragweedPollenCount = when { + ragweedPollenMeasure == null -> Pollen.PollenCount.UNKNOWN + ragweedPollenMeasure < 10 -> Pollen.PollenCount.LOW + ragweedPollenMeasure < 50 -> Pollen.PollenCount.MODERATE + ragweedPollenMeasure < 500 -> Pollen.PollenCount.HIGH + ragweedPollenMeasure >= 500 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + } + } + } catch (ex: Exception) { + pollenData = null + Logger.writeLine( + Log.ERROR, + ex, + "OpenMeteoWeatherProvider: error getting pollen data" + ) + } finally { + response?.closeQuietly() + } + + return@withContext pollenData + } + + @Throws(WeatherException::class) + override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + + val offset = location.tzOffset + + // Update tz for weather properties + weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) + weather.condition!!.observationTime = + weather.condition!!.observationTime.withZoneSameInstant(offset) + + weather.astronomy = try { + SunMoonCalcProvider().getAstronomyData(location, weather.condition!!.observationTime) + } catch (e: WeatherException) { + Logger.writeLine(Log.ERROR, e, "Error") + SolCalcAstroProvider().getAstronomyData(location, weather.condition!!.observationTime) + } + + weather.condition?.icon.let { + weather.condition!!.icon = getWeatherIcon(it) + weather.condition!!.weather = getWeatherCondition(it) + } + + weather.forecast?.forEach { forecast -> + forecast.date = forecast.date.plusSeconds(offset.totalSeconds.toLong()) + + forecast.icon.let { + forecast.icon = getWeatherIcon(it) + forecast.condition = getWeatherCondition(it) + } + } + + weather.hrForecast?.forEach { hrf -> + hrf.date = hrf.date.withZoneSameInstant(offset) + + hrf.icon?.let { + hrf.icon = getWeatherIcon(it) + hrf.condition = getWeatherCondition(it) + } + } + + weather.minForecast?.forEach { minutelyForecast -> + minutelyForecast.date = minutelyForecast.date.withZoneSameInstant(offset) + } + } + + override suspend fun updateLocationQuery(weather: Weather): String { + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") + return String.format( + Locale.ROOT, + "latitude=%s&longitude=%s", + df.format(weather.location!!.latitude), + df.format(weather.location!!.longitude) + ) + } + + override suspend fun updateLocationQuery(location: LocationData): String { + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") + return String.format( + Locale.ROOT, + "latitude=%s&longitude=%s", + df.format(location.latitude), + df.format(location.longitude) + ) + } + + override fun getWeatherIcon(icon: String?): String { + var isNight = false + + if (icon == null) return WeatherIcons.NA + + if (icon.endsWith("_0")) isNight = true + + return getWeatherIcon(isNight, icon) + } + + override fun getWeatherIcon(isNight: Boolean, icon: String?): String { + var weatherIcon = "" + + val conditionCode = + icon?.split('_')?.getOrNull(0)?.toIntOrNull() ?: return WeatherIcons.NA + + when (conditionCode) { + /* + * 0: Clear sky + * 1: Mainly clear + */ + 0, 1 -> { + weatherIcon = if (isNight) WeatherIcons.NIGHT_CLEAR else WeatherIcons.DAY_SUNNY + } + /* + * 2: Partly cloudy + */ + 2 -> { + weatherIcon = + if (isNight) WeatherIcons.NIGHT_ALT_PARTLY_CLOUDY else WeatherIcons.DAY_PARTLY_CLOUDY + } + + /* + * 3: overcast + */ + 3 -> { + weatherIcon = WeatherIcons.OVERCAST + } + + /* + * 45: Fog + * 48: depositing rime fog + */ + 45, 48 -> { + weatherIcon = WeatherIcons.FOG + } + + /* + * 51, 53, 55: Drizzle: Light, moderate, and dense intensity + */ + 51, 53, 55 -> { + weatherIcon = WeatherIcons.SPRINKLE + } + + /* + * 56, 57: Freezing Drizzle: Light and dense intensity + */ + 56, 57 -> { + weatherIcon = WeatherIcons.RAIN_MIX + } + + /* + * 61, 63, 65: Rain: Slight, moderate and heavy intensity + */ + 61, 63 -> { + weatherIcon = WeatherIcons.RAIN + } + + 65 -> { + weatherIcon = WeatherIcons.RAIN_WIND + } + + /* + * 66, 67: Freezing Rain: Light and heavy intensity + */ + 66, 67 -> { + weatherIcon = WeatherIcons.RAIN_MIX + } + + /* + * 71, 73, 75: Snow fall: Slight, moderate, and heavy intensity + * 77: Snow grains + */ + 71, 73, 77 -> { + weatherIcon = WeatherIcons.SNOW + } + + 75 -> { + weatherIcon = WeatherIcons.SNOW_WIND + } + + /* + * 80, 81, 82: Rain showers: Slight, moderate, and violent + */ + 80, 81 -> { + weatherIcon = WeatherIcons.SHOWERS + } + + 82 -> { + weatherIcon = WeatherIcons.STORM_SHOWERS + } + + /* + * 85, 86: Snow showers slight and heavy + */ + 85 -> { + weatherIcon = WeatherIcons.SNOW + } + + 86 -> { + weatherIcon = WeatherIcons.SNOW_WIND + } + + /* + * 95: Thunderstorm: Slight or moderate + * 96, 99: Thunderstorm with slight and heavy hail + */ + 95 -> { + weatherIcon = WeatherIcons.THUNDERSTORM + } + + 96, 99 -> { + weatherIcon = WeatherIcons.SNOW_THUNDERSTORM + } + } + + if (weatherIcon.isBlank()) { + // Not Available + logMissingIcon(icon) + weatherIcon = WeatherIcons.NA + } + return weatherIcon + } + + override fun getWeatherCondition(icon: String?): String { + val conditionCode = icon?.split('_')?.getOrNull(0)?.toIntOrNull() + ?: return super.getWeatherCondition(icon) + + return when (conditionCode) { + /* 0: Clear sky */ + 0 -> context.getString(R.string.weather_clearsky) + /* 1: Mainly clear */ + 1 -> context.getString(R.string.weather_mostlyclear) + /* 2: partly cloudy */ + 2 -> context.getString(R.string.weather_partlycloudy) + /* 3: overcast */ + 3 -> context.getString(R.string.weather_overcast) + /* 45, 48: Fog and depositing rime fog */ + 45, 48 -> context.getString(R.string.weather_fog) + /* 51, 53, 55: Drizzle: Light, moderate, and dense intensity */ + 51, 53, 55 -> context.getString(R.string.weather_drizzle) + /* + * 56, 57: Freezing Drizzle: Light and dense intensity + * 66, 67: Freezing Rain: Light and heavy intensity + */ + 56, 57, 66, 67 -> context.getString(R.string.weather_freezingrain) + /* 61, 63, 65: Rain: Slight, moderate and heavy intensity */ + 61 -> context.getString(R.string.weather_lightrain) + 63 -> context.getString(R.string.weather_rain) + 65 -> context.getString(R.string.weather_heavyrain) + /* + * 71, 73, 75: Snow fall: Slight, moderate, and heavy intensity + * 77: Snow grains + */ + 71 -> context.getString(R.string.weather_lightsnowshowers) + 73, 77 -> context.getString(R.string.weather_snow) + 75 -> context.getString(R.string.weather_heavysnow) + /* 80, 81, 82: Rain showers: Slight, moderate, and violent */ + 80, 81, 82 -> context.getString(R.string.weather_rainshowers) + /* 85, 86: Snow showers slight and heavy */ + 85 -> context.getString(R.string.weather_lightsnowshowers) + 86 -> context.getString(R.string.weather_heavysnow) + /* + * 95: Thunderstorm: Slight or moderate + * 96, 99: Thunderstorm with slight and heavy hail + */ + 95, 96, 99 -> context.getString(R.string.weather_tstorms) + else -> { + logMissingIcon(icon) + context.getString(R.string.weather_notavailable) + } + } + } + + // Some conditions can be for any time of day + // So use sunrise/set data as fallback + override fun isNight(weather: Weather): Boolean { + var isNight = super.isNight(weather) + + if (!isNight) { + // Fallback to sunset/rise time just in case + var tz: ZoneOffset? = null + if (!weather.location!!.tzLong.isNullOrBlank()) { + val id = ZoneIdCompat.of(weather.location!!.tzLong) + tz = id.rules.getOffset(Instant.now()) + } + if (tz == null) { + tz = weather.location!!.tzOffset + } + + val sunrise = weather.astronomy?.sunrise?.toLocalTime() ?: LocalTime.of(6, 0) + val sunset = weather.astronomy?.sunset?.toLocalTime() ?: LocalTime.of(18, 0) + + val now = ZonedDateTime.now(tz).toLocalTime() + + // Determine whether its night using sunset/rise times + if (now.toNanoOfDay() < sunrise.toNanoOfDay() || now.toNanoOfDay() > sunset.toNanoOfDay()) + isNight = true + } + + return isNight + } +} \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/WeatherData.kt new file mode 100644 index 000000000..9358be8ea --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/WeatherData.kt @@ -0,0 +1,326 @@ +package com.thewizrd.weather_api.openmeteo + +import android.annotation.SuppressLint +import com.thewizrd.shared_resources.utils.ConversionMethods +import com.thewizrd.shared_resources.utils.getBeaufortScale +import com.thewizrd.shared_resources.weatherdata.WeatherAPI +import com.thewizrd.shared_resources.weatherdata.model.AirQuality +import com.thewizrd.shared_resources.weatherdata.model.Atmosphere +import com.thewizrd.shared_resources.weatherdata.model.Beaufort +import com.thewizrd.shared_resources.weatherdata.model.Condition +import com.thewizrd.shared_resources.weatherdata.model.Forecast +import com.thewizrd.shared_resources.weatherdata.model.ForecastExtras +import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast +import com.thewizrd.shared_resources.weatherdata.model.Location +import com.thewizrd.shared_resources.weatherdata.model.MinutelyForecast +import com.thewizrd.shared_resources.weatherdata.model.Pollen +import com.thewizrd.shared_resources.weatherdata.model.Precipitation +import com.thewizrd.shared_resources.weatherdata.model.UV +import com.thewizrd.shared_resources.weatherdata.model.Weather +import java.time.Instant +import java.time.ZoneOffset +import java.time.ZonedDateTime +import kotlin.math.max +import kotlin.math.roundToInt + +@SuppressLint("VisibleForTests") +fun createWeatherData(forecast: ForecastResponse, aqiResponse: AQIResponse): Weather { + return Weather().apply { + location = createLocation(forecast) + updateTime = ZonedDateTime.now(ZoneOffset.UTC) + + this.forecast = forecast.daily?.let { createForecasts(it) } + hrForecast = forecast.hourly?.let { createHourlyForecasts(it) } + minForecast = forecast.minutely15?.let { createMinutelyForecasts(it) } + + condition = forecast.current?.let { createCondition(it, aqiResponse.current) } + atmosphere = forecast.current?.let { createAtmosphere(it) } + precipitation = forecast.current?.let { createPrecipitation(it) } + + if ((condition?.highF == null || condition?.highC == null) && !this.forecast.isNullOrEmpty()) { + condition!!.highF = this.forecast!![0].highF + condition!!.highC = this.forecast!![0].highC + condition!!.lowF = this.forecast!![0].lowF + condition!!.lowC = this.forecast!![0].lowC + } + + ttl = 120 + source = WeatherAPI.OPENMETEO + } +} + +fun createLocation(forecast: ForecastResponse): Location { + return Location().apply { + // Use location name from location provider + name = null + latitude = forecast.latitude + longitude = forecast.longitude + tzLong = forecast.timezone + } +} + +fun createForecasts(daily: Daily): List? { + return daily.time?.mapIndexed { index, ts -> + Forecast().apply { + date = + ZonedDateTime.ofInstant(Instant.ofEpochSecond(ts), ZoneOffset.UTC).toLocalDateTime() + + daily.temperature2mMax?.getOrNull(index)?.let { + highF = ConversionMethods.CtoF(it) + highC = it + } + daily.temperature2mMin?.getOrNull(index)?.let { + lowF = ConversionMethods.CtoF(it) + lowC = it + } + + icon = (daily.weatherCode?.getOrNull(index) ?: -1).toString() + condition = icon + + // Extras + extras = ForecastExtras() + + extras.uvIndex = daily.uvIndexMax?.getOrNull(index) + extras.pop = daily.precipitationProbabilityMax?.getOrNull(index) + + daily.windSpeed10mMax?.getOrNull(index)?.let { + extras.windKph = it + extras.windMph = ConversionMethods.kphTomph(it) + } + + daily.windGusts10mMax?.getOrNull(index)?.let { + extras.windGustKph = it + extras.windGustMph = ConversionMethods.kphTomph(it) + } + + extras.windDegrees = daily.windDirection10mDominant?.getOrNull(index) + + extras.cloudiness = daily.cloudCoverMean?.getOrNull(index) + + daily.apparentTemperatureMean?.getOrNull(index)?.let { + extras.feelslikeC = it + extras.feelslikeF = ConversionMethods.CtoF(it) + } + + daily.dewPoint2mMean?.getOrNull(index)?.let { + extras.dewpointC = it + extras.dewpointF = ConversionMethods.CtoF(it) + } + + // 1hPA = 1mbar + daily.pressureMslMean?.getOrNull(index)?.let { + extras.pressureMb = it + extras.pressureIn = ConversionMethods.mbToInHg(it) + } + + extras.humidity = daily.relativeHumidity2mMean?.getOrNull(index) + + daily.visibilityMean?.getOrNull(index)?.let { + extras.visibilityKm = it / 1000 + extras.visibilityMi = ConversionMethods.kmToMi(it / 1000) + } + } + } +} + +fun createHourlyForecasts(hourly: Hourly): List? { + return hourly.time?.mapIndexed { index, ts -> + HourlyForecast().apply { + date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(ts), ZoneOffset.UTC) + + hourly.temperature2m?.getOrNull(index)?.let { + highC = it + highF = ConversionMethods.CtoF(it) + } + + val isDay = hourly.isDay?.getOrNull(index) ?: 1 + icon = hourly.weatherCode?.getOrNull(index)?.toString() + "_" + isDay + condition = icon + + // Extras + extras = ForecastExtras() + + extras.humidity = hourly.relativeHumidity2m?.getOrNull(index) + + hourly.dewPoint2m?.getOrNull(index)?.let { + extras.dewpointC = it + extras.dewpointF = ConversionMethods.CtoF(it) + } + + hourly.apparentTemperature?.getOrNull(index)?.let { + extras.feelslikeC = it + extras.feelslikeF = ConversionMethods.CtoF(it) + } + + extras.pop = hourly.precipitationProbability?.getOrNull(index) + + // 1hPA = 1mbar + hourly.pressureMsl?.getOrNull(index)?.let { + extras.pressureMb = it + extras.pressureIn = ConversionMethods.mbToInHg(it) + } + + extras.cloudiness = hourly.cloudCover?.getOrNull(index) + + hourly.visibility?.getOrNull(index)?.let { + extras.visibilityKm = it / 1000 + extras.visibilityMi = ConversionMethods.kmToMi(it / 1000) + } + + hourly.windSpeed10m?.getOrNull(index)?.let { speed -> + extras.windKph = speed + extras.windMph = ConversionMethods.kphTomph(speed) + } + + hourly.windGusts10m?.getOrNull(index)?.let { speed -> + extras.windGustKph = speed + extras.windGustKph = ConversionMethods.kphTomph(speed) + } + + extras.windDegrees = hourly.windDirection10m?.getOrNull(index) + + hourly.rain?.getOrNull(index)?.let { + extras.qpfRainMm = it + extras.qpfRainIn = ConversionMethods.mmToIn(it) + } + + hourly.snowfall?.getOrNull(index)?.let { + extras.qpfSnowCm = it + extras.qpfSnowIn = ConversionMethods.mmToIn(it * 10) + } + } + } +} + +fun createMinutelyForecasts(minutely15: Minutely15): List? { + return minutely15.time?.mapIndexed { index, ts -> + MinutelyForecast().apply { + date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(ts), ZoneOffset.UTC) + rainMm = minutely15.rain?.getOrNull(index) + snowMm = minutely15.snowfall?.getOrNull(index)?.let { it * 10 } + } + } +} + +fun createCondition(current: Current, aqi: CurrentAQI?): Condition { + return Condition().apply { + observationTime = + current.time?.let { ZonedDateTime.ofInstant(Instant.ofEpochSecond(it), ZoneOffset.UTC) } + + val isDay = current.isDay ?: 1 + icon = current.weatherCode?.toString() + "_" + isDay + weather = icon + + current.temperature2m?.let { + tempC = it + tempF = ConversionMethods.CtoF(it) + } + + current.apparentTemperature?.let { + feelslikeC = it + feelslikeF = ConversionMethods.CtoF(it) + } + + current.windSpeed10m?.let { + windKph = it + windMph = ConversionMethods.kphTomph(it) + beaufort = Beaufort(getBeaufortScale(mph = windMph.roundToInt())) + } + + current.windGusts10m?.let { + windGustKph = it + windGustMph = ConversionMethods.kphTomph(it) + } + + windDegrees = current.windDirection10m + + uv = current.uvIndex?.let { UV(it) } + + airQuality = AirQuality().apply { + index = aqi?.usAqi + pm25 = aqi?.usAqiPm25 + pm10 = aqi?.usAqiPm10 + o3 = aqi?.usAqiOzone + no2 = aqi?.usAqiNitrogenDioxide + co = aqi?.usAqiCarbonMonoxide + so2 = aqi?.usAqiSulphurDioxide + } + + val treePollenMeasure = if (aqi?.birchPollen != null && aqi.alderPollen != null) { + max(aqi.birchPollen!!, aqi.alderPollen!!) + } else { + aqi?.birchPollen ?: aqi?.alderPollen + } + val grassPollenMeasure = aqi?.grassPollen + val ragweedPollenMeasure = aqi?.ragweedPollen + + pollen = Pollen().apply { + treePollenCount = when { + treePollenMeasure == null -> Pollen.PollenCount.UNKNOWN + treePollenMeasure < 15 -> Pollen.PollenCount.LOW + treePollenMeasure < 90 -> Pollen.PollenCount.MODERATE + treePollenMeasure < 1500 -> Pollen.PollenCount.HIGH + treePollenMeasure >= 1500 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + + grassPollenCount = when { + grassPollenMeasure == null -> Pollen.PollenCount.UNKNOWN + grassPollenMeasure < 5 -> Pollen.PollenCount.LOW + grassPollenMeasure < 20 -> Pollen.PollenCount.MODERATE + grassPollenMeasure < 200 -> Pollen.PollenCount.HIGH + grassPollenMeasure >= 200 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + + ragweedPollenCount = when { + ragweedPollenMeasure == null -> Pollen.PollenCount.UNKNOWN + ragweedPollenMeasure < 10 -> Pollen.PollenCount.LOW + ragweedPollenMeasure < 50 -> Pollen.PollenCount.MODERATE + ragweedPollenMeasure < 500 -> Pollen.PollenCount.HIGH + ragweedPollenMeasure >= 500 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + } + } +} + +fun createAtmosphere(current: Current): Atmosphere { + return Atmosphere().apply { + humidity = current.relativeHumidity2m + + // 1hPa = 1mb + current.pressureMsl?.let { + pressureMb = it + pressureIn = ConversionMethods.mbToInHg(it) + } + pressureTrend = "" + + current.dewPoint2m?.let { + dewpointC = it + dewpointF = ConversionMethods.CtoF(it) + } + + current.visibility?.let { + visibilityKm = it / 1000 + visibilityMi = ConversionMethods.kmToMi(visibilityKm) + } + } +} + +fun createPrecipitation(current: Current): Precipitation { + return Precipitation().apply { + pop = current.precipitationProbability + cloudiness = current.cloudCover + + current.rain?.let { + qpfRainMm = it + qpfRainIn = ConversionMethods.mmToIn(it) + } + + current.snowfall?.let { + qpfSnowCm = it + qpfSnowIn = ConversionMethods.mmToIn(it * 10) + } + } +} \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Coord.java b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Coord.java index 74fda99d5..e3ca1fe39 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Coord.java +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Coord.java @@ -7,24 +7,24 @@ public class Coord { @Json(name = "lon") - private float lon; + private Float lon; @Json(name = "lat") - private float lat; + private Float lat; - public void setLon(float lon) { + public void setLon(Float lon) { this.lon = lon; } - public float getLon() { + public Float getLon() { return lon; } - public void setLat(float lat) { + public void setLat(Float lat) { this.lat = lat; } - public float getLat() { + public Float getLat() { return lat; } } \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Main.java b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Main.java index 8a41c06ff..40c6207ad 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Main.java +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/Main.java @@ -7,22 +7,22 @@ public class Main { @Json(name = "temp") - private float temp; + private Float temp; @Json(name = "feels_like") private Float feelsLike; @Json(name = "temp_min") - private float tempMin; + private Float tempMin; @Json(name = "temp_max") - private float tempMax; + private Float tempMax; @Json(name = "humidity") - private int humidity; + private Integer humidity; @Json(name = "pressure") - private float pressure; + private Float pressure; @Json(name = "sea_level") private Float seaLevel; @@ -30,11 +30,11 @@ public class Main { @Json(name = "grnd_level") private Float grndLevel; - public void setTemp(float temp) { + public void setTemp(Float temp) { this.temp = temp; } - public float getTemp() { + public Float getTemp() { return temp; } @@ -46,35 +46,35 @@ public Float getFeelsLike() { return feelsLike; } - public void setTempMin(float tempMin) { + public void setTempMin(Float tempMin) { this.tempMin = tempMin; } - public float getTempMin() { + public Float getTempMin() { return tempMin; } - public void setHumidity(int humidity) { + public void setHumidity(Integer humidity) { this.humidity = humidity; } - public int getHumidity() { + public Integer getHumidity() { return humidity; } - public void setPressure(float pressure) { + public void setPressure(Float pressure) { this.pressure = pressure; } - public float getPressure() { + public Float getPressure() { return pressure; } - public void setTempMax(float tempMax) { + public void setTempMax(Float tempMax) { this.tempMax = tempMax; } - public float getTempMax() { + public Float getTempMax() { return tempMax; } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt index 4bbc4a090..c3a2710f8 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt @@ -42,7 +42,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class OpenWeatherMapProvider : WeatherProviderImpl { @@ -250,6 +250,8 @@ class OpenWeatherMapProvider : WeatherProviderImpl { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // OWM reports datetime in UTC; add location tz_offset val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/WeatherData.kt index 7287b0a03..97f339e55 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/WeatherData.kt @@ -140,10 +140,6 @@ fun createHourlyForecast(hr_forecast: ListItem): HourlyForecast { icon = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.OPENWEATHERMAP) .getWeatherIcon(hr_forecast.weather[0].id.toString() + dn) - windDegrees = hr_forecast.wind.deg.roundToInt() - windMph = ConversionMethods.msecToMph(hr_forecast.wind.speed) - windKph = ConversionMethods.msecToKph(hr_forecast.wind.speed) - // Extras extras = ForecastExtras() extras.humidity = hr_forecast.main.humidity @@ -151,9 +147,9 @@ fun createHourlyForecast(hr_forecast: ListItem): HourlyForecast { // 1hPA = 1mbar extras.pressureMb = hr_forecast.main.pressure extras.pressureIn = ConversionMethods.mbToInHg(hr_forecast.main.pressure) - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = hr_forecast.wind.deg.roundToInt() + extras.windMph = ConversionMethods.msecToMph(hr_forecast.wind.speed) + extras.windKph = ConversionMethods.msecToKph(hr_forecast.wind.speed) if (highC > 0 && highC < 60 && hr_forecast.main.humidity > 1) { extras.dewpointC = calculateDewpointC(highC, hr_forecast.main.humidity) extras.dewpointF = ConversionMethods.CtoF(extras.dewpointC) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt index 94d00c6c0..e6228a661 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt @@ -11,7 +11,11 @@ import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.DateTimeUtils +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.ZoneIdCompat import com.thewizrd.shared_resources.weatherdata.AirQualityProvider import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.auth.AuthType @@ -40,7 +44,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit import com.thewizrd.weather_api.openweather.weather.onecall.Rootobject as OneCallRootobject import com.thewizrd.weather_api.openweather.weather.onecall.createWeatherData as createOneCallWeatherData @@ -243,6 +247,8 @@ class OWMOneCallWeatherProvider : WeatherProviderImpl, AirQualityProvider { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + // OWM reports datetime in UTC; add location tz_offset val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) @@ -290,13 +296,8 @@ class OWMOneCallWeatherProvider : WeatherProviderImpl, AirQualityProvider { if (weather.weatherAlerts?.isNotEmpty() == true) { for (alert in weather.weatherAlerts) { - if (alert.date.offset != offset) { - alert.date = alert.date.withZoneSameLocal(offset) - } - - if (alert.expiresDate.offset != offset) { - alert.expiresDate = alert.expiresDate.withZoneSameLocal(offset) - } + alert.date = alert.date.withZoneSameInstant(offset) + alert.expiresDate = alert.expiresDate.withZoneSameInstant(offset) } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/WeatherData.kt index 70f8be936..f80115656 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/WeatherData.kt @@ -134,10 +134,6 @@ fun createHourlyForecast(hr_forecast: HourlyItem): HourlyForecast { icon = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.OPENWEATHERMAP) .getWeatherIcon(hr_forecast.weather[0].id.toString() + dn) - windDegrees = hr_forecast.windDeg - windMph = ConversionMethods.msecToMph(hr_forecast.windSpeed) - windKph = ConversionMethods.msecToKph(hr_forecast.windSpeed) - // Extras extras = ForecastExtras() extras.feelslikeF = ConversionMethods.KtoF(hr_forecast.feelsLike) @@ -152,9 +148,9 @@ fun createHourlyForecast(hr_forecast: HourlyItem): HourlyForecast { // 1hPA = 1mbar extras.pressureMb = hr_forecast.pressure extras.pressureIn = ConversionMethods.mbToInHg(hr_forecast.pressure) - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = hr_forecast.windDeg + extras.windMph = ConversionMethods.msecToMph(hr_forecast.windSpeed) + extras.windKph = ConversionMethods.msecToKph(hr_forecast.windSpeed) if (hr_forecast.windGust != null) { extras.windGustMph = ConversionMethods.msecToMph(hr_forecast.windGust) extras.windGustKph = ConversionMethods.msecToKph(hr_forecast.windGust) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt index f496b6f14..a31f2a1aa 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt @@ -3,6 +3,7 @@ package com.thewizrd.weather_api.tomorrow import android.util.Log import androidx.core.net.toUri import com.ibm.icu.util.ULocale +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.icons.WeatherIcons @@ -21,7 +22,6 @@ import com.thewizrd.shared_resources.weatherdata.auth.AuthType import com.thewizrd.shared_resources.weatherdata.model.Pollen import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.extras.cacheRequestIfNeeded import com.thewizrd.weather_api.keys.Keys import com.thewizrd.weather_api.locationiq.LocationIQProvider @@ -46,7 +46,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { @@ -189,7 +189,7 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { .appendQueryParameter("location", query) .appendQueryParameter( "fields", - "temperature,temperatureApparent,temperatureMin,temperatureMax,dewPoint,humidity,windSpeed,windDirection,windGust,pressureSeaLevel,precipitationIntensity,precipitationProbability,snowAccumulation,sunriseTime,sunsetTime,visibility,cloudCover,moonPhase,weatherCode,weatherCodeFullDay,weatherCodeDay,weatherCodeNight,treeIndex,grassIndex,weedIndex,epaIndex,particulateMatter25,particulateMatter10,pollutantO3,pollutantNO2,pollutantCO,pollutantSO2" + "temperature,temperatureApparent,temperatureMin,temperatureMax,dewPoint,humidity,windSpeed,windDirection,windGust,pressureSeaLevel,precipitationIntensity,precipitationProbability,precipitationType,snowAccumulation,sunriseTime,sunsetTime,visibility,cloudCover,moonPhase,weatherCode,weatherCodeFullDay,weatherCodeDay,weatherCodeNight,treeIndex,grassIndex,weedIndex,epaIndex,particulateMatter25,particulateMatter10,pollutantO3,pollutantNO2,pollutantCO,pollutantSO2" ) .appendQueryParameter("timesteps", "current,1h,1d") .appendQueryParameter("units", "metric") @@ -207,7 +207,7 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { .appendQueryParameter("location", query) .appendQueryParameter( "fields", - "precipitationIntensity,precipitationProbability" + "precipitationIntensity,precipitationProbability,precipitationType" ) .appendQueryParameter("timesteps", "1m") .appendQueryParameter("units", "metric") @@ -258,8 +258,8 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { runCatching { minutelyResponse = client.newCall(minutelyRequest).await() - checkForErrors(minutelyResponse!!) - minutelyResponse!!.getStream().use { + checkForErrors(minutelyResponse) + minutelyResponse.getStream().use { minutelyRoot = JSONParser.deserializer(it, Rootobject::class.java) } @@ -267,8 +267,8 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { runCatching { alertsResponse = client.newCall(alertsRequest).await() - checkForErrors(alertsResponse!!) - alertsResponse!!.getStream().use { + checkForErrors(alertsResponse) + alertsResponse.getStream().use { alertsRoot = JSONParser.deserializer( it, AlertsRootobject::class.java @@ -396,6 +396,8 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset // Update tz for weather properties @@ -464,13 +466,8 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { if (!weather.weatherAlerts.isNullOrEmpty()) { for (alert in weather.weatherAlerts) { - if (alert.date.offset != offset) { - alert.date = alert.date.withZoneSameLocal(offset) - } - - if (alert.expiresDate.offset != offset) { - alert.expiresDate = alert.expiresDate.withZoneSameLocal(offset) - } + alert.date = alert.date.withZoneSameInstant(offset) + alert.expiresDate = alert.expiresDate.withZoneSameInstant(offset) } } } @@ -1010,7 +1007,9 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { 4210, 42100, 42101 -> context.getString(R.string.weather_rain) /* Heavy Rain */ 4201, 42010, 42011, - 4211, 42110, 42111 -> context.getString(R.string.weather_heavyrain) + 4211, 42110, 42111, + 4202, 42020, 42021, + 4212, 42120, 42121 -> context.getString(R.string.weather_heavyrain) /* Flurries */ 5001, 50010, 50011, 5115, 51150, 51151, diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/Values.java b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/Values.java index 106f5ec7a..008874720 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/Values.java +++ b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/Values.java @@ -21,6 +21,9 @@ public class Values { @Json(name = "precipitationIntensity") private Float precipitationIntensity; + @Json(name = "precipitationType") + private Integer precipitationType; + @Json(name = "temperatureApparent") private Float temperatureApparent; @@ -142,6 +145,14 @@ public Float getPrecipitationIntensity() { return precipitationIntensity; } + public Integer getPrecipitationType() { + return precipitationType; + } + + public void setPrecipitationType(Integer precipitationType) { + this.precipitationType = precipitationType; + } + public void setTemperatureApparent(Float temperatureApparent) { this.temperatureApparent = temperatureApparent; } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/WeatherData.kt index a670ce815..2464d8a9e 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/WeatherData.kt @@ -1,6 +1,7 @@ package com.thewizrd.weather_api.tomorrow import android.annotation.SuppressLint +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.AirQualityUtils.AQICO import com.thewizrd.shared_resources.utils.AirQualityUtils.AQINO2 @@ -27,7 +28,6 @@ import com.thewizrd.shared_resources.weatherdata.model.Pollen import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.TextForecast import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.weatherModule import java.time.LocalDateTime import java.time.ZoneOffset @@ -259,11 +259,11 @@ fun createHourlyForecast(item: IntervalsItem): HourlyForecast { extras.pressureIn = ConversionMethods.mbToInHg(it) } - extras.windDegrees = item.values.windDirection?.roundToInt()?.also { windDegrees = it } + extras.windDegrees = item.values.windDirection?.roundToInt() item.values.windSpeed?.let { speed -> - extras.windMph = ConversionMethods.msecToMph(speed).also { windMph = it } - extras.windKph = ConversionMethods.msecToKph(speed).also { windKph = it } + extras.windMph = ConversionMethods.msecToMph(speed) + extras.windKph = ConversionMethods.msecToKph(speed) } item.values.windGust?.let { @@ -281,7 +281,17 @@ fun createHourlyForecast(item: IntervalsItem): HourlyForecast { fun createMinutelyForecast(item: IntervalsItem): MinutelyForecast { return MinutelyForecast().apply { date = ZonedDateTime.parse(item.startTime).withZoneSameInstant(ZoneOffset.UTC) - rainMm = item.values.precipitationIntensity + /** + * 0: No precipitation + * 1: Rain + * 2: Snow + * 3: Freezing Rain + * 4: Ice Pellets / Sleet + */ + when (item.values.precipitationType) { + 2 -> snowMm = item.values.precipitationIntensity + else -> rainMm = item.values.precipitationIntensity + } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/ForecastResponse.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/ForecastResponse.kt index 4bc8f4858..35252b76c 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/ForecastResponse.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/ForecastResponse.kt @@ -7,161 +7,161 @@ import com.squareup.moshi.JsonClass data class ForecastResponse( @field:Json(name = "alerts") - var alerts: Alerts? = null, + var alerts: Alerts? = null, @field:Json(name = "current") - var current: Current? = null, + var current: Current? = null, @field:Json(name = "location") - var location: Location? = null, + var location: Location? = null, @field:Json(name = "forecast") - var forecast: Forecast? = null + var forecast: Forecast? = null ) @JsonClass(generateAdapter = true) data class AlertItem( @field:Json(name = "severity") - var severity: String? = null, + var severity: String? = null, @field:Json(name = "note") - var note: String? = null, + var note: String? = null, @field:Json(name = "expires") - var expires: String? = null, + var expires: String? = null, @field:Json(name = "certainty") - var certainty: String? = null, + var certainty: String? = null, @field:Json(name = "areas") - var areas: String? = null, + var areas: String? = null, @field:Json(name = "effective") - var effective: String? = null, + var effective: String? = null, @field:Json(name = "urgency") - var urgency: String? = null, + var urgency: String? = null, @field:Json(name = "instruction") - var instruction: String? = null, + var instruction: String? = null, @field:Json(name = "category") - var category: String? = null, + var category: String? = null, @field:Json(name = "event") - var event: String? = null, + var event: String? = null, @field:Json(name = "headline") - var headline: String? = null, + var headline: String? = null, @field:Json(name = "msgtype") - var msgtype: String? = null, + var msgtype: String? = null, @field:Json(name = "desc") - var desc: String? = null + var desc: String? = null ) @JsonClass(generateAdapter = true) data class HourItem( @field:Json(name = "feelslike_c") - var feelslikeC: Float? = null, + var feelslikeC: Float? = null, @field:Json(name = "feelslike_f") - var feelslikeF: Float? = null, + var feelslikeF: Float? = null, @field:Json(name = "wind_degree") - var windDegree: Int? = null, + var windDegree: Int? = null, @field:Json(name = "windchill_f") - var windchillF: Float? = null, + var windchillF: Float? = null, @field:Json(name = "windchill_c") - var windchillC: Float? = null, + var windchillC: Float? = null, @field:Json(name = "temp_c") - var tempC: Float? = null, + var tempC: Float? = null, @field:Json(name = "temp_f") - var tempF: Float? = null, + var tempF: Float? = null, @field:Json(name = "cloud") - var cloud: Int? = null, + var cloud: Int? = null, @field:Json(name = "wind_kph") - var windKph: Float? = null, + var windKph: Float? = null, @field:Json(name = "wind_mph") - var windMph: Float? = null, + var windMph: Float? = null, @field:Json(name = "humidity") - var humidity: Int? = null, + var humidity: Int? = null, @field:Json(name = "dewpoint_f") - var dewpointF: Float? = null, + var dewpointF: Float? = null, @field:Json(name = "will_it_rain") - var willItRain: Int? = null, + var willItRain: Int? = null, @field:Json(name = "uv") - var uv: Float? = null, + var uv: Float? = null, @field:Json(name = "heatindex_f") - var heatindexF: Float? = null, + var heatindexF: Float? = null, @field:Json(name = "dewpoint_c") - var dewpointC: Float? = null, + var dewpointC: Float? = null, @field:Json(name = "is_day") @get:JvmName("getIsDay") - @set:JvmName("setIsDay") - var isDay: Int? = null, + @set:JvmName("setIsDay") + var isDay: Int? = null, @field:Json(name = "precip_in") - var precipIn: Float? = null, + var precipIn: Float? = null, @field:Json(name = "heatindex_c") - var heatindexC: Float? = null, + var heatindexC: Float? = null, @field:Json(name = "wind_dir") - var windDir: String? = null, + var windDir: String? = null, @field:Json(name = "gust_mph") - var gustMph: Float? = null, + var gustMph: Float? = null, @field:Json(name = "pressure_in") - var pressureIn: Float? = null, + var pressureIn: Float? = null, @field:Json(name = "chance_of_rain") - var chanceOfRain: String? = null, + var chanceOfRain: String? = null, @field:Json(name = "gust_kph") - var gustKph: Float? = null, + var gustKph: Float? = null, @field:Json(name = "precip_mm") - var precipMm: Float? = null, + var precipMm: Float? = null, @field:Json(name = "condition") - var condition: Condition? = null, + var condition: Condition? = null, @field:Json(name = "will_it_snow") - var willItSnow: Int? = null, + var willItSnow: Int? = null, @field:Json(name = "vis_km") - var visKm: Float? = null, + var visKm: Float? = null, @field:Json(name = "time_epoch") var timeEpoch: Long? = null, @field:Json(name = "time") - var time: String? = null, + var time: String? = null, @field:Json(name = "chance_of_snow") - var chanceOfSnow: String? = null, + var chanceOfSnow: String? = null, @field:Json(name = "pressure_mb") - var pressureMb: Float? = null, + var pressureMb: Float? = null, @field:Json(name = "vis_miles") var visMiles: Float? = null, @@ -174,87 +174,87 @@ data class HourItem( data class Astro( @field:Json(name = "moonset") - var moonset: String? = null, + var moonset: String? = null, @field:Json(name = "moon_illumination") - var moonIllumination: String? = null, + var moonIllumination: String? = null, @field:Json(name = "sunrise") - var sunrise: String? = null, + var sunrise: String? = null, @field:Json(name = "moon_phase") - var moonPhase: String? = null, + var moonPhase: String? = null, @field:Json(name = "sunset") - var sunset: String? = null, + var sunset: String? = null, @field:Json(name = "moonrise") - var moonrise: String? = null + var moonrise: String? = null ) @JsonClass(generateAdapter = true) data class Alerts( @field:Json(name = "alert") - var alert: List? = null + var alert: List? = null ) @JsonClass(generateAdapter = true) data class Day( @field:Json(name = "avgvis_km") - var avgvisKm: Float? = null, + var avgvisKm: Float? = null, @field:Json(name = "uv") - var uv: Float? = null, + var uv: Float? = null, @field:Json(name = "avgtemp_f") - var avgtempF: Float? = null, + var avgtempF: Float? = null, @field:Json(name = "avgtemp_c") - var avgtempC: Float? = null, + var avgtempC: Float? = null, @field:Json(name = "daily_chance_of_snow") - var dailyChanceOfSnow: String? = null, + var dailyChanceOfSnow: String? = null, @field:Json(name = "maxtemp_c") - var maxtempC: Float? = null, + var maxtempC: Float? = null, @field:Json(name = "maxtemp_f") - var maxtempF: Float? = null, + var maxtempF: Float? = null, @field:Json(name = "mintemp_c") - var mintempC: Float? = null, + var mintempC: Float? = null, @field:Json(name = "avgvis_miles") - var avgvisMiles: Float? = null, + var avgvisMiles: Float? = null, @field:Json(name = "daily_will_it_rain") - var dailyWillItRain: Int? = null, + var dailyWillItRain: Int? = null, @field:Json(name = "mintemp_f") - var mintempF: Float? = null, + var mintempF: Float? = null, @field:Json(name = "totalprecip_in") - var totalprecipIn: Float? = null, + var totalprecipIn: Float? = null, @field:Json(name = "avghumidity") - var avghumidity: Float? = null, + var avghumidity: Float? = null, @field:Json(name = "condition") - var condition: Condition? = null, + var condition: Condition? = null, @field:Json(name = "maxwind_kph") - var maxwindKph: Float? = null, + var maxwindKph: Float? = null, @field:Json(name = "maxwind_mph") - var maxwindMph: Float? = null, + var maxwindMph: Float? = null, @field:Json(name = "daily_chance_of_rain") - var dailyChanceOfRain: String? = null, + var dailyChanceOfRain: String? = null, @field:Json(name = "totalprecip_mm") - var totalprecipMm: Float? = null, + var totalprecipMm: Float? = null, @field:Json(name = "daily_will_it_snow") var dailyWillItSnow: Int? = null, @@ -267,171 +267,199 @@ data class Day( data class Forecast( @field:Json(name = "forecastday") - var forecastday: List? = null + var forecastday: List? = null ) @JsonClass(generateAdapter = true) data class Current( @field:Json(name = "feelslike_c") - var feelslikeC: Float? = null, + var feelslikeC: Float? = null, @field:Json(name = "uv") - var uv: Float? = null, + var uv: Float? = null, @field:Json(name = "last_updated") - var lastUpdated: String? = null, + var lastUpdated: String? = null, @field:Json(name = "feelslike_f") - var feelslikeF: Float? = null, + var feelslikeF: Float? = null, @field:Json(name = "wind_degree") - var windDegree: Int? = null, + var windDegree: Int? = null, @field:Json(name = "last_updated_epoch") var lastUpdatedEpoch: Long? = null, @field:Json(name = "is_day") @get:JvmName("getIsDay") - @set:JvmName("setIsDay") - var isDay: Int? = null, + @set:JvmName("setIsDay") + var isDay: Int? = null, @field:Json(name = "precip_in") - var precipIn: Float? = null, + var precipIn: Float? = null, @field:Json(name = "air_quality") - var airQuality: AirQuality? = null, + var airQuality: AirQuality? = null, @field:Json(name = "wind_dir") - var windDir: String? = null, + var windDir: String? = null, @field:Json(name = "gust_mph") - var gustMph: Float? = null, + var gustMph: Float? = null, @field:Json(name = "temp_c") - var tempC: Float? = null, + var tempC: Float? = null, @field:Json(name = "pressure_in") - var pressureIn: Float? = null, + var pressureIn: Float? = null, @field:Json(name = "gust_kph") - var gustKph: Float? = null, + var gustKph: Float? = null, @field:Json(name = "temp_f") - var tempF: Float? = null, + var tempF: Float? = null, @field:Json(name = "precip_mm") - var precipMm: Float? = null, + var precipMm: Float? = null, @field:Json(name = "cloud") - var cloud: Int? = null, + var cloud: Int? = null, @field:Json(name = "wind_kph") - var windKph: Float? = null, + var windKph: Float? = null, @field:Json(name = "condition") - var condition: Condition? = null, + var condition: Condition? = null, @field:Json(name = "wind_mph") - var windMph: Float? = null, + var windMph: Float? = null, @field:Json(name = "vis_km") - var visKm: Float? = null, + var visKm: Float? = null, @field:Json(name = "humidity") - var humidity: Int? = null, + var humidity: Int? = null, @field:Json(name = "pressure_mb") - var pressureMb: Float? = null, + var pressureMb: Float? = null, @field:Json(name = "vis_miles") - var visMiles: Float? = null + var visMiles: Float? = null, + + @field:Json(name = "pollen") + var pollen: Pollen? = null, ) @JsonClass(generateAdapter = true) data class Condition( @field:Json(name = "code") - var code: Int? = null, + var code: Int? = null, @field:Json(name = "icon") - var icon: String? = null, + var icon: String? = null, @field:Json(name = "text") - var text: String? = null + var text: String? = null ) @JsonClass(generateAdapter = true) data class ForecastdayItem( @field:Json(name = "date") - var date: String? = null, + var date: String? = null, @field:Json(name = "astro") - var astro: Astro? = null, + var astro: Astro? = null, @field:Json(name = "date_epoch") var dateEpoch: Long? = null, @field:Json(name = "hour") - var hour: List? = null, + var hour: List? = null, @field:Json(name = "day") - var day: Day? = null + var day: Day? = null ) @JsonClass(generateAdapter = true) data class Location( @field:Json(name = "localtime") - var localtime: String? = null, + var localtime: String? = null, @field:Json(name = "country") - var country: String? = null, + var country: String? = null, @field:Json(name = "localtime_epoch") var localtimeEpoch: Long? = null, @field:Json(name = "name") - var name: String? = null, + var name: String? = null, @field:Json(name = "lon") - var lon: Float? = null, + var lon: Float? = null, @field:Json(name = "region") - var region: String? = null, + var region: String? = null, @field:Json(name = "lat") - var lat: Float? = null, + var lat: Float? = null, @field:Json(name = "tz_id") - var tzId: String? = null + var tzId: String? = null ) @JsonClass(generateAdapter = true) data class AirQuality( @field:Json(name = "no2") - var no2: Double? = null, + var no2: Double? = null, @field:Json(name = "o3") - var o3: Double? = null, + var o3: Double? = null, @field:Json(name = "us-epa-index") - var usEpaIndex: Int? = null, + var usEpaIndex: Int? = null, @field:Json(name = "so2") - var so2: Double? = null, + var so2: Double? = null, @field:Json(name = "pm2_5") - var pm25: Double? = null, + var pm25: Double? = null, @field:Json(name = "pm10") - var pm10: Double? = null, + var pm10: Double? = null, @field:Json(name = "co") - var co: Double? = null, + var co: Double? = null, @field:Json(name = "gb-defra-index") - var gbDefraIndex: Int? = null + var gbDefraIndex: Int? = null +) + +@JsonClass(generateAdapter = true) +data class Pollen( + + @field:Json(name = "Alder") + var alder: Double? = null, + + @field:Json(name = "Birch") + var birch: Double? = null, + + @field:Json(name = "Mugwort") + var mugwort: Double? = null, + + @field:Json(name = "Oak") + var oak: Double? = null, + + @field:Json(name = "Grass") + var grass: Double? = null, + + @field:Json(name = "Hazel") + var hazel: Double? = null, + + @field:Json(name = "Ragweed") + var ragweed: Double? = null ) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherAlerts.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherAlerts.kt index 0463ef176..11b053392 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherAlerts.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherAlerts.kt @@ -1,5 +1,6 @@ package com.thewizrd.weather_api.weatherapi.weather +import android.annotation.SuppressLint import com.thewizrd.shared_resources.weatherdata.model.WeatherAlert import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertSeverity import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertType @@ -9,7 +10,7 @@ import java.time.format.DateTimeFormatter fun createWeatherAlerts(alerts: Alerts?): Collection? { if (alerts?.alert.isNullOrEmpty()) return null - val weatherAlerts = ArrayList(alerts!!.alert!!.size) + val weatherAlerts = ArrayList(alerts.alert!!.size) for (alert in alerts.alert!!) { weatherAlerts.add(createWeatherAlert(alert)) @@ -18,6 +19,7 @@ fun createWeatherAlerts(alerts: Alerts?): Collection? { return weatherAlerts } +@SuppressLint("VisibleForTests") fun createWeatherAlert(alert: AlertItem): WeatherAlert { return WeatherAlert().apply { type = when { @@ -52,9 +54,11 @@ fun createWeatherAlert(alert: AlertItem): WeatherAlert { attribution = alert.note ?: "WeatherAPI.com" - date = ZonedDateTime.parse(alert.effective, - DateTimeFormatter.ISO_ZONED_DATE_TIME) - expiresDate = ZonedDateTime.parse(alert.expires, - DateTimeFormatter.ISO_ZONED_DATE_TIME) + date = + alert.effective?.let { ZonedDateTime.parse(it, DateTimeFormatter.ISO_ZONED_DATE_TIME) } + ?: ZonedDateTime.now() + expiresDate = + alert.expires?.let { ZonedDateTime.parse(it, DateTimeFormatter.ISO_ZONED_DATE_TIME) } + ?: date.plusDays(1) } } \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt index 86dc344e7..fce4a44ac 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt @@ -10,19 +10,24 @@ import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.remoteconfig.remoteConfigService import com.thewizrd.shared_resources.sharedDeps +import com.thewizrd.shared_resources.utils.DateTimeUtils import com.thewizrd.shared_resources.utils.JSONParser import com.thewizrd.shared_resources.utils.LocaleUtils import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.utils.ZoneIdCompat +import com.thewizrd.shared_resources.weatherdata.PollenProvider import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherAlertProvider import com.thewizrd.shared_resources.weatherdata.auth.AuthType +import com.thewizrd.shared_resources.weatherdata.model.Pollen import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.WeatherAlert import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid import com.thewizrd.weather_api.extras.cacheRequestIfNeeded import com.thewizrd.weather_api.keys.Keys import com.thewizrd.weather_api.locationiq.LocationIQProvider +import com.thewizrd.weather_api.nws.SolCalcAstroProvider +import com.thewizrd.weather_api.smc.SunMoonCalcProvider import com.thewizrd.weather_api.utils.APIRequestUtils.checkForErrors import com.thewizrd.weather_api.utils.APIRequestUtils.checkRateLimit import com.thewizrd.weather_api.utils.APIRequestUtils.throwIfRateLimited @@ -42,17 +47,19 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit -class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider { +class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider, PollenProvider { companion object { private const val BASE_URL = "https://api.weatherapi.com/v1/" private const val KEYCHECK_QUERY_URL = BASE_URL + "forecast.json?key=%s" private const val WEATHER_QUERY_URL = - BASE_URL + "forecast.json?q=%s&days=10&aqi=yes&alerts=yes&lang=%s&key=%s" + BASE_URL + "forecast.json?q=%s&days=10&aqi=yes&pollen=yes&alerts=yes&lang=%s&key=%s" private const val ALERTS_QUERY_URL = BASE_URL + "forecast.json?q=%s&days=1&hour=6&aqi=no&alerts=yes&lang=%s&key=%s" + private const val POLLEN_QUERY_URL = + BASE_URL + "current.json?q=%s&pollen=yes&key=%s" } init { @@ -293,9 +300,146 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider { return@withContext alerts } + override suspend fun getPollenData(location: LocationData): Pollen? = + withContext(Dispatchers.IO) { + var pollenData: Pollen? = null + + val key = getProviderKey() + + val client = sharedDeps.httpClient + var response: Response? = null + + try { + // If were under rate limit, deny request + checkRateLimit() + + if (key.isNullOrBlank()) { + throw WeatherException(ErrorStatus.INVALIDAPIKEY) + } + + val request = Request.Builder() + .cacheRequestIfNeeded(isKeyRequired(), 30, TimeUnit.MINUTES) + .url( + String.format( + POLLEN_QUERY_URL, + updateLocationQuery(location), + key + ) + ) + .build() + + // Connect to webstream + response = client.newCall(request).await() + checkForErrors(response) + + val stream = response.getStream() + + // Load weather + val root = JSONParser.deserializer( + stream, + ForecastResponse::class.java + ) + + // End Stream + stream.closeQuietly() + + requireNotNull(root) + + root.current?.pollen?.let { currentPollen -> + val treePollenValue = maxOf( + currentPollen.hazel ?: 0.0, + currentPollen.alder ?: 0.0, + currentPollen.birch ?: 0.0, + currentPollen.oak ?: 0.0 + ) + val grassPollenValue = currentPollen.grass ?: 0.0 + val ragweedPollenValue = + maxOf(currentPollen.ragweed ?: 0.0, currentPollen.mugwort ?: 0.0) + + pollenData = Pollen().apply { + treePollenCount = when { + treePollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + treePollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + treePollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + treePollenValue >= 300.0 -> Pollen.PollenCount.LOW + else -> Pollen.PollenCount.UNKNOWN + } + grassPollenCount = when { + grassPollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + grassPollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + grassPollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + grassPollenValue >= 300.0 -> Pollen.PollenCount.LOW + else -> Pollen.PollenCount.UNKNOWN + } + ragweedPollenCount = when { + ragweedPollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + ragweedPollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + ragweedPollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + ragweedPollenValue >= 300.0 -> Pollen.PollenCount.LOW + else -> Pollen.PollenCount.UNKNOWN + } + } + } + } catch (ex: Exception) { + pollenData = null + Logger.writeLine( + Log.ERROR, + ex, + "WeatherApiProvider: error getting weather alert data" + ) + } finally { + response?.closeQuietly() + } + + return@withContext pollenData + } + @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { - // no-op + super.updateWeatherData(location, weather) + + val newAstro = try { + SunMoonCalcProvider().getAstronomyData(location, weather.condition!!.observationTime) + } catch (e: WeatherException) { + Logger.writeLine(Log.ERROR, e, "Error") + SolCalcAstroProvider().getAstronomyData(location, weather.condition!!.observationTime) + } + + if (weather.astronomy != null) { + runCatching { + if (weather.astronomy!!.sunrise == null || DateTimeUtils.LOCALDATETIME_MIN.isEqual( + weather.astronomy!!.sunrise + ) + ) { + weather.astronomy!!.sunrise = newAstro.sunrise + } + if (weather.astronomy!!.sunset == null || DateTimeUtils.LOCALDATETIME_MIN.isEqual( + weather.astronomy!!.sunset + ) + ) { + weather.astronomy!!.sunset = newAstro.sunset + } + if (weather.astronomy!!.moonrise == null || DateTimeUtils.LOCALDATETIME_MIN.isEqual( + weather.astronomy!!.moonrise + ) + ) { + weather.astronomy!!.moonrise = newAstro.moonrise + } + if (weather.astronomy!!.moonset == null || DateTimeUtils.LOCALDATETIME_MIN.isEqual( + weather.astronomy!!.moonset + ) + ) { + weather.astronomy!!.moonset = newAstro.moonset + } + if (weather.astronomy!!.moonPhase == null) { + weather.astronomy!!.moonPhase = newAstro.moonPhase + } + }.getOrElse { + weather.astronomy = newAstro + } + } else { + weather.astronomy = newAstro + } } override suspend fun updateLocationQuery(weather: Weather): String { @@ -369,6 +513,32 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider { weatherIcon = WeatherIcons.OVERCAST } + /* 1012: Haze + * 1036: Smoky haze + */ + 1012, 1036 -> { + weatherIcon = WeatherIcons.HAZE + } + + /* + * 1015: Dust Haze + * 1018: Blowing dust + * 1021: Dust storm + * 1045: Saharan dust + * 1048: Dust + */ + 1015, 1018, 1021, 1045, 1048 -> { + weatherIcon = WeatherIcons.DUST + } + + /* + * 1024: Sandstorm + * 1027: Severe sandstorm + */ + 1024, 1027 -> { + weatherIcon = WeatherIcons.SANDSTORM + } + /* * 1030: Mist * 1135: Fog @@ -378,6 +548,21 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider { weatherIcon = WeatherIcons.FOG } + /* + * 1033: Smoke + */ + 1033 -> { + weatherIcon = WeatherIcons.SMOKE + } + + /* + * 1039: Smog + * 1042: Severe smog + */ + 1039, 1042 -> { + weatherIcon = WeatherIcons.SMOG + } + /* * 1063: Patchy rain possible * 1186: Moderate rain at times diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherData.kt index ceb9257cf..32023919f 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherData.kt @@ -1,5 +1,6 @@ package com.thewizrd.weather_api.weatherapi.weather +import android.annotation.SuppressLint import com.thewizrd.shared_resources.utils.AirQualityUtils.AQICO import com.thewizrd.shared_resources.utils.AirQualityUtils.AQINO2 import com.thewizrd.shared_resources.utils.AirQualityUtils.AQIO3 @@ -29,6 +30,7 @@ import com.thewizrd.shared_resources.weatherdata.model.ForecastExtras import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.Location import com.thewizrd.shared_resources.weatherdata.model.MoonPhase +import com.thewizrd.shared_resources.weatherdata.model.Pollen import com.thewizrd.shared_resources.weatherdata.model.Precipitation import com.thewizrd.shared_resources.weatherdata.model.UV import com.thewizrd.shared_resources.weatherdata.model.Weather @@ -43,6 +45,7 @@ import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import kotlin.math.roundToInt +@SuppressLint("VisibleForTests") fun createWeatherData(root: ForecastResponse): Weather { return Weather().apply { location = createLocation(root.location!!) @@ -52,20 +55,24 @@ fun createWeatherData(root: ForecastResponse): Weather { .withZoneSameInstant(tzid) } ?: ZonedDateTime.now(tzid) - forecast = ArrayList(root.forecast!!.forecastday!!.size) + forecast = ArrayList().apply { + root.forecast?.forecastday?.size?.let { + ensureCapacity(it) + } + } hrForecast = ArrayList().apply { - root.forecast!!.forecastday?.firstOrNull()?.hour?.size?.let { + root.forecast?.forecastday?.firstOrNull()?.hour?.size?.let { ensureCapacity(it) } } // Forecast - for (day in root.forecast!!.forecastday!!) { - val fcast = createForecast(day, tzid) + root.forecast?.forecastday?.forEach { day -> + val fcast = createForecast(day) day.hour?.forEach { hour -> val date = ZonedDateTime.ofInstant( - Instant.ofEpochSecond(hour.timeEpoch!!.toLong()), + Instant.ofEpochSecond(hour.timeEpoch!!), ZoneOffset.UTC ) @@ -79,15 +86,15 @@ fun createWeatherData(root: ForecastResponse): Weather { condition = createCondition(root.current!!, tzid) atmosphere = createAtmosphere(root.current!!) - if (root.forecast!!.forecastday!![0].date == condition!!.observationTime.toLocalDate() + if (root.forecast?.forecastday?.getOrNull(0)?.date == condition!!.observationTime.toLocalDate() .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) ) { - astronomy = createAstronomy(root.forecast!!.forecastday!![0].astro!!) + astronomy = createAstronomy(root.forecast?.forecastday?.getOrNull(0)?.astro) } precipitation = createPrecipitation(root.current!!) ttl = 180 - if ((condition!!.highF == null || condition!!.highC == null) && forecast!!.size > 0) { + if ((condition!!.highF == null || condition!!.highC == null) && forecast!!.isNotEmpty()) { condition!!.highF = forecast!![0].highF condition!!.highC = forecast!![0].highC condition!!.lowF = forecast!![0].lowF @@ -104,13 +111,13 @@ fun createLocation(location: com.thewizrd.weather_api.weatherapi.weather.Locatio return Location().apply { /* Use name from location provider */ //name = location.name - latitude = location.lat!!.toFloat() - longitude = location.lon!!.toFloat() + latitude = location.lat!! + longitude = location.lon!! tzLong = location.tzId!! } } -fun createForecast(day: ForecastdayItem, tzid: ZoneId): Forecast { +fun createForecast(day: ForecastdayItem): Forecast { return Forecast().apply { date = day.dateEpoch?.let { ZonedDateTime.ofInstant(Instant.ofEpochSecond(it), ZoneOffset.UTC) @@ -164,10 +171,6 @@ fun createHourlyForecast(hour: HourItem, tzId: ZoneId): HourlyForecast { icon = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.WEATHERAPI) .getWeatherIcon(hour.isDay == 0, hour.condition!!.code!!.toString()) - windMph = hour.windMph - windKph = hour.windKph - windDegrees = hour.windDegree - extras = ForecastExtras() extras.feelslikeF = hour.feelslikeF extras.feelslikeC = hour.feelslikeC @@ -183,9 +186,9 @@ fun createHourlyForecast(hour: HourItem, tzId: ZoneId): HourlyForecast { extras.qpfSnowIn = hour.snowCm?.let { ConversionMethods.mmToIn(it * 10) } extras.pressureIn = hour.pressureIn extras.pressureMb = hour.pressureMb - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = hour.windDegree + extras.windMph = hour.windMph + extras.windKph = hour.windKph extras.visibilityMi = hour.visMiles extras.visibilityKm = hour.visKm extras.windGustMph = hour.gustMph @@ -211,13 +214,49 @@ fun createCondition(current: Current, tzId: ZoneId): Condition { feelslikeC = current.feelslikeC icon = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.WEATHERAPI) - .getWeatherIcon(current.isDay == 0, current.condition!!.code!!.toString()) + .getWeatherIcon(current.isDay == 0, current.condition?.code?.toString()) beaufort = Beaufort(getBeaufortScale(windMph.toInt())) - uv = UV(current.uv!!) + uv = current.uv?.let { UV(it) } airQuality = createAirQuality(current.airQuality) + current.pollen?.let { currentPollen -> + val treePollenValue = maxOf( + currentPollen.hazel ?: 0.0, + currentPollen.alder ?: 0.0, + currentPollen.birch ?: 0.0, + currentPollen.oak ?: 0.0 + ) + val grassPollenValue = currentPollen.grass ?: 0.0 + val ragweedPollenValue = + maxOf(currentPollen.ragweed ?: 0.0, currentPollen.mugwort ?: 0.0) + + pollen = Pollen().apply { + treePollenCount = when { + treePollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + treePollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + treePollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + treePollenValue >= 300.0 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + grassPollenCount = when { + grassPollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + grassPollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + grassPollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + grassPollenValue >= 300.0 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + ragweedPollenCount = when { + ragweedPollenValue in 1.0..20.0 -> Pollen.PollenCount.LOW + ragweedPollenValue in 20.0..100.0 -> Pollen.PollenCount.MODERATE + ragweedPollenValue in 100.0..300.0 -> Pollen.PollenCount.HIGH + ragweedPollenValue >= 300.0 -> Pollen.PollenCount.VERY_HIGH + else -> Pollen.PollenCount.UNKNOWN + } + } + } + observationTime = current.lastUpdatedEpoch?.let { ZonedDateTime.ofInstant(Instant.ofEpochSecond(it), ZoneOffset.UTC) .withZoneSameInstant(tzId) @@ -245,33 +284,44 @@ fun createAtmosphere(current: Current): Atmosphere { } } -fun createAstronomy(astro: Astro): Astronomy { +fun createAstronomy(astro: Astro?): Astronomy { return Astronomy().apply { val now = LocalDate.now() runCatching { - sunrise = LocalTime.parse(astro.sunrise, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) + sunrise = + LocalTime.parse(astro?.sunrise, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) + }.getOrElse { + if (astro?.sunrise == "Polar Day" || astro?.sunrise == "Polar Night") { + sunrise = LocalDateTime.now().plusYears(1).minusNanos(1) + } } runCatching { sunset = - LocalTime.parse(astro.sunset, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) + LocalTime.parse(astro?.sunset, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) if (sunrise != null && sunset.isBefore(sunrise)) { // Is next day - sunset = LocalTime.parse(astro.sunset, DateTimeFormatter.ofPattern("hh:mm a")) + sunset = LocalTime.parse(astro?.sunset, DateTimeFormatter.ofPattern("hh:mm a")) .atDate(now.plusDays(1)) } + }.getOrElse { + if (astro?.sunset == "Polar Day" || astro?.sunset == "Polar Night") { + sunset = LocalDateTime.now().plusYears(1).minusNanos(1) + } } runCatching { - moonrise = LocalTime.parse(astro.moonrise, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) + moonrise = + LocalTime.parse(astro?.moonrise, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) } runCatching { - moonset = LocalTime.parse(astro.moonset, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) + moonset = + LocalTime.parse(astro?.moonset, DateTimeFormatter.ofPattern("hh:mm a")).atDate(now) } - when (astro.moonPhase) { + when (astro?.moonPhase) { "New Moon" -> moonPhase = MoonPhase(MoonPhase.MoonPhaseType.NEWMOON) "Waxing Crescent" -> moonPhase = MoonPhase(MoonPhase.MoonPhaseType.WAXING_CRESCENT) "First Quarter" -> moonPhase = MoonPhase(MoonPhase.MoonPhaseType.FIRST_QTR) @@ -284,10 +334,10 @@ fun createAstronomy(astro: Astro): Astronomy { // If the sun won't set/rise, set time to the future if (sunrise == null) { - sunrise = LocalDateTime.now().plusYears(1).minusNanos(1) + sunrise = DateTimeUtils.LOCALDATETIME_MIN } if (sunset == null) { - sunset = LocalDateTime.now().plusYears(1).minusNanos(1) + sunset = DateTimeUtils.LOCALDATETIME_MIN } if (moonrise == null) { moonrise = DateTimeUtils.LOCALDATETIME_MIN diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt index 016045da4..98372e50d 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt @@ -42,7 +42,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class WeatherBitIOProvider : WeatherProviderImpl(), WeatherAlertProvider { @@ -329,7 +329,7 @@ class WeatherBitIOProvider : WeatherProviderImpl(), WeatherAlertProvider { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { - // no-op + super.updateWeatherData(location, weather) } override suspend fun updateLocationQuery(weather: Weather): String { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherData.kt index 804367d48..1298a83ad 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherData.kt @@ -180,12 +180,6 @@ fun createHourlyForecast(forecast: HourlyForecastDataItem): HourlyForecast { icon = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.WEATHERBITIO) .getWeatherIcon(forecast.weather?.icon) - windDegrees = forecast.windDir - forecast.windSpd?.let { - windKph = ConversionMethods.msecToKph(it) - windMph = ConversionMethods.msecToMph(it) - } - // Extras extras = ForecastExtras() extras.humidity = forecast.rh @@ -233,6 +227,7 @@ fun createMinutelyForecast(item: MinutelyItem): MinutelyForecast { return MinutelyForecast().apply { date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(item.ts!!.toLong()), ZoneOffset.UTC) rainMm = item.precip + snowMm = item.snow } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderFactoryImpl.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderFactoryImpl.kt index b89fcaa0f..c1e646e7b 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderFactoryImpl.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderFactoryImpl.kt @@ -12,6 +12,7 @@ import com.thewizrd.weather_api.meteofrance.weather.MeteoFranceProvider import com.thewizrd.weather_api.meteomatics.weather.MeteomaticsWeatherProvider import com.thewizrd.weather_api.metno.MetnoWeatherProvider import com.thewizrd.weather_api.nws.NWSWeatherProvider +import com.thewizrd.weather_api.openmeteo.OpenMeteoWeatherProvider import com.thewizrd.weather_api.openweather.location.OpenWeatherMapLocationProvider import com.thewizrd.weather_api.openweather.weather.OpenWeatherMapProvider import com.thewizrd.weather_api.tomorrow.TomorrowIOWeatherProvider @@ -43,10 +44,11 @@ class WeatherProviderFactoryImpl : WeatherProviderFactory { WeatherAPI.DWD -> BrightSkyProvider() WeatherAPI.ECCC -> ECCCWeatherProvider() WeatherAPI.GOOGLE -> GoogleWeatherProvider() + WeatherAPI.OPENMETEO -> OpenMeteoWeatherProvider() else -> { if (!BuildConfig.DEBUG) { if (!BuildConfig.IS_NONGMS) - WeatherApiProvider() + OpenMeteoWeatherProvider() else MetnoWeatherProvider() } else { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderImpl.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderImpl.kt index 209d61a53..dd190c01b 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderImpl.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherdata/WeatherProviderImpl.kt @@ -2,6 +2,7 @@ package com.thewizrd.weather_api.weatherdata import android.location.Location import android.util.Log +import androidx.annotation.CallSuper import com.thewizrd.shared_resources.BuildConfig import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.appLib @@ -16,6 +17,8 @@ import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.Coordinate import com.thewizrd.shared_resources.utils.LocationUtils import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.shared_resources.utils.calculateDewpoint +import com.thewizrd.shared_resources.utils.calculateFeelsLikeTemp import com.thewizrd.shared_resources.weatherdata.AirQualityProvider import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherProvider @@ -30,14 +33,16 @@ import com.thewizrd.weather_api.aqicn.AQICNProvider import com.thewizrd.weather_api.extras.isPremiumEnabled import com.thewizrd.weather_api.google.pollen.GooglePollenProvider import com.thewizrd.weather_api.nws.alerts.NWSAlertProvider +import com.thewizrd.weather_api.openmeteo.OpenMeteoWeatherProvider import com.thewizrd.weather_api.utils.RateLimitedRequest import com.thewizrd.weather_api.utils.logMissingIcon import com.thewizrd.weather_api.weatherModule import com.thewizrd.weather_api.weatherapi.weather.WeatherApiProvider -import java.time.Duration import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.Locale +import kotlin.math.PI +import kotlin.math.sin abstract class WeatherProviderImpl : WeatherProvider, RateLimitedRequest { protected lateinit var mLocationProvider: WeatherLocationProvider @@ -200,6 +205,23 @@ abstract class WeatherProviderImpl : WeatherProvider, RateLimitedRequest { GooglePollenProvider().getPollenData(location)?.apply { attribution = context.getString(R.string.api_google) } + } else if (LocationUtils.isCAMSEuroCovered(location) && remoteConfigService.isProviderEnabled( + WeatherAPI.OPENMETEO + ) && (isPremiumEnabled() || BuildConfig.IS_NONGMS || settingsManager.isDevSettingsEnabled() && !settingsManager.getAPIKey( + WeatherAPI.OPENMETEO + ).isNullOrBlank()) + ) { + // Pollen coverage is only supported in Europe for Open-Meteo + // https://open-meteo.com/en/docs/air-quality-api + weather.condition!!.pollen = + OpenMeteoWeatherProvider().getPollenData(location)?.apply { + attribution = context.getString(R.string.api_openmeteo) + } + } else if (remoteConfigService.isProviderEnabled(WeatherAPI.WEATHERAPI) && !BuildConfig.IS_NONGMS) { + weather.condition!!.pollen = + WeatherApiProvider().getPollenData(location)?.apply { + attribution = context.getString(R.string.api_weatherapi) + } } } } @@ -215,7 +237,20 @@ abstract class WeatherProviderImpl : WeatherProvider, RateLimitedRequest { * @param weather The weather data to update */ @Throws(WeatherException::class) - protected abstract suspend fun updateWeatherData(location: LocationData, weather: Weather) + @CallSuper + protected open suspend fun updateWeatherData(location: LocationData, weather: Weather) { + weather.calculateDewpoint() + weather.calculateFeelsLikeTemp() + + weather.forecast?.forEach { + it.calculateDewpoint() + it.calculateFeelsLikeTemp() + } + weather.hrForecast?.forEach { + it.calculateDewpoint() + it.calculateFeelsLikeTemp() + } + } private suspend fun updateAQIData(location: LocationData, weather: Weather) { val aqicnData = AQICNProvider().getAirQualityData(location) @@ -237,36 +272,21 @@ abstract class WeatherProviderImpl : WeatherProvider, RateLimitedRequest { if (weather.condition?.uv == null && date.isEqual(weather.condition!!.observationTime.toLocalDate())) { if (weather.astronomy!!.sunrise != null && weather.astronomy!!.sunset != null) { - val obsLocalTime = weather.condition!!.observationTime.toLocalTime() - // if before sunrise, after sunset, or +/- 2hrs before/after sunrise/sunset, uv min - if (obsLocalTime.isBefore(weather.astronomy!!.sunrise.toLocalTime()) || - obsLocalTime.isAfter(weather.astronomy!!.sunset.toLocalTime()) || - Duration.between( - weather.astronomy!!.sunrise.toLocalTime(), - obsLocalTime - ).abs().toHours() <= 2 || - Duration.between( - weather.astronomy!!.sunset.toLocalTime(), - obsLocalTime - ).abs().toHours() <= 2 - ) { - weather.condition!!.uv = UV(uviData.min?.toFloat() ?: 0f) + val sunrise = + weather.astronomy!!.sunrise.toEpochSecond(location.tzOffset) + val sunset = + weather.astronomy!!.sunset.toEpochSecond(location.tzOffset) + val obsTime = weather.condition!!.observationTime.toEpochSecond() + + if (obsTime in (sunrise + 1) until sunset) { + val dayFraction = + (obsTime - sunrise).toDouble() / (sunset - sunrise) + val maxUV = uviData.max?.toFloat() ?: 0f + // Sinusoidal interpolation: peak at solar noon (dayFraction = 0.5) + weather.condition!!.uv = + UV(maxUV * sin(dayFraction * PI).toFloat()) } else { - val totalSunlightTime = - weather.astronomy!!.sunset.toEpochSecond(location.tzOffset) - weather.astronomy!!.sunrise.toEpochSecond( - location.tzOffset - ) - val solarNoon = - weather.astronomy!!.sunrise.plusSeconds(totalSunlightTime / 2) - - // If +/- 2hrs within solar noon, UV max - if (Duration.between(solarNoon.toLocalTime(), obsLocalTime) - .abs().toHours() <= 2 - ) { - weather.condition!!.uv = UV(uviData.max?.toFloat() ?: 0f) - } else { // else uv avg - weather.condition!!.uv = UV(uviData.avg?.toFloat() ?: 0f) - } + weather.condition!!.uv = UV(uviData.min?.toFloat() ?: 0f) } } } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherAlerts.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherAlerts.kt index 4a0e495ed..f0e459f32 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherAlerts.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherAlerts.kt @@ -1,5 +1,6 @@ package com.thewizrd.weather_api.weatherkit +import android.annotation.SuppressLint import com.thewizrd.shared_resources.weatherdata.model.WeatherAlert import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertSeverity import com.thewizrd.shared_resources.weatherdata.model.WeatherAlertType @@ -8,7 +9,7 @@ import java.time.ZonedDateTime fun createWeatherAlerts(alerts: WeatherAlertCollection?): Collection? { if (alerts?.alerts.isNullOrEmpty()) return null - val weatherAlerts = ArrayList(alerts!!.alerts.size) + val weatherAlerts = ArrayList(alerts.alerts.size) for (alert in alerts.alerts) { weatherAlerts.add(createWeatherAlert(alert)) @@ -17,13 +18,14 @@ fun createWeatherAlerts(alerts: WeatherAlertCollection?): Collection WeatherAlertSeverity.EXTREME Severity.SEVERE -> WeatherAlertSeverity.SEVERE diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherData.kt index fa22fc4db..58a3497d8 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherData.kt @@ -1,5 +1,6 @@ package com.thewizrd.weather_api.weatherkit +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.sharedDeps import com.thewizrd.shared_resources.utils.ConversionMethods import com.thewizrd.shared_resources.utils.DateTimeUtils @@ -9,11 +10,17 @@ import com.thewizrd.shared_resources.weatherdata.model.* import com.thewizrd.shared_resources.weatherdata.model.HourlyForecast import com.thewizrd.shared_resources.weatherdata.model.MoonPhase.MoonPhaseType import com.thewizrd.shared_resources.weatherdata.model.Weather -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.weatherModule import java.time.LocalDateTime import java.time.ZonedDateTime +import kotlin.apply +import kotlin.collections.ArrayList +import kotlin.collections.firstOrNull +import kotlin.collections.forEach +import kotlin.let import kotlin.math.roundToInt +import kotlin.run +import kotlin.runCatching fun createWeatherData(root: com.thewizrd.weather_api.weatherkit.Weather): Weather { return Weather().apply { @@ -145,10 +152,6 @@ fun createHourlyForecast(hour: HourWeatherConditions): HourlyForecast { condition = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.APPLE) .getWeatherCondition(hour.conditionCode) - windKph = hour.windSpeed - windMph = ConversionMethods.kphTomph(hour.windSpeed) - windDegrees = hour.windDirection - extras = ForecastExtras().apply { feelslikeC = hour.temperatureApparent feelslikeF = ConversionMethods.CtoF(hour.temperatureApparent) @@ -176,7 +179,7 @@ fun createHourlyForecast(hour: HourWeatherConditions): HourlyForecast { pressureIn = ConversionMethods.mbToInHg(hour.pressure) windDegrees = hour.windDirection windKph = hour.windSpeed - windMph = ConversionMethods.kphToMsec(hour.windSpeed) + windMph = ConversionMethods.kphTomph(hour.windSpeed) visibilityKm = hour.visibility / 1000 visibilityMi = ConversionMethods.kmToMi(hour.visibility / 1000) windGustKph = hour.windGust diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt index d6bc19c2c..748ac0f89 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt @@ -3,6 +3,7 @@ package com.thewizrd.weather_api.weatherkit import android.util.Log import androidx.core.net.toUri import com.ibm.icu.util.ULocale +import com.thewizrd.shared_resources.R import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.icons.WeatherIcons @@ -20,7 +21,6 @@ import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.auth.AuthType import com.thewizrd.shared_resources.weatherdata.model.Weather import com.thewizrd.shared_resources.weatherdata.model.isNullOrInvalid -import com.thewizrd.weather_api.R import com.thewizrd.weather_api.extras.cacheRequestIfNeeded import com.thewizrd.weather_api.google.location.getGoogleLocationProvider import com.thewizrd.weather_api.nws.SolCalcAstroProvider @@ -42,7 +42,7 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class WeatherKitProvider : WeatherProviderImpl() { @@ -189,6 +189,8 @@ class WeatherKitProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset // Update tz for weather properties diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherData.kt index 013e567ee..65d910a67 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherData.kt @@ -144,19 +144,15 @@ fun createHourlyForecast(timeframe: TimeframesItem): HourlyForecast { condition = timeframe.wxDesc icon = timeframe.wxCode.toString() - windDegrees = timeframe.winddirDeg.roundToInt() - windMph = timeframe.windspdMph - windKph = timeframe.windspdKmh - // Extras extras = ForecastExtras() extras.humidity = timeframe.humidPct.roundToInt() extras.cloudiness = timeframe.cloudtotalPct.roundToInt() extras.pressureMb = timeframe.slpMb extras.pressureIn = timeframe.slpIn - extras.windDegrees = windDegrees - extras.windMph = windMph - extras.windKph = windKph + extras.windDegrees = timeframe.winddirDeg.roundToInt() + extras.windMph = timeframe.windspdMph + extras.windKph = timeframe.windspdKmh extras.dewpointF = timeframe.dewpointF extras.dewpointC = timeframe.dewpointC extras.feelslikeF = timeframe.feelslikeF diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt index 616b28f05..587114d32 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt @@ -39,9 +39,10 @@ import java.time.Instant import java.time.LocalTime import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit +@Deprecated("Weather Unlocked API Services will be closing down on June 30th, 2026") class WeatherUnlockedProvider : WeatherProviderImpl() { companion object { private const val BASE_URL = "http://api.weatherunlocked.com/api/" @@ -187,6 +188,8 @@ class WeatherUnlockedProvider : WeatherProviderImpl() { @Throws(WeatherException::class) override suspend fun updateWeatherData(location: LocationData, weather: Weather) { + super.updateWeatherData(location, weather) + val offset = location.tzOffset weather.updateTime = weather.updateTime!!.withZoneSameInstant(offset) weather.condition!!.observationTime = diff --git a/weather-api/src/nongms/java/com/thewizrd/weather_api/keys/Keys.java b/weather-api/src/nongms/java/com/thewizrd/weather_api/keys/Keys.java index 5ed9660b5..db3c34149 100644 --- a/weather-api/src/nongms/java/com/thewizrd/weather_api/keys/Keys.java +++ b/weather-api/src/nongms/java/com/thewizrd/weather_api/keys/Keys.java @@ -60,4 +60,8 @@ public static String getWeatherBitIoKey() { public static String getGWeatherKey() { return null; } + + public static String getOpenMeteoKey() { + return null; + } } \ No newline at end of file