Initial commit

This commit is contained in:
MM20
2021-09-18 23:37:52 +02:00
commit 749e4e3073
938 changed files with 50475 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.mm20.launcher2.database">
/
</manifest>
@@ -0,0 +1,147 @@
package de.mm20.launcher2.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import de.mm20.launcher2.database.entities.*
@Database(entities = [ForecastEntity::class,
FavoritesItemEntity::class,
WebsearchEntity::class,
CurrencyEntity::class,
IconEntity::class,
IconPackEntity::class,
PluginEntity::class,
WidgetEntity::class], version = 14, exportSchema = true)
@TypeConverters(ComponentNameConverter::class, StringListConverter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun weatherDao(): WeatherDao
abstract fun searchDao(): SearchDao
abstract fun iconDao(): IconDao
abstract fun widgetDao(): WidgetDao
abstract fun currencyDao(): CurrencyDao
companion object {
private var _instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
val instance = _instance
?: Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "room")
//.fallbackToDestructiveMigration()
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
db.execSQL("INSERT INTO Websearch (urlTemplate, label, color, icon) VALUES " +
"('${context.getString(R.string.websearch_google_url)}', '${context.getString(R.string.websearch_google)}', 0xFF4285F4, NULL )," +
"('${context.getString(R.string.websearch_youtube_url)}', '${context.getString(R.string.websearch_youtube)}', 0xFFFF0000, NULL )," +
"('${context.getString(R.string.websearch_playstore_url)}', '${context.getString(R.string.websearch_playstore)}', 0xFF00D3FF, NULL );")
db.execSQL("INSERT INTO Widget (type, data, height, position, label) VALUES " +
"('internal', 'weather', -1, 0, '${context.getString(R.string.widget_name_weather)}')," +
"('internal', 'music', -1, 1, '${context.getString(R.string.widget_name_music)}')," +
"('internal', 'calendar', -1, 2, '${context.getString(R.string.widget_name_calendar)}');")
}
})
.addMigrations(
Migration_6_7(),
Migration_7_8(),
Migration_8_9(),
Migration_9_10(),
Migration_10_11(),
Migration_11_12(),
Migration_12_13(),
Migration_13_14()
).build()
if (_instance == null) _instance = instance
return instance
}
}
}
class Migration_6_7 : Migration(6, 7) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE Searchable2 (`key` TEXT NOT NULL, `searchable` TEXT, `launchCount` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `hidden` INTEGER NOT NULL, `inAllApps` INTEGER NOT NULL, PRIMARY KEY(`key`))")
database.execSQL("INSERT INTO Searchable2 SELECT * FROM Searchable")
database.execSQL("DROP TABLE Searchable")
database.execSQL("ALTER TABLE Searchable2 RENAME TO Searchable")
}
}
class Migration_7_8 : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `${ForecastEntity.TABLE_NAME}2` (`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, `rainPropability` INTEGER NOT NULL, `snowProbability` INTEGER NOT NULL, PRIMARY KEY(`timestamp`))")
database.execSQL("INSERT INTO ${ForecastEntity.TABLE_NAME}2 SELECT *, -1 as rainPropability, -1 as snowPropability FROM ${ForecastEntity.TABLE_NAME}")
database.execSQL("DROP TABLE ${ForecastEntity.TABLE_NAME}")
database.execSQL("ALTER TABLE ${ForecastEntity.TABLE_NAME}2 RENAME TO ${ForecastEntity.TABLE_NAME}")
}
}
class Migration_8_9 : Migration(8, 9) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `${ForecastEntity.TABLE_NAME}2` (" +
"`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`))")
database.execSQL("INSERT INTO ${ForecastEntity.TABLE_NAME}2 SELECT timestamp, temperature, minTemp, maxTemp, pressure, humidity, icon, condition, clouds, windSpeed, windDirection, rain, snow, night, location, provider, providerUrl, rainPropability as rainProbability, snowProbability, 0 as updateTime FROM ${ForecastEntity.TABLE_NAME}")
database.execSQL("DROP TABLE ${ForecastEntity.TABLE_NAME}")
database.execSQL("ALTER TABLE ${ForecastEntity.TABLE_NAME}2 RENAME TO ${ForecastEntity.TABLE_NAME}")
}
}
class Migration_9_10 : Migration(9, 10) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Plugins` (`packageName` TEXT NOT NULL, `label` TEXT NOT NULL, `description` TEXT NOT NULL, `pluginClassName` TEXT NOT NULL, `enabled` INTEGER NOT NULL, PRIMARY KEY(`packageName`) );")
}
}
class Migration_10_11 : Migration(10, 11) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `temp` (`key` TEXT NOT NULL, `searchable` TEXT NOT NULL, `launchCount` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `hidden` INTEGER NOT NULL, PRIMARY KEY(`key`))")
database.execSQL("INSERT INTO `temp` SELECT `key`, `searchable`, `launchCount`, `pinned`, `hidden` FROM `Searchable`")
database.execSQL("DROP TABLE `Searchable`")
database.execSQL("ALTER TABLE `temp` RENAME TO `Searchable`")
}
}
class Migration_11_12 : Migration(11, 12) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Currency` (`symbol` TEXT NOT NULL, `value` REAL NOT NULL, `lastUpdate` INTEGER NOT NULL, PRIMARY KEY(`symbol`))")
}
}
class Migration_12_13 : Migration(12, 13) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Plugin` (`packageName` TEXT NOT NULL, `data` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`packageName`, `data`))")
}
}
class Migration_13_14 : Migration(13, 14) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS `Plugins`;")
}
}
@@ -0,0 +1,34 @@
package de.mm20.launcher2.database
import android.content.ComponentName
import androidx.room.TypeConverter
import org.json.JSONArray
class ComponentNameConverter {
@TypeConverter
fun toString(componentName: ComponentName?): String? {
return componentName?.flattenToString()
}
@TypeConverter
fun toComponentName(string: String?) : ComponentName? {
string ?: return null
return ComponentName.unflattenFromString(string)
}
}
class StringListConverter {
@TypeConverter
fun toString(list: List<String>): String {
val json = JSONArray()
list.forEach { json.put(it) }
return json.toString()
}
@TypeConverter
fun toStringList(string: String): List<String> {
val json = JSONArray(string)
return (0..json.length()).map { json.getString(it) }
}
}
@@ -0,0 +1,34 @@
package de.mm20.launcher2.database
import androidx.room.*
import de.mm20.launcher2.database.entities.CurrencyEntity
@Dao
interface CurrencyDao {
@Query("SELECT value FROM Currency WHERE symbol = :symbol")
fun getExchangeRate(symbol: String) : Double?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(currency: CurrencyEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(currencies: List<CurrencyEntity>)
@Query("SELECT * FROM Currency WHERE symbol = :symbol")
fun getCurrency(symbol: String) : CurrencyEntity?
@Query("SELECT * FROM Currency WHERE symbol IN (:symbols)")
fun getCurrencies(symbols: List<String>) : List<CurrencyEntity>
@Query("SELECT * FROM Currency")
fun getAllCurrencies() : List<CurrencyEntity>
@Transaction
fun exists(symbol: String): Boolean {
return getCurrency(symbol) != null
}
@Query("SELECT lastUpdate FROM Currency WHERE symbol = :symbol")
fun getLastUpdate(symbol: String) : Long
}
@@ -0,0 +1,73 @@
package de.mm20.launcher2.database
import androidx.lifecycle.LiveData
import androidx.room.*
import de.mm20.launcher2.database.entities.IconEntity
import de.mm20.launcher2.database.entities.IconPackEntity
@Dao
interface IconDao {
@Insert
fun insertAll(icons: List<IconEntity>)
@Query("SELECT drawable FROM Icons WHERE componentName = :componentName AND iconPack = :iconPack")
fun getIconName(componentName: String, iconPack: String): String?
@Query("SELECT * FROM Icons WHERE componentName = :componentName AND iconPack = :iconPack")
fun getIcon(componentName: String, iconPack: String): IconEntity?
@Query("DELETE FROM Icons WHERE iconPack = :iconPack")
fun deleteIcons(iconPack: String)
@Transaction
fun installIconPack(iconPack: IconPackEntity, icons: List<IconEntity>) {
deleteIconPack(iconPack)
deleteIcons(iconPack.packageName)
insertAll(icons)
installIconPack(iconPack)
}
@Insert
fun installIconPack(iconPack: IconPackEntity)
@Query("SELECT * FROM IconPack")
fun getInstalledIconPacks(): List<IconPackEntity>
@Query("SELECT * FROM IconPack")
fun getInstalledIconPacksLiveData(): LiveData<List<IconPackEntity>>
@Delete
fun deleteIconPack(iconPack: IconPackEntity)
@Query("SELECT * FROM IconPack WHERE packageName = :packageName AND version = :version")
fun getPacks(packageName: String, version: String): List<IconPackEntity>
@Transaction
fun isInstalled(iconPack: IconPackEntity): Boolean {
return getPacks(iconPack.packageName, iconPack.version).isNotEmpty()
}
@Query("DELETE FROM Icons WHERE iconPack NOT IN (:packs)")
fun deleteAllIconsExcept(packs: List<String>)
@Query("DELETE FROM IconPack WHERE packageName NOT IN (:packs)")
fun deleteAllPacksExcept(packs: List<String>)
@Transaction
fun uninstallIconPacksExcept(packs: List<String>) {
deleteAllIconsExcept(packs)
deleteAllPacksExcept(packs)
}
@Query("SELECT drawable FROM Icons WHERE iconPack = :pack AND type = 'iconback'")
fun getIconBacks(pack: String): List<String>
@Query("SELECT drawable FROM Icons WHERE iconPack = :pack AND type = 'iconupon'")
fun getIconUpons(pack: String): List<String>
@Query("SELECT drawable FROM Icons WHERE iconPack = :pack AND type = 'iconmask'")
fun getIconMasks(pack: String): List<String>
@Query("SELECT scale FROM IconPack WHERE packageName = :pack")
fun getScale(pack: String): Float?
}
@@ -0,0 +1,120 @@
package de.mm20.launcher2.database
import androidx.lifecycle.LiveData
import androidx.room.*
import de.mm20.launcher2.database.entities.FavoritesItemEntity
import de.mm20.launcher2.database.entities.WebsearchEntity
@Dao
interface SearchDao {
@Insert()
fun insertAll(items: List<FavoritesItemEntity>)
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertAllSkipExisting(items: List<FavoritesItemEntity>)
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertSkipExisting(items: FavoritesItemEntity)
@Query("SELECT * FROM Searchable WHERE pinned > 0 ORDER BY pinned DESC, launchCount DESC")
fun getFavorites() : LiveData<List<FavoritesItemEntity>>
@Query("SELECT COUNT(key) as count FROM Searchable WHERE pinned = 1;")
fun getPinCount(): Int
@Query("SELECT * FROM Searchable WHERE pinned = 0 AND launchCount > 0 AND hidden = 0 ORDER BY launchCount DESC LIMIT :count")
fun getAutoFavorites(count: Int): List<FavoritesItemEntity>
@Query("DELETE FROM Searchable WHERE `key` IN (:keys)")
fun deleteAll(keys: List<String>)
@Query("UPDATE Searchable SET pinned = 1, hidden = 0 WHERE `key` = :key")
fun pinExistingItem(key: String)
@Transaction
fun pinToFavorites(item: FavoritesItemEntity) {
pinExistingItem(item.key)
insertSkipExisting(item)
}
@Query("UPDATE Searchable SET pinned = 0 WHERE `key` = :key")
fun unpinFavorite(key: String)
@Query("DELETE FROM Searchable WHERE `key` = :key")
fun deleteByKey(key: String)
@Query("UPDATE Searchable SET pinned = 0 WHERE `key` = :key")
fun unpinApp(key: String)
@Query("SELECT pinned FROM Searchable WHERE `key` = :key UNION SELECT 0 as pinned ORDER BY pinned DESC LIMIT 1")
fun isPinned(key: String): LiveData<Boolean>
@Query("UPDATE Searchable SET hidden = 1, pinned = 0 WHERE `key` = :key")
fun hideExistingItem(key: String)
@Transaction
fun hideItem(item: FavoritesItemEntity) {
hideExistingItem(item.key)
insertSkipExisting(item)
}
@Query("UPDATE Searchable SET hidden = 0 WHERE `key` = :key")
fun unhideItem(key: String)
@Query("SELECT hidden FROM Searchable WHERE `key` = :key UNION SELECT 0 as hidden ORDER BY hidden DESC LIMIT 1")
fun isHidden(key: String): LiveData<Boolean>
@Query("SELECT `key` FROM SEARCHABLE WHERE hidden = 1")
fun getHiddenItemKeys(): LiveData<List<String>>
@Query("SELECT * FROM SEARCHABLE WHERE hidden = 1")
fun getHiddenItems(): LiveData<List<FavoritesItemEntity>>
@Query("SELECT * FROM Websearch ORDER BY label ASC")
fun getWebSearches(): List<WebsearchEntity>
@Query("SELECT * FROM Websearch ORDER BY label ASC")
fun getWebSearchesLiveData(): LiveData<List<WebsearchEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertWebsearch(websearch: WebsearchEntity)
@Delete
fun deleteWebsearch(websearch: WebsearchEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAllWebsearches(websearches: List<WebsearchEntity>)
@Query("UPDATE Searchable SET launchCount = launchCount + 1 WHERE `key` = :key")
fun incrementExistingLaunchCount(key: String)
@Transaction
fun incrementLaunchCount(item: FavoritesItemEntity) {
incrementExistingLaunchCount(item.key)
insertSkipExisting(item)
}
@Query("SELECT * FROM Searchable WHERE `key` = :key")
fun getFavorite(key: String): FavoritesItemEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertReplaceExisting(toDatabaseEntity: FavoritesItemEntity)
@Query("SELECT * FROM Searchable WHERE (pinned > 0 OR launchCount > 0) AND hidden = 0 ORDER BY pinned DESC, launchCount DESC")
fun getAllFavoriteItems(): List<FavoritesItemEntity>
@Transaction
fun saveFavorites(favorites: List<FavoritesItemEntity>) {
deleteAllFavorites()
insertAll(favorites)
}
@Query("DELETE FROM Searchable WHERE hidden = 0")
fun deleteAllFavorites()
}
@@ -0,0 +1,27 @@
package de.mm20.launcher2.database
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query
import androidx.room.Transaction
import de.mm20.launcher2.database.entities.ForecastEntity
@Dao
interface WeatherDao {
@Query("SELECT * FROM ${ForecastEntity.TABLE_NAME} ORDER BY timestamp ASC")
fun getForecasts(): LiveData<List<ForecastEntity>>
@Insert(onConflict = REPLACE)
fun insertAll(forecasts: List<ForecastEntity>)
@Query("DELETE FROM ${ForecastEntity.TABLE_NAME}")
fun deleteAll()
@Transaction
fun replaceAll(forecasts: List<ForecastEntity>) {
deleteAll()
insertAll(forecasts)
}
}
@@ -0,0 +1,23 @@
package de.mm20.launcher2.database
import androidx.lifecycle.LiveData
import androidx.room.*
import de.mm20.launcher2.database.entities.WidgetEntity
@Dao
interface WidgetDao {
@Query("SELECT * FROM Widget ORDER BY position ASC")
fun getWidgets(): List<WidgetEntity>
@Transaction
fun updateWidgets(widgets: List<WidgetEntity>) {
deleteAll()
insertAll(widgets)
}
@Insert
fun insertAll(widgets: List<WidgetEntity>)
@Query("DELETE FROM Widget")
fun deleteAll()
}
@@ -0,0 +1,11 @@
package de.mm20.launcher2.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "Currency")
data class CurrencyEntity(
@PrimaryKey val symbol: String,
val value: Double,
val lastUpdate: Long
)
@@ -0,0 +1,14 @@
package de.mm20.launcher2.database.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "Searchable")
data class FavoritesItemEntity(
@PrimaryKey val key: String,
@ColumnInfo(name = "searchable") val serializedSearchable: String,
var launchCount: Int,
@ColumnInfo(name = "pinned") var pinPosition: Int,
var hidden: Boolean
)
@@ -0,0 +1,33 @@
package de.mm20.launcher2.database.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = ForecastEntity.TABLE_NAME)
data class ForecastEntity(
@PrimaryKey val timestamp: Long,
val temperature: Double,
val minTemp: Double = -1.0,
val maxTemp: Double = -1.0,
val pressure: Double = -1.0,
val humidity: Double = -1.0,
val icon: Int,
val condition: String,
val clouds: Int = -1,
val windSpeed: Double = -1.0,
val windDirection: Double = -1.0,
@ColumnInfo(name = "rain") val precipitation: Double = -1.0,
val snow: Double = -1.0,
val night: Boolean = false,
val location: String,
val provider: String,
val providerUrl: String = "",
@ColumnInfo(name = "rainProbability") val precipProbability: Int = -1,
val snowProbability: Int = -1,
val updateTime: Long
) {
companion object {
const val TABLE_NAME = "forecasts"
}
}
@@ -0,0 +1,15 @@
package de.mm20.launcher2.database.entities
import android.content.ComponentName
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "Icons")
data class IconEntity(
val type: String,
val componentName: ComponentName?,
val drawable: String?,
val iconPack: String,
val scale : Float? = null,
@PrimaryKey(autoGenerate = true) val id : Long? = null
)
@@ -0,0 +1,12 @@
package de.mm20.launcher2.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "IconPack")
data class IconPackEntity(
val name: String,
@PrimaryKey val packageName: String,
val version: String,
var scale: Float = 1f
)
@@ -0,0 +1,10 @@
package de.mm20.launcher2.database.entities
import androidx.room.Entity
@Entity(tableName = "Plugin", primaryKeys = ["packageName", "data"])
data class PluginEntity(
val packageName: String,
val data: String,
val type: String
)
@@ -0,0 +1,13 @@
package de.mm20.launcher2.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "Websearch")
data class WebsearchEntity(
var urlTemplate: String,
var label: String,
var color: Int,
var icon: String?,
@PrimaryKey(autoGenerate = true) val id: Long?
)
@@ -0,0 +1,15 @@
package de.mm20.launcher2.database.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "Widget")
data class WidgetEntity(
val type: String,
var data: String,
var height: Int,
var position: Int,
val label: String = "",
@PrimaryKey(autoGenerate = true) val id: Int? = null
)