parent
69876e8884
commit
24e25148f0
@ -185,7 +185,7 @@ class BackupManager(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BackupFormatMajor = 1
|
private const val BackupFormatMajor = 1
|
||||||
private const val BackupFormatMinor = 1
|
private const val BackupFormatMinor = 2
|
||||||
internal const val BackupFormat = "$BackupFormatMajor.$BackupFormatMinor"
|
internal const val BackupFormat = "$BackupFormatMajor.$BackupFormatMinor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
450
database/schemas/de.mm20.launcher2.database.AppDatabase/17.json
Normal file
450
database/schemas/de.mm20.launcher2.database.AppDatabase/17.json
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 17,
|
||||||
|
"identityHash": "3321ba63cb650a091b1ca102198a41ba",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "forecasts",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`timestamp` INTEGER NOT NULL, `temperature` REAL NOT NULL, `minTemp` REAL NOT NULL, `maxTemp` REAL NOT NULL, `pressure` REAL NOT NULL, `humidity` REAL NOT NULL, `icon` INTEGER NOT NULL, `condition` TEXT NOT NULL, `clouds` INTEGER NOT NULL, `windSpeed` REAL NOT NULL, `windDirection` REAL NOT NULL, `rain` REAL NOT NULL, `snow` REAL NOT NULL, `night` INTEGER NOT NULL, `location` TEXT NOT NULL, `provider` TEXT NOT NULL, `providerUrl` TEXT NOT NULL, `rainProbability` INTEGER NOT NULL, `snowProbability` INTEGER NOT NULL, `updateTime` INTEGER NOT NULL, PRIMARY KEY(`timestamp`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "temperature",
|
||||||
|
"columnName": "temperature",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "minTemp",
|
||||||
|
"columnName": "minTemp",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maxTemp",
|
||||||
|
"columnName": "maxTemp",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pressure",
|
||||||
|
"columnName": "pressure",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "humidity",
|
||||||
|
"columnName": "humidity",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "icon",
|
||||||
|
"columnName": "icon",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "condition",
|
||||||
|
"columnName": "condition",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "clouds",
|
||||||
|
"columnName": "clouds",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "windSpeed",
|
||||||
|
"columnName": "windSpeed",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "windDirection",
|
||||||
|
"columnName": "windDirection",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "precipitation",
|
||||||
|
"columnName": "rain",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "snow",
|
||||||
|
"columnName": "snow",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "night",
|
||||||
|
"columnName": "night",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "location",
|
||||||
|
"columnName": "location",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "provider",
|
||||||
|
"columnName": "provider",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "providerUrl",
|
||||||
|
"columnName": "providerUrl",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "precipProbability",
|
||||||
|
"columnName": "rainProbability",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "snowProbability",
|
||||||
|
"columnName": "snowProbability",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "updateTime",
|
||||||
|
"columnName": "updateTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"timestamp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Searchable",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `searchable` TEXT NOT NULL, `launchCount` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `hidden` INTEGER NOT NULL, PRIMARY KEY(`key`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "key",
|
||||||
|
"columnName": "key",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serializedSearchable",
|
||||||
|
"columnName": "searchable",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "launchCount",
|
||||||
|
"columnName": "launchCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pinPosition",
|
||||||
|
"columnName": "pinned",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hidden",
|
||||||
|
"columnName": "hidden",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Websearch",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlTemplate` TEXT NOT NULL, `label` TEXT NOT NULL, `color` INTEGER NOT NULL, `icon` TEXT, `encoding` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "urlTemplate",
|
||||||
|
"columnName": "urlTemplate",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "label",
|
||||||
|
"columnName": "label",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "color",
|
||||||
|
"columnName": "color",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "icon",
|
||||||
|
"columnName": "icon",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "encoding",
|
||||||
|
"columnName": "encoding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Currency",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`symbol` TEXT NOT NULL, `value` REAL NOT NULL, `lastUpdate` INTEGER NOT NULL, PRIMARY KEY(`symbol`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "symbol",
|
||||||
|
"columnName": "symbol",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "value",
|
||||||
|
"columnName": "value",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdate",
|
||||||
|
"columnName": "lastUpdate",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"symbol"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Icons",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `componentName` TEXT, `drawable` TEXT, `iconPack` TEXT NOT NULL, `scale` REAL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "componentName",
|
||||||
|
"columnName": "componentName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "drawable",
|
||||||
|
"columnName": "drawable",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "iconPack",
|
||||||
|
"columnName": "iconPack",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "scale",
|
||||||
|
"columnName": "scale",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "IconPack",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `packageName` TEXT NOT NULL, `version` TEXT NOT NULL, `scale` REAL NOT NULL, PRIMARY KEY(`packageName`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "packageName",
|
||||||
|
"columnName": "packageName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "version",
|
||||||
|
"columnName": "version",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "scale",
|
||||||
|
"columnName": "scale",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"packageName"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Widget",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `data` TEXT NOT NULL, `height` INTEGER NOT NULL, `position` INTEGER NOT NULL, `label` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "data",
|
||||||
|
"columnName": "data",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "height",
|
||||||
|
"columnName": "height",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "position",
|
||||||
|
"columnName": "position",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "label",
|
||||||
|
"columnName": "label",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "CustomAttributes",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `type` TEXT NOT NULL, `value` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "key",
|
||||||
|
"columnName": "key",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "value",
|
||||||
|
"columnName": "value",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3321ba63cb650a091b1ca102198a41ba')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,7 +18,7 @@ import de.mm20.launcher2.database.entities.*
|
|||||||
IconEntity::class,
|
IconEntity::class,
|
||||||
IconPackEntity::class,
|
IconPackEntity::class,
|
||||||
WidgetEntity::class,
|
WidgetEntity::class,
|
||||||
CustomAttributeEntity::class], version = 16, exportSchema = true)
|
CustomAttributeEntity::class], version = 17, exportSchema = true)
|
||||||
@TypeConverters(ComponentNameConverter::class, StringListConverter::class)
|
@TypeConverters(ComponentNameConverter::class, StringListConverter::class)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration_13_14(),
|
Migration_13_14(),
|
||||||
Migration_14_15(),
|
Migration_14_15(),
|
||||||
Migration_15_16(),
|
Migration_15_16(),
|
||||||
|
Migration_16_17(),
|
||||||
).build()
|
).build()
|
||||||
if (_instance == null) _instance = instance
|
if (_instance == null) _instance = instance
|
||||||
return instance
|
return instance
|
||||||
@ -165,4 +166,11 @@ class Migration_15_16 : Migration(15, 16) {
|
|||||||
)
|
)
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Migration_16_17 : Migration(16, 17) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Websearch ADD COLUMN encoding INTEGER")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -9,5 +9,6 @@ data class WebsearchEntity(
|
|||||||
var label: String,
|
var label: String,
|
||||||
var color: Int,
|
var color: Int,
|
||||||
var icon: String?,
|
var icon: String?,
|
||||||
|
var encoding: Int?,
|
||||||
@PrimaryKey(autoGenerate = true) val id: Long?
|
@PrimaryKey(autoGenerate = true) val id: Long?
|
||||||
)
|
)
|
||||||
@ -208,6 +208,11 @@
|
|||||||
<string name="websearch_dialog_custom_icon">Custom icon</string>
|
<string name="websearch_dialog_custom_icon">Custom icon</string>
|
||||||
<string name="websearch_dialog_import_url">Import from URL</string>
|
<string name="websearch_dialog_import_url">Import from URL</string>
|
||||||
<string name="websearch_dialog_import_error">The given URL cannot be imported automatically. You can try a different URL or enter the required data manually.</string>
|
<string name="websearch_dialog_import_error">The given URL cannot be imported automatically. You can try a different URL or enter the required data manually.</string>
|
||||||
|
<string name="websearch_dialog_advanced">Advanced</string>
|
||||||
|
<string name="websearch_dialog_query_endcoding">Query encoding</string>
|
||||||
|
<string name="websearch_dialog_query_endcoding_url">Percent-encoding</string>
|
||||||
|
<string name="websearch_dialog_query_endcoding_form">application/x-www-form-urlencoded</string>
|
||||||
|
<string name="websearch_dialog_query_endcoding_none">None</string>
|
||||||
<string name="menu_edit_widgets">Edit widgets</string>
|
<string name="menu_edit_widgets">Edit widgets</string>
|
||||||
<string name="widget_name_weather">Weather</string>
|
<string name="widget_name_weather">Weather</string>
|
||||||
<string name="widget_name_calendar">Calendar</string>
|
<string name="widget_name_calendar">Calendar</string>
|
||||||
|
|||||||
@ -244,6 +244,7 @@ internal class WebsearchRepositoryImpl(
|
|||||||
"label" to websearch.label,
|
"label" to websearch.label,
|
||||||
"template" to websearch.urlTemplate,
|
"template" to websearch.urlTemplate,
|
||||||
"icon" to icon,
|
"icon" to icon,
|
||||||
|
"encoding" to websearch.encoding,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -289,6 +290,7 @@ internal class WebsearchRepositoryImpl(
|
|||||||
color = json.optInt("color", 0),
|
color = json.optInt("color", 0),
|
||||||
label = json.getString("label"),
|
label = json.getString("label"),
|
||||||
icon = iconFile?.absolutePath,
|
icon = iconFile?.absolutePath,
|
||||||
|
encoding = json.optInt("encoding"),
|
||||||
id = null
|
id = null
|
||||||
)
|
)
|
||||||
websearches.add(entity)
|
websearches.add(entity)
|
||||||
|
|||||||
@ -3,41 +3,79 @@ package de.mm20.launcher2.search.data
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import de.mm20.launcher2.database.entities.WebsearchEntity
|
import de.mm20.launcher2.database.entities.WebsearchEntity
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
class Websearch(
|
class Websearch(
|
||||||
var urlTemplate: String,
|
var urlTemplate: String,
|
||||||
var label: String,
|
var label: String,
|
||||||
var color: Int,
|
var color: Int,
|
||||||
var icon: String?,
|
var icon: String?,
|
||||||
var id: Long? = null,
|
var id: Long? = null,
|
||||||
val query: String? = null
|
var encoding: QueryEncoding = QueryEncoding.UrlEncode,
|
||||||
|
val query: String? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
constructor(entity: WebsearchEntity, query: String? = null) : this(
|
constructor(entity: WebsearchEntity, query: String? = null) : this(
|
||||||
urlTemplate = entity.urlTemplate,
|
urlTemplate = entity.urlTemplate,
|
||||||
label = entity.label,
|
label = entity.label,
|
||||||
icon = entity.icon,
|
icon = entity.icon,
|
||||||
color = entity.color,
|
color = entity.color,
|
||||||
id = entity.id,
|
id = entity.id,
|
||||||
query = query
|
query = query,
|
||||||
|
encoding = QueryEncoding.fromInt(entity.encoding)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toDatabaseEntity(): WebsearchEntity {
|
fun toDatabaseEntity(): WebsearchEntity {
|
||||||
return WebsearchEntity(
|
return WebsearchEntity(
|
||||||
urlTemplate = urlTemplate,
|
urlTemplate = urlTemplate,
|
||||||
color = color,
|
color = color,
|
||||||
icon = icon,
|
icon = icon,
|
||||||
label = label,
|
label = label,
|
||||||
id = id
|
id = id,
|
||||||
|
encoding = encoding.toInt()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLaunchIntent(): Intent? {
|
fun getLaunchIntent(): Intent? {
|
||||||
if(query == null) return null
|
if (query == null) return null
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
val url = urlTemplate.replace("\${1}", Uri.encode(query))
|
val url = urlTemplate.replace("\${1}", encodeQuery(query, encoding))
|
||||||
intent.data = Uri.parse(url)
|
intent.data = Uri.parse(url)
|
||||||
return intent
|
return intent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun encodeQuery(query: String, encoding: QueryEncoding): String {
|
||||||
|
return when(encoding) {
|
||||||
|
QueryEncoding.UrlEncode -> Uri.encode(query)
|
||||||
|
QueryEncoding.FormData -> URLEncoder.encode(query, "UTF-8")
|
||||||
|
QueryEncoding.None -> query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class QueryEncoding {
|
||||||
|
UrlEncode,
|
||||||
|
FormData,
|
||||||
|
None;
|
||||||
|
|
||||||
|
fun toInt(): Int {
|
||||||
|
return when (this) {
|
||||||
|
UrlEncode -> 0
|
||||||
|
FormData -> 1
|
||||||
|
None -> 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromInt(value: Int?): QueryEncoding {
|
||||||
|
return when (value) {
|
||||||
|
1 -> FormData
|
||||||
|
2 -> None
|
||||||
|
else -> UrlEncode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -17,6 +17,7 @@ import androidx.compose.ui.window.Dialog
|
|||||||
fun <T> ListPreference(
|
fun <T> ListPreference(
|
||||||
title: String,
|
title: String,
|
||||||
icon: ImageVector? = null,
|
icon: ImageVector? = null,
|
||||||
|
iconPadding: Boolean = true,
|
||||||
items: List<ListPreferenceItem<T>>,
|
items: List<ListPreferenceItem<T>>,
|
||||||
value: T,
|
value: T,
|
||||||
summary: String? = items.firstOrNull { value == it.value }?.label,
|
summary: String? = items.firstOrNull { value == it.value }?.label,
|
||||||
@ -33,6 +34,7 @@ fun <T> ListPreference(
|
|||||||
title = title,
|
title = title,
|
||||||
summary = summary,
|
summary = summary,
|
||||||
icon = icon,
|
icon = icon,
|
||||||
|
iconPadding = iconPadding,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
showDialog = true
|
showDialog = true
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
fun Preference(
|
fun Preference(
|
||||||
title: String,
|
title: String,
|
||||||
icon: @Composable (() -> Unit),
|
icon: @Composable (() -> Unit),
|
||||||
|
iconPadding: Boolean = true,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
onClick: () -> Unit = {},
|
onClick: () -> Unit = {},
|
||||||
controls: @Composable (() -> Unit)? = null,
|
controls: @Composable (() -> Unit)? = null,
|
||||||
@ -29,13 +30,17 @@ fun Preference(
|
|||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.alpha(if (enabled) 1f else 0.38f),
|
.alpha(if (enabled) 1f else 0.38f),
|
||||||
) {
|
) {
|
||||||
Box(
|
if (iconPadding) {
|
||||||
modifier = Modifier
|
Box(
|
||||||
.width(56.dp)
|
modifier = Modifier
|
||||||
.padding(start = 4.dp),
|
.width(56.dp)
|
||||||
contentAlignment = Alignment.CenterStart
|
.padding(start = 4.dp),
|
||||||
) {
|
contentAlignment = Alignment.CenterStart
|
||||||
icon()
|
) {
|
||||||
|
icon()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Box(modifier = Modifier.size(0.dp))
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.weight(1f).padding(vertical = 16.dp)
|
modifier = Modifier.weight(1f).padding(vertical = 16.dp)
|
||||||
@ -63,13 +68,15 @@ fun Preference(
|
|||||||
fun Preference(
|
fun Preference(
|
||||||
title: String,
|
title: String,
|
||||||
icon: ImageVector? = null,
|
icon: ImageVector? = null,
|
||||||
|
iconPadding: Boolean = true,
|
||||||
summary: String? = null,
|
summary: String? = null,
|
||||||
onClick: () -> Unit = {},
|
onClick: () -> Unit = {},
|
||||||
controls: @Composable (() -> Unit)? = null,
|
controls: @Composable (() -> Unit)? = null,
|
||||||
enabled: Boolean = true
|
enabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
Preference(
|
Preference(
|
||||||
title, icon = {
|
title,
|
||||||
|
icon = {
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
@ -77,6 +84,6 @@ fun Preference(
|
|||||||
tint = MaterialTheme.colorScheme.primary,
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, summary, onClick, controls, enabled
|
}, iconPadding, summary, onClick, controls, enabled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -3,22 +3,65 @@ package de.mm20.launcher2.ui.settings.websearch
|
|||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.*
|
import androidx.compose.material.icons.rounded.Add
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material.icons.rounded.ArrowForward
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material.icons.rounded.Check
|
||||||
|
import androidx.compose.material.icons.rounded.CloudDownload
|
||||||
|
import androidx.compose.material.icons.rounded.MoreVert
|
||||||
|
import androidx.compose.material.icons.rounded.Search
|
||||||
|
import androidx.compose.material.icons.rounded.Tag
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.*
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.luminance
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -28,6 +71,7 @@ import com.godaddy.android.colorpicker.ClassicColorPicker
|
|||||||
import de.mm20.launcher2.search.data.Websearch
|
import de.mm20.launcher2.search.data.Websearch
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||||
|
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||||
@ -146,6 +190,7 @@ fun EditWebsearchDialog(
|
|||||||
var label by remember { mutableStateOf(value.label) }
|
var label by remember { mutableStateOf(value.label) }
|
||||||
var showError by remember { mutableStateOf(false) }
|
var showError by remember { mutableStateOf(false) }
|
||||||
var urlTemplate by remember { mutableStateOf(value.urlTemplate) }
|
var urlTemplate by remember { mutableStateOf(value.urlTemplate) }
|
||||||
|
var encoding by remember { mutableStateOf(value.encoding) }
|
||||||
var color by remember { mutableStateOf(value.color) }
|
var color by remember { mutableStateOf(value.color) }
|
||||||
var icon by remember { mutableStateOf(value.icon) }
|
var icon by remember { mutableStateOf(value.icon) }
|
||||||
|
|
||||||
@ -226,6 +271,7 @@ fun EditWebsearchDialog(
|
|||||||
}
|
}
|
||||||
value.icon = icon
|
value.icon = icon
|
||||||
value.color = color
|
value.color = color
|
||||||
|
value.encoding = encoding
|
||||||
onValueSaved(value)
|
onValueSaved(value)
|
||||||
} else {
|
} else {
|
||||||
showError = true
|
showError = true
|
||||||
@ -426,6 +472,37 @@ fun EditWebsearchDialog(
|
|||||||
text = stringResource(R.string.websearch_dialog_url_description),
|
text = stringResource(R.string.websearch_dialog_url_description),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var showAdvanced by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
AnimatedVisibility(!showAdvanced) {
|
||||||
|
TextButton(
|
||||||
|
modifier = Modifier.padding(vertical = 16.dp).align(Alignment.End),
|
||||||
|
onClick = { showAdvanced = true }) {
|
||||||
|
Text(stringResource(R.string.websearch_dialog_advanced))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(showAdvanced) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
|
) {
|
||||||
|
Divider()
|
||||||
|
ListPreference(
|
||||||
|
title = stringResource(R.string.websearch_dialog_query_endcoding),
|
||||||
|
items = listOf(
|
||||||
|
stringResource(R.string.websearch_dialog_query_endcoding_url) to Websearch.QueryEncoding.UrlEncode,
|
||||||
|
stringResource(R.string.websearch_dialog_query_endcoding_form) to Websearch.QueryEncoding.FormData,
|
||||||
|
stringResource(R.string.websearch_dialog_query_endcoding_none) to Websearch.QueryEncoding.None,
|
||||||
|
),
|
||||||
|
iconPadding = false,
|
||||||
|
value = encoding,
|
||||||
|
onValueChanged = {
|
||||||
|
encoding = it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user