diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml
index 5e359cbb..5b097d03 100644
--- a/i18n/src/main/res/values-de/strings.xml
+++ b/i18n/src/main/res/values-de/strings.xml
@@ -453,6 +453,8 @@
Vorschau einer Webseite anzeigen wenn die Suchanfrage eine URL ist
Websuchen
Shortcuts zu verschiedenen Websuch-Engines anzeigen
+ Build-Information
+ Weitere Informationen über diesen Build dieser App
Wikipedia-URL
diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml
index 7e3f4c6b..8219b674 100644
--- a/i18n/src/main/res/values/strings.xml
+++ b/i18n/src/main/res/values/strings.xml
@@ -489,6 +489,9 @@
- %1$d calendars selected
+ Build information
+ More information about this build of this app
+
Restrict to music apps
Ignore media sessions of apps that are not music apps
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
index 58899df8..ce0ddc0c 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
@@ -32,6 +32,7 @@ import de.mm20.launcher2.ui.settings.main.MainSettingsScreen
import de.mm20.launcher2.ui.settings.musicwidget.MusicWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreen
import de.mm20.launcher2.ui.settings.accounts.AccountsSettingsScreen
+import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
import de.mm20.launcher2.ui.settings.weatherwidget.WeatherWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.widgets.WidgetsSettingsScreen
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
@@ -120,6 +121,9 @@ class SettingsActivity : BaseActivity() {
composable("settings/about") {
AboutSettingsScreen()
}
+ composable("settings/about/buildinfo") {
+ BuildInfoSettingsScreen()
+ }
composable("settings/debug") {
DebugSettingsScreen()
}
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/about/AboutSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/about/AboutSettingsScreen.kt
index c83cd253..252e4eee 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/about/AboutSettingsScreen.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/about/AboutSettingsScreen.kt
@@ -41,6 +41,13 @@ fun AboutSettingsScreen() {
title = stringResource(R.string.preference_version),
summary = appVersion
)
+ Preference(
+ title = stringResource(R.string.preference_screen_buildinfo),
+ summary = stringResource(R.string.preference_screen_buildinfo_summary),
+ onClick = {
+ navController?.navigate("settings/about/buildinfo")
+ }
+ )
}
}
item {
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreen.kt
new file mode 100644
index 00000000..d35d1b2c
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreen.kt
@@ -0,0 +1,59 @@
+package de.mm20.launcher2.ui.settings.buildinfo
+
+import android.content.pm.PackageManager
+import android.os.Build
+import android.util.Base64
+import androidx.compose.runtime.*
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.viewmodel.compose.viewModel
+import de.mm20.launcher2.ui.BuildConfig
+import de.mm20.launcher2.ui.R
+import de.mm20.launcher2.ui.component.preferences.Preference
+import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
+import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
+import java.security.MessageDigest
+
+@Composable
+fun BuildInfoSettingsScreen() {
+ val viewModel: BuildInfoSettingsScreenVM = viewModel()
+ val context = LocalContext.current
+ PreferenceScreen(title = stringResource(R.string.preference_screen_buildinfo)) {
+ item {
+ Preference(title = "Build type", summary = BuildConfig.BUILD_TYPE)
+ var buildSignature by remember { mutableStateOf(null) }
+ LaunchedEffect(null) {
+ val signature = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ val pi = context.packageManager.getPackageInfo(
+ context.packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES
+ )
+ pi.signingInfo.apkContentsSigners.firstOrNull()
+ } else {
+ val pi = context.packageManager.getPackageInfo(
+ context.packageName,
+ PackageManager.GET_SIGNATURES
+ )
+ pi.signatures.firstOrNull()
+ }
+ val signatureHash = if (signature != null) {
+ val digest = MessageDigest.getInstance("SHA")
+ digest.update(signature.toByteArray())
+ Base64.encodeToString(digest.digest(), Base64.NO_WRAP)
+ } else "null"
+ buildSignature = signatureHash
+ }
+ Preference(title = "Signature hash", summary = buildSignature)
+ }
+ item {
+ PreferenceCategory(title = "Features") {
+ for (feature in viewModel.buildFeatures) {
+ Preference(
+ title = feature.key,
+ summary = if (feature.value) "YES" else "NO"
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreenVM.kt
new file mode 100644
index 00000000..587c9d8d
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/buildinfo/BuildInfoSettingsScreenVM.kt
@@ -0,0 +1,30 @@
+package de.mm20.launcher2.ui.settings.buildinfo
+
+import android.content.pm.PackageManager
+import android.os.Build
+import android.util.Base64
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.liveData
+import de.mm20.launcher2.accounts.AccountType
+import de.mm20.launcher2.accounts.AccountsRepository
+import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
+import de.mm20.launcher2.weather.WeatherRepository
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+import java.security.MessageDigest
+
+class BuildInfoSettingsScreenVM : ViewModel(), KoinComponent {
+ private val accountsRepository: AccountsRepository by inject()
+ private val weatherRepository: WeatherRepository by inject()
+
+ private val availableWeatherProviders = weatherRepository.getAvailableProviders()
+
+ val buildFeatures = mapOf(
+ "Accounts: Google" to accountsRepository.isSupported(AccountType.Google),
+ "Accounts: Microsoft" to accountsRepository.isSupported(AccountType.Microsoft),
+ "Weather providers: HERE" to availableWeatherProviders.contains(WeatherProvider.Here),
+ "Weather providers: Met No" to availableWeatherProviders.contains(WeatherProvider.MetNo),
+ "Weather providers: OpenWeatherMap" to availableWeatherProviders.contains(WeatherProvider.OpenWeatherMap),
+ "Weather providers: BrightSky" to availableWeatherProviders.contains(WeatherProvider.BrightSky),
+ )
+}
\ No newline at end of file
diff --git a/weather/src/main/java/de/mm20/launcher2/weather/WeatherRepository.kt b/weather/src/main/java/de/mm20/launcher2/weather/WeatherRepository.kt
index 0bd8eecc..227b7323 100644
--- a/weather/src/main/java/de/mm20/launcher2/weather/WeatherRepository.kt
+++ b/weather/src/main/java/de/mm20/launcher2/weather/WeatherRepository.kt
@@ -2,13 +2,16 @@ package de.mm20.launcher2.weather
import android.content.Context
import android.util.Log
-import androidx.datastore.dataStore
import androidx.work.*
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.WeatherSettings
+import de.mm20.launcher2.weather.brightsky.BrightskyProvider
+import de.mm20.launcher2.weather.here.HereProvider
+import de.mm20.launcher2.weather.metno.MetNoProvider
+import de.mm20.launcher2.weather.openweathermap.OpenWeatherMapProvider
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.koin.core.component.KoinComponent
@@ -31,6 +34,8 @@ interface WeatherRepository {
fun setAutoLocation(autoLocation: Boolean)
fun setLastLocation(lastLocation: WeatherLocation?)
+ fun getAvailableProviders(): List
+
fun selectProvider(provider: WeatherSettings.WeatherProvider)
val selectedProvider: Flow
@@ -133,7 +138,7 @@ class WeatherRepositoryImpl(
}
}
hasLocationPermission.collectLatest {
- if(it) requestUpdate()
+ if (it) requestUpdate()
}
}
}
@@ -194,11 +199,28 @@ class WeatherRepositoryImpl(
}
}
}
+
+ override fun getAvailableProviders(): List {
+ val providers = mutableListOf()
+ if (BrightskyProvider(context).isAvailable()) {
+ providers.add(WeatherSettings.WeatherProvider.BrightSky)
+ }
+ if (OpenWeatherMapProvider(context).isAvailable()) {
+ providers.add(WeatherSettings.WeatherProvider.OpenWeatherMap)
+ }
+ if (MetNoProvider(context).isAvailable()) {
+ providers.add(WeatherSettings.WeatherProvider.MetNo)
+ }
+ if (HereProvider(context).isAvailable()) {
+ providers.add(WeatherSettings.WeatherProvider.Here)
+ }
+ return providers
+ }
}
class WeatherUpdateWorker(val context: Context, params: WorkerParameters) :
CoroutineWorker(context, params), KoinComponent {
- val repository: WeatherRepository by inject()
+ val repository: WeatherRepository by inject()
override suspend fun doWork(): Result {
Log.d("MM20", "Requesting weather data")