Widget picker: Group widgets per app

Close #51
This commit is contained in:
MM20 2022-04-01 22:42:59 +02:00
parent 0d1b6fa33b
commit f1b606d8e4
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
3 changed files with 84 additions and 28 deletions

View File

@ -10,7 +10,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
@ -25,7 +24,7 @@ import de.mm20.launcher2.ui.ktx.toDp
@Composable @Composable
fun AppWidgetList( fun AppWidgetList(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
widgets: List<AppWidgetProviderInfo>, widgets: List<AppWidgetGroup>,
onWidgetSelected: (AppWidgetProviderInfo) -> Unit = {} onWidgetSelected: (AppWidgetProviderInfo) -> Unit = {}
) { ) {
val context = LocalContext.current val context = LocalContext.current
@ -33,8 +32,20 @@ fun AppWidgetList(
LazyColumn( LazyColumn(
modifier = modifier modifier = modifier
) { ) {
items(widgets) { for (group in widgets) {
key(it.provider.toShortString()) { item() {
Text(
modifier = Modifier.padding(
top = 16.dp,
start = 8.dp,
end = 8.dp,
bottom = 8.dp
),
text = group.appName,
style = MaterialTheme.typography.titleLarge
)
}
items(group.widgets) {
LauncherCard( LauncherCard(
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
@ -81,10 +92,6 @@ fun AppWidgetList(
modifier = mod modifier = mod
) { ) {
drawIntoCanvas { drawIntoCanvas {
val aspectRatio =
image.intrinsicWidth / image.intrinsicHeight
image.setBounds( image.setBounds(
0, 0,
0, 0,
@ -106,5 +113,6 @@ fun AppWidgetList(
} }
} }
} }
} }
} }

View File

@ -10,12 +10,16 @@ import androidx.activity.compose.setContent
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import de.mm20.launcher2.ui.MdcLauncherTheme import de.mm20.launcher2.ui.MdcLauncherTheme
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.BaseActivity import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.base.ProvideSettings import de.mm20.launcher2.ui.base.ProvideSettings
@ -27,6 +31,7 @@ class PickAppWidgetActivity : BaseActivity() {
private lateinit var appWidgetManager: AppWidgetManager private lateinit var appWidgetManager: AppWidgetManager
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
widgetHost = AppWidgetHost(this, 44203) widgetHost = AppWidgetHost(this, 44203)
@ -37,6 +42,25 @@ class PickAppWidgetActivity : BaseActivity() {
setContent { setContent {
MdcLauncherTheme { MdcLauncherTheme {
ProvideSettings { ProvideSettings {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(stringResource(R.string.widget_add_widget))
},
navigationIcon = {
IconButton(onClick = { finish() }) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
contentDescription = stringResource(
id = R.string.menu_back
)
)
}
}
)
}
) {
val available by availableWidgets.observeAsState() val available by availableWidgets.observeAsState()
val selected by selectedAppWidget.observeAsState() val selected by selectedAppWidget.observeAsState()
val widgets = available val widgets = available
@ -62,6 +86,7 @@ class PickAppWidgetActivity : BaseActivity() {
} }
} }
} }
}
private fun selectAppWidget(widget: AppWidgetProviderInfo) { private fun selectAppWidget(widget: AppWidgetProviderInfo) {
val appWidgetId = widgetHost.allocateAppWidgetId() val appWidgetId = widgetHost.allocateAppWidgetId()

View File

@ -3,13 +3,23 @@ package de.mm20.launcher2.ui.launcher.widgets.picker
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo import android.appwidget.AppWidgetProviderInfo
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import androidx.compose.ui.text.toLowerCase
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData import androidx.lifecycle.liveData
import de.mm20.launcher2.crashreporter.CrashReporter
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
typealias AppWidgetGroup = Pair<String, List<AppWidgetProviderInfo>>
inline val AppWidgetGroup.appName: String
get() = this.first
inline val AppWidgetGroup.widgets: List<AppWidgetProviderInfo>
get() = this.second
class PickAppWidgetVM : ViewModel() { class PickAppWidgetVM : ViewModel() {
var appWidgetId: MutableLiveData<Int?> = MutableLiveData(null) var appWidgetId: MutableLiveData<Int?> = MutableLiveData(null)
val selectedAppWidget: MutableLiveData<AppWidgetProviderInfo?> = MutableLiveData(null) val selectedAppWidget: MutableLiveData<AppWidgetProviderInfo?> = MutableLiveData(null)
@ -19,11 +29,24 @@ class PickAppWidgetVM: ViewModel() {
this.selectedAppWidget.value = appWidget this.selectedAppWidget.value = appWidget
} }
fun getAvailableWidgets(context: Context): LiveData<List<AppWidgetProviderInfo>?> = liveData { fun getAvailableWidgets(context: Context): LiveData<List<AppWidgetGroup>?> = liveData {
emit(null) emit(null)
val appWidgetManager = AppWidgetManager.getInstance(context) val appWidgetManager = AppWidgetManager.getInstance(context)
val widgets = withContext(Dispatchers.IO) { val widgets = withContext(Dispatchers.IO) {
appWidgetManager.installedProviders.sortedBy { it.loadLabel(context.packageManager) } appWidgetManager.installedProviders
.sortedBy { it.loadLabel(context.packageManager).lowercase() }
.groupBy {
val pkg = it.provider.packageName
val appInfo = try {
context.packageManager.getApplicationInfo(pkg, 0)
} catch (e: PackageManager.NameNotFoundException) {
CrashReporter.logException(e)
return@groupBy ""
}
appInfo.loadLabel(context.packageManager).toString()
}
.toList()
.sortedBy { it.first.lowercase() }
} }
emit(widgets) emit(widgets)
} }