Refactor widgets
This commit is contained in:
@@ -5,5 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val widgetsModule = module {
|
||||
single { WidgetRepository(androidContext()) }
|
||||
single<WidgetRepository> { WidgetRepositoryImpl(androidContext(), get()) }
|
||||
}
|
||||
@@ -1,32 +1,173 @@
|
||||
package de.mm20.launcher2.widgets
|
||||
|
||||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetHost
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import de.mm20.launcher2.database.entities.WidgetEntity
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
|
||||
data class Widget(
|
||||
val type: WidgetType,
|
||||
var data: String,
|
||||
var height: Int,
|
||||
val label: String = ""
|
||||
) {
|
||||
constructor(entity: WidgetEntity) : this(
|
||||
type = if (entity.type == "internal") WidgetType.INTERNAL else WidgetType. THIRD_PARTY,
|
||||
data = entity.data,
|
||||
height = entity.height,
|
||||
label = entity.label
|
||||
)
|
||||
sealed class Widget {
|
||||
abstract fun loadLabel(context: Context): String
|
||||
abstract fun toDatabaseEntity(position: Int = -1): WidgetEntity
|
||||
open val isConfigurable: Boolean = false
|
||||
open fun configure(context: Activity, appWidgetHost: AppWidgetHost) {}
|
||||
|
||||
fun toDatabaseEntity(position: Int): WidgetEntity {
|
||||
companion object {
|
||||
fun fromDatabaseEntity(context: Context, entity: WidgetEntity): Widget? {
|
||||
if (entity.type == WidgetType.INTERNAL.value) {
|
||||
return when (entity.data) {
|
||||
"weather" -> WeatherWidget
|
||||
"music" -> MusicWidget
|
||||
"calendar" -> CalendarWidget
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
val widgetId = entity.data.toIntOrNull() ?: return null
|
||||
val widgetInfo =
|
||||
AppWidgetManager.getInstance(context).getAppWidgetInfo(widgetId) ?: return null
|
||||
return ExternalWidget(
|
||||
height = entity.height,
|
||||
widgetId = widgetId,
|
||||
widgetProviderInfo = widgetInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object WeatherWidget : Widget() {
|
||||
override fun loadLabel(context: Context): String {
|
||||
return context.getString(R.string.widget_name_weather)
|
||||
}
|
||||
|
||||
override fun toDatabaseEntity(position: Int): WidgetEntity {
|
||||
return WidgetEntity(
|
||||
type = if (type == WidgetType.INTERNAL) "internal" else "3rdparty",
|
||||
label = label,
|
||||
position = position,
|
||||
height = height,
|
||||
data = data
|
||||
type = WidgetType.INTERNAL.value,
|
||||
data = "weather",
|
||||
height = -1,
|
||||
position = position
|
||||
)
|
||||
}
|
||||
|
||||
override val isConfigurable: Boolean = true
|
||||
|
||||
override fun configure(context: Activity, appWidgetHost: AppWidgetHost) {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
context.getPackageName(),
|
||||
"de.mm20.launcher2.ui.settings.SettingsActivity"
|
||||
)
|
||||
intent.putExtra(
|
||||
"de.mm20.launcher2.settings.ROUTE",
|
||||
"settings/widgets/weather"
|
||||
)
|
||||
context.tryStartActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
object MusicWidget : Widget() {
|
||||
override fun loadLabel(context: Context): String {
|
||||
return context.getString(R.string.widget_name_music)
|
||||
}
|
||||
|
||||
override fun toDatabaseEntity(position: Int): WidgetEntity {
|
||||
return WidgetEntity(
|
||||
type = WidgetType.INTERNAL.value,
|
||||
data = "music",
|
||||
height = -1,
|
||||
position = position
|
||||
)
|
||||
}
|
||||
|
||||
override val isConfigurable: Boolean = true
|
||||
|
||||
override fun configure(context: Activity, appWidgetHost: AppWidgetHost) {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
context.getPackageName(),
|
||||
"de.mm20.launcher2.ui.settings.SettingsActivity"
|
||||
)
|
||||
intent.putExtra(
|
||||
"de.mm20.launcher2.settings.ROUTE",
|
||||
"settings/widgets/music"
|
||||
)
|
||||
context.tryStartActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object CalendarWidget : Widget() {
|
||||
override fun loadLabel(context: Context): String {
|
||||
return context.getString(R.string.widget_name_calendar)
|
||||
}
|
||||
|
||||
override fun toDatabaseEntity(position: Int): WidgetEntity {
|
||||
return WidgetEntity(
|
||||
type = WidgetType.INTERNAL.value,
|
||||
data = "calendar",
|
||||
height = -1,
|
||||
position = position
|
||||
)
|
||||
}
|
||||
|
||||
override val isConfigurable: Boolean = true
|
||||
|
||||
override fun configure(context: Activity, appWidgetHost: AppWidgetHost) {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
context.getPackageName(),
|
||||
"de.mm20.launcher2.ui.settings.SettingsActivity"
|
||||
)
|
||||
intent.putExtra(
|
||||
"de.mm20.launcher2.settings.ROUTE",
|
||||
"settings/widgets/calendar"
|
||||
)
|
||||
context.tryStartActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalWidget(
|
||||
var height: Int,
|
||||
val widgetId: Int,
|
||||
val widgetProviderInfo: AppWidgetProviderInfo
|
||||
) : Widget() {
|
||||
override fun loadLabel(context: Context): String {
|
||||
return widgetProviderInfo.loadLabel(context.packageManager)
|
||||
}
|
||||
|
||||
override fun toDatabaseEntity(position: Int): WidgetEntity {
|
||||
return WidgetEntity(
|
||||
type = WidgetType.THIRD_PARTY.value,
|
||||
data = widgetId.toString(),
|
||||
height = height,
|
||||
position = position
|
||||
)
|
||||
}
|
||||
|
||||
override val isConfigurable: Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
widgetProviderInfo.widgetFeatures and AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE != 0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
override fun configure(context: Activity, appWidgetHost: AppWidgetHost) {
|
||||
appWidgetHost.startAppWidgetConfigureActivityForResult(
|
||||
context,
|
||||
widgetId,
|
||||
0,
|
||||
0,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum class WidgetType {
|
||||
INTERNAL,
|
||||
THIRD_PARTY
|
||||
enum class WidgetType(val value: String) {
|
||||
INTERNAL("internal"),
|
||||
THIRD_PARTY("3rdparty")
|
||||
}
|
||||
@@ -1,40 +1,79 @@
|
||||
package de.mm20.launcher2.widgets
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.widgets.R
|
||||
import de.mm20.launcher2.database.AppDatabase
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class WidgetRepository(
|
||||
val context: Context
|
||||
) {
|
||||
interface WidgetRepository {
|
||||
fun getWidgets(): Flow<List<Widget>>
|
||||
fun getInternalWidgets(): List<Widget>
|
||||
fun saveWidgets(widgets: List<Widget>)
|
||||
fun addWidget(widget: Widget, position: Int)
|
||||
fun removeWidget(widget: Widget)
|
||||
fun setWidgetHeight(widget: Widget, newHeight: Int)
|
||||
}
|
||||
|
||||
internal class WidgetRepositoryImpl(
|
||||
private val context: Context,
|
||||
private val database: AppDatabase,
|
||||
) : WidgetRepository {
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
|
||||
fun getWidgets(): Flow<List<Widget>> {
|
||||
return AppDatabase.getInstance(context).widgetDao()
|
||||
override fun getWidgets(): Flow<List<Widget>> {
|
||||
return database.widgetDao()
|
||||
.getWidgets()
|
||||
.map { it.map { Widget(it) } }
|
||||
.map { it.mapNotNull { Widget.fromDatabaseEntity(context, it) } }
|
||||
}
|
||||
|
||||
fun getInternalWidgets(): List<Widget> {
|
||||
return listOf(
|
||||
Widget(WidgetType.INTERNAL, "weather", -1, context.getString(R.string.widget_name_weather)),
|
||||
Widget(WidgetType.INTERNAL, "music", -1, context.getString(R.string.widget_name_music)),
|
||||
Widget(WidgetType.INTERNAL, "calendar", -1, context.getString(R.string.widget_name_calendar)),
|
||||
)
|
||||
override fun getInternalWidgets(): List<Widget> {
|
||||
return listOf(WeatherWidget, MusicWidget, CalendarWidget)
|
||||
}
|
||||
|
||||
|
||||
fun saveWidgets(widgets: List<Widget>) {
|
||||
override fun saveWidgets(widgets: List<Widget>) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).widgetDao().updateWidgets(widgets.mapIndexed { i, widget -> widget.toDatabaseEntity(i) })
|
||||
database.widgetDao()
|
||||
.updateWidgets(widgets.mapIndexed { i, widget -> widget.toDatabaseEntity(i) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addWidget(widget: Widget, position: Int) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.widgetDao()
|
||||
.insert(widget.toDatabaseEntity(position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeWidget(widget: Widget) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val ent = widget.toDatabaseEntity()
|
||||
database.widgetDao().deleteWidget(
|
||||
ent.type,
|
||||
ent.data
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setWidgetHeight(widget: Widget, newHeight: Int) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val ent = widget.toDatabaseEntity()
|
||||
database.widgetDao().updateHeight(
|
||||
ent.type,
|
||||
ent.data,
|
||||
newHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user