parent
c66f574862
commit
3aa28671a4
@ -47,6 +47,20 @@
|
|||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="de.mm20.launcher2.ui.launcher.LauncherActivity" />
|
android:value="de.mm20.launcher2.ui.launcher.LauncherActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".launcher.widgets.picker.PickAppWidgetActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/title_activity_settings"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:parentActivityName=".launcher.LauncherActivity"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:taskAffinity="de.mm20.launcher2.settings"
|
||||||
|
android:theme="@style/SettingsTheme.NoActionBar">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="de.mm20.launcher2.ui.launcher.LauncherActivity" />
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -8,6 +8,7 @@ import android.appwidget.AppWidgetManager
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -28,6 +29,7 @@ import de.mm20.launcher2.transition.ChangingLayoutTransition
|
|||||||
import de.mm20.launcher2.transition.OneShotLayoutTransition
|
import de.mm20.launcher2.transition.OneShotLayoutTransition
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.databinding.ViewWidgetsBinding
|
import de.mm20.launcher2.ui.databinding.ViewWidgetsBinding
|
||||||
|
import de.mm20.launcher2.ui.launcher.widgets.picker.PickAppWidgetActivity
|
||||||
import de.mm20.launcher2.ui.legacy.component.WidgetView
|
import de.mm20.launcher2.ui.legacy.component.WidgetView
|
||||||
import de.mm20.launcher2.widgets.Widget
|
import de.mm20.launcher2.widgets.Widget
|
||||||
import de.mm20.launcher2.widgets.WidgetType
|
import de.mm20.launcher2.widgets.WidgetType
|
||||||
@ -49,7 +51,6 @@ class WidgetsView @JvmOverloads constructor(
|
|||||||
private lateinit var widgets: MutableList<Widget>
|
private lateinit var widgets: MutableList<Widget>
|
||||||
|
|
||||||
private val pickWidgetLauncher: ActivityResultLauncher<Intent>
|
private val pickWidgetLauncher: ActivityResultLauncher<Intent>
|
||||||
private val configureWidgetLauncher: ActivityResultLauncher<Intent>
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
context as AppCompatActivity
|
context as AppCompatActivity
|
||||||
@ -57,34 +58,14 @@ class WidgetsView @JvmOverloads constructor(
|
|||||||
layoutTransition = ChangingLayoutTransition()
|
layoutTransition = ChangingLayoutTransition()
|
||||||
binding.widgetList.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
binding.widgetList.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||||
|
|
||||||
configureWidgetLauncher = context.registerForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) {
|
|
||||||
val data = it.data ?: return@registerForActivityResult
|
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
|
||||||
bindAppWidget(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pickWidgetLauncher = context.registerForActivityResult(
|
pickWidgetLauncher = context.registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) {
|
) {
|
||||||
val data = it.data ?: return@registerForActivityResult
|
val data = it.data ?: return@registerForActivityResult
|
||||||
val widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
val widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||||
if (widgetId == -1) return@registerForActivityResult
|
if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) return@registerForActivityResult
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
val appWidget = AppWidgetManager.getInstance(context)
|
bindAppWidget(widgetId)
|
||||||
.getAppWidgetInfo(widgetId) ?: return@registerForActivityResult
|
|
||||||
if (appWidget.configure != null) {
|
|
||||||
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE)
|
|
||||||
intent.component = appWidget.configure
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)
|
|
||||||
configureWidgetLauncher.launch(intent)
|
|
||||||
} else {
|
|
||||||
bindAppWidget(data)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
widgetHost.deleteAppWidgetId(widgetId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,18 +212,12 @@ class WidgetsView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
@Suppress("DEPRECATION") // I don't care that neutral buttons are discouraged.
|
@Suppress("DEPRECATION") // I don't care that neutral buttons are discouraged.
|
||||||
neutralButton(R.string.widget_add_external) {
|
neutralButton(R.string.widget_add_external) {
|
||||||
val appWidgetId = widgetHost.allocateAppWidgetId()
|
pickAppWidget()
|
||||||
val pickIntent = Intent(AppWidgetManager.ACTION_APPWIDGET_PICK)
|
|
||||||
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
|
||||||
pickWidgetLauncher.launch(pickIntent)
|
|
||||||
it.dismiss()
|
it.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val appWidgetId = widgetHost.allocateAppWidgetId()
|
pickAppWidget()
|
||||||
val pickIntent = Intent(AppWidgetManager.ACTION_APPWIDGET_PICK)
|
|
||||||
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
|
||||||
pickWidgetLauncher.launch(pickIntent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,9 +228,13 @@ class WidgetsView @JvmOverloads constructor(
|
|||||||
widgetHost.deleteAppWidgetId(id)
|
widgetHost.deleteAppWidgetId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindAppWidget(data: Intent) {
|
private fun pickAppWidget() {
|
||||||
val widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
val pickIntent = Intent(context, PickAppWidgetActivity::class.java)
|
||||||
if (widgetId == -1) return
|
pickWidgetLauncher.launch(pickIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindAppWidget(widgetId: Int) {
|
||||||
|
if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) return
|
||||||
val appWidget = AppWidgetManager.getInstance(context)
|
val appWidget = AppWidgetManager.getInstance(context)
|
||||||
.getAppWidgetInfo(widgetId) ?: return
|
.getAppWidgetInfo(widgetId) ?: return
|
||||||
val widget = Widget(
|
val widget = Widget(
|
||||||
|
|||||||
@ -0,0 +1,110 @@
|
|||||||
|
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.key
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||||
|
import androidx.compose.ui.graphics.nativeCanvas
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
|
import de.mm20.launcher2.ui.component.LauncherCard
|
||||||
|
import de.mm20.launcher2.ui.ktx.toDp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AppWidgetList(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
widgets: List<AppWidgetProviderInfo>,
|
||||||
|
onWidgetSelected: (AppWidgetProviderInfo) -> Unit = {}
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val density = (LocalDensity.current.density * 160).toInt()
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
items(widgets) {
|
||||||
|
key(it.provider.toShortString()) {
|
||||||
|
LauncherCard(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
onWidgetSelected(it)
|
||||||
|
}
|
||||||
|
.padding(16.dp),
|
||||||
|
) {
|
||||||
|
val label = remember { it.loadLabel(context.packageManager) }
|
||||||
|
Text(text = label, style = MaterialTheme.typography.titleMedium)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
|
||||||
|
val image: Drawable? = remember {
|
||||||
|
it.loadPreviewImage(context, density) ?: it.loadIcon(
|
||||||
|
context,
|
||||||
|
density
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image != null) {
|
||||||
|
|
||||||
|
val mod =
|
||||||
|
if (image.intrinsicWidth > 0 && image.intrinsicHeight > 0) {
|
||||||
|
Modifier
|
||||||
|
.heightIn(max = image.intrinsicHeight.toDp())
|
||||||
|
.widthIn(max = image.intrinsicWidth.toDp())
|
||||||
|
.aspectRatio(
|
||||||
|
image.intrinsicWidth.toFloat() / image.intrinsicHeight.toFloat(),
|
||||||
|
matchHeightConstraintsFirst = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Modifier.size(64.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas(
|
||||||
|
modifier = mod
|
||||||
|
) {
|
||||||
|
drawIntoCanvas {
|
||||||
|
val aspectRatio =
|
||||||
|
image.intrinsicWidth / image.intrinsicHeight
|
||||||
|
|
||||||
|
|
||||||
|
image.setBounds(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
size.width.toInt(),
|
||||||
|
size.height.toInt(),
|
||||||
|
)
|
||||||
|
image.draw(it.nativeCanvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isAtLeastApiLevel(31)) {
|
||||||
|
val description = remember { it.loadDescription(context)?.toString() }
|
||||||
|
if (description != null) {
|
||||||
|
Text(text = description, style = MaterialTheme.typography.bodySmall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetHost
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
|
import de.mm20.launcher2.preferences.Settings
|
||||||
|
import de.mm20.launcher2.ui.MdcLauncherTheme
|
||||||
|
import de.mm20.launcher2.ui.base.BaseActivity
|
||||||
|
import de.mm20.launcher2.ui.component.ProvideIconShape
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||||
|
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class PickAppWidgetActivity : BaseActivity() {
|
||||||
|
|
||||||
|
private val dataStore: LauncherDataStore by inject()
|
||||||
|
private val viewModel by viewModels<PickAppWidgetVM>()
|
||||||
|
|
||||||
|
private lateinit var widgetHost: AppWidgetHost
|
||||||
|
private lateinit var appWidgetManager: AppWidgetManager
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
widgetHost = AppWidgetHost(this, 44203)
|
||||||
|
appWidgetManager = AppWidgetManager.getInstance(this)
|
||||||
|
|
||||||
|
val availableWidgets = viewModel.getAvailableWidgets(this)
|
||||||
|
val selectedAppWidget = viewModel.selectedAppWidget
|
||||||
|
setContent {
|
||||||
|
MdcLauncherTheme {
|
||||||
|
val cardStyle by remember {
|
||||||
|
dataStore.data.map { it.cards }.distinctUntilChanged()
|
||||||
|
}.collectAsState(
|
||||||
|
Settings.CardSettings.getDefaultInstance()
|
||||||
|
)
|
||||||
|
val iconShape by remember {
|
||||||
|
dataStore.data.map {
|
||||||
|
if (it.easterEgg) Settings.IconSettings.IconShape.EasterEgg
|
||||||
|
else it.icons.shape
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
}.collectAsState(Settings.IconSettings.IconShape.Circle)
|
||||||
|
|
||||||
|
val favoritesEnabled by remember {
|
||||||
|
dataStore.data.map { it.favorites.enabled }.distinctUntilChanged()
|
||||||
|
}.collectAsState(true)
|
||||||
|
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalCardStyle provides cardStyle,
|
||||||
|
LocalFavoritesEnabled provides favoritesEnabled
|
||||||
|
) {
|
||||||
|
ProvideIconShape(iconShape) {
|
||||||
|
val available by availableWidgets.observeAsState()
|
||||||
|
val selected by selectedAppWidget.observeAsState()
|
||||||
|
val widgets = available
|
||||||
|
if (selected == null) {
|
||||||
|
if (widgets != null) {
|
||||||
|
AppWidgetList(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
widgets = widgets,
|
||||||
|
onWidgetSelected = {
|
||||||
|
selectAppWidget(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectAppWidget(widget: AppWidgetProviderInfo) {
|
||||||
|
val appWidgetId = widgetHost.allocateAppWidgetId()
|
||||||
|
viewModel.selectAppWidget(widget, appWidgetId)
|
||||||
|
configureWidget()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureWidget() {
|
||||||
|
val appWidgetId = viewModel.appWidgetId.value ?: return
|
||||||
|
val widget = viewModel.selectedAppWidget.value ?: return
|
||||||
|
val canBind = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, widget.provider)
|
||||||
|
Log.d("MM20", "Can bind: $canBind")
|
||||||
|
if (canBind) {
|
||||||
|
if (widget.configure != null) {
|
||||||
|
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE)
|
||||||
|
intent.component = widget.configure
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
widgetHost.startAppWidgetConfigureActivityForResult(
|
||||||
|
this,
|
||||||
|
appWidgetId,
|
||||||
|
0,
|
||||||
|
RequestCodeConfigure,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
finishWithResult(appWidgetId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply {
|
||||||
|
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, widget.provider)
|
||||||
|
}, RequestCodeBind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
when(requestCode) {
|
||||||
|
RequestCodeBind -> {
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
configureWidget()
|
||||||
|
} else {
|
||||||
|
viewModel.appWidgetId.value?.let { widgetHost.deleteAppWidgetId(it) }
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestCodeConfigure -> {
|
||||||
|
val widgetId = viewModel.appWidgetId.value ?: return cancel()
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
finishWithResult(widgetId)
|
||||||
|
} else {
|
||||||
|
widgetHost.deleteAppWidgetId(widgetId)
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun finishWithResult(widgetId: Int) {
|
||||||
|
val data = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)
|
||||||
|
setResult(RESULT_OK, data)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancel() {
|
||||||
|
setResult(RESULT_CANCELED)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val RequestCodeConfigure = 1
|
||||||
|
const val RequestCodeBind = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.liveData
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class PickAppWidgetVM: ViewModel() {
|
||||||
|
var appWidgetId: MutableLiveData<Int?> = MutableLiveData(null)
|
||||||
|
val selectedAppWidget: MutableLiveData<AppWidgetProviderInfo?> = MutableLiveData(null)
|
||||||
|
|
||||||
|
fun selectAppWidget(appWidget: AppWidgetProviderInfo, appWidgetId: Int) {
|
||||||
|
this.appWidgetId.value = appWidgetId
|
||||||
|
this.selectedAppWidget.value = appWidget
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAvailableWidgets(context: Context): LiveData<List<AppWidgetProviderInfo>?> = liveData {
|
||||||
|
emit(null)
|
||||||
|
val appWidgetManager = AppWidgetManager.getInstance(context)
|
||||||
|
val widgets = withContext(Dispatchers.IO) {
|
||||||
|
appWidgetManager.installedProviders.sortedBy { it.loadLabel(context.packageManager) }
|
||||||
|
}
|
||||||
|
emit(widgets)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user