diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml
index 94cfc2e8..ee9f002a 100644
--- a/i18n/src/main/res/values-de/strings.xml
+++ b/i18n/src/main/res/values-de/strings.xml
@@ -58,7 +58,7 @@
Durchscheinende Karten
Debug
Debug-Informationen exportieren
- Exportiere nach %1$s
+ Exportiert nach %1$s
https://de.wikipedia.org
Aus Wikipedia
Symbole
diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml
index 8e3860d7..a4507594 100644
--- a/i18n/src/main/res/values/strings.xml
+++ b/i18n/src/main/res/values/strings.xml
@@ -91,7 +91,7 @@
Translucent cards
Debug
Export debug information
- Exporting to %1$s
+ Exported to %1$s
https://en.wikipedia.org
From Wikipedia
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/activity/ComposeActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/activity/ComposeActivity.kt
index 9e9c9a33..8b84cb02 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/activity/ComposeActivity.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/activity/ComposeActivity.kt
@@ -17,6 +17,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
+import androidx.navigation.navArgument
import com.google.accompanist.insets.ProvideWindowInsets
import de.mm20.launcher2.ui.LauncherTheme
import de.mm20.launcher2.ui.locals.LocalAppWidgetHost
@@ -24,6 +25,8 @@ import de.mm20.launcher2.ui.locals.LocalColorScheme
import de.mm20.launcher2.ui.locals.LocalNavController
import de.mm20.launcher2.ui.locals.LocalWindowSize
import de.mm20.launcher2.ui.screens.LauncherMainScreen
+import de.mm20.launcher2.ui.screens.settings.SettingsAboutScreen
+import de.mm20.launcher2.ui.screens.settings.SettingsLicenseScreen
import de.mm20.launcher2.ui.screens.settings.SettingsMainScreen
import de.mm20.launcher2.ui.theme.WallpaperColors
import de.mm20.launcher2.ui.theme.colors.DefaultColorScheme
@@ -100,6 +103,17 @@ class ComposeActivity : AppCompatActivity() {
composable("settings") {
SettingsMainScreen()
}
+ composable("settings/about") {
+ SettingsAboutScreen()
+ }
+ composable(
+ "settings/license?library={libraryName}",
+ arguments = listOf(navArgument("libraryName") {
+ nullable = true
+ })
+ ) {
+ SettingsLicenseScreen(it.arguments?.getString("libraryName"))
+ }
}
}
}
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/icons/Icons.kt b/ui/src/main/java/de/mm20/launcher2/ui/icons/Icons.kt
index f07e8e35..12b69aba 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/icons/Icons.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/icons/Icons.kt
@@ -645,4 +645,122 @@ val Icons.Rounded.NotificationBadge
arcTo(4f, 4f, 0f, false, false, 18f, 14f)
close()
}
+ }
+
+val Icons.Rounded.GitHub
+ get() = materialIcon("Icons.Rounded.GitHub") {
+ materialPath {
+ moveTo(12f, 2f)
+ arcTo(10f, 10f, 0f, false, false, 2f, 12f)
+ curveTo(2f, 16.42f, 4.87f, 20.17f, 8.84f, 21.5f)
+ curveTo(9.34f, 21.58f, 9.5f, 21.27f, 9.5f, 21f)
+ curveTo(9.5f, 20.77f, 9.5f, 20.14f, 9.5f, 19.31f)
+ curveTo(6.73f, 19.91f, 6.14f, 17.97f, 6.14f, 17.97f)
+ curveTo(5.68f, 16.81f, 5.03f, 16.5f, 5.03f, 16.5f)
+ curveTo(4.12f, 15.88f, 5.1f, 15.9f, 5.1f, 15.9f)
+ curveTo(6.1f, 15.97f, 6.63f, 16.93f, 6.63f, 16.93f)
+ curveTo(7.5f, 18.45f, 8.97f, 18f, 9.54f, 17.76f)
+ curveTo(9.63f, 17.11f, 9.89f, 16.67f, 10.17f, 16.42f)
+ curveTo(7.95f, 16.17f, 5.62f, 15.31f, 5.62f, 11.5f)
+ curveTo(5.62f, 10.39f, 6f, 9.5f, 6.65f, 8.79f)
+ curveTo(6.55f, 8.54f, 6.2f, 7.5f, 6.75f, 6.15f)
+ curveTo(6.75f, 6.15f, 7.59f, 5.88f, 9.5f, 7.17f)
+ curveTo(10.29f, 6.95f, 11.15f, 6.84f, 12f, 6.84f)
+ curveTo(12.85f, 6.84f, 13.71f, 6.95f, 14.5f, 7.17f)
+ curveTo(16.41f, 5.88f, 17.25f, 6.15f, 17.25f, 6.15f)
+ curveTo(17.8f, 7.5f, 17.45f, 8.54f, 17.35f, 8.79f)
+ curveTo(18f, 9.5f, 18.38f, 10.39f, 18.38f, 11.5f)
+ curveTo(18.38f, 15.32f, 16.04f, 16.16f, 13.81f, 16.41f)
+ curveTo(14.17f, 16.72f, 14.5f, 17.33f, 14.5f, 18.26f)
+ curveTo(14.5f, 19.6f, 14.5f, 20.68f, 14.5f, 21f)
+ curveTo(14.5f, 21.27f, 14.66f, 21.59f, 15.17f, 21.5f)
+ curveTo(19.14f, 20.16f, 22f, 16.42f, 22f, 12f)
+ arcTo(10f, 10f, 0f, false, false, 12f, 2f)
+ close()
+ }
+ }
+
+val Icons.Rounded.Telegram
+ get() = materialIcon("Icons.Rounded.Telegram") {
+ materialPath {
+ moveTo(9.78f, 18.65f)
+ lineTo(10.06f, 14.42f)
+ lineTo(17.74f, 7.5f)
+ curveTo(18.08f, 7.19f, 17.67f, 7.04f, 17.22f, 7.31f)
+ lineTo(7.74f, 13.3f)
+ lineTo(3.64f, 12f)
+ curveTo(2.76f, 11.75f, 2.75f, 11.14f, 3.84f, 10.7f)
+ lineTo(19.81f, 4.54f)
+ curveTo(20.54f, 4.21f, 21.24f, 4.72f, 20.96f, 5.84f)
+ lineTo(18.24f, 18.65f)
+ curveTo(18.05f, 19.56f, 17.5f, 19.78f, 16.74f, 19.36f)
+ lineTo(12.6f, 16.3f)
+ lineTo(10.61f, 18.23f)
+ curveTo(10.38f, 18.46f, 10.19f, 18.65f, 9.78f, 18.65f)
+ close()
+ }
+ }
+
+val Icons.Rounded.Fdroid
+ get() = materialIcon("Icons.Rounded.Fdroid") {
+ materialPath {
+ moveTo(4.4570312f, 3.6269531f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 4.1757812f, 3.71875f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 4.0957031f, 4.3378906f)
+ lineTo(5.3691406f, 5.984375f)
+ curveTo(5.3240789f, 6.102208f, 5.2949219f, 6.2272726f, 5.2949219f, 6.3613281f)
+ lineTo(5.2949219f, 6.5507812f)
+ lineTo(5.2949219f, 7.4199219f)
+ lineTo(5.2949219f, 7.7714844f)
+ lineTo(5.2949219f, 8.640625f)
+ lineTo(5.2949219f, 8.8300781f)
+ curveTo(5.2949219f, 9.4165531f, 5.7670378f, 9.8886719f, 6.3535156f, 9.8886719f)
+ lineTo(17.646484f, 9.8886719f)
+ curveTo(18.232962f, 9.8886719f, 18.705078f, 9.4165531f, 18.705078f, 8.8300781f)
+ lineTo(18.705078f, 8.640625f)
+ lineTo(18.705078f, 6.5507812f)
+ lineTo(18.705078f, 6.3613281f)
+ curveTo(18.705078f, 6.2272726f, 18.675921f, 6.102208f, 18.630859f, 5.984375f)
+ lineTo(19.904297f, 4.3378906f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 19.824219f, 3.71875f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 19.566406f, 3.6269531f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 19.207031f, 3.796875f)
+ lineTo(17.990234f, 5.3710938f)
+ curveTo(17.881129f, 5.3332803f, 17.768779f, 5.3027344f, 17.646484f, 5.3027344f)
+ lineTo(6.3535156f, 5.3027344f)
+ curveTo(6.2312214f, 5.3027344f, 6.1188708f, 5.3332803f, 6.0097656f, 5.3710938f)
+ lineTo(4.7929688f, 3.796875f)
+ arcTo(0.44109249f, 0.44109249f, 0f, false, false, 4.4570312f, 3.6269531f)
+ close()
+ moveTo(8.5664062f, 6.625f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 8.6035156f, 6.625f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 9.7949219f, 7.8164062f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 8.6035156f, 9.0078125f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 7.4121094f, 7.8164062f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 8.5664062f, 6.625f)
+ close()
+ moveTo(15.447266f, 6.625f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 15.484375f, 6.625f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 16.675781f, 7.8164062f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 15.484375f, 9.0078125f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 14.292969f, 7.8164062f)
+ arcTo(1.1909523f, 1.1909465f, 0f, false, true, 15.447266f, 6.625f)
+ close()
+ moveTo(6.3535156f, 10.242188f)
+ curveTo(5.7670378f, 10.242188f, 5.2949219f, 10.714306f, 5.2949219f, 11.300781f)
+ lineTo(5.2949219f, 11.572266f)
+ lineTo(5.2949219f, 13.771484f)
+ lineTo(5.2949219f, 15.888672f)
+ lineTo(5.2949219f, 18.087891f)
+ lineTo(5.2949219f, 18.359375f)
+ curveTo(5.2949219f, 18.94585f, 5.7670378f, 19.417969f, 6.3535156f, 19.417969f)
+ lineTo(17.646484f, 19.417969f)
+ curveTo(18.232962f, 19.417969f, 18.705078f, 18.94585f, 18.705078f, 18.359375f)
+ lineTo(18.705078f, 18.087891f)
+ lineTo(18.705078f, 11.572266f)
+ lineTo(18.705078f, 11.300781f)
+ curveTo(18.705078f, 10.714306f, 18.232962f, 10.242187f, 17.646484f, 10.242188f)
+ lineTo(6.3535156f, 10.242188f)
+ close()
+ }
}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsAboutScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsAboutScreen.kt
new file mode 100644
index 00000000..da280718
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsAboutScreen.kt
@@ -0,0 +1,173 @@
+package de.mm20.launcher2.ui.screens.settings
+
+import android.content.Intent
+import android.net.Uri
+import androidx.compose.material.SnackbarDuration
+import androidx.compose.material.SnackbarResult
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.Info
+import androidx.compose.material.rememberScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.core.content.FileProvider
+import de.mm20.launcher2.crashreporter.CrashReporter
+import de.mm20.launcher2.debug.DebugInformationDumper
+import de.mm20.launcher2.ktx.tryStartActivity
+import de.mm20.launcher2.licenses.OpenSourceLicenses
+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 de.mm20.launcher2.ui.icons.Fdroid
+import de.mm20.launcher2.ui.icons.GitHub
+import de.mm20.launcher2.ui.icons.Telegram
+import de.mm20.launcher2.ui.locals.LocalNavController
+import kotlinx.coroutines.launch
+import java.io.File
+
+@Composable
+fun SettingsAboutScreen() {
+ val context = LocalContext.current
+ val navController = LocalNavController.current
+ val scaffoldState = rememberScaffoldState()
+ val scope = rememberCoroutineScope()
+ PreferenceScreen(
+ title = stringResource(id = R.string.preference_screen_about),
+ scaffoldState = scaffoldState
+ ) {
+ item {
+ PreferenceCategory {
+ val version = context.packageManager.getPackageInfo(
+ context.packageName,
+ 0
+ ).versionName
+ Preference(
+ title = stringResource(id = R.string.preference_version),
+ summary = version
+ )
+ }
+ }
+ item {
+ PreferenceCategory(title = stringResource(id = R.string.preference_category_license)) {
+ Preference(
+ icon = Icons.Rounded.Info,
+ title = stringResource(id = R.string.preference_about_license),
+ summary = stringResource(id = R.string.preference_about_license_summary),
+ onClick = {
+ navController?.navigate("settings/license")
+ }
+ )
+ }
+ }
+ item {
+ PreferenceCategory(title = stringResource(id = R.string.preference_category_links)) {
+ Preference(
+ icon = Icons.Rounded.Telegram,
+ title = stringResource(id = R.string.preference_about_telegram),
+ summary = "t.me/Kvaesitso",
+ onClick = {
+ context.startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://t.me/Kvaesitso")
+ })
+ }
+ )
+ Preference(
+ icon = Icons.Rounded.Fdroid,
+ title = stringResource(id = R.string.preference_about_fdroid),
+ summary = "github.com/MM2-0/fdroid",
+ onClick = {
+ context.startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data =
+ Uri.parse("https://raw.githubusercontent.com/MM2-0/fdroid/master/fdroid/repo")
+ })
+ }
+ )
+ Preference(
+ icon = Icons.Rounded.GitHub,
+ title = "GitHub",
+ summary = "github.com/MM2-0/Kvaesitso",
+ onClick = {
+ context.startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/MM2-0/Kvaesitso")
+ })
+ }
+ )
+ }
+ }
+ item {
+ PreferenceCategory(title = stringResource(id = R.string.preference_category_debug)) {
+ Preference(
+ title = stringResource(id = R.string.preference_crash_reporter),
+ onClick = {
+ context.startActivity(CrashReporter.getLaunchIntent())
+ }
+ )
+ Preference(
+ title = stringResource(id = R.string.preference_export_debug),
+ onClick = {
+ scope.launch {
+ val path = DebugInformationDumper().dump(context)
+ val result = scaffoldState.snackbarHostState.showSnackbar(
+ context.getString(R.string.debug_export_information_file, path),
+ actionLabel = context.getString(R.string.menu_share),
+ duration = SnackbarDuration.Long
+ )
+ if (result == SnackbarResult.ActionPerformed) {
+ context.tryStartActivity(Intent(Intent.ACTION_SEND).apply {
+ type = "text/plain"
+ putExtra(
+ Intent.EXTRA_STREAM, FileProvider.getUriForFile(
+ context,
+ context.applicationContext.packageName + ".fileprovider",
+ File(path)
+ )
+ )
+ })
+ }
+ }
+ }
+ )
+ Preference(
+ title = stringResource(id = R.string.preference_export_databases),
+ onClick = {
+ scope.launch {
+ val path = DebugInformationDumper().exportDatabases(context)
+ val result = scaffoldState.snackbarHostState.showSnackbar(
+ context.getString(R.string.debug_export_information_file, path),
+ actionLabel = context.getString(R.string.menu_share),
+ duration = SnackbarDuration.Long
+ )
+ if (result == SnackbarResult.ActionPerformed) {
+ context.tryStartActivity(Intent(Intent.ACTION_SEND).apply {
+ type = "application/x-sqlite3"
+ putExtra(
+ Intent.EXTRA_STREAM, FileProvider.getUriForFile(
+ context,
+ context.applicationContext.packageName + ".fileprovider",
+ File(path)
+ )
+ )
+ })
+ }
+ }
+ }
+ )
+ }
+ }
+ item {
+ PreferenceCategory(title = stringResource(id = R.string.preference_category_licenses)) {
+ for (library in OpenSourceLicenses.sortedBy { it.name.lowercase() }) {
+ Preference(
+ title = library.name,
+ summary = library.description,
+ onClick = {
+ navController?.navigate("settings/license?library=${library.name}")
+ }
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsLicenseScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsLicenseScreen.kt
new file mode 100644
index 00000000..2202459d
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/screens/settings/SettingsLicenseScreen.kt
@@ -0,0 +1,93 @@
+package de.mm20.launcher2.ui.screens.settings
+
+import android.content.Intent
+import android.net.Uri
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Icon
+import androidx.compose.material.LocalContentColor
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.OpenInBrowser
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import de.mm20.launcher2.licenses.AppLicense
+import de.mm20.launcher2.licenses.OpenSourceLicenses
+import de.mm20.launcher2.ui.R
+import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
+import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
+
+@Composable
+fun SettingsLicenseScreen(libraryName: String? = null) {
+ val context = LocalContext.current
+ val library = if (libraryName == null) {
+ AppLicense.get(context)
+ } else {
+ OpenSourceLicenses.first { it.name == libraryName }
+ }
+ PreferenceScreen(title = stringResource(id = R.string.preference_screen_about)) {
+ item {
+ PreferenceCategory {
+ Column(
+ modifier = Modifier.padding(16.dp)
+ ) {
+ Text(text = library.name, style = MaterialTheme.typography.subtitle1)
+ library.description?.let { Text(text = it) }
+ }
+ CompositionLocalProvider(
+ LocalContentColor provides MaterialTheme.colors.primary
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ context.startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse(library.url)
+ })
+ }
+ .padding(all = 16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(imageVector = Icons.Rounded.OpenInBrowser, contentDescription = null)
+ Text(
+ modifier = Modifier.padding(start = 8.dp),
+ text = stringResource(id = R.string.open_webpage),
+ style = MaterialTheme.typography.button
+ )
+ }
+ }
+ }
+ }
+ item {
+ PreferenceCategory {
+ Column(
+ modifier = Modifier.padding(16.dp)
+ ) {
+ Text(
+ text = stringResource(id = library.licenseName),
+ style = MaterialTheme.typography.subtitle2
+ )
+ library.copyrightNote?.let {
+ Text(
+ text = it,
+ modifier = Modifier.padding(vertical = 4.dp)
+ )
+ }
+ Text(
+ text = context.resources.openRawResource(library.licenseText).reader()
+ .readText()
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file