fix(weather): keep met-weather DTOs from R8 so Gson works; add +4h reading (v0.3.8)
Some checks failed
Android Main Branch CI / Build, Sign & Upload (push) Has been cancelled
Update CHANGELOG.md / changelog (push) Has been cancelled
Validate Gradle Wrapper / Validation (push) Has been cancelled
Android Release CI / Build, Sign & Release (push) Has been cancelled
Nightly Release / release (push) Has been cancelled
Nightly Release / Build, Sign & Release (push) Has been cancelled
Delete Unused Caches / delete (push) Has been cancelled
Close Inactive Issues & Pull Requests / close-issues (push) Has been cancelled
GitHub Actions Version Updater / build (push) Has been cancelled
Some checks failed
Android Main Branch CI / Build, Sign & Upload (push) Has been cancelled
Update CHANGELOG.md / changelog (push) Has been cancelled
Validate Gradle Wrapper / Validation (push) Has been cancelled
Android Release CI / Build, Sign & Release (push) Has been cancelled
Nightly Release / release (push) Has been cancelled
Nightly Release / Build, Sign & Release (push) Has been cancelled
Delete Unused Caches / delete (push) Has been cancelled
Close Inactive Issues & Pull Requests / close-issues (push) Has been cancelled
GitHub Actions Version Updater / build (push) Has been cancelled
- ProGuard keep rule for dk.haugesenspil.metweather.** (R8 was obfuscating the Gson DTOs -> ClassCastException, weather glyph vanished). - Home current-weather now shows 'current -> ~4h' (nearest MET hourly point), cached in met_weather_prefs. release build v0.3.8
This commit is contained in:
@@ -38,7 +38,7 @@ export JAVA_HOME=~/jdk21 # Gradle 8.13, compileSdk/targetSdk 36, minSdk 2
|
||||
## Release flow (see git history for the v0.3.x pattern)
|
||||
|
||||
1. Bump `versionCode`/`versionName` in `app/build.gradle.kts`
|
||||
(currently 37 / 0.3.7).
|
||||
(currently 38 / 0.3.8).
|
||||
2. Build both flavors, then sign each:
|
||||
|
||||
```bash
|
||||
@@ -46,9 +46,9 @@ PASS=$(cat ~/android-keystores/easylauncher-release.pass)
|
||||
~/android-sdk/build-tools/36.0.0/apksigner sign --v4-signing-enabled true \
|
||||
--ks ~/android-keystores/easylauncher-release.jks --ks-key-alias easylauncher \
|
||||
--ks-pass "pass:$PASS" --key-pass "pass:$PASS" \
|
||||
--out dist/EasyLauncher-Internet-v0.3.7-Signed.apk \
|
||||
--out dist/EasyLauncher-Internet-v0.3.8-Signed.apk \
|
||||
app/build/outputs/apk/withInternet/release/app.easy.launcher_v0.3.7-Release.apk
|
||||
# repeat for withoutInternet -> dist/EasyLauncher-v0.3.7-Signed.apk
|
||||
# repeat for withoutInternet -> dist/EasyLauncher-v0.3.8-Signed.apk
|
||||
```
|
||||
|
||||
3. `apksigner verify --print-certs` should show the keystore SHA-256.
|
||||
|
||||
@@ -19,8 +19,8 @@ android {
|
||||
applicationId = "app.easy.launcher"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = 37
|
||||
versionName = "0.3.7"
|
||||
versionCode = 38
|
||||
versionName = "0.3.8"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
manifestPlaceholders["internetPermission"] = "android.permission.INTERNET"
|
||||
|
||||
3
app/proguard-rules.pro
vendored
3
app/proguard-rules.pro
vendored
@@ -26,5 +26,8 @@
|
||||
-keep class com.github.droidworksstudio.launcher.helper.weather.Main { *; }
|
||||
-keep class com.github.droidworksstudio.launcher.helper.weather.Weather { *; }
|
||||
|
||||
# Keep the shared met-weather library classes (Gson DTOs must keep field names)
|
||||
-keep class dk.haugesenspil.metweather.** { *; }
|
||||
|
||||
# Keep all model classes and their fields that Gson might use for serialization/deserialization
|
||||
-keep class com.github.droidworksstudio.launcher.helper.weather.** { *; }
|
||||
|
||||
@@ -59,6 +59,7 @@ class AppHelper @Inject constructor() {
|
||||
private companion object {
|
||||
/** MET requires a descriptive User-Agent identifying the app + contact. */
|
||||
const val MET_USER_AGENT = "app.easy.launcher (https://gitea.haugesenspil.dk/jonas/EasyLauncher)"
|
||||
private const val FOUR_HOURS_MILLIS = 4L * 60 * 60 * 1000
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant", "PrivateApi")
|
||||
@@ -562,7 +563,13 @@ class AppHelper @Inject constructor() {
|
||||
data class CachedWeatherData(val timestamp: Long, val weatherResponse: WeatherResponse)
|
||||
|
||||
sealed class MetWeatherResult {
|
||||
data class Success(val temperature: Int, val symbolCode: String) : MetWeatherResult()
|
||||
data class Success(
|
||||
val temperature: Int,
|
||||
val symbolCode: String,
|
||||
val temperature4h: Int? = null,
|
||||
val symbol4h: String? = null,
|
||||
) : MetWeatherResult()
|
||||
|
||||
data class Failure(val errorMessage: String) : MetWeatherResult()
|
||||
}
|
||||
|
||||
@@ -592,9 +599,15 @@ class AppHelper @Inject constructor() {
|
||||
return try {
|
||||
val weather = MetWeatherClient(MET_USER_AGENT)
|
||||
.fetch(latitude.toDouble(), longitude.toDouble())
|
||||
val now = System.currentTimeMillis()
|
||||
val plus4 = weather.hourly.minByOrNull {
|
||||
kotlin.math.abs(it.epochMillis - (now + FOUR_HOURS_MILLIS))
|
||||
}
|
||||
val result = MetWeatherResult.Success(
|
||||
weather.temperatureC.roundToInt(),
|
||||
weather.symbolCode,
|
||||
temperature = weather.temperatureC.roundToInt(),
|
||||
symbolCode = weather.symbolCode,
|
||||
temperature4h = plus4?.temperatureC?.roundToInt(),
|
||||
symbol4h = plus4?.symbolCode,
|
||||
)
|
||||
context.cacheMetWeather(result)
|
||||
result
|
||||
@@ -605,11 +618,21 @@ class AppHelper @Inject constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the home-screen weather text: nerd-font weather glyph followed
|
||||
* by the temperature in Celsius, e.g. "\uE312 16°".
|
||||
* Builds the home-screen weather text: the current nerd-font weather glyph
|
||||
* and Celsius value, plus the reading ~4 hours out when available, e.g.
|
||||
* "\uE302 16° → \uE31D 18°".
|
||||
*/
|
||||
fun buildCurrentWeatherText(temperature: Int, symbolCode: String): String {
|
||||
return "${MetSymbolMapper.glyphFor(symbolCode)} $temperature°"
|
||||
fun buildCurrentWeatherText(
|
||||
temperature: Int,
|
||||
symbolCode: String,
|
||||
temperature4h: Int? = null,
|
||||
symbol4h: String? = null,
|
||||
): String {
|
||||
val current = "${MetSymbolMapper.glyphFor(symbolCode)} $temperature°"
|
||||
if (temperature4h != null && symbol4h != null) {
|
||||
return "$current → ${MetSymbolMapper.glyphFor(symbol4h)} $temperature4h°"
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
private fun Context.cacheMetWeather(result: MetWeatherResult.Success) {
|
||||
@@ -618,6 +641,8 @@ class AppHelper @Inject constructor() {
|
||||
.putLong(Constants.MET_WEATHER_TIMESTAMP, System.currentTimeMillis())
|
||||
.putInt(Constants.MET_WEATHER_TEMPERATURE, result.temperature)
|
||||
.putString(Constants.MET_WEATHER_SYMBOL, result.symbolCode)
|
||||
.putInt(Constants.MET_WEATHER_TEMPERATURE_4H, result.temperature4h ?: Int.MIN_VALUE)
|
||||
.putString(Constants.MET_WEATHER_SYMBOL_4H, result.symbol4h ?: "")
|
||||
.apply()
|
||||
}
|
||||
|
||||
@@ -627,6 +652,14 @@ class AppHelper @Inject constructor() {
|
||||
if (timestamp == -1L) return null
|
||||
val temperature = sharedPreferences.getInt(Constants.MET_WEATHER_TEMPERATURE, 0)
|
||||
val symbol = sharedPreferences.getString(Constants.MET_WEATHER_SYMBOL, "cloudy") ?: "cloudy"
|
||||
return timestamp to MetWeatherResult.Success(temperature, symbol)
|
||||
val temp4h = sharedPreferences.getInt(Constants.MET_WEATHER_TEMPERATURE_4H, Int.MIN_VALUE)
|
||||
val symbol4h = sharedPreferences.getString(Constants.MET_WEATHER_SYMBOL_4H, "") ?: ""
|
||||
val result = MetWeatherResult.Success(
|
||||
temperature = temperature,
|
||||
symbolCode = symbol,
|
||||
temperature4h = temp4h.takeIf { it != Int.MIN_VALUE },
|
||||
symbol4h = symbol4h.takeIf { it.isNotEmpty() },
|
||||
)
|
||||
return timestamp to result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +393,9 @@ class HomeFragment : Fragment(),
|
||||
is AppHelper.MetWeatherResult.Success -> {
|
||||
binding.currentWeather.text = appHelper.buildCurrentWeatherText(
|
||||
result.temperature,
|
||||
result.symbolCode
|
||||
result.symbolCode,
|
||||
result.temperature4h,
|
||||
result.symbol4h,
|
||||
)
|
||||
binding.currentWeather.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ object Constants {
|
||||
const val MET_WEATHER_TIMESTAMP = "MET_WEATHER_TIMESTAMP"
|
||||
const val MET_WEATHER_TEMPERATURE = "MET_WEATHER_TEMPERATURE"
|
||||
const val MET_WEATHER_SYMBOL = "MET_WEATHER_SYMBOL"
|
||||
const val MET_WEATHER_TEMPERATURE_4H = "MET_WEATHER_TEMPERATURE_4H"
|
||||
const val MET_WEATHER_SYMBOL_4H = "MET_WEATHER_SYMBOL_4H"
|
||||
const val WEATHER_RESPONSE = "WEATHER_RESPONSE"
|
||||
const val WEATHER_UNITS = "WEATHER_UNITS"
|
||||
const val LATITUDE = "LATITUDE"
|
||||
|
||||
BIN
dist/EasyLauncher-Internet-v0.3.8-Signed.apk
vendored
Normal file
BIN
dist/EasyLauncher-Internet-v0.3.8-Signed.apk
vendored
Normal file
Binary file not shown.
BIN
dist/EasyLauncher-Internet-v0.3.8-Signed.apk.idsig
vendored
Normal file
BIN
dist/EasyLauncher-Internet-v0.3.8-Signed.apk.idsig
vendored
Normal file
Binary file not shown.
BIN
dist/EasyLauncher-v0.3.8-Signed.apk
vendored
Normal file
BIN
dist/EasyLauncher-v0.3.8-Signed.apk
vendored
Normal file
Binary file not shown.
BIN
dist/EasyLauncher-v0.3.8-Signed.apk.idsig
vendored
Normal file
BIN
dist/EasyLauncher-v0.3.8-Signed.apk.idsig
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user